analogRead() Problems

Hi,

Haven't found answers to these (using Arduino Uno):

  1. I am reading a potentiometer voltage using analogRead(). Starting at 3.9V (measured on the analog pin with a voltmeter) the analogRead() returns 1028. Rotating the potentiometer further, the voltage keeps climbing up until the max 4.9V, however the analogRead() remains same 1028.

  2. How can the analogRead() return 1028???

I am suspecting the ADC being faulty and causing the above. Any one has any ideas?

Thanks,
Dan

Let’s see your code.

This is my function for reading the potentiometers. I am printing the variable measureToPrint which shows the behavior described in the previous message.

void readPotentiometers(){
  for (int i=0; i< 200; i++) { // taking the average of 200 readings to stabilize the display
    measure = measure + analogRead(potIn);
    if (i==199) {
      avgMeasure = measure/200;
      measure = analogRead(potIn);
    }
  }

  measureToPrint = avgMeasure; // the analog measured value is saved beacause avgMeasure is going to be mapped afterwards

  for (int i=0; i<1000; i++) {
    if (i==999) {    //take a measurment once in 1000 cycles
      actualSelectReading = analogRead(selectorPot);
      for (z=0; z < 18 && abs(actualSelectReading - correspondingReading[z]) > 15; z++) { //check which plate the reading corresponds to
      }
      plateNo = z;
      plateSize = plateNo + 88; //convert plate number to plate size for printing on LCD (values 88-105)
    }
      
  }
}

Thanks

the analogRead() returns 1028.

You have got serious problems.

Disconnect the hardware and out it to one side. Preferably outside, on a non-flammable surface.

Seriously, post your code.
All of it.

By a strange coincidence if you get 201 x 1023 and then divide by 200 you get 1028.

When is measure ever zeroed?

Steve

TheMemberFormerlyKnownAsAWOL:
Seriously, post your code.
All of it.

Here is all of the code:

/* Comado052
 * - added testingHeight variable for testing
 * - Now printing on LCD testingHeight instead of calcHeight
 * - added line 168 - calculating testingHeight
 * - Changed the way curent limit works - now stops both on motion up and down if overcurrent occurs. 
 * - corrected values of CL and CR, previous values were wrong.
 * - Implemented the in-plate mounted resistor system
 * - Added blinking of LCD message while plate is not mounted
 */

// include the library code:
#include <LiquidCrystal.h>

// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 13, en = 10, d4 = 5, d5 = 6, d6 = 3, d7 = 2;   // replaced pins: 12->13, 4->6
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

#include "DualMC33926MotorShield.h"

DualMC33926MotorShield md;

//=====================================================================================================
//============== User can change the values below =====================================================

//=========== Definition of arrays for 18 cases of plates=========
//plate No.               0     1     2      3      4      5      6      7      8      9      10     11     12     13     14     15     16     17
float At[18]        =    {72.3, 72.3, 72.3,  72.3,  78.3,  78.3,  78.3,  78.3,  81.6,  81.6,  81.6,  81.6,  81.6,  85.5,  85.5,  85.5,  85.5,  85.5}; //arc top
float Ab[18]        =    {98.7, 99.6, 100.5, 101.4, 104.3, 105.2, 106.1, 107.0, 106.1, 107.1, 108.1, 109.0, 110.0, 111.0, 112.0, 112.9, 113.9, 114.9}; // arc bottom
float CL[18]        =    {13.7, 14.3, 14.9,  15.6,  13.4,  14.1,  14.7,  15.4,  13.4,  14.0,  14.6,  15.3,  16.0,  14.5,  15.2,  15.9,  16.5,  16.8}; // left triangle base
float CR[18]        =    {12.1, 12.4, 12.8,  13.1,  12.2,  12.5,  12.9,  13.2,  12.4,  12.7,  13.1,  13.4,  13.8,  13.2,  13.5,  13.9,  14.2,  14.6}; // right triangle base
float hC[18]        =    {3.6,  3.6,  3.6,   3.6,   3.6,   3.6,   3.6,   3.6,   6.6,   6.6,   6.6,   6.6,   6.6,   8.6,   8.6,   8.6,   8.6,   8.6} ; //initial hieght

float plateRvalue[18] =  {1,    2,    3,     3.9,   5.1,   6.2,   7.5,   8.2,   9.1,   10,    11,    12,    13,    15,    16,    18,    20,    22}; //value of resistor of each plate in kOhm
int correspondingReading[18]; // this is the expected corresponding reading that the program should see for each plate - calculated and assigned under Setup


const int currentLimit = 800; // current limit in mA


//=====================================================================================================
//=====================================================================================================

//=====================================================================================================
//=============The program below NOT to be touched ====================================================

int potIn = A5;
int selectorPot = A2;
int fwdButton = A3;
int rvsButton = 8;
int z=0; //counter
boolean ovrCurrent = false;
boolean BlinkOnOff = false;

#define Blink_interval  500 

unsigned long previousMillis = 0;

