Program size and Analog read ... Solved #5

Its a single channel datalogger application. With the Adafruit 32U4 Basic Proto… its a menu driven code interfacing with a LabVIEW app and all works as expected. Except the stability of the AnalogRead… the sensor is a LM35 chip and steady as a rock by itself.

After lots of struggle I decided to segregate only the Analog read part to check if that by itself is steady. That code is attached . This is very steady. SO this elimnates the following :

  1. Random Noise pickup by sensor wiring.
  2. The Analog input pin and the MCU itself.
  3. The code used for reading / averaging / displaying.

As you can see from the code attached there are lots of commented parts in the loop - these have nothing to do with the analog read part as mostly they are for the user menu interface.

The size difference between the attached code and the actual code is huge … the actual is at 99% of the available flash. And the dynamic variables take 1700 bytes. Still OK for the 32U4.

I have observed the raw count as returned by the attached code - its steady at 96 counts. Which is approx 30 Deg C .

Whereas the actual code returns anything from 60 to 180 counts and pretty wildly varying.

Does code size have anything to do with the analog reads ?

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include "RTClib.h"
#include "RunningAverage.h"
#include <phi_interfaces.h>
#include <EEPROM.h>
#include <SD.h>

LiquidCrystal_I2C  lcd(0x3F, 2, 1, 0, 4, 5, 6, 7);        //  0x3F is the I2C bus address of LCD
RTC_PCF8523 rtc;
File logFile;
File root;


#define newFilePB     A1
#define apendFilePB A2
#define sendFilePB   A3
#define LogOnSW     A4
# define VBATPIN     9

const byte scan_LED    = 11;
const byte SDCselect   = 10;
const int lm35Pin          =  A0;                    // Analog pin to use.

#define total_buttons 3
char mapDIN[] = {'N', 'D', 'S'};                      // This is a list of names for each button.
byte pinDIN[] = { newFilePB, apendFilePB, sendFilePB };  // The digital pins connected to the 4 buttons.
phi_button_groups MyDIN(mapDIN, pinDIN, total_buttons);

boolean homeDispGate = true, setClockBit ;
boolean beginLogGate = true, fileChooseGate, newFileGate, oldFileGate, dumpDataGate ;
boolean eraseConfGate, doLoggingGate, logSwitchGate, waitOnSerGate, slTransmittGate, prepareTransfer;
boolean started, ended, readyToReceiveDump;

byte prevSecond;
byte index1;

char validDIN = '0';
char incomingByte ;                         //Variable to store the incoming Serial1 byte
char tBuffer[10];
char clockStringNow[17];
char LCDmsg[17];
char dataToLog[40];
char msgFromLVapp[40];                // Storage for message received from LabVIEW app

unsigned int  loopInterval = 50;
unsigned int loggingInterval ;                        // Enter the interval in second
unsigned int epromAddress = 10;
unsigned int RA_SampleSize = 50;
unsigned int Val_00 = 0;                              // Variable to hold raw AI data
unsigned long scanMs = millis();

float measuredvbat;
float analog_Ch0Val, tempDegC;
float battVolts ;

RunningAverage RA_Ch00(RA_SampleSize);

//================= SETUP =========================

void setup() {

  // START SERIAL FOR DEBUGGING
  Serial.begin(9600);
  Serial.println( "Starting TempLogger Application !!");

  pinMode(scan_LED, OUTPUT);

  // START THE LCD INTERFACE
  lcd.begin(16, 2);
  lcd.setBacklightPin(3, POSITIVE);
  lcd.setBacklight(HIGH);
  lcd.clear();
  lcd.print(F("TempratureLogger" ));
  lcd.setCursor(0, 1);
  lcd.print(F(" Version :DLite " ));
  delay (1000);
  lcd.clear();

  EEPROM.get(epromAddress, loggingInterval);
  if ( loggingInterval > 600 || loggingInterval < 1) {
    loggingInterval = 1;
    EEPROM.put(epromAddress, loggingInterval);
  }
  lcd.print(F("Logging Interval" ));
  lcd.setCursor(0, 1);
  char logInterval[17];
  sprintf( logInterval, "   %03u %s", loggingInterval, "second");
  lcd.print(logInterval);
  delay (1000);
  lcd.clear();

  // START THE RTC INTERFACE
  if (! rtc.begin()) {
    lcd.print(F("Couldn't find RTC"));
    while (1);
  }

  if (! rtc.initialized()) {
    Serial.println("RTC is NOT running!");
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));  // Set the RTC to the date & time this sketch was compiled
  }

  // CHECK THE PRESENCE OF SD CARD
  lcd.print(F("Checking SDcard"));
  lcd.setCursor(0, 1);
  lcd.print(F("Interface.. Wait"));
  delay (1000);
  lcd.clear();
  if (!SD.begin(SDCselect)) {                        // See if the card can be initialized:
    Serial.print(F("SD Card Fail !!"));
  }
  else {
    lcd.print(F(" SDCard Pass!!"));
  }
}

//================ SCAN LOOP ======================

void loop()
{
  
  //if (homeDispGate || waitOnSerGate) readSerial(); // Do not put this inside any timed loop...

  acquireTempVal();                                           // Read the Temperature
  if (scanMs - millis() > loopInterval)                  // Loop interval = 100ms now.
  {
    scanMs = millis();
    validDIN = MyDIN.getKey();                           // Read the Push buttons  for every scan..
    displayHome(); 
   // readBatVolt();
   // if (measuredvbat < 3.5 ) {
   //    digitalWrite(lowBatt_LED, HIGH);
   // }
    // else {
    //  digitalWrite(lowBatt_LED, LOW);
    //  }
    //    Serial.print("Battery voltage is  ");
    //    Serial.println(measuredvbat); 
    //checkKeys();                                             // Enable to check key wiring...to use uncomment this line & function also
    // startLogging();                                            // Handle all SD card routines and logging here
  }                                                // Scan end
}                                                  // loop end

