ATMEGA328 adc , registors - Page 1
Forum section: electronics / general

author: 0x007
author_rank: Contributor
timestamp: April 29, 2016, 07:09:51 pm
content: Hi everyone !I have a bit of a miss understanding of the way I should address registers on AVRs .I am playing with the mega328p and I just cant understand what the F**** is going on with the registers.I am trying to use the ADC but I can't understand how to initialize the registers , I seen some code examples and they all look like this:ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADEN); , why?why can't it look like a normal register setup :"ADCSRA = 0x7f;", obviously it is not working for me....I can copy it all like an idiot but I want to understand why I should declare it like this :ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADEN);sorry if this is confusing , I am really frustrated .can someone explain this?

author: firewalker
author_rank: Super Contributor
timestamp: April 29, 2016, 07:31:33 pm
content: Bit mathematics.http://playground.arduino.cc/Code/BitMathAlexander.

author: MatthewEveritt
author_rank: Unknown
timestamp: April 29, 2016, 07:34:17 pm
content: Haha, the idea is to make it easier to understand! You absolutely can just set a hex constant, if that's what works for you.What the example is doing is constructing the constant by shifting (<<) a 1 over to the specified position, so for example including (1<<ADEN) means turn on the adc enable bit. The binary or (|) combines the selected bits into a single byte. The |= then updates the register, without upsetting what's already there. You can use = to set it exactly if that's what you need.

author: sleemanj
author_rank: Super Contributor
timestamp: April 29, 2016, 11:46:52 pm
content: Quote from: MatthewEveritt on April 29, 2016, 07:34:17 pmHowever, consider that if you should move to a different chip which is close-but-not-quite the same as the one you developed on that by using a hex constant you are hardcoding to that specific chip and also making it hard to do a search across your codebase for instances where you are fiddling a bit.Using the named bits is a better idea generally.If the bit-shifting irritates, you can use the _BV() macro.ADCSRA |= _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0) | _BV(ADEN);

author: retrolefty
author_rank: Super Contributor
timestamp: April 30, 2016, 12:47:04 am
content: Quote from: 0x007 on April 29, 2016, 07:09:51 pmUsing register names instead of hard coded HEX values allow better portability between models of AVR. The 'names' get automatically converted to the approprate HEX values by the build tools supplied.

author: Psi
author_rank: Super Contributor
timestamp: April 30, 2016, 01:29:01 am
content: It's just a way to easily change some of the bits to turn a feature on/off without effecting other bits.It all makes perfect sense once you understand Bit mathematics in C.Its not that complicated, it just looks like it.Its well with sitting down and figuring out whats happening.

author: FreddyVictor
author_rank: Regular Contributor
timestamp: April 30, 2016, 07:35:37 am
content: Quote from: 0x007 on April 29, 2016, 07:09:51 pmand what the heck does that do?oh well, it's off to the datasheet...Quote from: 0x007 on April 29, 2016, 07:09:51 pmoh right, sets pre-scaler bits 0,1 + 2 and then enables it

author: 0x007
author_rank: Contributor
timestamp: April 30, 2016, 07:55:33 am
content: ah, ok that's explains it, I see now it makes sense.It drove me nuts because I am not used to it, I learnd mcu programming thru 8051 chips they are much more straight forward(and don't have as much registers).Thank you very much, I'll try to implement this knowledge now but I have one little question :I want to use adc channel 0 of the atmega328p chip, I need to do the next:1. hook up the lead to the 23rd pin of the chip.2. feed ADMUX register 0 , because I am using the channel 0 and the external reference.3. set ADCSRA to ADEN=1,ADSC=0(not starting conversion yet),ADATE=0,ADIF=(leaving it alone),ADIE=0,ADSPS = 011(it doesn't meter set the clock to/8).4. when I want to start a conversion I ADSC to 1 and whit for ADIF to become logic 1.5. then I read the ADCL and ADCH registers ,int val=0, val|=ADCL, val<<=4,val |=ADCL.Am I correct ?and I don't quite get how DIDR1 and DIDR0 effect the adc?