float measure = 0; // the potentiometer value
float avgMeasure = 0;
float PL = 0;
float PR = 0;
float testingHeight = 0;
float perimeterCnst; // the constant part of the perimeter 
int plateNo = 0; // number of plate selected
int plateSize = 88; // the size of selected plate (88-105)
int measureToPrint;
int actualSelectReading = 0; // actual reading of plate selecting input
int fwd = 0; // store the state of fwdButton pin
int rvs = 0; // store the state of rvsButton pin
double calcHeight = 0; // the calculated height
double perimeter; // the calculated perimeter

void setup() {
  pinMode(fwdButton, INPUT);
  pinMode(rvsButton, INPUT);
  
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  md.init();
  Serial.begin(9600);

  for (int k=0; k<18; k++) {
    correspondingReading[k] = 1024.0*1.25*((float)plateRvalue[k])/(9.8 + (float)plateRvalue[k]); // this is the expected corresponding reading that the program should see for each plate. 1.25 is correction factor, reading is off by this factor
  }
}

void loop() {
  perimeterCnst = At[plateNo] + Ab[plateNo];
  md.setM2Speed(0);

  readPotentiometers();
  
  readButtons();
  
  movement();

  calculate();   

  lcdPrint();
  
  delay(10);
}

void readPotentiometers(){
  for (int i=0; i< 200; i++) { // taking the average of 200 readings to stabilize the display
    measure = measure + analogRead(potIn);
    if (i==199) {
      avgMeasure = measure/200;
      measure = analogRead(potIn);
    }
  }

  measureToPrint = avgMeasure; // the analog measured value is saved beacause avgMeasure is going to be mapped afterwards

  for (int i=0; i<1000; i++) {
    if (i==999) {    //take a measurment once in 1000 cycles
      actualSelectReading = analogRead(selectorPot);
      for (z=0; z < 18 && abs(actualSelectReading - correspondingReading[z]) > 15; z++) { //check which plate the reading corresponds to
      }
      plateNo = z;
      plateSize = plateNo + 88; //convert plate number to plate size for printing on LCD (values 88-105)
    }
      
  }
}
    

void readButtons () {
  if (digitalRead(fwdButton) && fwd==LOW && rvs==LOW){
    fwd = HIGH;
    rvs = LOW;
  }
  if (digitalRead(rvsButton) && fwd==LOW && rvs==LOW){
    rvs = HIGH;
    fwd = LOW;
  }
//  if ((digitalRead(fwdButton) || digitalRead(rvsButton)) && (rvs || fwd)){
//    fwd = LOW;
//    rvs = LOW;
//  }
}

void movement() {
    if (md.getM1CurrentMilliamps()>currentLimit) { //checks overcurrent condition and if happens, stops motion
      ovrCurrent = true;
      md.setM1Speed(0);
    }  
    if (fwd == HIGH && avgMeasure >180 && ovrCurrent == false) { //check conditions and then move DOWN
      md.setM1Speed(400);
    }
    else if (rvs == HIGH && avgMeasure < 980  && ovrCurrent == false) { //check conditions and then move UP
      md.setM1Speed(-400);
    }
    else {
      ovrCurrent = false;      
      md.setM1Speed(0);
      rvs = LOW;
      fwd = LOW;    
    }
}

void calculate(){
   avgMeasure = map((float)avgMeasure, 180.0, 980.0, 4350.0, 2650.0); // the smallest distance between pivot points is 26.5mm and the biggest is 43.5mm
   calcHeight = (float(hC[plateNo]) + (sqrt(20250000.0 - (float)avgMeasure*(float)avgMeasure))/100); //side of triangle is 45mm, squared is 2025
   PL = sqrt(float(CL[plateNo])*float(CL[plateNo]) + float(calcHeight)*float(calcHeight));
   PR = sqrt(float(CR[plateNo])*float(CR[plateNo]) + float(calcHeight)*float(calcHeight));
   perimeter = (float)perimeterCnst + (float)PL + (float)PR;
   perimeter = round(float(perimeter)*10)/10.0;
   testingHeight = (sqrt(20250000.0 - (float)avgMeasure*(float)avgMeasure))/100 - 3.05;

   
}

void lcdPrint(){
  lcd.setCursor(0,0);
  lcd.print("P: ");
  lcd.print(perimeter);
  lcd.setCursor(10, 0);
  lcd.print("H");
  lcd.print(testingHeight);
    
  if (actualSelectReading > 100 && actualSelectReading < 900) {
    lcd.setCursor(0, 1);
    lcd.print("L");
    if (plateSize <=99){
      lcd.setCursor(1, 1);
      lcd.print(plateSize);
      lcd.print("      "); 
    }
    if (plateSize > 99){
      lcd.setCursor(1, 1);
      lcd.print(plateSize);
      lcd.print("     ");
     
    }
  }
  else {
    blinkError();
  }
  lcd.setCursor(10, 1);
  lcd.print("AN");
  lcd.print(measureToPrint);
}


