A few hours to optimize some bloated code?

Hi,

I am developing a tool to assist with calibration of torque gauges. This tool is almost complete and while functionality is almost there I am running into the limit of my experience with coding e.g. It took me two days and finally with help from this forum, to change a var def from long to unsigned long which solved the issue.

With this in mind, I would like to engage someone to assist with trimming the fat out of my program and give me some space back for a couple more calculations/features.

Arduino Micro 32u4 platform with Nextion NX832T035_011, uSD card reader, DS1307 RTC and ADS1115 16-bit ADC.

As I said, everything is operational but I want to free up some of the 97% used program memory, which I think could be accomplished with string replacement.

Anyone interested should reply, or DM with rates for what I would estimate 2 to 5 hours work and a few back & forth sessions.

FYI, I would love to expand my coding knowledge but time is getting tight ... Diesel driven power packs to repair.

depending how you have been using the String class, it might require way more than 2 to 5 hours of work.. Don't discount the time just to get a feel for your code if it's long.

For example...

st2next = ("t0.txt=\"" + String(ftlbf) + "\"");                 //compile the ftlbf string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t2.txt=\"" + String(psi) + "\"");                   //compile the psi string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t4.txt=\"" + String(lbf) + "\"");                   //compile the lbf string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t16.txt=\"" + String(pxzero) + "\"");               //compile the pxzero string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t18.txt=\"" + String(pxgain) + "\"");               //compile the pxgain string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t21.txt=\"" + String(adc0) + "\"");                 //compile the adc0 string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t23.txt=\"" + (datetime) + "\"");                   //compile the datetime string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t30.txt=\"" + String(gagval * 0.25) + "\"");        //compile the gagval/4 string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t31.txt=\"" + String(psifs * 0.25) + "\"");         //compile the psi full scale / 4 string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t33.txt=\"" + String(gagval * 0.5) + "\"");         //compile the gagval/2 string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t34.txt=\"" + String(psifs * 0.5) + "\"");          //compile the psi full scale / 4 string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t36.txt=\"" + String(gagval * 0.75) + "\"");        //compile the gagval*0.75 string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t37.txt=\"" + String(psifs * 0.75) + "\"");         //compile the psi full scale * 0.75 string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t39.txt=\"" + String(gagval) + "\"");               //compile the gagval string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t40.txt=\"" + String(psifs) + "\"");                //compile the psi full scale string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t41.txt=\"" + String(psi) + "\"");                  //compile the psi string
  stringtoNextion();                                              //send the string to Nextion
void stringtoNextion() {//------------------print nextion commands followed by three 0xff
  Serial1.print(st2next);                             //print st2next string to serial1
  three0xff();                                        //send three 0xff
  st2next = "";                                       //reset string variable to empty
}

void three0xff() {//------------------------Three 0xff needed by Nextion following a command
  Serial1.write(0xff);                                //print 0xff to serial1
  Serial1.write(0xff);                                //print 0xff to serial1
  Serial1.write(0xff);                                //print 0xff to serial1
}

If you plan to add code then that 97% is clearly important. If not, don't worry about it.

If your RAM utilization is high though, you may have a problem. String objects in a low RAM situation are a disaster waiting to happen.

Arduino style hardware is cheap. For the price of a few hours expert help, you can buy a small box of far more capable processors :wink:

Hey wildbill,

I guess I could use a couple 555's as well. That's the other boilerplate response.

I have further plans for this project, but just want to test its "legs" on hardware at hand.

I could go complete computer vision etc using a laptop and some nice NI hardware, but that's not my goal.

My point is that if you are using a low powered Arduino, $20 will get you something much much more capable e.g. Teensy, Adafruit feather or ESPxxx. If you want to improve your skills, it's worth working on your code, but if you are pressed for time (as I think you are), you can just buy your way out of trouble for now.

Post your code. The folks here are pretty generous with their time and can likely give you some good hints to help trim it down.

Edit: I see this is in the paid help section. Not sure it was before. Message me.

Complete code as it stands, and works at the moment...

#include "RTClib.h"                   //RTC DS1307 library
RTC_DS1307 rtc;                       //initialise specific RTC
#include <Adafruit_ADS1X15.h>         //ADC library
Adafruit_ADS1115 ads;                 //initialise specific ADC
//-----------------------------Nextion
const int BUFFER_SIZE = 10;           //buffer size for incoming serial from Nextion
char buf[BUFFER_SIZE];                //actual buffer of buffer_size
String celldisp = "4.00";             //initial cell area displayed
String armdisp = "12.00";             //initial arm length displayed
String gagdisp = "5000";              //initial full-scale gauge displayed
String pxdisp = "3000";               //initial pressure transducer value displayed
String st2next;                       //Strings for each command sent to Nextion
int cellpos = 0;                      //initial cell area switch-case setting
int armpos = 1;                       //initial arm length switch-case setting
int gagpos = 0;                       //initial full-scale gauge switch-case setting
int pxpos = 5;                        //initial pressure transducer switch-case setting
//-----------------------------SD card
#include <SD.h>                       //sd card library
Sd2Card card;                         //sd card comms and error handling
SdVolume volume;                      //sdcard filesystem (fat) handling
SdFile root;                          //sdcard file read & write handling
File dataFile;                        //define variable dataFile as the file
const int chipSelect = 5;             //sc card chip select pin
String dataString;                    //set dataString variable as empty string
int sdflag = 0;                       //used to record if the logging button has been pressed, 1=yes
int sdflag2 = 0;                      //used to record if setup parameters have been written to sd card, 1=yes
//-----------------------------Torque variables
//float psi;                          //pounds-per-square-inch
float cellval = 4.00;                 //initial cell area
float armval = 12.00;                 //initial arm length
long gagval = 5000;                   //initial gauge full scale
int wave;                             //waveform variable
int16_t adc0;                         //16-bit integer assignment for adc0
//-----------------------------Calibration data
#include <EEPROM.h>                   //include the eeprom library
struct MyObject {                     //object to 
  float field1;                       //enable storage 
  byte field2;                        //of variables
  char name[20];                      //to eeprom
};                                    //
int pxval = 3000;                     //initial pressure transmitter full scale (used if eeprom is empty)
int pxzero;                           //calibration zero
int pxgain;                           //calibration gain
String pxserial;                      //pressure transmitter serial number
unsigned long caldatetime;            //calibration date and time
int pxvaladd = 0;                     //pressure transmitter full scale
int pxzeroadd = 5;                    //calibration zero eeprom address
int pxgainadd = 10;                   //calibration gain eeprom address
int pxserialadd = 20;                 //px serial eeprom address
int caldateadd = 30;                  //px cal date eeprom address
int pxrange;                          //px adc0 range
float pxratio;                        //px adc to pxval ratio
//-----------------------------date & time
String datetime;                        //current date & time variable

void setup() {
  Serial1.begin(115200);                //Nextion default baud= 9600
  EEPROM.get(pxvaladd, pxval);          //read stored pressure transmitter full scale from eeprom
  EEPROM.get(pxzeroadd, pxzero);        //read stored pxzero setting from eeprom
  EEPROM.get(pxgainadd, pxgain);        //read stored pxzero setting from eeprom
  pxrange = (pxgain - pxzero);          //compute pxgain minus px zero to give span
  pxratio = (pxrange / pxval);

  DDRF |= (1 << PF0);
  DDRD |= (1 << PD6);

  if (!SD.begin(chipSelect)) {          //check if the sd card is present and can be initialized
    PORTD |= (1 << PD6);                //turn on card present LED if no card
    Serial1.print(F("vis b1,0"));       //hide start logging button if no card present
    three0xff();                        //send three 0xff
  }
  ads.begin(0x48);                      //set ADS1115 I2C address and begin comms
  //ads.setGain(GAIN_TWOTHIRDS);        //2/3x gain +/- 6.144V  1 bit = 3mV
  //ads.setGain(GAIN_ONE);              //1x gain   +/- 4.096V  1 bit = 0.125mV
  ads.setGain(GAIN_TWO);                //2x gain   +/- 2.048V  1 bit = 0.0625mV

  if (! rtc.begin()) {                  //check if the RTC is not available
    PORTF |= (1 << PF0);       //turn rtcled led on
  }
  if (!rtc.isrunning()) {                                         //check if the RTC is not running
    //Serial.println(F("RTC is NOT running, let's set the time!")); //print to serial port, replace with led flash
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));               //write the compilation date & time to the RTC
  }
  //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));               //write the compilation date & time to the RTC
  //---------------------------------------------------------Initial comms with the Nextion
  Serial1.print("t8.txt=\"" + String(celldisp) + "\"");           //prints initial cell value to Nextion
  three0xff();                                                    //send three 0xff
  Serial1.print("t10.txt=\"" + String(armdisp) + "\"");           //prints initial armlength value to Nextion
  three0xff();                                                    //send three 0xff
  Serial1.print("t12.txt=\"" + String(gagdisp) + "\"");           //prints initial gauge full-scale value to Nextion
  three0xff();                                                    //send three 0xff
}

void loop() {
  datestring();
  HMI_read();                                                     //read HMI
  adc0 = ads.readADC_SingleEnded(0);                              //read the AD and store the value in var adc0
  updatenextion();
  //---------------------------------------------------------Check sdflags
  if (sdflag == 1) {                                              //if the start logging button has been pressed
    st2next = ("vis b0,0");                                       //hide the settings button
    stringtoNextion();                                            //send three 0xff
    //-------------------------------------------------------Add file header information
    File dataFile = SD.open("datalog", FILE_WRITE);               //Create the dataFile
    if (dataFile) {                                               //Check if dataFile exists
      if (sdflag2 == 1) {                                         //Check if sdflag2 is set, skip writing header if = 1
        dataFile.println(datetime);                               //Store date & time to sdcard
        EEPROM.get(caldateadd, caldatetime);                      //Read stored calibration date from eeprom
        dataFile.println(caldatetime);                            //Store calibration date to sdcard
        dataFile.println((int)pxval, HEX);                        //Pressure transmitter full scale to sdcard
        dataFile.println(pxzero, HEX);                            //Store pressure transmitter zero reading to sdcard
        dataFile.println(pxgain, HEX);                            //Store pressure transmitter gain reading to sdcard
        dataFile.println((int)(cellval * 100), HEX);              //Store cell size to sdcard
        dataFile.println((int)(armval * 100), HEX);               //Store arm length to sdcard
        dataFile.println(gagval / 2, HEX);                        //Store gauge full-scale divided by two as HEX
        sdflag2 = 0;                                              //Set sdflag2 to 0 to ensure next time around the loop these parameters are not stored
      }
      PORTD |= (1 << PD6);                                        //Turn on logging LED
      dataFile.println(adc0, HEX);                                //Store adc0 value to sd card
      dataFile.close();                                           //Close the file on sd card
      PORTD &= !(1 << PD6);                                       //Turn off the logging LED
      dataString = "";                                            //Empty the datastring
    }
    dataFile.close();                                             //Close the file on the sd card
  }
  else {
    st2next = ("vis b0,1");                                       //Hide b1 if no card present
    stringtoNextion();                                            //Send the string to Nextion
  }
  datetime = "";                                                  //Reset datetime string to empty
}
//-----------------------------------------------------------HMI_read takes the data sent from the Nextion to the serial port
void HMI_read() {                                                 //There are 3 levels of nested switch statements corresponding to the page, object and index of the object.
  static uint8_t HMI_read_data[10];                               //Temporary buffer to hold the data from the display, space for 10 bytes
  static uint8_t HMI_read_data_i;                                 //Count of how many bytes have been received from the display.
  static uint8_t a5count;                                         //0xa5 repeated 3 times is used as a start indicator, this is a count of how many times it has been received.
  uint8_t readtemp;                                               //Hold the last received byte to ensure that it is only read from the receive buffer once.
  while (Serial1.available() > 0) {                               //Read every byte in the receive buffer
    readtemp = Serial1.read();                                    //Assign readtemp variable to incoming serial data
    if (readtemp == 0xa5) {                                       //Count the number of times 0xa5 has been received
      ++a5count;                                                  //Increment a5 counter
      if (a5count > 2) {                                          //If a5 count=3,
        a5count = 0;                                              //Set a5count variable to 0
        HMI_read_data_i = 0;                                      //Set HMI_read_data_i variable to 0
      }
    }
    else {
      a5count = 0;                                                //if there is an a5 count followed by anything else, reset the a5count to 0
    }
    HMI_read_data[HMI_read_data_i] = readtemp;
    if (HMI_read_data_i == 6) {
      switch (HMI_read_data[1]) {                                         //HMI_read_data[1] contains the page the data has come from
        case 0://----------------------------------------------------page 0
          switch (HMI_read_data[2]) {                                     //HMI_read_data[2] contains the type of object on the page that the data has come from
            case 0:                                                       //case 0 selects a page
              break;
            case 1:
              switch (HMI_read_data[3]) {                                 //HMI_read_data[3] is the index of the type of button, so 0 as there is 1 button to begin logging.
                case 0:                                                   //this is where to begin logging then set a flag to 1 so that this same routine can stop logging
                  if (sdflag == 0) {                                      //check if sdflag = 0
                    sdflag = 1;                                           //set sdflag to 1
                    sdflag2 = 1;                                          //set sdflag2 to 1
                    st2next = ("b1.txt=\"" + String{"Stop Log"} + "\"");  //compile the stop log string
                    stringtoNextion();                                    //send the string to Nextion
                  }
                  else {
                    dataFile.close();                                     //close the satafile
                    sdflag = 0;                                           //set sdflag to 0
                    st2next = ("b1.txt=\"" + String{"Start Log"} + "\""); //compile the start log string
                    stringtoNextion();                                    //send the string to Nextion
                  }
                  break;
              }
              break;
          }
          break;
        case 1://----------------------------------page 1
          switch (HMI_read_data[2]) {                   //HMI_read_data[2] is the index of the
            case 1:
              switch (HMI_read_data[3]) {               //HMI_read_data[3] is the index of the type of button, 0 to 5 as there are 6 buttons for setup.
                case 0://--------------------------cell down
                  cellpos--;                            //decrement cellpos variable
                  cellpos = constrain(cellpos, 0, 7);   //keep cellpos variable between 0 to 10
                  change_cell();                        //call change_cell routine
                  break;
                case 1://--------------------------cell up
                  cellpos++;                            //increment cellpos variable
                  cellpos = constrain(cellpos, 0, 7);   //keep cellpos variable between 0 to 10
                  change_cell();                        //call change_cell routine
                  break;
                case 2://--------------------------arm down
                  armpos--;                             //decrement armpos variable
                  armpos = constrain(armpos, 0, 12);    //keep armpos variable between 0 to 10
                  armsel();                             //call armsel routine
                  break;
                case 3://--------------------------arm up
                  armpos++;                             //increment armpos variable
                  armpos = constrain(armpos, 0, 12);    //keep armpos variable between 0 to 10
                  armsel();                             //call armsel routine
                  break;
                case 4://--------------------------gauge down
                  gagpos--;                             //decrement gagpos variable
                  gagpos = constrain(gagpos, 0, 15);    //keep gagpos variable between 0 to 10
                  gaugesel();                           //call gaugesel routine
                  break;
                case 5://--------------------------gauge up
                  gagpos++;                             //increment gagpos variable
                  gagpos = constrain(gagpos, 0, 15);    //keep gagpos variable between 0 to 10
                  gaugesel();                           //call gaugesel routine
                  break;
                case 6://--------------------------px serial number
                  //Serial.println("page1, case6");
                  break;
              }
              break;
          }
          break;
        case 2://------------------------------------------------page 2
          switch (HMI_read_data[2]) {
            case 1:
              switch (HMI_read_data[3]) {                             //HMI_read_data[3] is the index of the type of button, 0 to 5 as there are 6 buttons for setup.
                case 0://----------------------------------------Transmitter down
                  pxpos--;                                            //decrement pxpos variable
                  pxpos = constrain(pxpos, 0, 10);                    //keep pxpos variable between 0 to 10
                  pxsel();                                            //call pxsel routine
                  break;
                case 1://----------------------------------------Transmitter up
                  pxpos++;                                            //increment pxpos variable
                  pxpos = constrain(pxpos, 0, 10);                    //keep pxpos variable between 0 to 10
                  pxsel();                                            //call pxsel routine
                  break;
                case 2://----------------------------------------Calibration set zero
                  pxzero = ads.readADC_SingleEnded(0);                //read the adc
                  st2next = ("t16.txt=\"" + String(pxzero) + "\"");   //set st2next equal to pxzero variable
                  stringtoNextion();                                  //send the string to Nextion
                  EEPROM.put(pxzeroadd, pxzero);                      //write zero reading to eeprom
                  break;
                case 3://----------------------------------------Calibration set gain
                  pxgain = ads.readADC_SingleEnded(0);                //read the adc
                  st2next = ("t18.txt=\"" + String(pxgain) + "\"");   //set st2next equal to pxgain variable
                  stringtoNextion();                                  //send the string to Nextion
                  pxrange = (pxgain - pxzero);                        //compute pxgain minus px zero to give span
                  st2next = ("t19.txt=\"" + String(pxrange) + "\"");  //set st2next equal to pxrange variable
                  stringtoNextion();                                  //send the string to Nextion
                  EEPROM.put(pxgainadd, pxgain);                      //write gain reading to eeprom
                  delay(100);                                         //delay 100mS for EEprom write
                  EEPROM.put(pxvaladd, pxval);                        //write gain reading to eeprom
                  delay(100);                                         //delay 100mS for EEprom write
                  caldatelong();                                      //Call caldatestring routine
                  delay(100);                                         //delay 100mS for EEprom write
                  break;
              }
              break;
          }
          break;
      }
    }
    ++HMI_read_data_i;
    if (HMI_read_data_i > 9) {
      HMI_read_data_i = 9;
    }
  }
}
void change_cell() {//-------------------------------Selectable range of cell areas
  switch (cellpos) {
    case 0:
      cellval = 4.00;
      celldisp = ("4.00");
      break;
    case 1:
      cellval = 4.08;
      celldisp = ("4.08");
      break;
    case 2:
      cellval = 6.44;
      celldisp = ("6.44");
      break;
    case 3:
      cellval = 6.53;
      celldisp = ("6.53");
      break;
    case 4:
      cellval = 8.00;
      celldisp = ("8.00");
      break;
    case 5:
      cellval = 10.80;
      celldisp = ("10.80");
      break;
    case 6:
      cellval = 12.00;
      celldisp = ("12.00");
      break;
    case 7:
      cellval = 16.00;
      celldisp = ("16.00");
      break;
  }
  st2next = ("t8.txt=\"" + String(celldisp) + "\"");  //set st2next equal to celldisp variable
  stringtoNextion();                                  //send the string to Nextion
}
void armsel() {//-------------------------------------Selectable range of arm lengths
  switch (armpos) {
    case 0:
      armval = 1.0;
      armdisp = ("0.00");
      break;
    case 1:
      armval = 12.0;
      armdisp = ("12.00");
      break;
    case 2:
      armval = 18.0;
      armdisp = ("18.00");
      break;
    case 3:
      armval = 20.0;
      armdisp = ("20.00");
      break;
    case 4:
      armval = 22.0;
      armdisp = ("22.00");
      break;
    case 5:
      armval = 24.0;
      armdisp = ("24.00");
      break;
    case 6:
      armval = 26.0;
      armdisp = ("26.00");
      break;
    case 7:
      armval = 30.0;
      armdisp = ("30.00");
      break;
    case 8:
      armval = 32.0;
      armdisp = ("32.00");
      break;
    case 9:
      armval = 36.0;
      armdisp = ("36.00");
      break;
    case 10:
      armval = 42.0;
      armdisp = ("42.00");
      break;
    case 11:
      armval = 49.5;
      armdisp = ("49.5");
      break;
    case 12:
      armval = 52.0;
      armdisp = ("52.00");
      break;
  }
  st2next = ("t10.txt=\"" + String(armdisp) + "\"");  //set st2next equal to armdisp variable
  stringtoNextion();                                  //send the string to Nextion
}
void gaugesel() {//-------------------------Gauge selectable range of fsd torques
  switch (gagpos) {
    case 0:
      gagval = 5000;
      gagdisp = ("5000");
      break;
    case 1:
      gagval = 6000;
      gagdisp = ("6000");
      break;
    case 2:
      gagval = 8000;
      gagdisp = ("8000");
      break;
    case 3:
      gagval = 10000;
      gagdisp = ("10000");
      break;
    case 4:
      gagval = 12000;
      gagdisp = ("12000");
      break;
    case 5:
      gagval = 15000;
      gagdisp = ("15000");
      break;
    case 6:
      gagval = 18000;
      gagdisp = ("18000");
      break;
    case 7:
      gagval = 20000;
      gagdisp = ("20000");
      break;
    case 8:
      gagval = 25000;
      gagdisp = ("25000");
      break;
    case 9:
      gagval = 30000;
      gagdisp = ("30000");
      break;
    case 10:
      gagval = 35000;
      gagdisp = ("35000");
      break;
    case 11:
      gagval = 40000;
      gagdisp = ("40000");
      break;
    case 12:
      gagval = 50000;
      gagdisp = ("50000");
      break;
    case 13:
      gagval = 75000;
      gagdisp = ("75000");
      break;
    case 14:
      gagval = 80000;
      gagdisp = ("80000");
      break;
    case 15:
      gagval = 120000;
      gagdisp = ("120000");
      break;
  }
  st2next = ("t12.txt=\"" + String(gagdisp) + "\"");  //set st2next equal to gagdisp variable
  stringtoNextion();                                  //send the string to Nextion
}
void pxsel() {//----------------------------Selectable range of full scale pressures
  switch (pxpos) {
    case 0:
      pxval = 1000.0;
      pxdisp = ("1000");
      break;
    case 1:
      pxval = 1500.0;
      pxdisp = ("1500");
      break;
    case 2:
      pxval = 1800.0;
      pxdisp = ("1800");
      break;
    case 3:
      pxval = 2000.0;
      pxdisp = ("2000");
      break;
    case 4:
      pxval = 2600.0;
      pxdisp = ("2600");
      break;
    case 5:
      pxval = 3000.0;
      pxdisp = ("3000");
      break;
    case 6:
      pxval = 3500.0;
      pxdisp = ("3500");
      break;
    case 7:
      pxval = 4000.0;
      pxdisp = ("4000");
      break;
    case 8:
      pxval = 4500.0;
      pxdisp = ("4500");
      break;
    case 9:
      pxval = 5000.0;
      pxdisp = ("5000");
      break;
    case 10:
      pxval = 6000.0;
      pxdisp = ("6000");
      break;
  }
  st2next = ("t24.txt=\"" + String(pxdisp) + "\"");   //set st2next equal to pxdisp variable
  stringtoNextion();                                  //send the string to Nextion
}
void updatenextion() {//----------------------------------update the Nextion and do some crucial calcs
  float psi = (adc0 / pxratio);                                   //pounds-per-square-inch as a factor of adc0
  float lbf = (psi * cellval);                                    //cell pressure pounds-force
  float armft = armval / 12;                                      //convert arm inches to arm in feet for calcs only
  float ftlbf = (lbf * armft);                                    //foot-pounds torque
  float lbffs = (gagval / armft);                                 //line pull pounds-force full scale
  float psifs = (lbffs / cellval);                                //pounds-per-square-inch full scale
  float prpsi = (lbf / cellval);                                  //linepull divided by cell area equals pounds-per-square-inch
  wave = map(adc0, 0, 32752, 0, 255);                             //maps AD output for display on the grid only
  //------------------------------------------------------strings to Nextion
  st2next = ("t0.txt=\"" + String(ftlbf) + "\"");                 //compile the ftlbf string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t2.txt=\"" + String(psi) + "\"");                   //compile the psi string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t4.txt=\"" + String(lbf) + "\"");                   //compile the lbf string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t16.txt=\"" + String(pxzero) + "\"");               //compile the pxzero string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t18.txt=\"" + String(pxgain) + "\"");               //compile the pxgain string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t21.txt=\"" + String(adc0) + "\"");                 //compile the adc0 string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t23.txt=\"" + (datetime) + "\"");                   //compile the datetime string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t30.txt=\"" + String(gagval * 0.25) + "\"");        //compile the gagval/4 string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t31.txt=\"" + String(psifs * 0.25) + "\"");         //compile the psi full scale / 4 string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t33.txt=\"" + String(gagval * 0.5) + "\"");         //compile the gagval/2 string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t34.txt=\"" + String(psifs * 0.5) + "\"");          //compile the psi full scale / 4 string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t36.txt=\"" + String(gagval * 0.75) + "\"");        //compile the gagval*0.75 string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t37.txt=\"" + String(psifs * 0.75) + "\"");         //compile the psi full scale * 0.75 string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t39.txt=\"" + String(gagval) + "\"");               //compile the gagval string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t40.txt=\"" + String(psifs) + "\"");                //compile the psi full scale string
  stringtoNextion();                                              //send the string to Nextion
  st2next = ("t41.txt=\"" + String(psi) + "\"");                  //compile the psi string
  stringtoNextion();                                              //send the string to Nextion
  //---------------------------------------------------------Graph data
  String Tosend = "add 6,0,";                                     //send the string "add id,channel,"
  Tosend += wave;                                                 //Send the value and 3 full bytes
  Serial1.print(Tosend);                                          //send wave value to Nextion (string)
  three0xff();                                                    //send three 0xff
}

void stringtoNextion() {//------------------print nextion commands followed by three 0xff
  Serial1.print(st2next);                             //print st2next string to serial1
  three0xff();                                        //send three 0xff
  st2next = "";                                       //reset string variable to empty
}

void three0xff() {//------------------------Three 0xff needed by Nextion following a command
  Serial1.write(0xff);                                //print 0xff to serial1
  Serial1.write(0xff);                                //print 0xff to serial1
  Serial1.write(0xff);                                //print 0xff to serial1
}

void datestring() {//-----------------------Compile date and time "now" into a single string
  DateTime now = rtc.now();                           //grab date & time from the RTC
  long datetime1 = (now.unixtime());
  String datetimehex = String(datetime1);
  datetime += (datetimehex);
}

void caldatelong() {//-----------------------Compile date and time "now" into a single string
  DateTime now = rtc.now();                           //grab date & time from the RTC
  caldatetime = (now.unixtime());                    //assign unixtime to caldatetime
  EEPROM.put(caldateadd, caldatetime);               //write calibration date to eeprom
}

I did some simple changes and got it down to 93% code and 66% RAM . Lots more scope there I think.

String will take a variable like int, float or long and stringify it. That means that you don't need to do this:

    case 0:
      armval = 1.0;
      armdisp = ("0.00");

Instead you can do this:

void armsel()  //-------------------------------------Selectable range of arm lengths
{
  switch (armpos)
  {
    case 0:
      armval = 1.0;
//      armdisp = ("0.00");
      break;
    case 1:
      armval = 12.0;
//      armdisp = ("12.00");
      break;
    case 2:
      armval = 18.0;
//      armdisp = ("18.00");
      break;
    case 3:
      armval = 20.0;
//      armdisp = ("20.00");
      break;
    case 4:
      armval = 22.0;
//      armdisp = ("22.00");
      break;
    case 5:
      armval = 24.0;
//      armdisp = ("24.00");
      break;
    case 6:
      armval = 26.0;
//      armdisp = ("26.00");
      break;
    case 7:
      armval = 30.0;
//      armdisp = ("30.00");
      break;
    case 8:
      armval = 32.0;
//      armdisp = ("32.00");
      break;
    case 9:
      armval = 36.0;
//      armdisp = ("36.00");
      break;
    case 10:
      armval = 42.0;
//      armdisp = ("42.00");
      break;
    case 11:
      armval = 49.5;
//      armdisp = ("49.5");
      break;
    case 12:
      armval = 52.0;
//      armdisp = ("52.00");
      break;
  }
  st2next = ("t10.txt=\"" + String(armval) + "\"");  //set st2next equal to armdisp variable
  stringtoNextion();                                  //send the string to Nextion
}

The armDisp global isn't needed any more.

You have a couple of other functions that use the same pattern. Once those are fixed you get the numbers I mentioned at the start of this post.

Even then though, all those String objects are going to kill you with heap fragmentation.

Thank you wildbill, you don't f*** around.
Appreciate your time.

On line 121, did you intend to use the ~ operator or is ! correct?

      PORTD &= !(1 << PD6);                                       //Turn off the logging LED

It seems to work i.e toggles off

( 1 << PD6 ) = 01000000 binary
!( 1 << PD6 ) = 00000000 binary (logical NOT of any non-zero value is zero)
~( 1 << PD6 ) = 10111111 binary (bitwise inversion of 01000000)

you can save also by simplifying printing to the Nextion by having separate statements

for example this code could be changed

  Serial1.print("t8.txt=\"" + String(celldisp) + "\"");           //prints initial cell value to Nextion
  three0xff();                                                    //send three 0xff
  Serial1.print("t10.txt=\"" + String(armdisp) + "\"");           //prints initial armlength value to Nextion
  three0xff();                                                    //send three 0xff
  Serial1.print("t12.txt=\"" + String(gagdisp) + "\"");           //prints initial gauge full-scale value to Nextion
  three0xff();       

into

Serial1.print(F("t8.txt=\"")); Serial1.print(cellval); Serial1.print(F("\"")); //prints initial cell value to Nextion
three0xff();                                                                 //send three 0xff
Serial1.print(F("t10.txt=\"")); Serial1.print(armval); Serial1.print(F("\"")); //prints initial armlength value to Nextion
three0xff();                                                                 //send three 0xff
Serial1.print(F("t12.txt=\"")); Serial1.print(gagval); Serial1.print(F("\"")); //prints initial gauge full-scale value to Nextion
three0xff();    

using the values instead of the display strings as @wildbill said in #8

and you could create a function where you pass the value and the id of the text widget which will further optimise what makes it into memory

inline void sendToTxt(byte txtId, long value) {
  Serial1.write('t'); Serial1.print(txtId); Serial1.print(F(".txt=\"")); Serial1.print(value); Serial1.print(F("\""));
  three0xff();
}

inline void sendToTxt(byte txtId, flaot value, byte decimalDigits = 2) {
  Serial1.write('t'); Serial1.print(txtId); Serial1.print(F(".txt=\"")); Serial1.print(value, decimalDigits); Serial1.print(F("\""));
  three0xff();
}

sendToTxt(8,cellval);
sendToTxt(10,armval);
sendToTxt(12,gagval);

the compiler will be smart enough to store only once in PROGMEM the strings that are the same like F(".txt=\"")

Unless there has been a recent change to the compiler, identical text with the F() macro is not recognized by the compiler and only stored once, so you have to store the text in PROGMEM yourself. I'm a bit lazy and don't want to have to cast the char array in PROGMEM to __FlashStringHelper* every time I print it, so I usually create a macro to save a bit of typing.

#define FF(x) ((__FlashStringHelper*)x)
const char nextionTxt[] PROGMEM = ".txt=\"";

void sendToNextion(byte nextionT, double num) {
  Serial1.print('t');
  Serial1.print(nextionT);
  Serial1.print(FF(nextionTxt));
  Serial1.print(num);
  Serial1.print('\"');
  sendThree0xff();                                        
}

void sendToNextion(byte nextionT, long num) {
  Serial1.print('t');
  Serial1.print(nextionT);
  Serial1.print(FF(nextionTxt));
  Serial1.print(num);
  Serial1.print('\"');
  sendThree0xff();                                        
}

The armsel function mentioned in the previous post can also be greatly simplified using a lookup table instead of the case statement (I'm not checking for a valid value for armpos because the code is already constraining its value)

void armsel() {//-------------------------------------Selectable range of arm lengths
  static const float armvals[13] PROGMEM = {
    1.0, //armpos = 0
    12.0, //armpos = 1
    18.0, //armpos = 2
    20.0, //armpos = 3
    22.0, //armpos = 4
    24.0, //armpos = 5
    26.0, //armpos = 6
    30.0, //armpos = 7
    32.0, //armpos = 8
    36.0, //armpos = 9
    42.0, //armpos = 10
    49.5, //armpos = 11
    52.0, //armpos = 12
  };
  armval = pgm_read_float(&armvals[armpos]);
  sendToNextion(t10, armval); //note - t10 has the value of 10, I created the variable to improve readability
}

You're right indeed. bummer ;).. need to define those manually (and then of course it's no longer an issue)

There are several other functions that could benefit from the same treatment.

and seems the values don't need to be float... a byte would be enough for storage... 52 bytes of flash --> 13 bytes

The 49.5 is the odd one, could be stored as an int and converted to a float, but was not going to get into changing the type of the variable, particularly when a future change in value might need the float.

ah, I missed that one. I think it's time for coffee

You guys are awesome.

Forgive my ignorance as I can't compile anything at the moment, but does the compiler accept the two sendtoNextion functions with the only difference being the number type i.e. long and float? or double and long?