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.
3 Answers 3
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.
-
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.R R.– R R.12/19/2017 18:25:00Commented 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.R R.– R R.12/19/2017 20:35:37Commented 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);
.Edgar Bonet– Edgar Bonet12/19/2017 20:56:52Commented Dec 19, 2017 at 20:56
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;
}
-
2It 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.Edgar Bonet– Edgar Bonet12/19/2017 18:23:11Commented Dec 19, 2017 at 18:23
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.
-
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?R R.– R R.12/19/2017 17:42:05Commented 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.Michel Keijzers– Michel Keijzers12/19/2017 17:45:31Commented 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.R R.– R R.12/19/2017 17:49:10Commented 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.R R.– R R.12/19/2017 18:06:23Commented 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.Michel Keijzers– Michel Keijzers12/19/2017 19:40:46Commented Dec 19, 2017 at 19:40
ADC
are from -512 to 511. But It's not possible (supported) byanalogRead()
(note: there is no analogueRead).