void blinkError() {
  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > Blink_interval)   {
    lcd.setCursor(0,1);
    previousMillis = currentMillis;
   
    if(BlinkOnOff){
      lcd.print("errPlate");
    }
    else {
      lcd.print("        ");
    }
    BlinkOnOff = !BlinkOnOff;
  }
}

slipstick:
By a strange coincidence if you get 201 x 1023 and then divide by 200 you get 1028.

Hmm... think you got something there... trying to trace that loop..

When is measure ever zeroed?

With a voltmeter? Haven't tried that.

Thanks,
Dan

This should be changed from

void readPotentiometers(){
  for (int i=0; i< 200; i++) { // taking the average of 200 readings to stabilize the display
    measure = measure + analogRead(potIn);
    if (i==199) {
      avgMeasure = measure/200;
      measure = analogRead(potIn);
    }
  }

to

void readPotentiometers(){
  long measure = 0L ;  // long won't overflow, use a local variable for local values.
  for (int i=0; i< 200; i++) // taking the average of 200 readings to stabilize the display
    measure += analogRead(potIn);
  avgMeasure = measure / 200.0 ;
}

and lose this global definition of measure:

float measure = 0; // the potentiometer value

Note that variables that are used locally should be declared locally, not clutter up the global namespace.

Averaging is more straight-forward than your code made it. Set to zero, iterate and sum, then divide.
Avoiding a float variable in the loop will be a little faster, note.

You could (should) make readPotentiometers into a function returning the average value, more handy to use, and you can lose another global variable too.

Hi Mark,

Thanks a lot - now understand that the int variable was overflowing at some point.

void readPotentiometers(){
  long measure = 0L ;  // long won't overflow, use a local variable for local values.
  for (int i=0; i< 200; i++) // taking the average of 200 readings to stabilize the display
    measure += analogRead(potIn);
  avgMeasure = measure / 200.0 ;
}

Do you miss setting measure to zero at some place here? If not setting it to zero after each for loop, then I will indeed be summing 201 instances of measure, as Steve noted. Or I could divide by 201 instead.

Dan

dan13:
Hi Mark,

Thanks.

void readPotentiometers(){

long measure = 0L ;  // long won’t overflow, use a local variable for local values.
  for (int i=0; i< 200; i++) // taking the average of 200 readings to stabilize the display
    measure += analogRead(potIn);
  avgMeasure = measure / 200.0 ;
}




Do you miss setting measure to zero at some place here? If not setting it to zero after each *for* loop, then I will indeed be summing 201 instances of measure, as Steve noted. Or I could divide by 201 instead.

Dan

No I didn’t. The local variable is set to zero when the variable is declared. You perhaps don’t understand
that local variables are declared afresh every time the function is called. Indeed with recursion you can
even have multiple extant copies of the same local variable, one for each function call that’s in-flight.

Thanks a lot, Mark. I was missing that point indeed.

Dan

But, now that I think of it, a float variable (like I had before) is also 4-byte long, so how it could overflow with (roughly) 1000*200=200000?

Dan

Or am I wrong and don't understand how float is treated?

Dan

dan13:
But, now that I think of it, a float variable (like I had before) is also 4-byte long, so how it could overflow with (roughly) 1000*200=200000?

Dan

I use long rather than int to prevent truncation. I avoid float because its very slow on an 8-bit microcontroller.

So I don't understand then how it comes to solve my problem number 1 described in my first message in this topic?

Note: Haven't tested it, will only be able to test it tomorrow

Dan

Problem number 1 mentions analogRead returning 1028.

analogRead does not return 1028.

No, what I was trying to describe in problem number 1, was that the reading tops out at something like 3.9V and turning the potentiometer further increases the voltage (measured with a voltmeter), but the reading remains the same.

Dan

The ADC cannot read a voltage higher than the analogue reference voltage.

So? You mean I must use the aref pin and feed it with 5V? As far as I know this is not needed.

dan13:
So? You mean I must use the aref pin and feed it with 5V? As far as I know this is not needed.

1. Look at the following diagram (Fig-1) for the internal details of the ADC Module of ATmega328P MCU of UNO Board and then decide whether you should connect any voltage at AREF-pin or not. The default voltage of VREF-point of the ADC is 5V (AVCC connected with Vcc by a jumper in UNO).

adc328p.png
Figure-1:

2. Voltage connected at VREF-point is called the Full Scale (FS) of the ADC. In Fig-1, the FS is 5V for the ADC.

3. Take a jumper and short AREF-pin and A0-pin of the UNO and then execute this code: unsigned int = analogRead(A0);. How much value do you expect for the variable x? 5V of VREF-point will be digitized by the ADC and all the 10-bits of the ADC will assume 1s; as a result you will get this value: 000000 11 1111 1111 binary = 0x03FF hex = 1023 decimal for x. Why are you getting 1028? Follow step-by-step methodology to program the ADC; you will always come up with correct result.

adc328p.png