Shop OBEX P1 Docs P2 Docs Learn Events
Inconsistent adc_volts() function ??? — Parallax Forums

Inconsistent adc_volts() function ???

RsadeikaRsadeika Posts: 3,837
edited 2015-01-08 12:12 in Learn with BlocklyProp
I am getting inconsistent readings with my avolts function. I am reading two voltage sources, Parallax Li-ion Power Pack and a 12V SLA battery. While the readings for the power pack are the expected values, the readings for the 12V battery are all over the place, 8.xxx, 15.xxx, 11.xxx, 23.xxx, and so on. Both have the appropriate voltage divider setup [+V 10K . 10K -V] for the Power Pack, and [+V 10K-10K-10K . 10K -V] for the 12V battery. I am not sure what the cure for this would be, hopefully somebody will try it out to replicate this.

I brought this up in another thread, but decided maybe this specific problem? should be highlighted here.

Ray

/*
  SAabsun.c

*/
#include "simpletools.h"
#include "simpletext.h"
#include "fdserial.h"
#include "adcDCpropab.h"

serial *xbee;
float v3,v2;

void menu();
void mvolts();
void avolts();

int main()
{
  // Add startup code here.
  char inBuff[40];
  adc_init(21, 20, 19, 18);
  
  xbee = fdserial_open(11, 10, 0, 9600);
  pause(50);
 
  while(1)
  {
    // Add main loop code here.
    if(fdserial_rxReady(xbee))
    {
      readStr(xbee, inBuff, 40);
      if(!strcmp(inBuff, "help")) menu();
      else if(!strcmp(inBuff, "mbat")) mvolts();
      else if(!strcmp(inBuff, "abat")) avolts();
      else
      {
        writeLine(xbee,"Unknown Command.");    
      }      
    }    
  }
  return 0;  
}

void menu()
{
  writeStr(xbee,"Menu -  help, mbat, abat \n");
}

void mvolts()
{
  v3 = adc_volts(3);
  v3 = (v3*2);
  
  writeStr(xbee,"mBattery ");
  writeFloat(xbee,v3);
  writeStr(xbee," Volts\n");
}

void avolts()
{
//  adc_init(21, 20, 19, 18);
  v2 = adc_volts(2);
  v2 =(v2*8.50);
  
  writeStr(xbee,"aBattery ");
  writeFloat(xbee,v2);
  writeStr(xbee," Volts\n");  
}

