Pages: [1] 2   Go Down
Author Topic: Accurate voltmeter (or could be renamed : uC's ADC ... State of the art)  (Read 576 times)
0 Members and 1 Guest are viewing this topic.
France
Offline Offline
Jr. Member
**
Karma: 1
Posts: 85
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 !

« Last Edit: April 27, 2014, 03:14:53 pm by hary » Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 65
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

 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...


Logged

Phillipsburg, NJ
Offline Offline
Full Member
***
Karma: 6
Posts: 184
Author: Matrix Keypad Library
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

France
Offline Offline
Jr. Member
**
Karma: 1
Posts: 85
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Is this Arduino ?

Code:
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.
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17293
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Logged

France
Offline Offline
Jr. Member
**
Karma: 1
Posts: 85
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

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

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

Code:

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

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

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 301
Posts: 26240
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
« Last Edit: April 27, 2014, 07:07:34 am by AWOL » Logged

"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.

UK
Offline Offline
Tesla Member
***
Karma: 121
Posts: 6955
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 216
Posts: 13670
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
That is the problem copying code without understanding it ! It can lead to serious mistake !
pure wisdom , seldom seen
Logged

Rob Tillaart

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

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 216
Posts: 13670
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Logged

Rob Tillaart

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

France
Offline Offline
Jr. Member
**
Karma: 1
Posts: 85
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 ?


Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17293
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 301
Posts: 26240
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

"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.

France
Offline Offline
Jr. Member
**
Karma: 1
Posts: 85
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 301
Posts: 26240
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

What chance has the beginner (or indeed anyone) if you just wrote
Code:
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?   smiley-wink. )
Logged

"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.

Pages: [1] 2   Go Up
Jump to: