In my project, there is a timer that I have created that starts as soon as the loop section of the code starts running. If there are any hardware errors, I have created a function with a while loop, and as soon as all hardware errors are resolved, the code soft resets and the timer, datalogging etc all reset. It did work for a while, but now it doesn't reset, the reset button on my arduino barely works and the tactile button I have wired to RST barely resets it either. I bought a cheap 'UK' arduino nano knockoff with a CH340 driver, and 3 of the 5 nano's I purchased have already stopped working after a few months. Could someone help me to make sure that it isn't my code that is causing the reset problem? I have taken this project apart and put it back together again about 50 times, so I am sure there are no wiring issues. I just don't want to start altering the code unnecessarily, as I am ordering an arduino nano ESP32 to use instead, and want to have a functional code prior to getting it. This is the code:
/* _______________________________________________________________________________________________________________________________________________________________________
ㅤㅤ /\ \ / /\
ㅤ ㅤ|_\ \ DATALOGGER / /_|
ㅤㅤ |__\ \________________________________ 20x4 LCD, SD ADAPTER, DS3231, DS18B20 (5.1kPU), FLOAT SWITCH ________________________________/ /__|
ㅤㅤ |___\ \____________________________________________________________________/ /___|
ㅤㅤ |____\ /____|
ㅤ ㅤ|_____\ _______________________________________________________________________________________________________________________ /_____|
ㅤㅤ \______\ / \ /______/
ㅤㅤ \_____/\______________/ THIS PROGRAM MAY ALSO BE USED AS A GENERAL DATA LOGGER BY MODIFYING THE SENSOR CODE AND INPUTTING THE NECESSARY CODE \______________/\_____/
ㅤ ㅤ \________________________________________________________________________________________________________________________/
___________________________________________________________________________________________________________________________________________________________________________________
ㅤ ㅤ ㅤ ㅤ/ (ALL VCC AND GND TO BE WIRED TO VCC AND GND) \ /
HARDWARE WIRING LIST: / \ PROGRAM DESCRIPTION: /
_____________________/ \_______________________/
ㅤ
_________________________________ _________________________________________________________________
FOR 20X4 LIQUID CRYSTAL DISPLAY: \ / \
............_____________________/ / This program is designed to log data from a DS18B20 temperature \
-VSS GND / | sensor and read a float switch value. Once the SD card is |
-VDD 5V \____ | initialised and the RTC reads the set time, the program will |
-V0 2k RESISTOR \ | create a file in the SD card and name it according to the date |
-RS PIN A0 ____/ | (the date is retrieved using a DS3231 RTC). once the file and |
-RW GND / | file name is created, 8 data samples from all DS18B20 sensors |
-E PIN A1 | | are averaged, formatted and logged within the logging |
-D0 X / | interval into the created file, as well as the time of the day |
-D1 X / | in seconds and the current state of the float switch. If the |
-D2 X \ | program is ran until the next day, data logging will be |
-D3 X \ | stopped, and another file will be created and named according |
-D4 PIN A2 \ | to the date. The liquid crystal display and serial monitor |
-D5 PIN A3 \ | will show all relevant info, and can be used to ensure that the |
-D6 PIN D2 | | program runs correctly, displaying SD card initialisation, RTC |
-D7 PIN D7 / | initialisation, the filename the data is writing to, the time |
-A 10K POT / | the data started logging in DHHMMSS, and the current time of |
-K GND / \ the RTC. If any Errors occur, the LCD or serial monitor will /
_________/ \__________________ display an Error message. __________________/
ㅤ \___________________________/
____________________________
FOR SD CARD ADAPTER MODULE: \
....................________/
-chipSelect PIN D10 \
-MOSI PIN D11 _____/
-MISO PIN D12 /
-SCK PIN D13 /
____________/
_________________
FOR DS3231 RTC: \
..................\
-SCL PIN SCL OR A5 \
-SDA PIN SDA OR A4 |
-SQW X ___________/
_______/
________________________________
FOR DS18B20 TEMPERATURE SENSOR: \
........._______________________/
-POS 5V \
-NEG GND \__
-DQ 5.1kPU \________________
-5.1kPU LINKING PIN D9 AND 5V \______________
-104pF CERAMIC CAPACITOR LIKNING POS AND NEG \
_____________________________________________/
__________________
FOR FLOAT SWITCH: \
............._____/
-POS PIN D4 /
-NEG GND __/
________/
// INCLUDE LIBRARIES AND DEFINED CONSTANTS:
/********************************************************************************************************************************************************************************/
#include <OneWire.h>
#include <DallasTemperature.h>
#include <SD.h>
#include <SPI.h>
#include <LiquidCrystal.h>
#include <DS1307RTC.h>
#include <TimeLib.h>
#define BLUE 3
#define floatSw 4
#define GREEN 5
#define RED 6
#define buzzer 8
#define ONE_WIRE_BUS 9
#define chipSelect 10
#define buzzerTogglePin A6
#define year() tmYearToCalendar(tm.Year) - 2000
#define printAll(txt) Serial.println(txt), lcd.print(txt)
// used as general global variables
/********************************************************************************************************************************************************************************/
File dataFile;
LiquidCrystal lcd(A0, A1, A2, A3, 2, 7);
tmElements_t tm;
unsigned long tStart = millis();
unsigned long totMillis;
unsigned long lastMillis = 0;
unsigned long logTm = 10000;
unsigned long sampleTm = 1250;
unsigned long tLog = totMillis + logTm;
unsigned long tSample = totMillis + sampleTm;
int buzzerState = 1;
int BTstate;
char dirName[8] = "TANKLOG";
char fileName[13];
char fullPath[22];
// variables only used for the specific type of datalogging
/********************************************************************************************************************************************************************************/
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// function runs if a hardware error occurs
/********************************************************************************************************************************************************************************/
void hardwareErr() {
while (!SD.begin(chipSelect) || !RTC.read(tm) || !SD.open(fullPath)) {
digitalWrite(buzzer, 1);
delay(100);
digitalWrite(buzzer, 0);
delay(1900);
}
if(SD.begin(chipSelect) && RTC.read(tm) && SD.open(fullPath)) {
void (*reset)(void) = 0;
}
}
// initialises most of the hardware
/********************************************************************************************************************************************************************************/
void initialisation() {
sensors.begin();
sensors.setWaitForConversion(false);
lcd.begin(20, 4);
lcd.clear();
sensors.requestTemperatures();
pinMode(buzzer, OUTPUT);
pinMode(buzzerTogglePin, INPUT);
buzzerState = 1;
pinMode(floatSw, INPUT_PULLUP);
pinMode(RED, OUTPUT);
pinMode(GREEN, OUTPUT);
pinMode(BLUE, OUTPUT);
Serial.begin(115200);
SD.begin(chipSelect);
RTC.get();
Serial.print(F(""));
if (!SD.begin(chipSelect)) {
printAll(F("SD Card Failed."));
hardwareErr();
}
if (!RTC.read(tm)) {
printAll(F("RTC failed."));
hardwareErr();
}
}
// creates the file and name, and prints lcd info if the file is available to write to
/*******************************************************************************************************************************************************************************/
void createFileAndName() {
sprintf(fileName, "%02d-%02d-%d.txt", tm.Day, tm.Month, year());
strlcpy(fullPath, dirName, sizeof fullPath);
strlcat(fullPath, "/", sizeof fullPath);
strlcat(fullPath, fileName, sizeof fullPath);
SD.mkdir(dirName);
// INITIALISE LCD DISPLAY DATA
/********************************************************************************************************************************************************************************/
Serial.println(fullPath);
lcd.print(dirName);
lcd.print(" ");
lcd.print(fileName);
lcd.setCursor(0, 1);
lcd.print(F("TEMP:"));
lcd.setCursor(0, 2);
lcd.print(F("TANK LVL:"));
lcd.setCursor(17, 2);
}
void firstWrite() {
dataFile = SD.open(fullPath, FILE_WRITE);
dataFile.close();
dataFile = SD.open(fullPath, FILE_WRITE);
if (!dataFile) {
printAll("First Write Error.");
hardwareErr();
}
dataFile.println("#Time Sw Temp");
dataFile.close();
}
// DATA AND DIAGNOSTICS:
/********************************************************************************************************************************************************************************/
void DatalogAndDiagnostics() {
// TIME INFO:
/********************************************************************************************************************************************************************************/
char displayTime[21];
if (!RTC.read(tm)) {
lcd.clear();
printAll(F("RTC failed"));
printAll(F("RTC failed"));
hardwareErr();
}
if (tm.Hour == 0 && tm.Minute == 0 && tm.Second == 0) {
createFileAndName();
delay(750);
}
unsigned long totMillis = millis() - tStart;
unsigned long totSeconds = (millis() - tStart) / 1000;
unsigned long totMinutes = totSeconds / 60;
unsigned long totHours = totMinutes / 60;
unsigned long totDays = totHours / 24;
totSeconds %= 60;
totMinutes %= 60;
totHours %= 24;
totDays %= 7;
char charDays[2];
char charHours[3];
char charMinutes[3];
char charSeconds[3];
dtostrf(totDays, 1, 0, charDays);
dtostrf(totHours, 2, 0, charHours);
dtostrf(totMinutes, 2, 0, charMinutes);
dtostrf(totSeconds, 2, 0, charSeconds);
sprintf(displayTime, "%02d:%02d:%02d %sd%02sh%02sm%02ss", tm.Hour, tm.Minute, tm.Second, charDays, charHours, charMinutes, charSeconds);
lcd.setCursor(0, 3);
lcd.print(displayTime);
unsigned long hToM = tm.Hour * 60;
unsigned long hToS = hToM * 60;
unsigned long mToS = (tm.Minute * 60);
unsigned long sToS = tm.Second;
unsigned long tmDayInS = hToS + mToS + sToS;
//SPECIFIC DATALOGGING CODE:
/********************************************************************************************************************************************************************************/
static int floatSwState;
static byte nSample = 0;
const int highTempTm = 1000;
const int tempErrTm = 1500;
const int floatSwTm = 500;
static bool highTempErrState = 0;
static bool hardwareErrState = 0;
static bool floatSwErrState = 0;
lcd.setCursor(10, 2);
if (digitalRead(floatSw) == 1) {
lcd.print("OK ");
floatSwState = 1;
floatSwErrState = 0;
} else if (digitalRead(floatSw == 0)) {
lcd.print("NOT OK");
floatSwState = 0;
floatSwErrState = 1;
if (totMillis - lastMillis > floatSwTm) {
lastMillis = totMillis;
if (buzzerState == 1) {
digitalWrite(buzzer, 1);
}
digitalWrite(RED, 0);
digitalWrite(GREEN, 0);
digitalWrite(BLUE, 1);
} else {
digitalWrite(buzzer, 0);
}
}
lcd.setCursor(6, 1);
sensors.getTempCByIndex(0);
lcd.print(sensors.getTempCByIndex(0));
lcd.print("\337C");
sensors.requestTemperatures();
if (sensors.getTempCByIndex(0) >= 0 && sensors.getTempCByIndex(0) <= 22) {
digitalWrite(RED, 0);
digitalWrite(GREEN, 1);
digitalWrite(BLUE, 0);
highTempErrState = 0;
} else if (sensors.getTempCByIndex(0) > 22 && sensors.getTempCByIndex(0) <= 23) {
analogWrite(RED, 255);
analogWrite(GREEN, 255);
digitalWrite(BLUE, 0);
highTempErrState = 0;
} else if (sensors.getTempCByIndex(0) > 23 && sensors.getTempCByIndex(0) <= 24) {
analogWrite(RED, 255);
analogWrite(GREEN, 90);
digitalWrite(BLUE, 0);
highTempErrState = 0;
} else if (sensors.getTempCByIndex(0) > 24 && sensors.getTempCByIndex(0) <= 25) {
digitalWrite(RED, 1);
digitalWrite(GREEN, 0);
digitalWrite(BLUE, 0);
highTempErrState = 0;
} else if (sensors.getTempCByIndex(0) > 25) {
highTempErrState = 1;
if (totMillis - lastMillis > highTempTm) {
lastMillis = totMillis;
if (buzzerState == 1) {
digitalWrite(buzzer, 1);
}
digitalWrite(RED, 1);
digitalWrite(GREEN, 0);
digitalWrite(BLUE, 0);
} else {
digitalWrite(buzzer, 0);
digitalWrite(RED, 0);
digitalWrite(GREEN, 0);
digitalWrite(BLUE, 0);
}
} else {
hardwareErrState = 1;
if (totMillis - lastMillis > tempErrTm) {
lastMillis = totMillis;
if (buzzerState == 1) {
digitalWrite(buzzer, 1);
}
digitalWrite(RED, 1);
digitalWrite(GREEN, 1);
digitalWrite(BLUE, 1);
} else {
digitalWrite(buzzer, 0);
digitalWrite(RED, 0);
digitalWrite(GREEN, 0);
digitalWrite(BLUE, 0);
}
}
static float aveT1 = sensors.getTempCByIndex(0);
static float totT1 = aveT1;
static char charAveT1[9];
static char charTotT1[9];
static char charTemp[9];
dtostrf(aveT1, 7, 2, charAveT1);
dtostrf(totT1, 8, 2, charTotT1);
dtostrf(sensors.getTempCByIndex(0), 7, 2, charTemp);
if (totMillis > tSample) {
nSample += 1;
aveT1 = totT1 / nSample;
totT1 += sensors.getTempCByIndex(0);
sensors.requestTemperatures();
char sampleData[70];
sprintf(sampleData, "Sample: %d Sw: %d temp(°C):%s Ave:%s Tot:%s",
nSample, floatSwState, charTemp, charAveT1, charTotT1);
Serial.println(sampleData);
tSample += sampleTm;
}
if (highTempErrState == 0 && hardwareErrState == 0 && floatSwErrState == 0) {
digitalWrite(buzzer, 0);
}
// OPEN FILE:
/********************************************************************************************************************************************************************************/
char aveData[20];
char charTmDayInS[7];
dtostrf(tmDayInS, 5, 0, charTmDayInS);
sprintf(aveData, "%ls %d%s", charTmDayInS, floatSwState, charAveT1);
dataFile = SD.open(fullPath, FILE_WRITE);
if (dataFile) {
if (totMillis > tLog) {
dataFile.println(aveData);
Serial.println("#Time Sw Temp");
Serial.println(aveData);
tLog += logTm;
}
if (nSample > 7) {
nSample = 0;
totT1 = sensors.getTempCByIndex(0);
}
} else {
printAll(F("File write Err"));
lcd.clear();
printAll(F("File write Err"));
hardwareErr();
}
// ALARM
/********************************************************************************************************************************************************************************/
static bool lastBTstate = 0;
unsigned long lastDebounceTime = 0;
const byte debounceDelay = 50;
lcd.setCursor(13, 1);
lcd.print(" ALARM");
int newBTstate = analogRead(buzzerTogglePin) < 500 ? 1 : 0;
if (newBTstate != lastBTstate) {
lastDebounceTime = totMillis;
}
if ((totMillis - lastDebounceTime) > debounceDelay) {
if (newBTstate != BTstate) {
BTstate = newBTstate;
if (BTstate == 1) {
buzzerState = !buzzerState;
}
}
}
lcd.setCursor(17, 2);
if (buzzerState == 1) {
lcd.print(" ON");
}
else if (buzzerState == 0) {
lcd.print("OFF");
}
lastBTstate = newBTstate;
dataFile.close();
}
// SETUP() FUNCTION
/********************************************************************************************************************************************************************************/
void setup() {
initialisation();
createFileAndName();
firstWrite();
tStart = millis();
}
// LOOP() FUNCTION
/********************************************************************************************************************************************************************************/
void loop() {
DatalogAndDiagnostics();
}
// END OF PROGRAM
/********************************************************************************************************************************************************************************/