I'm using this sketch to measure the analogread from A0 and take multiple readings.
It works so far with 16 samples but when I change it to 60 or 80 I get negative results (16 is the original value set to nSamp). This is the page where I got it from.
/*
* measure adc voltage accurately by taking multiple readings - see notes on this page
* http://www.skillbank.co.uk/arduino/adc1.htm
*
* www.skillbank.co.uk Sept 2020
*/
//Analog input and pin assignments
const byte V1Pin = A0; // use will use analog pin 1 for voltage 1
int reading; //the value we read from the ADC
// sampling parameters
int nSamp = 80; // Number of Samples to take for each reading - best if it's a power of two.
int interval = 7; // milliseconds interval between successive readings
unsigned long sum1 = 0; // the total of nSamp readings from the ADC
//calculating voltages
int result; // calculated value of measured voltage in millivolts
//float vScale=5; //choose the right scale to suit the reference you have chosen.
//float vScale=3.3;
//float vScale=2.56;
float vScale=1.1;
//*** If you calibrate the system you can adjust the value of vScale to give more accurate readings.
void setup()
{
Serial.begin(115200);
analogReference(INTERNAL); // program is being tested on a 5V Arduino Micro Pro - 32U4 chip so this will be 5.0V
//*** The chip on your Arduino - depending on type - is provided with SOME of the following reference voltages
//DEFAULT: the default analog reference of 5 volts (on 5V Arduino boards) or 3.3 volts (on 3.3V Arduino boards)
//INTERNAL: a built-in reference, equal to 1.1 volts on the ATmega168 or ATmega328 and 2.56 volts on the ATmega8 and 32U4 chip boards.
//EXTERNAL: the voltage applied to the AREF pin. The Arduino Micro Pro does not have a pin to let you do this
vScale = vScale * 1000/1024; //scale the reading to read in millivolts
reading = analogRead(V1Pin); // dummy read to settle ADC Mux
delay(5);
}
void loop()
{
sum1 = 0; //ready to start adding values
//add up nSamp successive readings;
for (byte count = 0; count < nSamp; count++ )
{
reading = analogRead(V1Pin); // actual read
sum1 = sum1 + reading;
delay(interval);
}
// we print reading values to help with calibration
//Serial.print("Total of ");
//Serial.print(nSamp);
//Serial.print(" readings is: ");
Serial.print(String(sum1));
result = convReadings(sum1, nSamp, vScale);
Serial.print(" ");
//Serial.print("Voltage is ");
Serial.println(result);
//Serial.println(" millivolts.");
delay(10);
}
//
// Calculate average sensor reading, convert to voltage
//
int convReadings(int sum, int number, float scale)
{
sum = sum + (number >>1); // add a correction of 0.5 of the reading - see notes
float mV = sum * scale; // mV = sum * (Vref * 1000 / 1024 )
mV = mV / number; //divide by number of readings last to keep precision high
return ((int) mV); //return the result as an integer as decimal point values arent valid
// (int) is a "cast" to change a float variable to an integer. Values after the decimal point are "cut off" so float 1.93 becomes int 1
}
Maybe I miss something or there is a reason why it's 16 (and obiously I don'i get it).
Any help is appreciated.
1023 is the max value for a 10bit number and 32767 is quite the half way to 65535, wich is the max value for a 16bit unsigned number (r max value for a signed number).
You declared your data "readings" as a int, so I can assume it is a 16bit (it actually depends on your board).
by doing successive sum of the reading data, I guess you reach the limit of a 16bit number. Therefore, your calculation is not true anymore.
Plan should be:
always take care of the format data;
do mean calculation with fewer values, or with smaller values, or in several steps
2nd hint. While your sum1 is a long, what type is the incoming variable "sum", in the subroutine convReadings()? And what is the maximum positive value it can hold?
I have now in the setup the same routine as in the loop (with "sum" as int) but interestingly it did not produce negative results even when I read 100 samples.
float vScale=1.1;
void CheckConvertWith(unsigned long value){
Serial.print(value);
Serial.print("\t");
Serial.println(convReadings(value,100,vScale));
Serial.println("-------------------------------------------");
}
void setup()
{
Serial.begin(115200);
vScale = vScale * 1000/1024; //scale the reading to read in millivolts
Serial.println("long\tsum\tsum+50\tresult");
for (unsigned long s = 98250;s < 98260;s++) CheckConvertWith(s);
for (unsigned long s = 65530;s < 65540;s++) {
Serial.print(s);
Serial.print("\t");
Serial.println(int (s));
};
while(1);
}
void loop() {
}
//
// Calculate average sensor reading, convert to voltage
//
int convReadings(int sum, int number, float scale)
{
Serial.print(sum);
Serial.print("\t");
sum = sum + (number >>1); // add a correction of 0.5 of the reading - see notes
Serial.print(sum);
Serial.print("\t");
float mV = sum * scale; // mV = sum * (Vref * 1000 / 1024 )
mV = mV / number; //divide by number of readings last to keep precision high
return ((int) mV); //return the result as an integer as decimal point values arent valid
// (int) is a "cast" to change a float variable to an integer. Values after the decimal point are "cut off" so float 1.93 becomes int 1
}
It tests the function convReadings() as you use it now. The results for a certain range are: