My Nano (running at about 4.5 V) ADC with Vbg ref (REFS[1:0] = 00) gives:
- low Vbg values (MUX[3:0] = 1110) of 1016 to 1017; I expected closer to1023, and
- high GND values (MUX[3:0] = 1111) of 1 to 3; I expected closer to 0.
Is this fixable? Have I made a mistake? A workaround suggestion?
Sample code (hacked from larger program) follows
(BTW Where's 'insert code? Where's post preview? Let's try BlockQuote; umm no, maybe preformat? Any also attached as upload)
const int kLoopsPerSecond = 10; // was 50 in main prog
long nV = 0;
bool bLogThisLoop = false;
int ePin[2] = {14, 15};
double V[2] = {0.0, 0.0};
double minV[2] = {9e9, 9e9};
double maxV[2] = {-9e9, -9e9};
double sumV[2] = {0.0, 0.0};
double sumV2[2] = {0.0, 0.0};
// the setup function runs once when you press reset or power the board
void setup() {
//Serial.begin(57600); // ESP8266 default of 74880 not supported on Linux
Serial.begin(115200); // ESP8266 default of 74880 not supported on Linux
while(!Serial); // for the Arduino Leonardo/Micro only
Serial.println();
Serial.println(F(__DATE__ " @ " __TIME__));
Serial.println(F(__FILE__));
Serial.println();
pinMode(LED_BUILTIN, OUTPUT);
InitADCbg_ec_a();
Serial.print(F("ADMUX=0x"));Serial.println(ADMUX, HEX);
Serial.print(F("ADCSRA=0x"));Serial.println(ADCSRA, HEX);
Serial.println();
}
void PrintStats(){
static double vCC = 4.5;
String res;
double vRef;
for(int ix = 0; ix < 2; ++ix){
res = F("vbg:");
vRef = 1.1;
int iP = ePin[ix];
res += String(iP);
res += F("=");
if(iP == 0xE){ res += F("V1.1"); }
if(iP == 0xF){ res += F("GND"); }
double v = V[ix];
res += F("\t=");
res += String(v);
res += F(" \tavg = ");
double avg = sumV[ix] / nV;
res += String(avg);
res += F(" \t std = ");
double sd = sqrt(((sumV2[ix] / nV) - (avg * avg)));
res += String(sd);
res += F(" \t min = ");
res += String(minV[ix]);
res += F(" \t max = ");
res += String(maxV[ix]);
res += F(" \t V = ");
res += String(vRef * ((avg + 0.5) / 1024.0), 4);
Serial.println(res);
}
}
long GetLoopPeriod_lps(int loopsPerSecond){
return millis() * loopsPerSecond / 1000;
}
bool IsSignificantNumber(int n, int maxInDecade){
if(maxInDecade > 9) { maxInDecade = 9; }
if(maxInDecade < 1) { maxInDecade = 1; }
String str, strMaxInDecade;
str = n;
strMaxInDecade = maxInDecade;
str.replace("0", "");
str.replace("-", "");
if(str.length() == 0) return true; // 0 is significant
if(str.length() >= 2) return false; // NN cannot be significant
return str <= strMaxInDecade; // N only significat if in range 1 - maxInDecade
}
// the loop function runs over and over again forever
void loop() {
++nV;
digitalWrite(LED_BUILTIN, nV % 2 ? HIGH : LOW);
bLogThisLoop = IsSignificantNumber(nV, 5);
long period = GetLoopPeriod_lps(kLoopsPerSecond);
if(bLogThisLoop){
Serial.print(F("Loop Start nV="));Serial.println(nV, DEC);
}
char ch = 0;
while(Serial.available() > 0){
int sr = Serial.read();
Serial.print(F("Serial.read()=0x"));Serial.println(sr, HEX);
ch = sr;
}
for(int ix = 0; ix < 2; ++ix){
uint16_t v;
ReadAnalog_ec_a(0); // just get one out the way
int iP = ePin[ix];
v = ReadAnalog_ec_a(iP);
if(v < minV[ix]) { minV[ix] = v; }
if(v > maxV[ix]) { maxV[ix] = v; }
V[ix] = v;
sumV[ix] += v;
sumV2[ix] += (double)v * v;
}
if(bLogThisLoop) {
PrintStats();
Serial.println();
}
while(period == GetLoopPeriod_lps(kLoopsPerSecond)){} // pause whilst same time period
}
void InitADCbg_ec_a()
{
ADMUX = 0; // do full reset
ADMUX |= (1<<REFS1) | (1<<REFS0); // 11 = 1.1V // Select Vref=Vbg
ADCSRA = 0; // do full reset
// prescaler range is 2 to 128; ADPS[2:0] 00x = /2, 010 = /4, 011 = /8, 100 = /16, 101 = /32, 110 = /64, 111 = /128
//set prescaller to 128 (ADPS2+1+0) and enable ADC
ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADEN);
ReadAnalog_ec_a(0); // just get one out the way
}
uint16_t ReadAnalog_ec_a(uint8_t ADCchannel)
{
// https://embedds.com/adc-on-atmega328-part-1/
//select ADC channel with safety mask
ADMUX = (ADMUX & 0xF0) | (ADCchannel & 0x0F);
uint16_t res;
res = physical_ReadAnalog_ec_a();
res = physical_ReadAnalog_ec_a();
res = physical_ReadAnalog_ec_a();
res = physical_ReadAnalog_ec_a();
res = physical_ReadAnalog_ec_a();
return res;
}
uint16_t physical_ReadAnalog_ec_a()
{
//single conversion mode
ADCSRA |= (1<<ADSC);
// wait until ADC conversion is complete
while( ADCSRA & (1<<ADSC) ){}
return ADC;
}
NanoBoardAdcInternalRefMinimal.ino (4.0 KB)