Go Down

Topic: Accurate voltmeter (or could be renamed : uC's ADC ... State of the art) (Read 743 times) previous topic - next topic

hary

Hello everybody.

Since a while I'm struggling with accurate voltmeter.

I first found this witch is absolutely interesting :
http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/

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.

Any link welcome.

Regards to all !


jn-wp

have you tried to understand the two articles that are mentioned in the beginning?

1.) http://hacking.majenko.co.uk/node/57
and
2.) http://code.google.com/p/tinkerit/wiki/SecretVoltmeter

they are both written in the "arduino-language".

hope that could help...



mstanley

I'm not sure what problem you are having.  I just copied the readVcc() function from the web page and pasted it to the bottom of the BareMinimum.ino sketch and hit verify.  It compiled perfectly.

It should Just Work if you do the same.  Then to use it you call the function readVcc() in your sketch.

hary

Is this Arduino ?

Code: [Select]
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.

retrolefty

Quote

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.


hary

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
Code: [Select]
#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
Code: [Select]
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 ?
Code: [Select]
ADCSRA |= _BV(ADSC); // Start conversion 

Code: [Select]
  while (bit_is_set(ADCSRA,ADSC)); // measuring

Code: [Select]

  uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH 
  uint8_t high = ADCH; // unlocks both


Code: [Select]

  long result = (high<<8) | low;


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

AWOL

#6
Apr 27, 2014, 02:00 pm Last Edit: Apr 27, 2014, 02:07 pm by AWOL Reason: 1
Quote
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.
Quote
Plus what means these different piece of code ?

Read the helpful comments.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Robin2

If you study the Atmel datasheet for whatever MCU you are using you will discover that all these things
Quote
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

robtillaart

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

pure wisdom , seldom seen
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

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.

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

hary


If you study the Atmel datasheet for whatever MCU you are using you will discover that all these things
Quote
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.


Quote
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 !


Quote
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 !


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 ?



retrolefty

Quote

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.

AWOL

Quote
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.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

hary


Quote
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 !

AWOL

What chance has the beginner (or indeed anyone) if you just wrote
Code: [Select]
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?   ;). )
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Go Up