author: old gregg
author_rank: Regular Contributor
timestamp: April 30, 2016, 10:56:34 am
content: DIRD0 is the register to disable the hardware logic circuitry of the D port. You can use it to reduce power consumption while using the ADC (cf p.252 datasheet).ADMUX shouldn't be 0, only the last 4 bits significate the channel you're using. ADMUX also sets the reference voltage.take a look at this series of video they're very nice :https://www.youtube.com/playlist?list=PLE72E4CFE73BD1DE1

author: 0x007
author_rank: Contributor
timestamp: April 30, 2016, 04:21:08 pm
content: I maneged to get it working, but for some reason in order to take a reading I need to reset the chip each time .this is the function:Code:int ADC_get(){unsigned int AVal=0;ADMUX = 0x40;ADCSRA = 0xc5;Delay_ms(8);while(!ADIF);AVal|=ADCH,Aval<<=8,Aval|=ADCL;return AVal;}and for some reason it wont work with out the delay .long story shortwhat have I done wrong ?

author: PeterFW
author_rank: Frequent Contributor
timestamp: April 30, 2016, 04:52:54 pm
content: Quote from: 0x007 on April 30, 2016, 04:21:08 pmYou do not give the µC time to finish the conversion, check the ADSC bit in the ADCSRA register wich gets cleared after the conversion is finished in single conversion mode, if you do not use free running:while(ADCSRA & (1<<ADSC));Alternatively, flash the arduino bootloader on the chip and use the Arduino IDE wich spares a lot of trouble and grief at the expense of code size.

author: mikerj
author_rank: Super Contributor
timestamp: May 01, 2016, 07:30:20 pm
content: Quote from: PeterFW on April 30, 2016, 04:52:54 pmThe OP is trying to poll the ADIF bit to check for end of conversion which can be done (though polling ADSC is easier overall), but there are two problems:1) ADIF is a bit position, not a register, so while(ADIF) will always be true.2) ADIF must be cleared by software after it's set.If you want to use ADIF for a particular reason, something like this should work */Code:int ADC_get(){ADCSRA |= _BV(ADIF); /* Clear the ADC interrupt flag by writing a '1' to the bit */ADMUX = 0x40;ADCSRA = 0xc5;while( (ADCSRA & _BV(ADIF)) == 0x00 ); /* ADIF will be set when conversion has completed *//* ADCW is a 16 bit pseudo register which reads the ADC bytes in the correct order.Works in (at least) GCC, IAR, ImageCraft, Rowley and Codevision compilers */return ADCW;}

author: Neverther
author_rank: Regular Contributor
timestamp: May 01, 2016, 08:00:40 pm
content: I had the same, one conversion and second one did not work.I noticed is that the example for reading ADCH and ADCL separately did not work for some reason. Use the ADC/ADCW instead as it will get it right (I guess gcc optimizer or something broke it?). With that change my code worked.It is supposed to read low byte first, that will lock the registers and they can be written only when the high byte is retrieved.Read high first, then low = the registers are locked and new conversions wont save.

author: dannyf
author_rank: Super Contributor
timestamp: May 01, 2016, 08:06:43 pm
content: Code:AVal|=ADCH,Aval<<=8,Aval|=ADCL;I would doCode:AVal = ADC;orCode:AVal = (ADCH << 8) | ADCL;Faster ways exist.

author: Neverther
author_rank: Regular Contributor
timestamp: May 02, 2016, 05:51:50 am
content: Quote from: dannyf on May 01, 2016, 08:06:43 pmThis type of assigment was the one that failed for me.

author: mikerj
author_rank: Super Contributor
timestamp: May 03, 2016, 10:30:06 am
content: Quote from: dannyf on May 01, 2016, 08:06:43 pmADC does not exist as a virtual register in all compilers, primarily because of potential conflict with the ADC instruction. ADCW does and is the preferred solution.Quote from: dannyf on May 01, 2016, 08:06:43 pmBearing in mind that the registers need to be read in a specific order this has no guarantee of working, and no guarantee of the same behaviour across different compilers or even compiler versions. Not a good solution in this case.