Accurate voltmeter (or could be renamed : uC's ADC ... State of the art)

Is this Arduino ?

long readVcc() { long result; // Read 1.1V reference against AVcc
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert while (bit_is_set(ADCSRA,ADSC));
result = ADCL; result |= ADCH<<8;
result = 1125300L /result; // Back-calculate AVcc in mV return result; }

I know I'm not very good, but these ADMUX and ADSRA stuff have something to do with ATmega register.
I don't understand all these "_BV(MUX3)", "|" and "|=" signs.
I think, they belongs to C language...

I stuck to understand these part of the code.

But my problem is the guy is programming in C I think, not in ARDUINO.
And I can't understand this hard stuff.
Would be somebody able to explain (put a lot of comment for each line) or do the same but in Arduino instead of raw C.

I guess for the uninitiated world they will always consider that arduino is some different unique "programming language". One programs an arduino in C/C++ using the well known open source gcc compiler. The fact that the arduino comes with many many functions that perform useful stuff on the avr chip does not make it none standard C/C++. One if free not to utilize any of the standard supplied arduino functions and create there own. The main deviation for using C/C++ on a typical PC platform is that the arduino IDE supplies a main() function in which if wraps your sketch functions into and it also builds and needed function prototypes automatically for you, for all the functions you create in your sketch.

Well I'm not sure I did express myself correctly.

In fact I copied/paste the code in my arduino IDE but the code is slightly different from place to place (different links).
I'm using a Mega and I need the code with the

#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
    ADMUX = _BV(MUX5) | _BV(MUX0);
  #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
    ADMUX = _BV(MUX3) | _BV(MUX2);
  #else
    ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #endif

piece of code to properly configure my own Mega ADMUX.

That is the problem copying code without understanding it ! It can lead to serious mistake !

One more question by now.
What means thix line

result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000

I wonder where the "1125300L" come from ?
On an other link, it changes to "1126400L"
I think it has something to do with the real voltage of the internal reference measured with an external Digital multimeter to calibrate a specific Arduino board.
But what would be my personal value to put in ? And what this "L" means ?

Plus what means these different piece of code ?

ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring
  uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH  
  uint8_t high = ADCH; // unlocks both
  long result = (high<<8) | low;

I really need to dig in these stuff now, otherwise I'm stuck !

I wonder where the "1125300L" come from ?

The calculation is set out at the end of the line.
You're quite correct however, is should be 1024, not 1023.

Plus what means these different piece of code ?

Read the helpful comments.

If you study the Atmel datasheet for whatever MCU you are using you will discover that all these things

ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);

are register names and bit names within the registers of the microprocessor.

Personally I find this notation very opaque and I prefer to write my code in the style ADMUX &= B01001010 where the 1s and 0s directly correspond with the bits. (By the way B01001010 is just random stuff for example purposes).

...R

That is the problem copying code without understanding it ! It can lead to serious mistake !

pure wisdom , seldom seen

Arduino is not a PC but an embedded processor, it has no operating system that shields of the low level thingies (HAL)
When you program an Arduino (or similar device) youare have to programming much closer to the hardware level than you typically do in an PC environment where every device is e.g. a (more or less) nice .NET Class.

If you take a few days to go through the tutorial section, and study, execute, adapt the sketches there you will see most register and bit-masking thingies is not very very difficult. But it takes several dozen projects to get used to it.

Robin2:
If you study the Atmel datasheet for whatever MCU you are using you will discover that all these things

ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);

are register names and bit names within the registers of the microprocessor.

Personally I find this notation very opaque and I prefer to write my code in the style ADMUX &= B01001010 where the 1s and 0s directly correspond with the bits. (By the way B01001010 is just random stuff for example purposes).

...R

Yes I'm more or less clear with ADMUX register "configuration". Despite I don't know what the "_BV" means
Your notation is quite interesting because it remind the configuration of each bit each time you write it. But what I don't understand in this case is the "&="
But what about the rest : "ADCSRA |= _BV(ADSC);"
for instance.

AWOL:

I wonder where the "1125300L" come from ?

The calculation is set out at the end of the line.
You're quite correct however, is should be 1024, not 1023.

I'm not sure I agree with you !I think despite there is 1024 value possible, in the calculation you must use 1023.
The comments don't help me understand.
As I said, I don't know how to "read" :
"ADCSRA |= _BV(ADSC);"
I think this kind of expression is closer to C that to Arduino programming !

robtillaart:

That is the problem copying code without understanding it ! It can lead to serious mistake !

pure wisdom , seldom seen

Many thanks for securing and encouraging me in that direction. otherwise, I sometime feel like an alien, wanting understanding every bits !

robtillaart:
Arduino is not a PC but an embedded processor, it has no operating system that shields of the low level thingies (HAL)
When you program an Arduino (or similar device) youare have to programming much closer to the hardware level than you typically do in an PC environment where every device is e.g. a (more or less) nice .NET Class.

If you take a few days to go through the tutorial section, and study, execute, adapt the sketches there you will see most register and bit-masking thingies is not very very difficult. But it takes several dozen projects to get used to it.

You got it I think. That register and bit-masking stuff that I need. But how to get a start with it. I've been turning around this for a while already. I feel, it's what I need, but can't get things on its way.
I think this "Accurate voltmeter" is extremely important with this Arduino things where we need to deal with lots of analogRead() and analogWrite(). That's basis of sensors accuracy. And with Arduino, what to do with no sensor ?
You catch what I need to be able to read this code. Any advice for a start ?

I wonder where the "1125300L" come from ?
On an other link, it changes to "1126400L"

In a perfect world an AVR chips internal 1.1 vdc band-gap voltage value would be 1100000 microvolts, however in reality the datasheet will tell us that the tolerance from chip to chip can vary (from memory) 1000000 to 1200000 uv, however it will have good or at least decent stability at whatever exact value one's chip has. So consider that a constant value that has to be a 'tweak for best results' value, until the value the function returns agrees with a direct measurement of the Vcc voltage as measured with an accurate DVM that you trust. So in effect the sketch is only portable in the sense that results will vary from chip to chip and needs to be optimized for each chip you run it on if best possible results is required or desired.

As I said, I don't know how to "read" :
"ADCSRA |= _BV(ADSC);"

"BV" means "bit value", so given a bit position as a number (LSB is zero), it turns that into a bit mask.
BV(2) is the same as 1 << 2, which is same as 4.
"|=" says bit wise OR the variable on the left with the mask on the right, and assign the result to the variable on the left.

AWOL:

As I said, I don't know how to "read" :
"ADCSRA |= _BV(ADSC);"

"BV" means "bit value", so given a bit position as a number (LSB is zero), it turns that into a bit mask.
BV(2) is the same as 1 << 2, which is same as 4.
"|=" says bit wise OR the variable on the left with the mask on the right, and assign the result to the variable on the left.

So can I say :
ADCSRA |= _BV(ADSC);
is equivalent to :
ADCSRA = ADCSRA | _BV(ADSC);
is equivalent to :
ADCSRA =ADCSRA | 0b01000000 (see Atmel datasheet, -BV(ADSC) = 0b01000000)
is equivalent to :
ADSRA = ADCSRA | 0x40
is equivalent to :
ADCSRA |= 1<<6
is equivalent to :
ADCSRA |= 64

Mmmm ! So many writting to say the same thing ! No wonder why a beginner can't understand !

What chance has the beginner (or indeed anyone) if you just wrote ADCSRA |= 64?
At least the BV form gives an idea what is going on.

(BTW, you realise ADCSRA is a macro too, don't you? ;). )

hary:

AWOL:

As I said, I don't know how to "read" :
"ADCSRA |= _BV(ADSC);"

"BV" means "bit value", so given a bit position as a number (LSB is zero), it turns that into a bit mask.
BV(2) is the same as 1 << 2, which is same as 4.
"|=" says bit wise OR the variable on the left with the mask on the right, and assign the result to the variable on the left.

So can I say :
ADCSRA |= _BV(ADSC);
is equivalent to :
ADCSRA = ADCSRA | _BV(ADSC);
is equivalent to :
ADCSRA =ADCSRA | 0b01000000 (see Atmel datasheet, -BV(ADSC) = 0b01000000)
is equivalent to :
ADSRA = ADCSRA | 0x40
is equivalent to :
ADCSRA |= 1<<6
is equivalent to :
ADCSRA |= 64

Mmmm ! So many writting to say the same thing ! No wonder why a beginner can't understand !

I think what you may be missing is that by using the _BV(ADSC) method that the function will work correctly for the different AVR chips versions that the IDE supports that otherwise if you used fixed values like 64 it might work correctly on a 328P chip but not a 2560 chip. Same goes for using register names like ADCSRA where the actual physical address of that register might again be different for the different AVR chips used in the Arduino world. They are pretty cryptic to read, at least for me also, but there is a method to their madness.

AWOL:
What chance has the beginner (or indeed anyone) if you just wrote ADCSRA |= 64?
At least the BV form gives an idea what is going on.

(BTW, you realise ADCSRA is a macro too, don't you? ;). )

Is it a macro, or a defined constant that can change with AVR chip type?

I'm now wondering if using 1024 or 1023 in the calculation of VCC !

AWOL:
What chance has the beginner (or indeed anyone) if you just wrote ADCSRA |= 64?
At least the BV form gives an idea what is going on.

(BTW, you realise ADCSRA is a macro too, don't you? ;). )

ADCSRA ? A macro ? I don't see what you mean.

This topic is really leading me to deep. Somebody to help stay tuned on the most important things ?
Properly using uC seems to be quite difficult indeed ! Interesting, but a little bet hard for a beginner !

I'm now wondering if using 1024 or 1023 in the calculation of VCC !

Ask yourself why semiconductor manufacturers like TI or National would go to the trouble of designing and marketing reference voltage devices with strange, non-physical constant (like band gap voltage) voltages, like 1.024V.

I think then your question answers itself.

retrolefty:

AWOL:
What chance has the beginner (or indeed anyone) if you just wrote ADCSRA |= 64?
At least the BV form gives an idea what is going on.

(BTW, you realise ADCSRA is a macro too, don't you? ;). )

Is it a macro, or a defined constant that can change with AVR chip type?

Of course it is a macro.
How could you have a constant on the left-hand side of an assignment?

AWOL:

retrolefty:

AWOL:
What chance has the beginner (or indeed anyone) if you just wrote ADCSRA |= 64?
At least the BV form gives an idea what is going on.

(BTW, you realise ADCSRA is a macro too, don't you? ;). )

Is it a macro, or a defined constant that can change with AVR chip type?

Of course it is a macro.
How could you have a constant on the left-hand side of an assignment?

Hell I don't know, solder it in?

hary:
This topic is really leading me to deep. Somebody to help stay tuned on the most important things ?
Properly using uC seems to be quite difficult indeed ! Interesting, but a little bet hard for a beginner !

As with every area of expertise (lawyers, doctors ....) people who know stuff like to talk about the things they know.

The trick is to take what you need from the arcane discussions.

You seem to have it figured out when you listed all the options. Just use the system that will best help you to know what your code means when you come back to it after a 6 month break.

...R