NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.
Microcontroller Programming » Analog to Digital Conversion
April 23, 2012 by jlaskowski |
I don't quite understand how to interpret the digital value returned from the analog-to-digital conversion. I understand it's a number from 0 to 1023, and I sense that what it actually means is dependent upon the reference voltage, but I don't know the relationship exactly. Would someone please explain the relationships? Does it only return voltages between 0 and the reference voltage? |
---|---|
April 23, 2012 by Ralphxyz |
For a reference using the Nerdkit Temp Sensor project connect PC0 to GND(-) what do you get? Then connect PC0 to VCC(+) now what do you have? So now you see the full range of ADC values. You can also use a potentiometer with the wiper to PC0 to see varying readouts proportional to wiper voltage. Then best to spend some time with the mcu specsheet in the ADC Section 23.
Ralph |
April 23, 2012 by jlaskowski |
So, it can't convert voltages less than 0 or greater than VCC? |
April 23, 2012 by Ralphxyz |
correct, well the reference voltage might not be 5 volts. I am not sure if it may be > 5 volts I'll have to check the specsheet. I am sure it can be < 5 volts. Ralph |
April 23, 2012 by jlaskowski |
In case someone else was looking for a simple explanation of the relationship between the input voltage, reference voltage, and digital value produced by the converter, I found this statement in the article, ABCs of ADCs: An ADC has an analog reference voltage or current against which the analog input is compared. The digital output word tells us what fraction of the reference voltage or current is the input voltage or current. So, basically, the ADC is a divider. So, input_voltage = (conversion_result / max_conversion_values)) * reference_voltage. In the Atmel chip that comes with the USB Nerdkit, the result comes in 10 bits, so the max_conversion_values is 1024. |
April 23, 2012 by jlaskowski |
Thanks, that's good to know, Ralph. In that case, I won't expect to use it to test the 120V AC from the outlet (without seriously stepping down the voltage)! |
April 23, 2012 by Ralphxyz |
I do not believe you can use AC. Ralph |
April 24, 2012 by Tyron |
Ralhxyz, Not to change the subject, even though I am in the first few program blocks regarding the ADC for the Temperature Sensor project. Quick-fast curiosities that I need explained; in the first program block-page 50, there are two OR symbols "|", one following the "//" in the second comment line. The other is in the last command line of the first program block, ADCSRA |= (1<<ADSC). Moreover, there is also another (ADCSRA |= (1<<ADSC)) at the end of the second program block--page 51. The last thing I wish exprained is the, correct my nomenclature if needed, "typedef" ( _t ) following the function, uint16. I am trying to follow Nerdkit's admonition to back-ground study instead of just copy/paste-ing text. Regards, Tyron |
April 24, 2012 by Ralphxyz |
Tyron, I do not understand your question. Here is the first block of code please be more specific in exactly what you are asking.
Ralph |
April 24, 2012 by 6ofhalfdozen |
Tyron, I believe the first "or" you mention is the cursor in the screen cap the NK guys used for the manual. There is no reason to put an "or" there and it does look a little scrawny and offset for a true "or". So for the first, it is an oops and not a valid character. As for the second, it makes the "=" become something else, a bitwise Or. If you read on in the manual, there is more mentioned about those in pages 57-63 and later on during the bitwise arithmetic project. As for the "_t", no clue. never figured that one out... |
April 24, 2012 by jlaskowski |
Tyron, Your first question is regarding this in the PDF:
The OR symbol after the comment in the second line is a typo, it is part of the comment and does nothing. Though shown in the PDF, it doesn't exist in the downloaded code. The second OR symbol that you are asking about is in this line of code:
This is actually a special C-operator that does OR and assignment in one shorthand operator. Thus, it is equivalent to this:
|
April 24, 2012 by jlaskowski |
As far as uint16_t, it is not a function, but a return type for the function and you'll see it used throughout the code. uint16_t is actually an alias for the type, "unsigned int." When you download the development environment and the sample code, the C header file, stdint.h, which is under avr/include/ (in the development environment installation directory, not the sample code directory) has the following line:
This simply says that instead of typing "unsigned int" a lot through your code, you can shorthand it for uint16_t. The uint part tells you that it's an unsigned integer, the 16 tells you that the complier, when compiling for this chip, will make unsigned ints 16-bits. I believe the "_t" is a naming convention for "type". So, uint16_t is a 16-bit, unsigned integer type. |
April 25, 2012 by Tyron |
Thank You All, I will look over, in depth, all your responses. I like what I see just skimming through it. You know , just blo'n off steam here, I got to say, the Blogisphere, what a rats nest. Unless you work in the bowels of Bell Labs or Motorola, how does anyone get a clear, non-conflicting answer from anybody. Is C programming actually C programming or what? Or does it change from day to day? Is it me, or is it a case of "more than one way to skin a cat"? Feel free to offer an "Intro to C" that is considered "good and applicable", by most of the programming community. I'm actually starting to fear my OWN questions. Again, Thank You for your interest and support!!!! Tyron |
April 26, 2012 by hevans (NerdKits Staff) |
Hi Tyron, There are many beginners that get this same feeling of frustration when first starting out with hardware programming. I think most of the conflicting answers you get come not from the fact that C itself is evolving or changing from day to day, but from the fact that it is used to run so many different embedded devices out there and each of them interfaces in a slightly different way. There really isn't such a thing as "good and applicable" to all of embedded programming because that book would take several years to read. That is why our approach is to try and start you off with some of the basics and try to support you and our community as you explore other facets of embedded programming that you are interested in. Keep on asking great questions, and most importantly don't give up! Humberto |
April 29, 2012 by Tyron |
Hey Humberto, What you say seems to be the only reasonable explanation. Since I'm at the terminal, let me ask a couple of questions. On page 51, regarding the "while loop" command line, two braces "{}" are containing a comment: // do nothing... just hold your breath. Are these braces "{}" there as part of the "subroutine" of the "while loop", or for some other reason? The other question is a little more involved. Back to page 50; specifically, the ADCSRA command line that ORs several bits of that register. Now in the center page explanation bubble, there is explained the need to create four individual binary numbers, and then OR-ing these four individual binary numbers that represent bits already in that particular register. Jumping to conclusions: Does this mean that the controller is assessing all seven bits of that register, first, before giving a "result" for that register? How should I interpret? Spanx, Tyron |
April 30, 2012 by hevans (NerdKits Staff) |
Hi Tyron, The two braces are part of the syntax for the while loop. That is just how while loops are written.
I don't really understand your second question. Perhaps you are getting confused about the use of ADEN,ADPS2, etc. On that line the only thing that is a real register on the chip is ADCSRA. We are setting the ADCSRA register to a number of our choosing. Depending on which bits of the ADCSRA register we set, the ADC will be have differently. The number we create on the right hand side of the equal sign is just a number, the ADEN,ADPS2 etc are just variables that stand for the bit positions of those particular bits. Humberto |
May 02, 2012 by Tyron |
Thax Humberto, That's what I thought regarding the "while loop". Just needed validation. Thanks again, Tyron |
May 02, 2012 by pcbolt |
Tyron - I know Humberto could answer this better than I could but if he doesn't get a chance to answer right away I can give it a shot. When you asked "would not =(s) work?", the answer is yes equals would work. We could set the register ADCSRA equal to 10000111 in a couple of different ways like...
So yes there are many ways to skin the ol' cat. But if you look at the 4 statements, the one that is most informative to what you are actually trying to accomplish is the first one. You can tell right away you set the enable ADC bit (ADEN), and the 3 "prescaler" bits (ADPS 2,1,0). When you're in the trenches writing code you may not care, but if you need to debug it months later you'll be glad to took the time to spell things out. As far as using the AND statement, that won't work in this case. If you AND them all together you'll just get 00000000. Here's some things to keep in mind when dealing with bit-wise operators:
I know it looks strange, but believe it or not these are actually shortcuts. |
May 03, 2012 by Rick_S |
The reason to use the OR logic is to change only the registers (bits in the byte) we want to change without effecting the other bits in that byte. Using equality logic works fine as long as your goal is to set every bit to a certain state. For instance, Lets say you want to use the Analog to digital coverter. The ADCSRA register is a prime example of where you probably would not want to use equality. The reason being, there are 8 bits in that register that effect the settings of the ADC. One of those bits (ADSC) actually starts a conversion. If you look at the tempsensor project, you'll see a line that does the setup of the ADC
Then a couple of lines after you see this line:
So in the first line they use logical OR to "create" the Byte. They then assign that byte (with the equal sign) to ADSRA. Then however, a single bit in that byte needs toggled on to start a conversion. That is when using OR comes in handy. Because by OR'ing (1<<ADSC) (remember ADSC is equal to 6 as defined in the includes) you only turn on bit 6 in that byte leaving all the configuration bits alone. Rick |
May 03, 2012 by Tyron |
Rock on fellas, This is the kind of detail I'm looking for. I think I am what you call a "bottom-up" learner. So, it's hard for me to just do something, "because that's the way we do it". Only to be given the explanation a couple years later, like mathematics. And besides, what you've given me, I will have some homework to do-I like that. Someday, I'll get this temperature sensor running. Again thanks for the quick responses, Tyron |
May 04, 2012 by Ralphxyz |
Tyron, just so you'll not feel alone, try searching the forum for ADCSRA this is probable one of the most common (repeated) questions here. But it's good each time I read it it gets closer to actually sinking in. Ralph |
May 30, 2012 by Tyron |
Hey Ralph, I'm still working on the temp sensor programming. I checked the blogisphere regarding "The While Loop". I understand the protocol, while ( condition ){}, and as long as the condition remains true, the code block that follows,continues. I "read" the statement, "while(ADCSRA & (1<<ADSC))", as follows: "WHILE" the ADCSRA register is ONE--AND--ADSC is ONE(on), the conversion continues. The confusion is, if we're to put the "operand" ADCSRA in the condition without its own operator, unlike 1<<ADSC. Does the C protocol for while loops let us assume ADCSRA is ONE? Moreover, why could we not write (1<<ADSC) as (1=ASDC)? In this statment, how would you explain "<<"? Let me refine my question(s): CONNOTATIVELY, how would you describe, or state, this condition to the layperson? As a programmer, how would you deduce to state it this way? REGARDS, Tyron |
May 30, 2012 by Ralphxyz |
Ok, here is a test "what the heck does 1<<ADSC mean or do"? Hint: ADCSRA is a register not an operand (of course my recollection of operand is rather rusty). Ralph |
May 30, 2012 by pcbolt |
Tyron - It would be more accurate to say that as long as the expression within the parenthesis of the "while" statement IS NOT zero, continue with the loop. In other words you could write:
In the statement:
...you are not using the logical compare AND statement which is &&, you are using a bitwise AND operator which is a single &. If you wanted the condition you described above, namely, ""WHILE" the ADCSRA register is ONE--AND--ADSC is ONE(on)", you would have to write it like this:
The statement;
...will read as "Take the contents of register ADCSRA, bitwise AND it with the number 1 shifted left ADSC number of places (6 places in this case) and if the result is anything but zero, keep on looping". When the ADC conversion is taking place the 6th bit in ADCSRA will be 1. We don't really know what the other bits are so we need an easy way to ask "If bit 6 in ADCSRA is 1, stay inside the while loop and do nothing". So without going into some ugly "for loops", we take the number 1 (which is 00000001 in binary) shift it over 6 places to get 01000000, then bitwise AND it with ADCSRA. If ADCSRA is x1xxxxxxx (where "x" can be either 1 or 0) and we bitwise AND it with 01000000 we would get 01000000 as a result no matter what the x's are. It's important to note here that the result is not 1 but actually 64 in decimal. If ADCSRA is x0xxxxxx, the result would be 00000000, and we would not execute the while loop. |
May 30, 2012 by pcbolt |
Oh Tyron one other thing, the symbol ADSC isn't the value in the ADC register, it is only a substitution for the number 6. It is an easy way to remember where the "Start Conversion" bit placement is inside the ADCSRA register. It is actually defined when you placed "include <avr/io.h>" in your program. That file calls up another called "iom168p.h" where you'll find this:
So every time the compiler sees ADSC it hard copies "6" in it's place. |
May 31, 2012 by Ralphxyz |
pcbolt said:
Which is correct, BUT when one asks why is ADSC the number 6 you have to go to the ATmega168 specsheet. 23.9.2 ADCSRA – ADC Control and Status Register A There has to be a reason why ADSC is 6.
It's funny I, not being a programmer, always think of the specsheet first and rarely, if ever, think of referencing avr/io.h and iom168p.h. But pcbolt being the programmer that he is always has this logical programming perspective which I only wish I could develop. When I see 1<<ADSC I do not see move 1 over 6 places to the left I see move one over to the place of the ADSC bit in the ADCSRA register. I think 6 places to the left would probable be easier to grasp but it doesn't tell you why. One could go through life just thinking ADSC means 6 and never have to get confused reading the specsheet. pcbolt I really appreciate your explanations. Like your explanation above it really makes sense, thank you. Ralph |
June 01, 2012 by Tyron |
OMG pcbolt, I am giddy as a school girl, but haven't a clue what you and Ralph have just explained. I can tell, however, that it is "rudimentary" and gets at the heart of what's going on in there!! This opens up A huge adventure; better knowing what or how the questions should be asked to gain a little more understanding. Most information out there is to abstract or presumptuous, and maybe a little secret-squirrel. For example, "<<" as far as I have seen, has always meant "left-shift"---Now it makes sense, supports the context, and it still means "left-shift", by your explanation. Small but HUGE!! Thanks for your patience, time, and effort (All you guys)! True product support, not the electronics part--the learning part. Best Regards, Tyron |
December 07, 2012 by cadiz1 |
// PIN DEFINITIONS: // // PC0 -- temperature sensor analog input void adc_init() { // set analog to digital converter // for external reference (5v), single ended input ADC0 ADMUX = 0; // set analog to digital converter // to be enabled, with a clock prescale of 1/128 // so that the ADC clock runs at 115.2kHz. ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // fire a conversion just to get the ADC warmed up ADCSRA |= (1<<ADSC); } Hi Everyone , The above code is a function definition. where is the function declaration(prototype) ? Thanks Cadiz |
December 07, 2012 by Ralphxyz |
I do not believe prototypes are "required" in C but if you wanted to add one they would go before
or in a library. Ralph |
December 07, 2012 by cadiz1 |
Hi Ralph, Thanks I am pretty sure you do need them, all the C books I have explain this. They must be declared in some other file. I was also trying to find where uint16_t comes from. Cadiz |
December 07, 2012 by Noter |
A prototype is not necessary if a function declaration precedes usage of the function in the source file. Any function that is called anywhere in the source must already be declared if you do not want to use prototypes. Since functions that are in external objects or library's are not defined anywhere in your source, their prototypes are usually in an include file. Sometimes I prototype my local functions and put them after main() and other times I'll just declare them before my main() and forego the prototyping. |
December 08, 2012 by cadiz1 |
Hi Noter, I am in agreement with what you have stated. There seems a little confusion. A function prototype is the same as a function declaration. From Using borland c++ . A function declaration(also called the function prototype) tells the compiler about the function. |
December 08, 2012 by Noter |
I am probably confused on the terms. What I mean is if you place your function above where you call it in the source you don't need separate prototypes. |
December 08, 2012 by cadiz1 |
New problem. I am confounded. The adc_read() function is used in the trafficlight.c program. I cannot find the function definition in any of these files below. These header files should have this information. I did a search through all of them. where is the compiler picking up the function from? include <stdio.h> include <math.h> include <avr/io.h> include <avr/interrupt.h> include <avr/pgmspace.h> include <inttypes.h> include "../libnerdkits/delay.h" include "../libnerdkits/lcd.h" include "../libnerdkits/uart.h" |
December 08, 2012 by esoderberg |
Cadiz1, The function is defined right in the traffic light code:
|
December 09, 2012 by cadiz1 |
Thanks esoderberg your right ! It is there and used in the tempsensor and the trafficlight programs. I should have asked where is the function declaration for this function? Thanks Again |
December 09, 2012 by cadiz1 |
I just had a look at the delay.c ,lcd.c and uart.c, the functions inside . The delay.h, lcd.h and uart.h contain the function declarations. This makes sense. Now I have to track down the declarations for the adc_init() and adc_read(). |
December 09, 2012 by Noter |
adc_init() and acd_read() are not prototyped anywhere. Prototyping is not required if the function is defined before it is used. |
December 15, 2012 by cadiz1 |
Hi Everyone, Suppose ADCSRA is a 8 bit register. I put 11011010 into ADCRSA. Then I do : ADCRSA &= ~(1 << 3); I NOT bit 3 and then AND with 1101010(ADCSRA). This is how I read it. Am I correct? |
December 15, 2012 by cadiz1 |
2nd Version I think I made a mistake. Although the result will be the same. ADCRSA &= ~(1 << 3) translation : I set bit 3 to 1 , then NOT bit 3 (0), then AND. This way bit 3 is always cleared. |
December 15, 2012 by sask55 |
This is the way I think of the statement NOT involves the entire 8 bit byte. each of the bit values in the byte are changed ~ 11001100 = 00110011 OR and AND involve all 8 bits in two bytes and will result in a third byte value. In order to use NOT or OR I will require two bytes. To clear any bit location in a byte we can use the AND statement, because a zero bit AND anything will always produce a zero. So xxxxxxxx the bit values of x may be unknown AND 01000100 A bit mask to clear the bit values in bit locations that contain a zero Is 0x000x00 The resulting byte To set any bit location in a byte we can use the OR statement, because a one bit OR anything will always produce a one. So xxxxxxxx the bit values of x may be unknown OR 01000100 A bit mask to set the bit values in bit locations that contain a one Is x1xxx1xx The resulting byte To clear a specific bit in the byte ADCRSA we will require the correct bit mask byte. If we want to clear the bit value in bit location 3 we will require a bit mask byte where the value in bit location 3 is zero and all the other bit values are one. That is 11110111 To produce the bit mask we can use shift and NOT. In this case decimal 1 is binary 00000001 (1<<3) is shift 1 to the left 3 times resulting in binary 00001000 ~(1<<3) is NOT(00001000) resulting in 11110111 Those two operations produce the correct bit mask. ADCRSA &=~(1<<3); is shorthand for ADCRSA = ADCRSA AND NOT (00000001 shifted left three times) if ADCRSA = 11011010 and ~(1<<3) = 11110111 ADCRSA 11011010 AND 11110111 Resulting 11010010 this byte value in placed back into ADCRSA The value in bit location 3 is cleared all other bit locations remain as they where in ADCRSA before the AND. I am not certain this explanation will make things any clearer. |
December 15, 2012 by sask55 |
Hi cadiz1 Just a suggestion for next time you may be asking about something. I just noticed now that your question is not really related to this thread. You should have started a new thread with your question. Darryl |
December 18, 2012 by cadiz1 |
Hi sask55, Thanks for your very good explanation. I posted a question regarding bit shifting now in another thread. It is unanswered. I tried and tried but couldn't get how 11011010 &=~(1<<3) = 11010010.
my result was 110110010. Tonight I noticed your line. ADCRSA &=~(1<<3); is shorthand for ADCRSA = ADCRSA AND NOT (00000001 shifted left three times) There it is ! You started with 1 at bit location 0. when I did the bit shift (1<<3) 1st shift = 00000001 , 2nd shift= 00000010. 3rd shift =000000100 . I should be 00001000 . I will check the other exercises Thanks a billion |
December 18, 2012 by Rick_S |
The reason (1<<3) is 00000001 shifted left 3 times is because 00000001 binary = 1 decimal = 01 Hexadecimal. The statement could just have as easily said (0b00000001 << 3) or (0b00000001 << 0b00000011) or (0x01<<0x03). In AVR-gcc, Decimal numbers need no prefix to be used literally. Binary has a 0b prefix and Hexadecimal has the 0x prefix. Rick |
Please log in to post a reply.
Did you know that 20 LEDs can be controlled from 11 microcontroller pins, to make a twinkling heart outline? Learn more...
|