Menu

Analog Output scaling

bed
2017-10-18
2017-10-19
  • bed

    bed - 2017-10-18

    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
  • bed

    bed - 2017-10-19

    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)

     
  • stan cartwright

    stan cartwright - 2017-10-19

    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
    
     
  • bed

    bed - 2017-10-19

    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 :-)

     
  • William Roth

    William Roth - 2017-10-20

    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
    
     
  • bed

    bed - 2017-10-20

    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.

     
  • William Roth

    William Roth - 2017-10-20

    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

     
  • bed

    bed - 2017-10-21

    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

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.