//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

void displayHome()
{
  DateTime now = rtc.now();                       // Get the current date time details ..
  if ( now.second() != prevSecond )
  {
    prevSecond = now.second();
    lcd.setCursor(0, 0);                                // Print to LCD
    sprintf(clockStringNow, " %02d-%02d %02d:%02d:%02d ", now.day(), now.month(), now.hour(), now.minute(), now.second());
    lcd.print(clockStringNow);
    dtostrf(tempDegC, 5, 2, tBuffer);
    lcd.setCursor(0, 1);
    sprintf(clockStringNow, "  Deg C = %s ", tBuffer);
    lcd.print(clockStringNow);
  }
}

//*********************************************

// Function to Acquire the analog value and average it..

void acquireTempVal()
{
  battVolts = 3.3;
  Val_00 = analogRead(lm35Pin);
  RA_Ch00.addValue(Val_00);
  analog_Ch0Val = RA_Ch00.getAverage();
  tempDegC = 100 * (mapf(RA_Ch00.getAverage(), 0, 1023, 0, battVolts));
}

//************************************************

// Function to map the analog count to required voltage level.

float mapf(long x, float in_min, float in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

//************************************************

Does code size have anything to do with the analog reads ?

No.

Whereas the actual code returns anything from 60 to 180 counts and pretty wildly varying.

So, you have some code that works perfectly, and some code that you have questions about. And, you decided that posting the perfect code was the right thing to do. I can not imagine the thought process that led to THAT conclusion as being reasonable.

Sorry Paul for being unreasonable … !!

I am now attaching the code that does NOT work as expected and varies the temperature readings randomly and almost 10 degress C above the actual.

Its a ZIP file due to the size of the code…

Feather_32U4_DataLog.zip (6.88 KB)

The Documentation.ino file purports to describe all the connections, but it says that nothing is connected to pin 14 and that the LM35 is connected to pin A0. On the Uno, those are the same pin. Are they really different pins on the feather?

In the code in the zip file, comment out all the code except for the code that reads the analog pin that the LM35 is connected to.

Is the value read from that pin steady?

Start uncommenting code. Uncommenting which code causes the value to be unsteady?

@PaulS
Thanks for patiently reading the code.

Yes the Feather does not break out all pins and actually there is no pin 14 and in any case A0 seems to be wired fine as i am able to read the LM35 value very well when run in the truncated code after removing rest of the code. I will now correct the documenation.ino to reflect the actual nomeclature of the 32U4 Feather

Maybe I will try what you said - i kind of did it already by actually deleting code that was not reading the A0 pin and creating a compact sketch. But as you said your method is slightly different and may have a pointer.

@Paul.

Your idea worked . Thanks.

The offending code segment was the last function which was reading the battery voltage on VABTPIN. The moment i blocked that everything became normal.

But frankly I still have to find out what s=wrong with a code as simple as this :

// Read the battery volts..
void readBatVolt()
{
  measuredvbat = analogRead(VBATPIN);
  measuredvbat *= 2;                               // we divided by 2, so multiply back
  measuredvbat *= 3.3;                            // Multiply by 3.3V, our intrenal reference voltage
  measuredvbat /= 1024;                          // convert to voltage
}

//*********************************

void updateBattStatus() {
  readBatVolt();
  if (measuredvbat < 3.5 ) {
    digitalWrite(lowBatt_LED, HIGH);
  }
  else {
    digitalWrite(lowBatt_LED, LOW);
  }
}

Anyway for the time being the unit is packed and put into use. Maybe over the weekend I have to see waht really is the issue with this.

The Arduino has only one analog to digital converter. It is shared by the 6 analog pins. When you switch which pin you are reading from, the ADC needs some time to acknowledge that. Typically, the first reading on the new pin is suspect, and is usually discarded.

Your code is not doing that.

Try reading the battery pin twice, discarding the first result. Also read the other pin twice, discarding the first result.

PaulS:
Typically, the first reading on the new pin is suspect, and is usually discarded.

That's not usually the case unless the source impedance is significantly above 10k, and you use
more than one analog pin (which is the case here).

Not knowing the impedance of the battery voltage resistive divider its not possible to say this
is the problem, but its easily cured by adding a 10n to 100nF capacitors from the VBATPIN to
ground and from the lm35 pin to ground to reduce those pins source impedance sufficiently.
It certainly won't hurt as you don't need high bandwidth on a battery voltage monitor or
temperature monitor.

I think the definition of VBATPIN as 9 can also be A9, since digital and analog 9 are same pin (though
I'm assuming this board is just like the Leonardo ATmega32u4 one)

@PaulS
@MarkT

Thanks to both for your tips. Let me answer the points :

  1. Yes i had wrongly assigned the VBATPIN to 9 instead of A9. A previous verison of the code does in fact have that as A9 only ... not sure when the A vanished. ( I know I must have done it ... who else )

  2. The potential divider for the battery voltage reading is two nos of 100K resistors between the +terminal and Gnd. The A9 is fed from the mid tap off. I know they did this to reduce the continuous drain on the battery and maybe the 0.1uf can help.

  3. Now that i know i need to read two analog parameters, I better plan my averaging properly and give enough time between the reads for SH amplifier to settle. Will do this weekend when i get the unit back ... its happily logging data right now !!