Sketch Too Big for Arduino Leonardo

Hello all!

I am making a Ionizing Radiation Detector project, but my sketch is too big! I would rather not remove any of the functionality I have added, although I may have to if I cannot find another way to lower the sketch size by 2%.

The current sketch size is 29446(102%)bytes. Maximum is 28672 bytes.
The current global variables is 2055(80%)bytes, leaving 505 bytes for local variables. Maximum is 2560 bytes.

Current sketch is 380 lines long.

Sketch:

//Geiger Counter Project / DFRobot

#include <TinyGPS++.h>
#include <SD.h>
#include <SPI.h>
#include <DFRobot_RGBLCD1602.h>
#include <SoftwareSerial.h>
#include <DFRobot_Geiger.h>
#include <EEPROM.h>

#define geigerPin 0//D0
#define vibration 10//D10
#define SDss A0
#define button A1

#define startuSvh 12
#define dangeruSvh 50

#define arrSize(X) sizeof(X) / sizeof(X[0])

int values[] =             {     1,        5,          10,         40,      100,       250,          400,          1000,      10000   };
const char* equivalent[] = { "Airport", "Dental", "Norm(1day)", "Flight", "X-Ray", "NPP(1year)", "Mammogram",  "Gov Limit", "CT Scan" };

byte hazardChar[8] = {
  0b00000,
  0b00000,
  0b01110,
  0b11001,
  0b10101,
  0b10011,
  0b01110,
  0b00000
};

byte motor1Char[8] = {
  0b00110,
  0b00110,
  0b00100,
  0b01110,
  0b01110,
  0b01110,
  0b01110,
  0b01110
};

byte motor2Char[8] = {
  0b01100,
  0b01100,
  0b00100,
  0b01110,
  0b01110,
  0b01110,
  0b01110,
  0b01110
};

byte fullChar[8] = {
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b11111
};

int savegeigertime = 300000;//5 min
int savegeigergpstime = 120000; //2 min

static const int RXPin = 1, TXPin = 9;//D1/D9
static const uint32_t GPSBaud = 9600;

int timer1 = 0;
int timer2 = 0;
int timer3 = 0;
int mode = 0;
boolean vib = false;
int count = 0;
int count2 = 0;

int CPM = 0;
int uSvh = 0;
int nSvh = 0;

File myFile;
char fileName[] = "geiger.txt";
char wfileName[] = "warnings.txt";


DFRobot_Geiger geiger(geigerPin);
DFRobot_RGBLCD1602 lcd(/*lcdCols*/16,/*lcdRows*/2);
TinyGPSPlus gps;
SoftwareSerial ss(RXPin, TXPin);

void setup() {
  pinMode(button, INPUT_PULLUP);
  pinMode(SDss, OUTPUT);
  pinMode(vibration, OUTPUT);

  ss.begin(GPSBaud);

  geiger.start();
  
  lcd.init();
  lcd.customSymbol(1,motor1Char);
  lcd.customSymbol(2,motor2Char);
  lcd.customSymbol(3,hazardChar);
  lcd.customSymbol(4,fullChar);
  lcd.setCursor(1,4);
  lcd.print("Geiger");
  lcd.setCursor(2,3);
  lcd.print("Counter");
  lcd.setRGB(0,255,0);
  delay(3000);
  for (int i=0;i<17;i++){
    lcd.scrollDisplayLeft();
    delay(50);
  }

  if (!SD.begin(SDss)) {
    lcd.setRGB(255, 0, 0);
    lcd.setCursor(1,1);
    lcd.print("SD Init Failed");
    delay(3000);
  }
  lcd.clear();
  lcd.setRGB(0,255,0);

  EEPROM.get(0,mode);
  EEPROM.get(1,vib);
  
}

void loop() {
  geiger.pause();
  CPM = geiger.getCPM();
  uSvh = geiger.getuSvh();
  nSvh = geiger.getnSvh();
  geiger.start();
  
  if (button == LOW){
    redo:
    timer1++;
    delay(1);
    while (button == LOW){ goto redo;}

    if (timer1 <= 1000){
      mode = 1;
      lcd.setRGB(0, 255, 0);
      lcd.setCursor(0,1);
      lcd.print("Standard Mode");
      delay(3000);
      lcd.clear();
    }
    else if (timer1 > 1500 && timer1 <= 2500){
      mode = 2;
      lcd.setRGB(0, 255, 255);
      lcd.setCursor(3,0);
      lcd.print("Bar Mode");
      delay(3000);
      lcd.clear();
    }
    else if (timer1 > 2500 && timer1 <= 3500){
      mode = 3;
      lcd.setRGB(0, 0, 255);
      lcd.setCursor(0,1);
      lcd.print("Equivalents Mode");
      delay(3000);
      lcd.clear();
    }
    else if (timer1 > 3500 && timer1 <= 4500){
      vib = !vib;
      lcd.setRGB(255, 0, 255);
      for (int i=0;i<6;i++){
        lcd.setCursor(0,1);
        lcd.print("Vibration");
        lcd.setCursor(1,6);
        lcd.print(vib > 0 ? "On" : "Off");
        lcd.setCursor(1,14);
        lcd.write(1);
        delay(500);
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("Vibration");
        lcd.setCursor(6,1);
        lcd.print(vib > 0 ? "On" : "Off");
        lcd.setCursor(14,1);
        lcd.write(2);
        delay(500);
        lcd.clear();
      }
      //delay(3000);
      lcd.clear();
      EEPROM.write(1, vib);
      if (mode == 1){
        lcd.setRGB(0, 255, 0);
      }
      else if (mode == 2){
        lcd.setRGB(0, 255, 255);
      }
      else if (mode == 3){
        lcd.setRGB(0, 0, 255);
      }
    }
    EEPROM.write(0, mode);
  }

  lcdDisplayData(uSvh);
  
  if (uSvh > startuSvh && uSvh < (dangeruSvh - 1)){
    lcd.setRGB(255, 172, 28);
    lcd.setCursor(14,2);
    lcd.write(3);
    if (vib){
      analogWrite(vibration, 128);
    }
    myFile = SD.open(wfileName, FILE_WRITE);
    if (myFile){
      myFile.println("---------Warning---------");
      myFile.println("------Type=Moderate------");
      myFile.println("Time: " + String(gps.time.hour()) + ":" + String(gps.time.minute()) + ":" + String(gps.time.second()));
      myFile.println("Date: " + String(gps.date.month()) + "/" + String(gps.date.day()) + "/" + String(gps.date.year()));
      myFile.println("Millis: " + String(millis()));
      myFile.println("Geiger (CPM): " + String(CPM));
      myFile.println("Geiger (nSvh): " + String(nSvh));
      myFile.println("Geiger (uSvh): " + String(uSvh));
      myFile.println("----------------------------------------------------------");
      myFile.println("");
      myFile.close(); 
    }
  }
  else if (uSvh >= dangeruSvh){
    lcd.setRGB(255, 0, 0);
    lcd.setCursor(1,14);
    lcd.write(3);
    if (vib){
      analogWrite(vibration, 255);
    }
    myFile = SD.open(wfileName, FILE_WRITE);
    if (myFile){
      myFile.println("---------Warning---------");
      myFile.println("-------Type=Severe-------");
      myFile.println("Time: " + String(gps.time.hour()) + ":" + String(gps.time.minute()) + ":" + String(gps.time.second()));
      myFile.println("Date: " + String(gps.date.month()) + "/" + String(gps.date.day()) + "/" + String(gps.date.year()));
      myFile.println("Millis: " + String(millis()));
      myFile.println("Geiger (CPM): " + String(CPM));
      myFile.println("Geiger (nSvh): " + String(nSvh));
      myFile.println("Geiger (uSvh): " + String(uSvh));
      myFile.println("----------------------------------------------------------");
      myFile.println("");
      myFile.close(); 
    }
  }
  
  if (mode == 2){
    timer2++;
    delay(1);
    if (timer2 >= savegeigertime){
      count++;
      myFile = SD.open(fileName, FILE_WRITE);
      if (myFile){
        myFile.println("Time: " + String(gps.time.hour()) + ":" + String(gps.time.minute()) + ":" + String(gps.time.second()));
        myFile.println("Date: " + String(gps.date.month()) + "/" + String(gps.date.day()) + "/" + String(gps.date.year()));
        myFile.println("Count: " + String(count));
        myFile.println("Millis: " + String(millis()));
        myFile.println("Geiger (CPM): " + String(CPM));
        myFile.println("Geiger (nSvh): " + String(nSvh));
        myFile.println("Geiger (uSvh): " + String(uSvh));
        myFile.println("----------------------------------------------------------");
        myFile.println("");
        myFile.close(); 
      }
      timer2 = 0;
    }
  }
  else if (mode == 3){
    timer3++;
    delay(1);
    if (timer3 >= savegeigergpstime){
      count2++;
      myFile = SD.open(fileName, FILE_WRITE);
      if (myFile){
        myFile.println("Time: " + String(gps.time.hour()) + ":" + String(gps.time.minute()) + ":" + String(gps.time.second()));
        myFile.println("Date: " + String(gps.date.month()) + "/" + String(gps.date.day()) + "/" + String(gps.date.year()));
        myFile.println("Count: " + String(count2));
        myFile.println("Millis: " + String(millis()));
        myFile.println("Latitude: " + String(gps.location.lat()));
        myFile.println("Longitude: " + String(gps.location.lng()));
        myFile.println("Satellites: " + String(gps.satellites.value()));
        myFile.println("Altitude: " + String(gps.altitude.feet()));
        myFile.println("Course: " + String(gps.course.deg()));
        myFile.println("Speed: " + String(gps.speed.mph()));
        myFile.println("Geiger (CPM): " + String(CPM));
        myFile.println("Geiger (nSvh): " + String(nSvh));
        myFile.println("Geiger (uSvh): " + String(uSvh));
        myFile.println("----------------------------------------------------------");
        myFile.println("");
        myFile.close();
      }
      timer3 = 0;
    }
  }
  delay(1000);
  lcd.clear();
}

int nearestEqual(int x, bool sorted = true) {
  int idx = 0; // by default near first element
  int distance = abs(values[idx] - x);
  for (int i = 1; i < arrSize(values); i++) {
    int d = abs(values[i] - x);
    if (d < distance) {
      idx = i;
      distance = d;
    }
    else if (sorted) return idx;
  }
  return idx;
}

void lcdDisplayData(int re){
  if (mode == 1){
    lcd.setCursor(0,0);
    lcd.print("Geiger Val(nSv):");
    lcd.setCursor(4,1);
    lcd.print(re);
  }
  else if (mode == 2){
    lcd.setCursor(0,0);
    lcd.print("Geiger:");
    lcd.setCursor(9,0);
    lcd.print(re);
    lcd.setCursor(0,1);
    lcd.print(equivalent[nearestEqual(re)]);
  }
  else if (mode == 3){
    lcd.setCursor(0,0);
    lcd.print("Geiger:");
    lcd.setCursor(9,0);
    lcd.print(re);
    lcd.setCursor(0,1);
    lcdBar(re);
  }
  lcdbacklight(re);
}

void lcdBar(int re){
  for (int i=0;i<nearestEqual(re);i++){
    lcd.setCursor(i,1);
    lcd.write(4);
  }
}

void lcdbacklight(int re){
  if (nearestEqual(re) == 1 || nearestEqual(re) == 2){//green
    lcd.setRGB(0,255,0);
  }
  else if (nearestEqual(re) == 3){//green/yellow
    lcd.setRGB(150,255,0);
  }
  else if (nearestEqual(re) == 4){//yellow
    lcd.setRGB(255,255,0);
  }
  else if (nearestEqual(re) == 5){//orange
    lcd.setRGB(255,180,0);
  }
  else if (nearestEqual(re) == 6){//orange/red
    lcd.setRGB(255,100,0);
  }
  else if (nearestEqual(re) == 7){//red
    lcd.setRGB(255,0,0);
  }
  else if (nearestEqual(re) == 8){//pink
    lcd.setRGB(255,0,150);
  }
  else if (nearestEqual(re) == 9){//purple
    lcd.setRGB(175,0,255);
  }
}

Thanks in advance for any advice!

You are repeating a lot of strings. Consider making variables for repeated words or strings, and referencing them in multiple places.

You might also be able to add repeated code to a function and call it from different places. WORA.

1 Like

I don't know if the compiler could possibly optimize this stretch, through the peephole I see

void lcdbacklight(int re) {

  int theNearestEqual = nearestEqual(re);

  if (theNearestEqual == 1 || theNearestEqual == 2){//green
    lcd.setRGB(0,255,0);
  }
  else if (theNearestEqual == 3){//green/yellow
    lcd.setRGB(150,255,0);
  }
... 

It would be faster anyway.

a7

1 Like

Thanks @alto777 and @er_name_not_found !

I should have thought of that @alto777 lol. I did change that, an although the program would be faster now, it didn't change the size at all; not even one byte.

I made two String variables @er_name_not_found for the time and date strings, and now the code compiles!

Sketch uses 28490 bytes (99%) of program storage space. Maximum is 28672 bytes.
Global variables use 2055 bytes (80%) of dynamic memory, leaving 505 bytes for local variables. Maximum is 2560 bytes.
Low memory available, stability problems may occur.

Current sketch:

//Geiger Counter Project / DFRobot

#include <TinyGPS++.h>
#include <SD.h>
#include <SPI.h>
#include <DFRobot_RGBLCD1602.h>
#include <SoftwareSerial.h>
#include <DFRobot_Geiger.h>
#include <EEPROM.h>

#define geigerPin 0//D0
#define vibration 10//D10
#define SDss A0
#define button A1

#define startuSvh 12
#define dangeruSvh 50

#define arrSize(X) sizeof(X) / sizeof(X[0])

int values[] =             {     1,        5,          10,         40,      100,       250,          400,          1000,      10000   };
const char* equivalent[] = { "Airport", "Dental", "Norm(1day)", "Flight", "X-Ray", "NPP(1year)", "Mammogram",  "Gov Limit", "CT Scan" };

byte hazardChar[8] = {
  0b00000,
  0b00000,
  0b01110,
  0b11001,
  0b10101,
  0b10011,
  0b01110,
  0b00000
};

byte motor1Char[8] = {
  0b00110,
  0b00110,
  0b00100,
  0b01110,
  0b01110,
  0b01110,
  0b01110,
  0b01110
};

byte motor2Char[8] = {
  0b01100,
  0b01100,
  0b00100,
  0b01110,
  0b01110,
  0b01110,
  0b01110,
  0b01110
};

byte fullChar[8] = {
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b11111
};

int savegeigertime = 300000;//5 min
int savegeigergpstime = 120000; //2 min

static const int RXPin = 1, TXPin = 9;//D1/D9
static const uint32_t GPSBaud = 9600;

int timer1 = 0;
int timer2 = 0;
int timer3 = 0;
int mode = 0;
boolean vib = false;
int count = 0;
int count2 = 0;

int CPM = 0;
int uSvh = 0;
int nSvh = 0;

File myFile;
char fileName[] = "geiger.txt";
char wfileName[] = "warnings.txt";


DFRobot_Geiger geiger(geigerPin);
DFRobot_RGBLCD1602 lcd(/*lcdCols*/16,/*lcdRows*/2);
TinyGPSPlus gps;
SoftwareSerial ss(RXPin, TXPin);

void setup() {
  pinMode(button, INPUT_PULLUP);
  pinMode(SDss, OUTPUT);
  pinMode(vibration, OUTPUT);

  ss.begin(GPSBaud);

  geiger.start();
  
  lcd.init();
  lcd.customSymbol(1,motor1Char);
  lcd.customSymbol(2,motor2Char);
  lcd.customSymbol(3,hazardChar);
  lcd.customSymbol(4,fullChar);
  lcd.setCursor(1,4);
  lcd.print("Geiger");
  lcd.setCursor(2,3);
  lcd.print("Counter");
  lcd.setRGB(0,255,0);
  delay(3000);
  for (int i=0;i<17;i++){
    lcd.scrollDisplayLeft();
    delay(50);
  }

  if (!SD.begin(SDss)) {
    lcd.setRGB(255, 0, 0);
    lcd.setCursor(1,1);
    lcd.print("SD Init Failed");
    delay(3000);
  }
  lcd.clear();
  lcd.setRGB(0,255,0);

  EEPROM.get(0,mode);
  EEPROM.get(1,vib);
  
}

void loop() {
  String TIME = "Time: " + String(gps.time.hour()) + ":" + String(gps.time.minute()) + ":" + String(gps.time.second());
  String DATE = "Date: " + String(gps.date.month()) + "/" + String(gps.date.day()) + "/" + String(gps.date.year());

  geiger.pause();
  CPM = geiger.getCPM();
  uSvh = geiger.getuSvh();
  nSvh = geiger.getnSvh();
  geiger.start();
  
  if (button == LOW){
    redo:
    timer1++;
    delay(1);
    while (button == LOW){ goto redo;}

    if (timer1 <= 1000){
      mode = 1;
      lcd.setRGB(0, 255, 0);
      lcd.setCursor(0,1);
      lcd.print("Standard Mode");
      delay(3000);
      lcd.clear();
    }
    else if (timer1 > 1500 && timer1 <= 2500){
      mode = 2;
      lcd.setRGB(0, 255, 255);
      lcd.setCursor(3,0);
      lcd.print("Bar Mode");
      delay(3000);
      lcd.clear();
    }
    else if (timer1 > 2500 && timer1 <= 3500){
      mode = 3;
      lcd.setRGB(0, 0, 255);
      lcd.setCursor(0,1);
      lcd.print("Equivalents Mode");
      delay(3000);
      lcd.clear();
    }
    else if (timer1 > 3500 && timer1 <= 4500){
      vib = !vib;
      lcd.setRGB(255, 0, 255);
      for (int i=0;i<6;i++){
        lcd.setCursor(0,1);
        lcd.print("Vibration");
        lcd.setCursor(1,6);
        lcd.print(vib > 0 ? "On" : "Off");
        lcd.setCursor(1,14);
        lcd.write(1);
        delay(500);
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("Vibration");
        lcd.setCursor(6,1);
        lcd.print(vib > 0 ? "On" : "Off");
        lcd.setCursor(14,1);
        lcd.write(2);
        delay(500);
        lcd.clear();
      }
      //delay(3000);
      lcd.clear();
      EEPROM.write(1, vib);
      if (mode == 1){
        lcd.setRGB(0, 255, 0);
      }
      else if (mode == 2){
        lcd.setRGB(0, 255, 255);
      }
      else if (mode == 3){
        lcd.setRGB(0, 0, 255);
      }
    }
    EEPROM.write(0, mode);
  }

  lcdDisplayData(uSvh);
  
  if (uSvh > startuSvh && uSvh < (dangeruSvh - 1)){
    lcd.setRGB(255, 172, 28);
    lcd.setCursor(14,2);
    lcd.write(3);
    if (vib){
      analogWrite(vibration, 128);
    }
    myFile = SD.open(wfileName, FILE_WRITE);
    if (myFile){
      myFile.println("---------Warning---------");
      myFile.println("------Type=Moderate------");
      myFile.println(TIME);
      myFile.println(DATE);
      myFile.println("Millis: " + String(millis()));
      myFile.println("Geiger (CPM): " + String(CPM));
      myFile.println("Geiger (nSvh): " + String(nSvh));
      myFile.println("Geiger (uSvh): " + String(uSvh));
      myFile.println("----------------------------------------------------------");
      myFile.println("");
      myFile.close(); 
    }
  }
  else if (uSvh >= dangeruSvh){
    lcd.setRGB(255, 0, 0);
    lcd.setCursor(1,14);
    lcd.write(3);
    if (vib){
      analogWrite(vibration, 255);
    }
    myFile = SD.open(wfileName, FILE_WRITE);
    if (myFile){
      myFile.println("---------Warning---------");
      myFile.println("-------Type=Severe-------");
      myFile.println(TIME);
      myFile.println(DATE);
      myFile.println("Millis: " + String(millis()));
      myFile.println("Geiger (CPM): " + String(CPM));
      myFile.println("Geiger (nSvh): " + String(nSvh));
      myFile.println("Geiger (uSvh): " + String(uSvh));
      myFile.println("----------------------------------------------------------");
      myFile.println("");
      myFile.close(); 
    }
  }
  
  if (mode == 2){
    timer2++;
    delay(1);
    if (timer2 >= savegeigertime){
      count++;
      myFile = SD.open(fileName, FILE_WRITE);
      if (myFile){
        myFile.println(TIME);
        myFile.println(DATE);
        myFile.println("Count: " + String(count));
        myFile.println("Millis: " + String(millis()));
        myFile.println("Geiger (CPM): " + String(CPM));
        myFile.println("Geiger (nSvh): " + String(nSvh));
        myFile.println("Geiger (uSvh): " + String(uSvh));
        myFile.println("----------------------------------------------------------");
        myFile.println("");
        myFile.close(); 
      }
      timer2 = 0;
    }
  }
  else if (mode == 3){
    timer3++;
    delay(1);
    if (timer3 >= savegeigergpstime){
      count2++;
      myFile = SD.open(fileName, FILE_WRITE);
      if (myFile){
        myFile.println(TIME);
        myFile.println(DATE);
        myFile.println("Count: " + String(count2));
        myFile.println("Millis: " + String(millis()));
        myFile.println("Latitude: " + String(gps.location.lat()));
        myFile.println("Longitude: " + String(gps.location.lng()));
        myFile.println("Satellites: " + String(gps.satellites.value()));
        myFile.println("Altitude: " + String(gps.altitude.feet()));
        myFile.println("Course: " + String(gps.course.deg()));
        myFile.println("Speed: " + String(gps.speed.mph()));
        myFile.println("Geiger (CPM): " + String(CPM));
        myFile.println("Geiger (nSvh): " + String(nSvh));
        myFile.println("Geiger (uSvh): " + String(uSvh));
        myFile.println("----------------------------------------------------------");
        myFile.println("");
        myFile.close();
      }
      timer3 = 0;
    }
  }
  delay(1000);
  lcd.clear();
}

int nearestEqual(int x, bool sorted = true) {
  int idx = 0; // by default near first element
  int distance = abs(values[idx] - x);
  for (int i = 1; i < arrSize(values); i++) {
    int d = abs(values[i] - x);
    if (d < distance) {
      idx = i;
      distance = d;
    }
    else if (sorted) return idx;
  }
  return idx;
}

void lcdDisplayData(int re){
  if (mode == 1){
    lcd.setCursor(0,0);
    lcd.print("Geiger Val(nSv):");
    lcd.setCursor(4,1);
    lcd.print(re);
  }
  else if (mode == 2){
    lcd.setCursor(0,0);
    lcd.print("Geiger:");
    lcd.setCursor(9,0);
    lcd.print(re);
    lcd.setCursor(0,1);
    lcd.print(equivalent[nearestEqual(re)]);
  }
  else if (mode == 3){
    lcd.setCursor(0,0);
    lcd.print("Geiger:");
    lcd.setCursor(9,0);
    lcd.print(re);
    lcd.setCursor(0,1);
    lcdBar(re);
  }
  lcdbacklight(re);
}

void lcdBar(int re){
  for (int i=0;i<nearestEqual(re);i++){
    lcd.setCursor(i,1);
    lcd.write(4);
  }
}

void lcdbacklight(int re){
  int theNearestEqual = nearestEqual(re);
  if (theNearestEqual == 1 || theNearestEqual == 2){//green
    lcd.setRGB(0,255,0);
  }
  else if (theNearestEqual == 3){//green/yellow
    lcd.setRGB(150,255,0);
  }
  else if (theNearestEqual == 4){//yellow
    lcd.setRGB(255,255,0);
  }
  else if (theNearestEqual == 5){//orange
    lcd.setRGB(255,180,0);
  }
  else if (theNearestEqual == 6){//orange/red
    lcd.setRGB(255,100,0);
  }
  else if (theNearestEqual == 7){//red
    lcd.setRGB(255,0,0);
  }
  else if (theNearestEqual == 8){//pink
    lcd.setRGB(255,0,150);
  }
  else if (theNearestEqual == 9){//purple
    lcd.setRGB(175,0,255);
  }
}

I think I should still keep going although it now compiles, because I don't want any issues while running.

Well I am looking through the little window, but you mentioned making some Strings…

And I hope you have used them carefully as they are notorious for wreaking enough havoc that some people totally don't use them. At all ever.

There are I hear things you can do to be safe.

a7

1 Like

What would I use instead of a String @alto777 ? Maybe a char :thinking: ?

I used the strings like this:

String TIME = "Time: " + String(gps.time.hour()) + ":" + String(gps.time.minute()) + ":" + String(gps.time.second());
String DATE = "Date: " + String(gps.date.month()) + "/" + String(gps.date.day()) + "/" + String(gps.date.year());

The code for printing to file is repeated 4 times. You could move that to a separate function.
Maybe something like:

void printToFile(file myFile, bool includeLongSats)
{
        myFile.println(TIME);
        myFile.println(DATE);
        myFile.println("Count: " + String(count2));
        myFile.println("Millis: " + String(millis()));
        if(includeLongSats){
            myFile.println("Latitude: " + String(gps.location.lat()));
            myFile.println("Longitude: " + String(gps.location.lng()));
            myFile.println("Satellites: " + String(gps.satellites.value()));
            myFile.println("Altitude: " + String(gps.altitude.feet()));
            myFile.println("Course: " + String(gps.course.deg()));
            myFile.println("Speed: " + String(gps.speed.mph()));
        }
        myFile.println("Geiger (CPM): " + String(CPM));
        myFile.println("Geiger (nSvh): " + String(nSvh));
        myFile.println("Geiger (uSvh): " + String(uSvh));
        myFile.println("----------------------------------------------------------");
        myFile.println("");
}

gcc is smart enough to optimize this.
i.e. it can optimize multiple of the exact same strings into a single pointer to one copy of it.

'-fmerge-all-constants(which also implies-fmerge-constants`)
but it looks like the IDE does not turn it on in the platform.txt file.
bummer....
However... you could easily patch the platform.txt file to set the options to enable it.

Probably should be brought up on the arduino developers list to ask why this isn't being done.

--- bill

1 Like

If you just eliminate the use of String entirely, your sketch will (just barely) fit.
That means changing code that looks like:

    if (myFile){
      myFile.println("---------Warning---------");
      myFile.println("------Type=Moderate------");
      myFile.println("Time: " + String(gps.time.hour()) + ":" + String(gps.time.minute()) + ":" + String(gps.time.second()));
      myFile.println("Date: " + String(gps.date.month()) + "/" + String(gps.date.day()) + "/" + String(gps.date.year()));
      myFile.println("Millis: " + String(millis()));
      myFile.println("Geiger (CPM): " + String(CPM));
      myFile.println("Geiger (nSvh): " + String(nSvh));
      myFile.println("Geiger (uSvh): " + String(uSvh));
      myFile.println("----------------------------------------------------------");
      myFile.println("");
      myFile.close(); 
    }

to look like:

    if (myFile){
      myFile.println("---------Warning---------");
      myFile.println("------Type=Moderate------");
      myFile.println("Time: ");
      myFile.println(gps.time.hour());
     ;
myFile.println(":");
myFile.println(gps.time.minute());
myFile.println(":");
myFile.println(gps.time.second());
      myFile.println("Date: ");
myFile.println(gps.date.month());
myFile.println("/");
myFile.println(gps.date.day());
myFile.println("/");
myFile.println(gps.date.year());
      myFile.println("Millis: ");
myFile.println(millis());
      myFile.println("Geiger (CPM): ");
myFile.println(CPM);
      myFile.println("Geiger (nSvh): ");
myFile.println(nSvh);
      myFile.println("Geiger (uSvh): ");
myFile.println(uSvh);
      myFile.println("----------------------------------------------------------");
      myFile.println("");
      myFile.close(); 
    }
  }

(indendtation left wonky to highlight the changes!)

moving common code to functions (printDate, printGeiger) will probably save some more (as others have suggested.)

Why a Leonardo? This would comfortably fit on a Nano Every, and you'd get an additional HardwareSerial that would make things work better...

Oh, good idea @westfw !

I'm using a Leonardo because I'm being sponsored for this project, and I figured I could use the Leonardo for a computer mouse project also.

Thanks @touch1337 !

I changed the code how you suggested.

Sketch uses 27874 bytes (97%) of program storage space. Maximum is 28672 bytes.
Global variables use 2081 bytes (81%) of dynamic memory, leaving 479 bytes for local variables. Maximum is 2560 bytes.
Low memory available, stability problems may occur.

Current sketch:

//Geiger Counter Project / DFRobot

#include <TinyGPS++.h>
#include <SD.h>
#include <SPI.h>
#include <DFRobot_RGBLCD1602.h>
#include <SoftwareSerial.h>
#include <DFRobot_Geiger.h>
#include <EEPROM.h>

#define geigerPin 0//D0
#define vibration 10//D10
#define SDss A0
#define button A1

#define startuSvh 12
#define dangeruSvh 50

#define arrSize(X) sizeof(X) / sizeof(X[0])

int values[] =             {     1,        5,          10,         40,      100,       250,          400,          1000,      10000   };
const char* equivalent[] = { "Airport", "Dental", "Norm(1day)", "Flight", "X-Ray", "NPP(1year)", "Mammogram",  "Gov Limit", "CT Scan" };

byte hazardChar[8] = {
  0b00000,
  0b00000,
  0b01110,
  0b11001,
  0b10101,
  0b10011,
  0b01110,
  0b00000
};

byte motor1Char[8] = {
  0b00110,
  0b00110,
  0b00100,
  0b01110,
  0b01110,
  0b01110,
  0b01110,
  0b01110
};

byte motor2Char[8] = {
  0b01100,
  0b01100,
  0b00100,
  0b01110,
  0b01110,
  0b01110,
  0b01110,
  0b01110
};

byte fullChar[8] = {
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b11111
};

String TIME;
String DATE;
String fileCPM;
String fileuSvh;
String filenSvh;

int savegeigertime = 120000;//2 min

static const int RXPin = 1, TXPin = 9;//D1/D9
static const uint32_t GPSBaud = 9600;

int timer1 = 0;
int timer2 = 0;
int mode = 0;
boolean vib = false;
int count = 0;
int count2 = 0;

int CPM = 0;
int uSvh = 0;
int nSvh = 0;

File myFile;
char fileName[] = "geiger.txt";
char wfileName[] = "warnings.txt";


DFRobot_Geiger geiger(geigerPin);
DFRobot_RGBLCD1602 lcd(/*lcdCols*/16,/*lcdRows*/2);
TinyGPSPlus gps;
SoftwareSerial ss(RXPin, TXPin);

