0

Explanatory Comment: The ADC conversion result is a 10 bit number and is placed in two 8 bit registers: ADCH & ADCL. AnalogueRead() reads the output of the ADC. This, I believe is an unsigned number. But, generally taken as only a positive number.

I'm interested in what changes, if any, take place to the number (in it's representation, interpretation, or construction or whatever) when analogueRead() reads the number and presumably makes something of it, or sends it or stores it somewhere.

asked Dec 19, 2017 at 17:25
1
  • In other variants, like Mega, there is a possibility to configure ADC to measure differential value between two channels. In this case, the values insife of ADC are from -512 to 511. But It's not possible (supported) by analogRead() (note: there is no analogueRead). Commented Dec 19, 2017 at 17:59

3 Answers 3

2

There is no change in representation. analogRead() reads two I/O registers, ADCL and ADCH, which on the Uno are memory-mapped to addresses 0x0078 and 0x0079 respectively. It returns the result in a register pair, r24 and r25, which per the AVR C calling conventions is the standard way of returning a 16-bit number. Thus, r24 holds the value read from ADCL, and r25 the value read from ADCH. That's it. No conversion whatsoever.

There is a change in interpretation... of sorts. The function is declared as returning an int, which on the AVR is a 16-bit signed integer, whereas it could be argued that the I/O registers contain an unsigned number. However, since the sign bit will always be zero, the signed/unsigned distinction is moot: either way the result will be interpreted as a number between 0 and 1023.


Edit: As a clarification: the ADC register (which is another name for the ADCL/ADCH register pair) is a 16-bit I/O register. At the end of a conversion, it holds the 10-bit result right-adjusted into this 16-bit space, zero-padded on the left, as follows:

-------- ADCH --------- --------- ADCL --------
0 0 0 0 0 0 r9 r8 r7 r6 r5 r4 r3 r2 r1 r0
----------------- ADC (16 bits) ---------------

where the bits r9..r0 represent the 10-bit conversion result. Since the MSB is zero, it is irrelevant whether you interpret it as a sign bit or as a regular unsigned bit.

Just for completeness, it could be noted that it is possible (though not through the Arduino core library) to configure the ADC to left-adjust the result, as follows:

-------- ADCH --------- --------- ADCL --------
r9 r8 r7 r6 r5 r4 r3 r2 r1 r0 0 0 0 0 0 0
----------------- ADC (16 bits) ---------------

In this case, the MSB could be one, at it would obviously be incorrect to interpret it as a sign bit.

As a side note, the avr-libc defines ADC as (*(volatile uint16_t *)(0x78)), which is unsigned. And it makes sense considering that, unlike the users of Arduino core, the users of avr-libc are supposed to know they have the choice to get a left-adjusted result.

answered Dec 19, 2017 at 17:48
3
  • What I am understanding, is that the number in ADCH & ADCL (put together) is a 10 bit number. Unless it's held to be a 16 bit number because the register is 16 bits. Although that does not sound convincing to me. There is no sign bit in the ADC result register. But, an int store is 16 bit number. And the MSB is signed. That change from 10 bit to 16 bit, and unsigned to signed, seems to represent a change of some nature. Maybe on a practical level, no difference, but on the level of theory - a change. Commented Dec 19, 2017 at 18:25
  • As I understand, it is nicely convenient that analogueRead() returns a 16 bit number, when reading a 10 bit conversion result, because there is then space for the sign bit. And I'm pretty sure whether the conversion result is left or right adjusted the MSB in int, will be a sign bit. A zero. Commented Dec 19, 2017 at 20:35
  • @RR.: You wrote: "I'm pretty sure whether the conversion result is left or right adjusted the MSB in int, will be a sign bit. A zero." Not necessarily a zero if left-adjusted. Try this: Serial.begin(9600); PORTC|=_BV(PC0); ADMUX=_BV(REFS0)|_BV(ADLAR); ADCSRA=_BV(ADEN)|_BV(ADSC)|7; loop_until_bit_is_clear(ADCSRA,ADSC); Serial.println((int)ADC);. Commented Dec 19, 2017 at 20:56
1

It doesn't change anything, it just combines the two 8-bit register values to one 16-bit integer.

You can just look it up in the source code for analogRead.

int analogRead(uint8_t pin)
{
 uint8_t low, high;
[...]
 // we have to read ADCL first; doing so locks both ADCL
 // and ADCH until ADCH is read. reading ADCL second would
 // cause the results of each conversion to be discarded,
 // as ADCL and ADCH would be locked when it completed.
 low = ADCL;
 high = ADCH;
[...]
 // combine the two bytes
 return (high << 8) | low;
}
answered Dec 19, 2017 at 17:33
1
  • 2
    It is worth noting that this part of the code could be written more succinctly as return ADC;. The way it is actually written is inspired by the Atmel datasheets, which were probably written in ancient times, when gcc did not know how to properly handle 16-bit I/O registers. Commented Dec 19, 2017 at 18:23
0

I assume you mean AnalogRead, see AnalogRead.

What it effectively does is mapping 0 to 5V to values 0 to 1,023. The unit is thus 5/1,024 V. What this number means depend on the ADC used.

Probably the two bytes (ADCH as most significant bits and ADCL as least significant bits) contain this 0-1,023 value.

answered Dec 19, 2017 at 17:32
5
  • But, analogueRead() returns an int. Which is a 16 bit number, and the first bit is signed. Is that not a change in the original unsigned number? Commented Dec 19, 2017 at 17:42
  • It is indeed a 16 bit (signed) number. But according to the documentation it only returns values from 0 to 1,023. AnalogRead could also be have an uint(32) or uint(16) as return variable, but probably for novice users a 'simple' int is chosen. So there is no need to change the original unsigned number. an unsigned 16 bit value perfectly fits in an integer type. Commented Dec 19, 2017 at 17:45
  • The way I am looking at things, as a novice, is that analogueRead() has taken an unsigned 10 bit number, and stored it (by way of default action) as a 16 bit signed number. And so, my answer to the question I posed (short form) would be yes. Commented Dec 19, 2017 at 17:49
  • Oh, I see that folks see the number is ADCH & ADCL, as a 16 bit number, even though it's only holding a 10 bit result. So, it's not as if a 10 bit number is being turned into a 16 bit number. Commented Dec 19, 2017 at 18:06
  • True ... like e.g. the max value 1,023 is in binary 0000 0011 1111 1111 (16 bits) where ADCH is probably the first 8 bits and ADCL the last 8 bits. Commented Dec 19, 2017 at 19:40

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.