For my current Project I decided to measure and display the Voltage for an accu which is providing round about 3.7 Volts for a stepup module which supports the Project with 5 Volts.
The easy way is just measure the 3.x Volts and display the floating Value.
GreatCownBasic doesn't have floating point arhytmetrics Libray.
I you ask me, that is not needed anyway for most tasks.
So I implemented a simple somewhat pragmatic approch and publish it here for discussion.
The princip is scaling it up to the border of Integer.
Because Integer doesn't know any thing about Values < 1 we have to scale up. I did a rough measurement and my approach is correct enough, your milage will vary.
DIM ad_val,Voltage as integer
DIM VOLTS,COLONVOLTS AS BYTE
'read 10-bit value to Variable
ad_val = ReadAd10(an0)
'Voltage = (30000 /1024) * ad_val / 600 ' exact calculation
' but this would be much easier
VOLTS = ad_val / 200
COLONVOLTS = ad_val - VOLTS
GLCDPrint 65, 10, VOLTS
GLCDPrint 70, 10, "."
GLCDPrint 75, 10, COLONVOLTS
GLCDPrint 90, 10, "Volts"
Have Fun!
I wonder if it is a good Idea for a new forum, called snippets?
Last edit: bed 2017-10-18
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
After rethinking I'found a flaw when measuring a Voltage like 3.01 Volts it would printed as 3.4 and not as 3.04
so one must handle it making 2 extra IF Queries
Such as
IF COLONVOLTS < 100 THEN
GLCDPrint 70, 10, ".0"
GLCDPrint 80, 10, COLONVOLTS
END IF
....
So my intention to save some code is absurd, I fear (200 was not correct either, 205 would fit better)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Similar idea for Readad. I didn't like using goto. More decimal places would not mean more accurate.
adcval=ReadAD(an0)
;
adcval=adcval*100
adcval=adcval/51
volts=str(adcval)
if adcval<10 then
volts="0.0"+left(volts,1,1)
goto volt_format_done
end if
if adcval<100 then
volts="0."+mid(volts,1,2)
else
volts=left(volts,1,1)+"."+mid(volts,2,2)
end if
volt_format_done:
GLCDPrint (50,10,volts,1) ;print Voltage
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Yeah, thank you. I do use this now. My first thought was to omitt String manipulation as far as possible. On the other hand unused RAM is wasted RAM :-)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Your voltage display value will not be accurate given a 5V' ADC reference and a 3.7V input to the ADC.. There is a somewhat common formula for scaling a range of numbers that can be used with ADC. The formula is:
.
scaled_value = (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
.
Where x = the raw ADC value.
Since the ADC reference voltage is 5.00V, the output needs to be scaled so that so that 0 to 1023 IN returns 0 to 500 OUT.
The GCB code might look something like this:
#chip 16f1829, 32
#config FOSC_INTOSC , WDTE_OFF , PWRTE_OFF , MCLRE_OFF
;Software I2C For LCD
#define I2C_MODE Master
#define I2C_DATA PORTB.6
#define I2C_CLOCK PORTB.5
#define I2C_DISABLE_INTERRUPTS ON
#define LCD_IO 10
#define LCD_I2C_Address_1 0x7E ; default to 0x4E
#define LCD_SPEED FAST
#define LCD_Backlight_On_State 1
#define LCD_Backlight_Off_State 0
CLS
Dim ad_val as word
Dim Volts as byte
Dim hundredths as byte
Do
;get raw data
AD_VAL = Readad10(An4)
;Scale/Map where 0.00 to 5.00V in = 0 to 500 out
AD_VAL = [long]AD_Val * 500 / 1023 ;casting to prevent overflow
'Modify for display
Volts = AD_VAL / 100 ;Get volts
Hundredths = (AD_Val - (Volts * 100)) ;Get hundredths
;display the voltage as X.xx
Locate 0,0
Print Volts ; 0 to 5
Print "." ;decimal point
If hundredths < 10 then Print "0"
Print hundredths
LCDSPACE 2 ;clear any trailing data
Loop
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Yes, but no.
My Hardware ist beeing powered by a single Li Ion Accu, which is stepped up to 5V.
So the Reference is 5,x V not as exact as a real Reference, but my sample has 5.05 Volts which is near to perfect.
Or did I got you wrong? And you mean even when Power supply is 5Volts we have to calibrate?
But good to have such a formula in hand if it comes to that situation.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I simply ran your code as posted and noted the errors. With your suggested code an input voltage of 2.0V displays "2.214". 3.70V displays "3.202".
Volts = AD_VAL / 200
This is not scaling. It is simple division. While it will return 0 to 5 given an AD Value of 0 to 1023
COLONVOLTS = AD_VAL - Volts
I have no idea what this is supposed to do. It most certainly does not scale anything. And given that
"Volts" will be an integer between 0 and 5 , all it does is subract one of these integers from the raw "unscaled" ADC value returning a meaningless number.
Example1: Apply 2.5 V to the ADC Pin. The ADC will return ~511 given a 5.0V supply reference.
Volts will be 2. Colonvolts will be 511 - 2 or 509. Since colonvolts is a byte, it will OVERFLOW and actually be 251. 251 is meaningless
Example 2: Apply 3.7V to the ADC Pin. The ADC will read ~758 given a 5.0V supply reference.
Volts will be 3. Colonvolts will be 758 - 3 = 755. Since Colonvolts is a byte, it will OVERFLOW and actually be 243 . 243 is meaningless.
It is only by accident that the code is somewhat accurate at any given voltage. I suggest you rethink your method.
William
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
William, you are right.
My first attempt was not thought through.
I thought about to use integer and not strings do build an reasonable Display. Integer was an error anyway should have used word and ColonVolt was for the part <1Volt for ommiting string, which was not correct, also.
I have to admit that I worked with ADC and Controllers in whole worked >30 years ago as a hobby and and now after this long period I a bit overhelmed from the possibilities that the chips have developed to.
But William, now we have a good explained solution for this small problem, which surely will found by others newbies like me :-)
Last edit: bed 2017-10-21
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
For my current Project I decided to measure and display the Voltage for an accu which is providing round about 3.7 Volts for a stepup module which supports the Project with 5 Volts.
The easy way is just measure the 3.x Volts and display the floating Value.
GreatCownBasic doesn't have floating point arhytmetrics Libray.
I you ask me, that is not needed anyway for most tasks.
So I implemented a simple somewhat pragmatic approch and publish it here for discussion.
The princip is scaling it up to the border of Integer.
Because Integer doesn't know any thing about Values < 1 we have to scale up. I did a rough measurement and my approach is correct enough, your milage will vary.
Have Fun!
I wonder if it is a good Idea for a new forum, called snippets?
Last edit: bed 2017-10-18
After rethinking I'found a flaw when measuring a Voltage like 3.01 Volts it would printed as 3.4 and not as 3.04
so one must handle it making 2 extra IF Queries
Such as
So my intention to save some code is absurd, I fear (200 was not correct either, 205 would fit better)
Similar idea for Readad. I didn't like using goto. More decimal places would not mean more accurate.
Yeah, thank you. I do use this now. My first thought was to omitt String manipulation as far as possible. On the other hand unused RAM is wasted RAM :-)
Your voltage display value will not be accurate given a 5V' ADC reference and a 3.7V input to the ADC.. There is a somewhat common formula for scaling a range of numbers that can be used with ADC. The formula is:
.
scaled_value = (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
.
Where x = the raw ADC value.
Since the ADC reference voltage is 5.00V, the output needs to be scaled so that so that 0 to 1023 IN returns 0 to 500 OUT.
The GCB code might look something like this:
Yes, but no.
My Hardware ist beeing powered by a single Li Ion Accu, which is stepped up to 5V.
So the Reference is 5,x V not as exact as a real Reference, but my sample has 5.05 Volts which is near to perfect.
Or did I got you wrong? And you mean even when Power supply is 5Volts we have to calibrate?
But good to have such a formula in hand if it comes to that situation.
I simply ran your code as posted and noted the errors. With your suggested code an input voltage of 2.0V displays "2.214". 3.70V displays "3.202".
This is not scaling. It is simple division. While it will return 0 to 5 given an AD Value of 0 to 1023
I have no idea what this is supposed to do. It most certainly does not scale anything. And given that
"Volts" will be an integer between 0 and 5 , all it does is subract one of these integers from the raw "unscaled" ADC value returning a meaningless number.
Example1: Apply 2.5 V to the ADC Pin. The ADC will return ~511 given a 5.0V supply reference.
Volts will be 2. Colonvolts will be 511 - 2 or 509. Since colonvolts is a byte, it will OVERFLOW and actually be 251. 251 is meaningless
Example 2: Apply 3.7V to the ADC Pin. The ADC will read ~758 given a 5.0V supply reference.
Volts will be 3. Colonvolts will be 758 - 3 = 755. Since Colonvolts is a byte, it will OVERFLOW and actually be 243 . 243 is meaningless.
It is only by accident that the code is somewhat accurate at any given voltage. I suggest you rethink your method.
William
William, you are right.
My first attempt was not thought through.
I thought about to use integer and not strings do build an reasonable Display.
Integer was an error anyway should have used word and ColonVolt was for the part <1Volt for ommiting string, which was not correct, also.
I have to admit that I worked with ADC and Controllers in whole worked >30 years ago as a hobby and and now after this long period I a bit overhelmed from the possibilities that the chips have developed to.
But William, now we have a good explained solution for this small problem, which surely will found by others newbies like me :-)
Last edit: bed 2017-10-21