void setup() {
  pinMode(button, INPUT_PULLUP);
  pinMode(SDss, OUTPUT);
  pinMode(vibration, OUTPUT);

  ss.begin(GPSBaud);

  geiger.start();
  
  lcd.init();
  lcd.customSymbol(1,motor1Char);
  lcd.customSymbol(2,motor2Char);
  lcd.customSymbol(3,hazardChar);
  lcd.customSymbol(4,fullChar);
  lcd.setCursor(1,4);
  lcd.print("Geiger");
  lcd.setCursor(2,3);
  lcd.print("Counter");
  lcd.setRGB(0,255,0);
  delay(3000);
  for (int i=0;i<17;i++){
    lcd.scrollDisplayLeft();
    delay(50);
  }

  if (!SD.begin(SDss)) {
    lcd.setRGB(255, 0, 0);
    lcd.setCursor(1,1);
    lcd.print("SD Init Failed");
    delay(3000);
  }
  lcd.clear();
  lcd.setRGB(0,255,0);

  EEPROM.get(0,mode);
  EEPROM.get(1,vib);
  
}

void loop() {
  TIME = "Time: " + String(gps.time.hour()) + ":" + String(gps.time.minute()) + ":" + String(gps.time.second());
  DATE = "Date: " + String(gps.date.month()) + "/" + String(gps.date.day()) + "/" + String(gps.date.year());
  
  geiger.pause();
  CPM = geiger.getCPM();
  uSvh = geiger.getuSvh();
  nSvh = geiger.getnSvh();
  geiger.start();

  fileCPM = "Geiger (CPM): " + String(CPM);
  fileuSvh = "Geiger (nSvh): " + String(nSvh);
  filenSvh = "Geiger (uSvh): " + String(uSvh);
  if (button == LOW){
    redo:
    timer1++;
    delay(1);
    while (button == LOW){ goto redo;}

    if (timer1 <= 1000){
      mode = 1;
      lcd.setRGB(0, 255, 0);
      lcd.setCursor(0,1);
      lcd.print("Standard Mode");
      delay(3000);
      lcd.clear();
    }
    else if (timer1 > 1500 && timer1 <= 2500){
      mode = 2;
      lcd.setRGB(0, 255, 255);
      lcd.setCursor(3,0);
      lcd.print("Bar Mode");
      delay(3000);
      lcd.clear();
    }
    else if (timer1 > 2500 && timer1 <= 3500){
      mode = 3;
      lcd.setRGB(0, 0, 255);
      lcd.setCursor(0,1);
      lcd.print("Equivalents Mode");
      delay(3000);
      lcd.clear();
    }
    else if (timer1 > 3500 && timer1 <= 4500){
      vib = !vib;
      lcd.setRGB(255, 0, 255);
      for (int i=0;i<6;i++){
        lcd.setCursor(0,1);
        lcd.print("Vibration");
        lcd.setCursor(1,6);
        lcd.print(vib > 0 ? "On" : "Off");
        lcd.setCursor(1,14);
        lcd.write(1);
        delay(500);
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("Vibration");
        lcd.setCursor(6,1);
        lcd.print(vib > 0 ? "On" : "Off");
        lcd.setCursor(14,1);
        lcd.write(2);
        delay(500);
        lcd.clear();
      }
      //delay(3000);
      lcd.clear();
      EEPROM.write(1, vib);
      if (mode == 1){
        lcd.setRGB(0, 255, 0);
      }
      else if (mode == 2){
        lcd.setRGB(0, 255, 255);
      }
      else if (mode == 3){
        lcd.setRGB(0, 0, 255);
      }
    }
    EEPROM.write(0, mode);
  }

  lcdDisplayData(uSvh);
  
  if (uSvh > startuSvh && uSvh < (dangeruSvh - 1)){
    lcd.setRGB(255, 172, 28);
    lcd.setCursor(14,2);
    lcd.write(3);
    if (vib){
      analogWrite(vibration, 128);
    }
    saveToFile(2);
  }
  else if (uSvh >= dangeruSvh){
    lcd.setRGB(255, 0, 0);
    lcd.setCursor(1,14);
    lcd.write(3);
    if (vib){
      analogWrite(vibration, 255);
    }
    saveToFile(1);
  }
  
  timer2++;
  delay(1);
  if (timer2 >= savegeigertime){
    count++;
    saveToFile(0);
    timer2 = 0;
  }
  delay(1000);
  lcd.clear();
}