Comments

  • Duane DegnDuane Degn Posts: 10,588
    edited 2015-01-02 10:19
    Often ADC have a harder time reading the voltage of high impedance sources. It looks like you have 30K ohm between your 12V battery and the ADC input. One suggestion would be to switch the 10K resistors for 1K resistors (I bet this would solve the issue). Another option is to add a capacitor at the ADC input. The cap (I'm not sure the appropriate size, I'd try a 0.1uf or 1 uF cap) would be between the voltage being read by the ADC and ground.
  • RsadeikaRsadeika Posts: 3,837
    edited 2015-01-02 10:32
    One suggestion would be to switch the 10K resistors for 1K resistors (I bet this would solve the issue).
    I am not sure I understand this, I do not think that that combination will get me down to the required 5V level needed for the ADC. I have this set up, more or less to read voltage as high as 20V, which presents another problem, the adjustment factor, so my readings will actually show what the actual voltage is on the 12V battery.

    Ray
  • Duane DegnDuane Degn Posts: 10,588
    edited 2015-01-02 11:39
    Rsadeika wrote: »
    I am not sure I understand this, I do not think that that combination will get me down to the required 5V level needed for the ADC. I have this set up, more or less to read voltage as high as 20V, which presents another problem, the adjustment factor, so my readings will actually show what the actual voltage is on the 12V battery.

    You list four 10K resistor in your voltage divider.
    Rsadeika wrote: »
    and [+V 10K-10K-10K . 10K -V] for the 12V battery

    If you used four 1K resistors instead of four 10K resistors the voltage at the divider should remain the same but the ADC would have an easier time measuring it.

    The adjustment factor is pretty easy stuff. It will probably be something like:
      scaledVolts := readingFromAdc * 20_000 / 4095
    

    The above should give you the volts times one thousand (or you can think of the number in units of millivolts). The code assume 20V will produce a reading of 4095.
  • RsadeikaRsadeika Posts: 3,837
    edited 2015-01-03 04:46
    I tried the new suggestion by Duane, [+V 1K-1K-1K . 1K -V], using the below adjustment factor, and below that shows the sampling values. The 12V SLA battery voltage as read by a voltmeter is 13.11V, so the sampling rate shows that the values should be doubled to get within the ballpark, but that would put only a couple of values within the actual battery voltage state.

    Now I am at a loss, not sure if it is the ADC chip on my Activity Board, the actual ADC_volts function or what, is the problem? Even if I took a sample of a thousand readings and averaged that, I am not sure that it would reveal the actual battery state. The next thing that I will try is testing with the other two ADC ports that are available, I cannot imagine that I already smoked this ADC port.

    Ray
      v2 = adc_volts(2);
      v2 =(v2*(20000/4095));
      
      writeStr(xbee,"aBattery ");
      writeFloat(xbee,v2);
      writeStr(xbee," Volts\n");
    
    sampling:
    abat
    aBattery 5.825195 Volts
    abat
    aBattery 4.819336 Volts
    abat
    aBattery 3.256836 Volts
    abat
    aBattery 3.549805 Volts
    abat
    aBattery 4.311523 Volts
    abat
    aBattery 7.749023 Volts
    abat
    aBattery 5.180664 Volts
    abat
    aBattery 6.591797 Volts
    abat
    aBattery 6.782227 Volts
    abat
    aBattery 7.211914 Volts
  • GordonMcCombGordonMcComb Posts: 3,366
    edited 2015-01-03 08:59
    For SLA batteries in particular battery voltage measurements should always be taken under load. Since you appear to get more consistent results with the Li-Ion battery, the likely "culprit" is the internal makeup of the battery, and not the ADC on the board.

    Lead acid batteries vary greatly in their makeup based on what they are for. You get different behaviors between starter and deep cycle batteries, for example. Most SLA batteries you purchase are for power backup, and have higher internal resistances.
  • edited 2015-01-03 10:12
    Also, make sure the battery negative terminals are connected to GND. The ground reference is required for valid measurements.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2015-01-03 10:58
    I think something is very "off" with these reading.

    Wouldn't the following code:
    Rsadeika wrote: »
      v2 = adc_volts(2);
      v2 =(v2*(20000/4095));
      
      writeStr(xbee,"aBattery ");
      writeFloat(xbee,v2);
      writeStr(xbee," Volts\n");
    

    Output the voltage in millivolts rather than volts?

    The "20_000 / 4_095" conversion was given assuming the calculations were being done with integers. I scaled the "20" by one thousand in order to preserve the precision. If floating point numbers are used, then the conversion to volts would be "20 / 4095". Right?

    Aren't the volts displayed actually off by several orders of magnitude?

    I'm not sure how the C compiler treats the equation:
    v2 =(v2*(20000/4095));
    


    Are the values "20000" and "4095" treated as floating point numbers right from the beginning or do they get converted to floats when they're multiplied by "v2"?

    If the calculation "20000/4095" is done in integer math, then there will be a large rounding error in the calculation. This rounding error, if it exists, doesn't explain the numbers displayed.
  • RsadeikaRsadeika Posts: 3,837
    edited 2015-01-03 11:38
    I made both circuits [+V 1K-1K-1K . 1K -V], and both are connected to the board GND. This seems to be a stable condition, the values that I am reading are the expected values. The difference seems to be that I have the 12V battery negative terminal connected to the board GND. The last time I tried something like that, I had lots of wires melting and smoking, plus the ADC got smoked. This time I am being a little more careful with my wiring scheme, if that what was the original problem.

    The '(20000/4095)' method was not yielding the expected values, so I am using a different scheme, now I am wondering if I am supplying an adjustment scheme to show the numbers that I want see for that time slice.

    Ray

    /*
      SAabsun.c
    
    */
    #include "simpletools.h"
    #include "simpletext.h"
    #include "fdserial.h"
    #include "adcDCpropab.h"
    
    serial *xbee;
    float v3,v2;
    
    void menu();
    void mvolts();
    void avolts();
    
    int main()
    {
      // Add startup code here.
      char inBuff[40];
      adc_init(21, 20, 19, 18);
      
      xbee = fdserial_open(11, 10, 0, 9600);
      pause(50);
     
      while(1)
      {
        // Add main loop code here.
        if(fdserial_rxReady(xbee))
        {
          readStr(xbee, inBuff, 40);
          if(!strcmp(inBuff, "help")) menu();
          else if(!strcmp(inBuff, "mbat")) mvolts();
          else if(!strcmp(inBuff, "abat")) avolts();
          else
          {
            writeLine(xbee,"Unknown Command.");    
          }      
        }    
      }
      return 0;  
    }
    
    void menu()
    {
      writeStr(xbee,"Menu -  help, mbat, abat \n");
    }
    
    void mvolts()
    {
      v3 = adc_volts(3);
    //  v3 = (v3*2);
      v3 = (v3*2.958);  // Calculation based on .986K value of resistor.
      
      writeStr(xbee,"mBattery ");
      writeFloat(xbee,v3);   // This now showing the correct voltage.
      writeStr(xbee," Volts\n");
    }
    
    void avolts()
    {
    /* This will be worked in after the battery gets
       put on line with the PWM solar controller.
      int x;
      for(x=0;x<1000;x++)
      {
        y1 = adc_volts(2);
        y3 = y3 + y1;
      }
      y3 = (y3/1000);
      y3 = (y3*4.425);
      v3 = y3;
    */
      v2 = adc_volts(2);
      v2 =(v2*4.425);   // Calculation based on manipulation
                        // to actual battery voltage reading.
      
      writeStr(xbee,"aBattery ");
      writeFloat(xbee,v2);  // After manipulation, reads correct voltage.
      writeStr(xbee," Volts\n");  
    }
    
  • RsadeikaRsadeika Posts: 3,837
    edited 2015-01-05 12:41
    The ADC on the Activity Board is a very finicky device, I thought I had everything working yesterday, well today, not so. In fact I had to break down the circuit(s), rebuild the circuit(s), verify the results, and then start over with the adjustment process. As soon as I change the batteries out, the whole scheme falls apart; I also thought that the adjustment factor was supposed to be good for whatever voltage battery I was using. As far as I can tell, ~4 is supposed to be the magic number for the adjustment factor, but that is being very elusive number.

    I am wondering if anybody else is having a problem like mine, using the ADC with more than one circuit. Today, for awhile I was thinking that maybe you can only use one active working circuit on an ADC port, and nothing on the other 3 ADC ports, at the same time. Today after verifying both circuits, adding another circuit on line, the voltage results changed for the same batteries that I used to verify the circuit to begin with.

    I was able to verify that the ADC chip is not smoked, but when I try to use it with more then one circuit, it starts to flake out. Not sure what to make of this situation. Anybody have any ideas?

    Ray
  • edited 2015-01-05 13:00
    Rsadeika wrote: »
    The ADC on the Activity Board is a very finicky device,...

    That may be your experience with this particular application, but it's not really fair to say that about the Activity Board and its ADC until you have tried the same circuit on other boards/ADCs without observing the same issue.

    Please post your current schematic and a zip of your test code. Close-up shots of your circuit might also help.

    In the meantime, I will wire up three voltage dividers on an Activity Board and test to rule out the possibility that a programming error made it into the library.

    Andy
  • DomanikDomanik Posts: 233
    edited 2015-01-05 13:43
    From the Datasheet:
    "Because the reference for the ADC124S021 is the supply voltage, any noise on the supply will degrade device
    noise performance. To keep noise off the supply, use a dedicated linear regulator for this device, or provide
    sufficient decoupling from other circuitry to keep noise off the ADC124S021 supply pin. Because of the
    ADC124S021's low power requirements, it is also possible to use a precision reference as a power supply to
    maximize performance."

    "Resistor R1 is the on resistance of the multiplexer and track / hold switch, and is typically 500 ohms. Capacitor C2 is the
    ADC124S021 sampling capacitor, and is typically 30 pF. The ADC124S021 will deliver best performance when
    driven by a low-impedance source to eliminate distortion caused by the charging of the sampling capacitance.
    This is especially important when using the ADC124S021 to sample AC signals. Also important when sampling
    dynamic signals is a band-pass or low-pass filter to reduce harmonics and noise, improving dynamic
    performance."

    ADCs can have sampling perturbations on the input at the time of sampling that cause readings to be off (a small amount). If your VA moves around then so is your VRef and your readings will be off. To get 12 bit accuracy you must have a steady VRef and the exact VA voltage used in calculations (ie 4.983V/4096). Each LSB bit will then be 1.22mv.
  • edited 2015-01-05 14:18
    Circuit

    attachment.php?attachmentid=112663&d=1420496146

    attachment.php?attachmentid=112662&d=1420496146

    Test Code
    /*
      Measure Volts (Test Four).c
    
      Derived from
      http://learn.parallax.com/propeller-c-simple-circuits/measure-volts
    */
    
    #include "simpletools.h"                      // Include simpletools
    #include "adcDCpropab.h"                      // Include adcDCpropab
    
    int main()                                    // Main function
    {
      adc_init(21, 20, 19, 18);                   // CS=21, SCL=20, DO=19, DI=18
    
      float v[4];                                 // Voltage variables
    
      while(1)                                    // Loop repeats indefinitely
      {
        print("%c", HOME);
        for(int i = 0; i < 4; i++)                // Cycle through adc channels
        {
          v[i] = adc_volts(i);                    // Get volts for each ADC
          print("A/D%d = %1.3f\n", i, v[i]);      // Display volts for each ADC
        }      
        pause(100);                               // Wait 1/10 s before repeat
      }  
    }
    


    Results

    Steady measurements, not at all like post number 5.
    attachment.php?attachmentid=112661&d=1420496146
    535 x 185 - 80K
    352 x 365 - 171K
    264 x 341 - 40K
  • Duane DegnDuane Degn Posts: 10,588
    edited 2015-01-05 14:36
    Andy, I'm guessing those are those 10K pots, right?

    I've been using the Activity Boards ADC in the OPP#8 without issue. I have a couple of Sharp IR sensors being read by the Activity Board's ADC and it appears to work fine. Of course this is in Spin but I don't think there's anything wrong with the Activity Boards ADC chip.
  • RsadeikaRsadeika Posts: 3,837
    edited 2015-01-05 15:02
    OK, I will assume that if I have a finicky ADC, then maybe I damaged it in some way, it will be the second one. I will try to verify one circuit, and then go from there, maybe it is the wiring harness. My application does not use a simple pots, but in theory it should work with pots or resistors that are being used. My bad.

    Ray
  • edited 2015-01-05 15:21
    So, I tried a 9 V battery on A/D3. The particular battery I started with was dead, so it started at 7.2 V, and decayed to around 6.2 V in a few minutes. Next battery was in better shape, and it has been sitting at 9.2 V for a while now.

    Circuit
    attachment.php?attachmentid=112665&d=1420500029
    attachment.php?attachmentid=112666&d=1420500029
    /*
      Measure Volts (3 Pots 1 Battery).c
    
      Derived from
      http://learn.parallax.com/propeller-c-simple-circuits/measure-volts
      
      9 V battery connected to A/D3 through a 10 k voltage divider.  See 
      line with "Scale voltage..." for correction factor.
    */
    
    #include "simpletools.h"                      // Include simpletools
    #include "adcDCpropab.h"                      // Include adcDCpropab
    
    int main()                                    // Main function
    {
      adc_init(21, 20, 19, 18);                   // CS=21, SCL=20, DO=19, DI=18
    
      float v[4];                                 // Voltage variables
    
      while(1)                                    // Loop repeats indefinitely
      {
        print("%c", HOME);
        for(int i = 0; i < 4; i++)                // Cycle through adc channels
        {
          v[i] = adc_volts(i);                    // Get volts for each ADC
          if(i == 3) v[i] = v[i] * 2.0;           // Scale voltage divider
          print("A/D%d = %1.3f\n", i, v[i]);      // Display volts for each ADC
        }      
        pause(100);                               // Wait 1/10 s before repeat
      }  
    }
    


    Results

    attachment.php?attachmentid=112667&d=1420500029
    366 x 286 - 54K
    504 x 320 - 170K
    535 x 187 - 74K
  • RsadeikaRsadeika Posts: 3,837
    edited 2015-01-06 14:19
    I found a problem, there might be other hidden problems, which I will have to catch. I use jst connectors for making connections the load side and the breadboard. This way I have a quick disconnect, and one or two ends can be a fixed semi connection. Today I was getting a .000V reading for voltage on the ADC, I removed the load wire from the ADC port and checked the voltage, the voltmeter was showing the expected voltage, but it had a minus in front of the value. So after checking the wire and the jst connections, a jst connection had the red wire connected to a black wire. The other post where it showed the varied voltage readings, I wonder if it was a poor connection inside of the jst plug. I guess now I have to verify the jst connectors before I use them, maybe it was just one or two bad ones out of the 100 pair batch that I bought. It was a good deal on the purchase.

    I am hoping that this is the last problem that I have to deal with, I am getting to old for this kind of adventure, or should I call it learning process.

    Ray
  • RsadeikaRsadeika Posts: 3,837
    edited 2015-01-07 12:12
    Everything seems to be working as expected, from a hardware perspective, have not seen any smoke from the wiring harness.

    I do need an explanation as to how the float variables work, in terms of calling them as global verses local define. In the avolts() function, when I have 'float y3,y1;' as a local call out, then the function does not work. When I change 'y3,y1' to global, then the function works as expected. I do not understand what is going on, if somebody could explain it, would be greatly appreciated.

    Ray

    /*
      SAabsun.c
    
    */
    #include "simpletools.h"
    #include "simpletext.h"
    #include "fdserial.h"
    #include "adcDCpropab.h"
    
    serial *xbee;
    float v3,v2,v1,v0,y3,y1;
    
    void menu();
    void mvolts();
    void avolts();
    void bvolts();
    void solpan();
    
    int main()
    {
      // Add startup code here.
      char inBuff[40];
      adc_init(21, 20, 19, 18);
    
    /*                     Rx  Tx  mode  BAUD   */  
      xbee = fdserial_open(11, 10,  0,   9600);
      pause(50);
     
      while(1)
      {
        // Add main loop code here.
        if(fdserial_rxReady(xbee))
        {
          readStr(xbee, inBuff, 40);
          if(!strcmp(inBuff, "help")) menu();
          else if(!strcmp(inBuff, "mbat")) mvolts();
          else if(!strcmp(inBuff, "abat")) avolts();
          else if(!strcmp(inBuff, "bbat")) bvolts();
          else if(!strcmp(inBuff, "solpan")) solpan();
          else
          {
            writeLine(xbee,"Unknown Command.");    
          }      
        }    
      }
      return 0;  
    }
    
    void menu()
    {
      writeStr(xbee,"Menu -  help, mbat, abat, bbat, solpan \n");
    }
    
    void mvolts()
    {
      v3 = adc_volts(3);
    //  v3 = (v3*2);
    //  v3 = (v3*2.958);  // Calculation based on .986K value of resistor.
      v3 = (v3*2.00);
      
      writeStr(xbee,"mBattery ");
      writeFloat(xbee,v3);   // This now showing the correct voltage.
      writeStr(xbee," Volts\n");
    }
    
    void avolts()
    {
    /* This will be worked in after the battery gets
       put on line with the PWM solar controller. */
      //float y3,y1;
      int x;
      for(x=0;x<1000;x++)
      {
        y1 = adc_volts(2);
        y3 = y3 + y1;
      }
      y3 = (y3/1000);
      y3 = (y3*4.00);
      v2 = y3;
    //*/
    /*  v2 = adc_volts(2);
      v2 =(v2*4.00);   // Calculation based on manipulation
                        // to actual battery voltage reading.
    
    */  
      writeStr(xbee,"aBattery ");
      writeFloat(xbee,v2);  // After manipulation, reads correct voltage.
      writeStr(xbee," Volts\n");  
    }
    
    void bvolts()
    {
    /* This will be worked in after the battery gets
       put on line with the PWM solar controller.
      float y3,y1;
      int x;
      for(x=0;x<1000;x++)
      {
        y1 = adc_volts(1);
        y3 = y3 + y1;
      }
      y3 = (y3/1000);
      y3 = (y3*4.425);
      v1 = y3;
    */
      v1 = adc_volts(1);
      v1 =(v1*4.00);   // Calculation based on manipulation
                        // to actual battery voltage reading.
      
      writeStr(xbee,"bBattery ");
      writeFloat(xbee,v1);  // After manipulation, reads correct voltage.
      writeStr(xbee," Volts\n");
    }
    
    void solpan()
    {
      v0 = adc_volts(1);
      v0 =(v0*4.00);   // Calculation based on manipulation
                        // to actual battery voltage reading.
      
      writeStr(xbee,"Solar Panel ");
      writeFloat(xbee,v0);  // After manipulation, reads correct voltage.
      writeStr(xbee," Volts\n");
    }
    
    
  • John AbshierJohn Abshier Posts: 1,116
    edited 2015-01-07 15:18
    I don't know why bvolts() would work and avolts() would not. Just saying it doesn't work doesn't give me anything to use to try to troubleshoot. What does avolts() do when y3, y1 are local? Not initializing y3 bothers me. It is not zero on calls after the first call to avolts(). I don't know what it's value is on the first call to avolts() is. Could a C expert chime in? I don't have a clue what the value of y3 is in calls to bvolts().

    John Abshier
  • RsadeikaRsadeika Posts: 3,837
    edited 2015-01-07 16:07
    In avolts() function, when I have y3 and y1 as local, and not global, I get a value something like 12557895678945672345.2347648, and the program freezes. When I make the y3 and y1 global then I get an expected value like 12.5578, and the program does not freeze up, it continues to run. I am not running bvolts() yet, so, I would expect the same problem. I think the problem might be is that y1 is using adc_init() which is in main(), but I am not sure. If that is the case, then I wonder if I can make adc_init() a global, and then I could use all my float defines as local?

    Ray
  • RsadeikaRsadeika Posts: 3,837
    edited 2015-01-08 03:47
    The other thing that I noticed today, which might be a little alarming, when float y3,y1 are a local call in avolts(), "Code Size 9,812 bytes (10,048)", when compiled. When float y3,y1 are global, when program is compiled, "Code Size 31,998 bytes (32,228)". That looks like a quite substantial jump in bytes used just by switching to global, which of course limits further expansion of the program.

    Ray
  • RsadeikaRsadeika Posts: 3,837
    edited 2015-01-08 12:12
    Without any fanfare, Parallax made available SimpleIDE RC-2, so I installed it, and ran my program. The change that I did make is Board Type: ACTIVITYBOARD-SDXMMC, and Memory Model: XMMC External Flash Code ... It compiled fine and runs as expected on an initial run, Code Size 60,096 bytes (60,172 total). Next I will have to try adding some newCOGs, and see if they also run in XMMC memory model.

    This is some really good news, I don't care about the global variable issue and increasing the compiled program size, now I have a lot more program size to work with. Now I can add the softRTC, data log to the uSD card, horns a tooting, lights a flashen, ...

    Ray
Sign In or Register to comment.