int nearestEqual(int x, bool sorted = true) {
  int idx = 0; // by default near first element
  int distance = abs(values[idx] - x);
  for (int i = 1; i < arrSize(values); i++) {
    int d = abs(values[i] - x);
    if (d < distance) {
      idx = i;
      distance = d;
    }
    else if (sorted) return idx;
  }
  return idx;
}

void lcdDisplayData(int re){
  if (mode == 1){
    lcd.setCursor(0,0);
    lcd.print("Geiger Val(nSv):");
    lcd.setCursor(4,1);
    lcd.print(re);
  }
  else if (mode == 2){
    lcd.setCursor(0,0);
    lcd.print("Geiger:");
    lcd.setCursor(9,0);
    lcd.print(re);
    lcd.setCursor(0,1);
    lcd.print(equivalent[nearestEqual(re)]);
  }
  else if (mode == 3){
    lcd.setCursor(0,0);
    lcd.print("Geiger:");
    lcd.setCursor(9,0);
    lcd.print(re);
    lcd.setCursor(0,1);
    lcdBar(re);
  }
  lcdbacklight(re);
}

void lcdBar(int re){
  for (int i=0;i<nearestEqual(re);i++){
    lcd.setCursor(i,1);
    lcd.write(4);
  }
}

void lcdbacklight(int re){
  int theNearestEqual = nearestEqual(re);
  if (theNearestEqual == 1 || theNearestEqual == 2){//green
    lcd.setRGB(0,255,0);
  }
  else if (theNearestEqual == 3){//green/yellow
    lcd.setRGB(150,255,0);
  }
  else if (theNearestEqual == 4){//yellow
    lcd.setRGB(255,255,0);
  }
  else if (theNearestEqual == 5){//orange
    lcd.setRGB(255,180,0);
  }
  else if (theNearestEqual == 6){//orange/red
    lcd.setRGB(255,100,0);
  }
  else if (theNearestEqual == 7){//red
    lcd.setRGB(255,0,0);
  }
  else if (theNearestEqual == 8){//pink
    lcd.setRGB(255,0,150);
  }
  else if (theNearestEqual == 9){//purple
    lcd.setRGB(175,0,255);
  }
}

void saveToFile(int warningType){
  if (warningType == 0){
    myFile = SD.open(fileName, FILE_WRITE);
    if (myFile){
      myFile.println(TIME);
      myFile.println(DATE);
      myFile.println("Count: " + String(count2));
      myFile.println("Millis: " + String(millis()));
      myFile.println("Latitude: " + String(gps.location.lat()));
      myFile.println("Longitude: " + String(gps.location.lng()));
      myFile.println("Satellites: " + String(gps.satellites.value()));
      myFile.println("Altitude: " + String(gps.altitude.feet()));
      myFile.println("Course: " + String(gps.course.deg()));
      myFile.println("Speed: " + String(gps.speed.mph()));
      myFile.println(fileCPM);
      myFile.println(fileuSvh);
      myFile.println(filenSvh);
      myFile.println("----------------------------------------------------------");
      myFile.println("");
      myFile.close();
    }
  }
  else {
    myFile = SD.open(wfileName, FILE_WRITE);
    if (myFile){
      myFile.println("---------Warning---------");
      if (warningType == 1){
        myFile.println("-------Type=Severe-------");
      }
      else {
        myFile.println("------Type=Moderate------");
      }
      myFile.println(TIME);
      myFile.println(DATE);
      myFile.println("Millis: " + String(millis()));
      myFile.println(fileCPM);
      myFile.println(fileuSvh);
      myFile.println(filenSvh);
      myFile.println("----------------------------------------------------------");
      myFile.println("");
      myFile.close(); 
    }
  }
}

You appear to be calling for software serial yet not using hardware serial at all. I'm not sure of the resources you are wasting because I'm not sure what you are doing with it, but it cannot possibly be a good idea.

You have an error on line #74, an integer cannot hold a number as large as 120000.

int savegeigertime = 120000;//2 min

As the previous post pointed out, there is a 2nd hardware serial port on the Leonardo, Serial is the USB interface, Serial1 is the RX/TX pins (D0/D1).

1 Like

goto statements are generally discouraged unless you really need to use them, and in this case you do not.

  if (button == LOW) {
redo:
    timer1++;
    delay(1);
    while (button == LOW) {
      goto redo;
    }

Consider this as a replacement.

  if (button == LOW) {
    do {
      timer1++;
      delay(1);
    } while (button == LOW);

Neither one will actually do what you intend, but you will find that out in testing.

2 Likes

Hello @Nick_Pyner !

This is the board I’m using:

It doesn’t have very many available pins, so I had to use the RX pin as an interrupt.

Ah, you’re right. Neither will do what I’m trying to do :man_facepalming: .

Ah, yep. Would a ‘long’ work?

long should work ok. int is limited to -32768 to +32767

1 Like

That's putting it mildly. Not suitable for the purpose sums it up better but, on reflection, can't you use one of the declared software serial pins for that?

Sorry, which ones are those? :man_shrugging:

these