What do you think about the changes I have made to the code? I have read through the article you linked multiple times now, thanks again for that. I am starting to grasp all of the concepts mentioned. I followed jremingtons advice to use f macros on all print functions (including logfile.prints). I also used sprintf to change all of the strings I was using.
Let me know if you still think its an issue with the RAM. Thanks.
In order to add a switch to stop datalogging safely, my plan is to add the following:
At the top of my code where I have all of my variables/definitions, I will add
const int buttonPin = 4; // This will be used to tell the arduino to stop datalogging safely via a switch
bool loggingEnabled = true; // Initially, logging is enabled
Then I will add
void loop()
{
if (digitalRead(buttonPin) == LOW) { // If the button is switched
loggingEnabled = false; // Change bool to false (disable)
logfile.close(); // Close the file safely
Serial.println("Logging stopped.");
}
if (!loggingEnabled) {
return; // Stop further data logging if logging is disabled
}
... rest of my loop code stuff ...
So, with my code taken care of, the question for me comes back to how to physically wire in the switch. What I planned to do was to just add a switch from pin 4 to ground, however, I googled it and saw that I might need a resistor. What size resistor would you recommend and why?
Please advise me if this is the proper way to handle this. Thanks!
I updated the code to include this switch. I have it all hooked up correctly. I tested it and it works.
While I do not think this addresses the root cause of the problem, I am hoping that it helps. Maybe now with this brand new SD Card and the fact that I will now be properly closing the file before turning off the Arduino, it will continue to run for days on end.
I will leave it running for the rest of the day. Tomorrow I will check on it and see if the Arduino is still running correctly. I have it hooked up to my computer this way I can check the serial log and see what happens. Thanks.
The datalogger failed again yesterday. It only lasted just over 2 hours before it stopped writing data completely. This time, it showed no errors with the date and time. It simply wrote the expected data, and then stopped completely. The SD Card was corrupted again.
If anyone has any ideas, please let me know what you think.
Thanks!
I think the advice you have been getting from other people is better than anything I might suggest. Topics like this tend to keep going as long as the OP (you) engage with the help. Do remember that the people with the ideas might not be anywhere near this forum right now.
I notice that your shield has a battery on it so I went and looked at the description. It has a RTC chip on it with the same I2C address as the DS3231. They are be fighting and occasionally causing a failure.
You probably want a simple SD card adapter rather than a data logger one.
I had thought about that.. that very well could be the problem.
I will look into buying a simple SD Card Adapter.
I try to buy from reputable places, so that is why I went through Adafruit for most of my purchases. However, they do not offer a simple SD Card adapter, outside of those MicroSD ones (I really want to stay away from using MicroSD cards).
Here is an amazon link to one that I found.. not sure where else I can buy something like this from a reputable vendor. Let me know if you think this would work:
Why? Many of them come with an adapter for use in SD readers for when you need that. I have used micro SD cards for years and have had no problems with them. The boards are smaller if you are space constrained.
What temperature range are you working in? If it normal room temperature the RTC on the data logger shield may be OK. If you are working over a wide range you definitely want the DS3231. I have used in a river monitor over a temperature range of 32-100 F and it was still within seconds after several months.
The Amazon device looks like a typical adapter board. The description is a little strange - it says that both 3.3V and 5V are required. I think it means either - there is an onboard regulator for 5V -> 3.3V. I'm not a fan of redundant double row headers, but it could be handy if you want to daisy chain another board.
The sole reason for not wanting to use Micro SD cards is because we have an abundant number of brand new normal SD Cards. We use them already. While I have an adapter for the micro SD card, I would not want to implement the use of an entirely new form factor. They are also smaller, meaning they are much easier to lose. I am working within a manufacturing environment. The simpler I can make things, the easier it will be on everyone. Its as simple as that. I started this project with the hope of using a regular USB thumb drive. That did not work well at all. For the time being, I'd very much like to stick to trying to get the normal SD Card to work.
The datalogger is stored in a climate controlled room; temperatures may vary from 60-80°F at the absolute most.
Sounds good. I will purchase that one and see if I can get it operational. In the mean time, I will play around with only using the RTC onboard the datalogging shield (PCF8523), and stop using the DS3231. If it works, I can determine if that is in fact the issue.
I am attempting to only use the RTC that is connected to the SD Card Shield.
I have disconnected the DS3231 RTC.
I am able to interface with the built-in RTC (PCF8523) correctly using the example code provided with RTClib.
When I try to use my current code (which I will post below- I made almost no changes to it), the RTC connects properly, but it no longer allows my SD Card to be read.
This is very strange. When I use the DS3231 RTC, the SD Card is read with no problems. However, when I use the PCF8523 RTC, the arduino can no longer connect to the SD Card.
Let me know if you have reasoning for this, I will continue to troubleshoot it.
Here is my code:
// In order to have the code work, you must find and download the following libraries for the Arduino IDE: --------------------------
#include <Adafruit_ADS1X15.h>
#include "RTClib.h"
#include <SD.h>
#include <SPI.h>
#include <Wire.h>
// The following define your basic variables: ---------------------------------------------------------------------------------------
#define LOG_INTERVAL 10000 // mills between entries (set to 10,000 for 10 seconds)
#define SYNC_INTERVAL 10000 // mills between calls to "flush()" (write data to the card)
uint32_t syncTime = 0; // time of last "sync()"
#define LED1 2 // Make LED1 Controlled by Pin 2 on the Arduino
#define LED2 3 // Make LED2 Controlled by Pin 3 on the Arduino
const int chipSelect = 10; // The Data Logging Shield uses Pin 10 to communicate with the SD Card
const int ADS1115_ADDRESS = 0x48; // Set the I2C address of the ADS1115 ADC (Wire.h allows for multiple devices to be connected to the same SDA/SCL pins)
const int RTC_ADDRESS = 0x68; // Set the I2C address of the PCF8523 RTC
const int buttonPin = 4; // The pin to which the button is connected
Adafruit_ADS1115 adc; // Create an Object for the ADC
RTC_PCF8523 rtc; // Create an Object for the RTC
File logfile; // Create the Variable for the File data type
// Enum to represent the four different error types----------------------------------------------------------------------------------
enum ErrorType {
ERROR_RTC,
ERROR_ADC,
ERROR_SD_CARD,
ERROR_OPEN_FILE
};
// These are the three functions that will be called upon continuously in the loop---------------------------------------------------
// They check to ensure that the RTC, ADC, and SD Card are still connected/working properly
bool isRTCConnected() {
return rtc.begin(); // Try to initialize the RTC and return the success status
}
bool isADCConnected() {
return adc.begin(ADS1115_ADDRESS); // Try to initialize the ADC and return the success status
}
bool isSDCardConnected() {
return SD.begin(chipSelect); // Try to initialize the SD card and return the success status
}
// Used for flashing LEDS for a way of user debugging--------------------------------------------------------------------------------
void flashLED(int pin, int flashes, int onTime, int offTime) { // This sets up a function to flash the debugging LEDs using the: pin, number of flashes, on time (ms), and off time (ms)
for (int i = 0; i < flashes; i++) { // This creates the loop. For "i" amount (the number of flashes):
digitalWrite(pin, HIGH); // Turn on the LED at the pin
delay(onTime); // For however many milliseconds
digitalWrite(pin, LOW); // Turn off the LED at the pin
delay(offTime); // For however many milliseconds
}
}
// The following section is created for debugging purposes---------------------------------------------------------------------------
void error(char *str, ErrorType errorType) {
digitalWrite(LED1, LOW); // Turn off the green LED signifying there is something wrong
Serial.println();
Serial.print(F("ERROR: "));
Serial.println(str);
while (!isRTCConnected() || !isADCConnected() || !isSDCardConnected() || errorType == ERROR_OPEN_FILE) {
switch (errorType) {
case ERROR_RTC:
flashLED(LED2, 3, 200, 200);
delay(5000);
break;
case ERROR_ADC:
flashLED(LED2, 6, 200, 200);
delay(5000);
break;
case ERROR_SD_CARD:
flashLED(LED2, 3, 500, 500);
delay(5000);
break;
case ERROR_OPEN_FILE:
flashLED(LED2, 6, 500, 500);
delay(5000);
break;
default:
break;
}
}
}
// Create the file's date&time signature---------------------------------------------------------------------------------------------
void dateTime(uint16_t* date, uint16_t* time) { // This function is used to set the date of the file in your file explorer
DateTime now = rtc.now(); // This initializes the RTC
*date = FAT_DATE(now.year(), now.month(), now.day()); // This returns the date using FAT_DATE macro to format fields
*time = FAT_TIME(now.hour(), now.minute(), now.second()); // This returns the time using FAT_TIME macro to format fields
}
// These are your initial setup parameters-------------------------------------------------------------------------------------------
void setup(void)
{
Serial.begin(9600); // Begins Serial Communication b/t Arduino and Computer
Serial.println(); // Prints a new line
// Set-up the Debugging LEDs
pinMode(LED1, OUTPUT); // Makes the pin that LED1 is connected to an output
pinMode(LED2, OUTPUT); // Makes the pin that LED2 is connected to an output
// Set-up the switch, connected to a pin, to stop datalogging
pinMode(buttonPin, INPUT_PULLUP); // This will be used to tell the arduino to stop datalogging safely via a switch
digitalWrite(LED1, HIGH); // Turns on LED1 to indicate the code is being executed with no problems
Wire.begin(); // Calls upon the Wire.h library to initialize
rtc.begin(); // Initialize the PCF8523 RTC
if (!rtc.begin()) { // If initializing the RTC fails:
error("RTC failed", ERROR_RTC); // This defines what will be typed on screen, along with what error type will be called
}
Serial.println(F("The PCF8523 RTC is Connected"));
// Un-Comment the following Lines to Adjust the Time on the RTC (then comment them out again once it has been adjusted!)
//DateTime adjustedTime(2023, 7, 6, 8, 22, 00); // Set the desired date and time
//rtc.adjust(adjustedTime); // Adjust the RTC time
adc.begin(ADS1115_ADDRESS); // Initialize the ADS1115 ADC with the desired I2C address
if (!adc.begin(ADS1115_ADDRESS)) { // If initializing the ADC fails:
error("ADC failed", ERROR_ADC); // This defines what will be typed on screen, along with what error type will be called
}
Serial.println(F("The ADS1115 ADC is Connected"));
// Initialize the SD Card
Serial.print(F("Initializing SD card..."));
pinMode(10, OUTPUT); // Pin 10 is used to communicate with the SD Card
if (!SD.begin(chipSelect)) { // If the SD Card cannot be connected to:
error("Card failed or not present", ERROR_SD_CARD); // This defines what will be typed on screen, along with what error type will be called
}
Serial.println(F("card initialized."));
// Create a New File
char filename[13]; // Buffer to hold the filename (8 characters for "YY-MM-DD", 1 for '.', 3 for "CSV", and 1 for null terminator)
DateTime now = rtc.now(); // Sets the DateTime variable to the current time
sprintf(filename, "%02d-%02d-%02d.CSV", now.year() % 100, now.month(), now.day()); // Makes the name of the file "YY-MM-DD"
SdFile::dateTimeCallback(dateTime); // This is used to set the date of the file in your file explorer
// Open the logfile with UTF-8 encoding. This is necessary so that there is not problem with the "°" Symbol
logfile = SD.open(filename, FILE_WRITE | O_WRITE | O_CREAT | O_APPEND);
if (!logfile) { // If there is a problem with opening the file:
error("couldnt create file", ERROR_OPEN_FILE); // This defines what will be typed on screen, along with what error type will be called
}
logfile.print(F("\xEF\xBB\xBF")); // Write UTF-8 BOM to indicate the encoding
Serial.print(F("Logging to: "));
Serial.println(filename);
// Output the Labels
Serial.println(F("Date Time,Oven 46 (V),Oven 47 (V),Oven 48 (V),Oven 49 (V),Oven 46 (°C),Oven 47 (°C),Oven 48 (°C),Oven 49 (°C)"));
logfile.println(F("Date Time,Oven 46 (V),Oven 47 (V),Oven 48 (V),Oven 49 (V),Oven 46 (°C),Oven 47 (°C),Oven 48 (°C),Oven 49 (°C)"));
}
// The following is what loops over and over again; in this case, collecting and writing data----------------------------------------
void loop()
{
if(digitalRead(buttonPin) == LOW) {
logfile.close(); // Close the SD Card's file safely
Serial.println(F("Datalogging has been safely stopped."));
while(1); // Hang here until reset button is pushed, or new program uploaded
}
if (!isRTCConnected()) {
error("RTC failed", ERROR_RTC);
}
if (!isADCConnected()) {
error("ADC failed", ERROR_ADC);
}
if (!isSDCardConnected()) {
error("Card failed or not present", ERROR_SD_CARD);
}
digitalWrite(LED1, HIGH); // Turn on LED1 to indicate the code is executing with no problems
// Read the Current Time from the RTC
DateTime now = rtc.now();
char ymdhms[20]; // Buffer for formatted date and time
// Convert Date and Time Values to a Formatted String with Leading Zeros
sprintf(ymdhms, "%02d-%02d-%02d %02d:%02d:%02d",
now.year() % 100, now.month(), now.day(),
now.hour(), now.minute(), now.second());
// Use an Array to Store Voltage and Temperature Values for All 4 Channels
float voltages[4];
float temperatures[4];
// Loop Through all 4 Channels, Read the Voltages, Convert it to Temperature
for (uint8_t channel = 0; channel < 4; channel++)
{
int16_t adcValue = adc.readADC_SingleEnded(channel); // Read from the current channel
float voltage = adcValue * 0.0001875; // Convert raw value to voltage (6.144V / (2^15bits))
voltages[channel] = voltage; // Sets the voltage to the voltage for each respective channel
float temperature = voltage * (1800 / 5); // Convert the voltage to a temperature (0-5v = 0-1800°C type of scale)
temperatures[channel] = temperature; // Sets the temperature to the temperature for each respective channel
}
// Serial Print data
Serial.print(ymdhms);
Serial.print(F(","));
for (uint8_t i=0; i<4; i++)
{
Serial.print(voltages[i], 3);
Serial.print(F(","));
}
for (uint8_t i=0; i<4; i++)
{
Serial.print(temperatures[i], 0);
Serial.print(F(","));
}
Serial.println();
// Log data to SD Card
logfile.print(ymdhms);
logfile.print(F(","));
for (uint8_t i=0; i<4; i++)
{
logfile.print(voltages[i], 3);
logfile.print(F(","));
}
for (uint8_t i=0; i<4; i++)
{
logfile.print(temperatures[i], 0);
logfile.print(F(","));
}
logfile.println();
// Delay for the amount of time we want between readings
delay((LOG_INTERVAL -1) - (millis() % LOG_INTERVAL));
// Check Passage of Time
if ((millis() - syncTime) < SYNC_INTERVAL) return;
syncTime = millis();
// Turn On Red LED, Write Data to SD Card, Turn Off Red LED
digitalWrite(LED2, HIGH);
delay(500);
logfile.flush();
delay(500);
digitalWrite(LED2, LOW);
}
This is what is output on the Serial Monitor:
The PCF8523 RTC is Connected
The ADS1115 ADC is Connected
Initializing SD card...
ERROR: Card failed or not present
I'm not sure what the effect of multiple call to .begin() would be. I never call them again after setup(). For SD files I check if the open() worked and send an error if it failed.
I am running into an issue where my code will not continue to loop and execute unless I un-comment out a Serial.print("...") line of code.
I will post my code below. It is a work in progress where I am attempting to create a datalogger. See my other post, " Unknown Failure in Datalogger" to read more about my code. I have a whole bunch of lines commented-out as I am trying to work through bugs.
// In order to have the code work, you must find and download the following libraries for the Arduino IDE: --------------------------
#include <Adafruit_ADS1X15.h>
#include "RTClib.h"
#include <SD.h>
#include <SPI.h>
#include <Wire.h>
// The following define your basic variables: ---------------------------------------------------------------------------------------
#define LOG_INTERVAL 10000 // mills between entries (set to 10,000 for 10 seconds)
#define SYNC_INTERVAL 10000 // mills between calls to "flush()" (write data to the card)
uint32_t syncTime = 0; // time of last "sync()"
#define LED1 2 // Make LED1 Controlled by Pin 2 on the Arduino
#define LED2 3 // Make LED2 Controlled by Pin 3 on the Arduino
const int chipSelect = 10; // The Data Logging Shield uses Pin 10 to communicate with the SD Card
const int ADS1115_ADDRESS = 0x48; // Set the I2C address of the ADS1115 ADC (Wire.h allows for multiple devices to be connected to the same SDA/SCL pins)
const int RTC_ADDRESS = 0x68; // Set the I2C address of the PCF8523 RTC
const int buttonPin = 4; // The pin to which the button is connected
Adafruit_ADS1115 adc; // Create an Object for the ADC
RTC_PCF8523 rtc; // Create an Object for the RTC
File logfile; // Create the Variable for the File data type
// Enum to represent the four different error types----------------------------------------------------------------------------------
enum ErrorType {
ERROR_RTC,
ERROR_ADC,
ERROR_SD_CARD,
ERROR_OPEN_FILE
};
// These are the three functions that will be called upon continuously in the loop---------------------------------------------------
// They check to ensure that the RTC, ADC, and SD Card are still connected/working properly
bool isRTCConnected() {
return rtc.begin(); // Try to initialize the RTC and return the success status
}
bool isADCConnected() {
return adc.begin(ADS1115_ADDRESS); // Try to initialize the ADC and return the success status
}
bool isSDCardConnected() {
return SD.begin(chipSelect); // Try to initialize the SD card and return the success status
}
// Used for flashing LEDS for a way of user debugging--------------------------------------------------------------------------------
void flashLED(int pin, int flashes, int onTime, int offTime) { // This sets up a function to flash the debugging LEDs using the: pin, number of flashes, on time (ms), and off time (ms)
for (int i = 0; i < flashes; i++) { // This creates the loop. For "i" amount (the number of flashes):
digitalWrite(pin, HIGH); // Turn on the LED at the pin
delay(onTime); // For however many milliseconds
digitalWrite(pin, LOW); // Turn off the LED at the pin
delay(offTime); // For however many milliseconds
}
}
// The following section is created for debugging purposes---------------------------------------------------------------------------
void error(char *str, ErrorType errorType) {
digitalWrite(LED1, LOW); // Turn off the green LED signifying there is something wrong
Serial.println();
Serial.print(F("ERROR: "));
Serial.println(str);
while (!isRTCConnected() || !isADCConnected() || !isSDCardConnected() || errorType == ERROR_OPEN_FILE) {
switch (errorType) {
case ERROR_RTC:
flashLED(LED2, 3, 200, 200);
delay(5000);
break;
case ERROR_ADC:
flashLED(LED2, 6, 200, 200);
delay(5000);
break;
case ERROR_SD_CARD:
flashLED(LED2, 3, 500, 500);
delay(5000);
break;
case ERROR_OPEN_FILE:
flashLED(LED2, 6, 500, 500);
delay(5000);
break;
default:
break;
}
}
}
// Create the file's date&time signature---------------------------------------------------------------------------------------------
void dateTime(uint16_t* date, uint16_t* time) { // This function is used to set the date of the file in your file explorer
DateTime now = rtc.now(); // This initializes the RTC
*date = FAT_DATE(now.year(), now.month(), now.day()); // This returns the date using FAT_DATE macro to format fields
*time = FAT_TIME(now.hour(), now.minute(), now.second()); // This returns the time using FAT_TIME macro to format fields
}
// These are your initial setup parameters-------------------------------------------------------------------------------------------
void setup(void)
{
Serial.begin(9600); // Begins Serial Communication b/t Arduino and Computer
Serial.println(); // Prints a new line
// Set-up the Debugging LEDs
pinMode(LED1, OUTPUT); // Makes the pin that LED1 is connected to an output
pinMode(LED2, OUTPUT); // Makes the pin that LED2 is connected to an output
// Set-up the switch, connected to a pin, to stop datalogging
pinMode(buttonPin, INPUT_PULLUP); // This will be used to tell the arduino to stop datalogging safely via a switch
digitalWrite(LED1, HIGH); // Turns on LED1 to indicate the code is being executed with no problems
Wire.begin(); // Calls upon the Wire.h library to initialize
rtc.begin(); // Initialize the PCF8523 RTC
if (!rtc.begin()) { // If initializing the RTC fails:
error("RTC failed", ERROR_RTC); // This defines what will be typed on screen, along with what error type will be called
}
rtc.start();
Serial.println(F("The PCF8523 RTC is Connected"));
// Un-Comment the following Lines to Adjust the Time on the RTC (then comment them out again once it has been adjusted!)
//DateTime adjustedTime(2023, 7, 6, 8, 22, 00); // Set the desired date and time
//rtc.adjust(adjustedTime); // Adjust the RTC time
adc.begin(ADS1115_ADDRESS); // Initialize the ADS1115 ADC with the desired I2C address
if (!adc.begin(ADS1115_ADDRESS)) { // If initializing the ADC fails:
error("ADC failed", ERROR_ADC); // This defines what will be typed on screen, along with what error type will be called
}
Serial.println(F("The ADS1115 ADC is Connected"));
// // Initialize the SD Card
// Serial.print(F("Initializing SD card..."));
// pinMode(10, OUTPUT); // Pin 10 is used to communicate with the SD Card
// if (!SD.begin(chipSelect)) { // If the SD Card cannot be connected to:
// error("Card failed or not present", ERROR_SD_CARD); // This defines what will be typed on screen, along with what error type will be called
// }
// Serial.println(F("card initialized."));
// // Create a New File
// char filename[13]; // Buffer to hold the filename (8 characters for "YY-MM-DD", 1 for '.', 3 for "CSV", and 1 for null terminator)
// DateTime now = rtc.now(); // Sets the DateTime variable to the current time
// sprintf(filename, "%02d-%02d-%02d.CSV", now.year() % 100, now.month(), now.day()); // Makes the name of the file "YY-MM-DD"
// SdFile::dateTimeCallback(dateTime); // This is used to set the date of the file in your file explorer
// // Open the logfile with UTF-8 encoding. This is necessary so that there is not problem with the "°" Symbol
// logfile = SD.open(filename, FILE_WRITE | O_WRITE | O_CREAT | O_APPEND);
// if (!logfile) { // If there is a problem with opening the file:
// error("couldnt create file", ERROR_OPEN_FILE); // This defines what will be typed on screen, along with what error type will be called
// }
// logfile.print(F("\xEF\xBB\xBF")); // Write UTF-8 BOM to indicate the encoding
Serial.print(F("Logging to: "));
// Serial.println(filename);
// Output the Labels
Serial.println(F("Date Time,Oven 46 (V),Oven 47 (V),Oven 48 (V),Oven 49 (V),Oven 46 (°C),Oven 47 (°C),Oven 48 (°C),Oven 49 (°C)"));
// logfile.println(F("Date Time,Oven 46 (V),Oven 47 (V),Oven 48 (V),Oven 49 (V),Oven 46 (°C),Oven 47 (°C),Oven 48 (°C),Oven 49 (°C)"));
}
// The following is what loops over and over again; in this case, collecting and writing data----------------------------------------
void loop()
{
if(digitalRead(buttonPin) == LOW) {
logfile.close(); // Close the SD Card's file safely
Serial.println(F("Datalogging has been safely stopped."));
while(1); // Hang here until reset button is pushed, or new program uploaded
}
//Serial.println(F("Datalogging has not been stopped"));
if (!isRTCConnected()) {
error("RTC failed", ERROR_RTC);
}
//Serial.println(F("The RTC is still Connected"));
if (!isADCConnected()) {
error("ADC failed", ERROR_ADC);
}
//Serial.println(F("The ADC is still Connected"));
// if (!isSDCardConnected()) {
// error("Card failed or not present", ERROR_SD_CARD);
// }
digitalWrite(LED1, HIGH); // Turn on LED1 to indicate the code is executing with no problems
// Read the Current Time from the RTC
DateTime now = rtc.now();
//Serial.println(F("The current time has been read"));
char ymdhms[20]; // Buffer for formatted date and time
// Convert Date and Time Values to a Formatted String with Leading Zeros
sprintf(ymdhms, "%02d-%02d-%02d %02d:%02d:%02d",
now.year() % 100, now.month(), now.day(),
now.hour(), now.minute(), now.second());
//Serial.println(F("Dates and Times have been converted"));
// Use an Array to Store Voltage and Temperature Values for All 4 Channels
float voltages[4];
float temperatures[4];
// Serial.println(F("Its not a problem with creating the arrays"));
int16_t adcValue0 = adc.readADC_SingleEnded(0); // Read from the current channel
float voltage0 = adcValue0 * 0.0001875; // Convert raw value to voltage (6.144V / (2^15bits))
voltages[0] = voltage0; // Sets the voltage to the voltage for each respective channel
float temperature0 = voltage0 * (1800 / 5); // Convert the voltage to a temperature (0-5v = 0-1800°C type of scale)
temperatures[0] = temperature0; // Sets the temperature to the temperature for each respective channel
Serial.flush();
int16_t adcValue1 = adc.readADC_SingleEnded(1); // Read from the current channel
float voltage1 = adcValue1 * 0.0001875; // Convert raw value to voltage (6.144V / (2^15bits))
voltages[1] = voltage1; // Sets the voltage to the voltage for each respective channel
float temperature1 = voltage1 * (1800 / 5); // Convert the voltage to a temperature (0-5v = 0-1800°C type of scale)
temperatures[1] = temperature1; // Sets the temperature to the temperature for each respective channel
Serial.flush();
int16_t adcValue2 = adc.readADC_SingleEnded(2); // Read from the current channel
float voltage2 = adcValue2 * 0.0001875; // Convert raw value to voltage (6.144V / (2^15bits))
voltages[2] = voltage2; // Sets the voltage to the voltage for each respective channel
float temperature2 = voltage2 * (1800 / 5); // Convert the voltage to a temperature (0-5v = 0-1800°C type of scale)
temperatures[2] = temperature2; // Sets the temperature to the temperature for each respective channel
Serial.flush();
int16_t adcValue3 = adc.readADC_SingleEnded(3); // Read from the current channel
float voltage3 = adcValue3 * 0.0001875; // Convert raw value to voltage (6.144V / (2^15bits))
voltages[3] = voltage3; // Sets the voltage to the voltage for each respective channel
float temperature3 = voltage3 * (1800 / 5); // Convert the voltage to a temperature (0-5v = 0-1800°C type of scale)
temperatures[3] = temperature3; // Sets the temperature to the temperature for each respective channel
Serial.flush();
//Serial.println(F("Voltages converted to temperatures"));
// Serial Print data
Serial.print(ymdhms);
Serial.print(F(","));
for (uint8_t i=0; i<4; i++)
{
Serial.print(voltages[i], 3);
Serial.print(F(","));
}
for (uint8_t i=0; i<4; i++)
{
Serial.print(temperatures[i], 0);
Serial.print(F(","));
}
Serial.println();
delay (5000);
Serial.flush();
// // Log data to SD Card
// logfile.print(ymdhms);
// logfile.print(F(","));
// for (uint8_t i=0; i<4; i++)
// {
// logfile.print(voltages[i], 3);
// logfile.print(F(","));
// }
// for (uint8_t i=0; i<4; i++)
// {
// logfile.print(temperatures[i], 0);
// logfile.print(F(","));
// }
// logfile.println();
// // Delay for the amount of time we want between readings
// delay((LOG_INTERVAL -1) - (millis() % LOG_INTERVAL));
// // Check Passage of Time
// if ((millis() - syncTime) < SYNC_INTERVAL) return;
// syncTime = millis();
// // Turn On Red LED, Write Data to SD Card, Turn Off Red LED
// digitalWrite(LED2, HIGH);
// delay(500);
// logfile.flush();
// delay(500);
// digitalWrite(LED2, LOW);
}
If I upload that code to my arduino mega, it will not continuously loop. HOWEVER, if I un-comment out the following line:
// Serial.println(F("Its not a problem with creating the arrays"));
Then the code will continuously loop.
What is going on here? I am only making this post because I want to better understand what I am missing. Thanks!
Often that would be an indication of some type of memory corruption, but in this case I don't see any obvious problems like that. The only thing that line really does is cause a delay when you reach the subsequent Serial.flush(), and the obvious thing I see wrong in the code is the continuous calls to begin(), as pointed out by @oldcurmudgeon. I doubt most libraries are written to properly handle multiple calls to begin(), and if you must have those then at least check to see if there is an end() function that needs to be called first.
You problem needs seems to be that you don't understand what the code is actually doing.
Let's take Serial.begin;
in this case the IDE Task the "Serial" PORT OBJECT
Side Note, when using C++ which is the language you are using with Arduino.
You are using and O.O.P.L. (Object Orientated Programming Language)
Look at these "Objects" Like chunks of LEGO Blocks that you can connect to each
other to do stuff.
So "Serial" is an Object and under that library we have lots of other stuff
3 of them being begin , print , println
The IDE Understands them as having certain predefined tasks.
So you get your Serial lego block and to signify that the next block is a sub block
of Serial you put a . then add begin like this Serial.begin
This tells the Serial Port Object to start, BUT... it doesn't know what to do
so we give it paramaters (A Baud Rate) like 9600 and we end the statement with ;
to get Serial.begin(9600);
RE
When you confuse yourself, nothing is simple...
But you don't have to confuse yourself, so when you understand what the program does
its' simple
Now... Hopefully you got the concept explained above , Let's now continue to work with the Serial Object now we'll use print
so now we have Serial.print , so the Serial Object is being called and told.. "Use your print sub object" to print stuff.
and it sits there and says.. Umm, right, what do you want me to print though ?
which means we have to provide an argument or parameter like
"Here is a Print Line that stays on one Line"
as you know, this is called "A TEXT STRING" so we get this...
Serial.print("Here is a Print Line that stays on one Line");
OK, So now you have the problem you have is, YOU'RE CHEWING UP MEMORY
because if you keep putting these things in and given the lack of Memory in an Arduino,
vs... Say an ESP32 You're going to run into problems
In saying that.. Regardless of what you upgrade to, IT SHOULD ALWAYS BE GOOD PRACTICE TO OPTIMIZE YOUR MEMORY
so... the print object instruction basically says "Print what is in the quotation marks and not the quotation marks and if another print statement follows, print it after this one"
so if you had this....
Serial.print("1");
Serial.print("2");
The Output would be
12
Now i put a space after each number like this so it doesn't look like 12
Serial.print("1 ");
Serial.print("2 ");
the output is
1 2
However if i want them to start on a new line i would do this
Serial.println("1 ");
Serial.println("2 ");
to get this
1
2
so we have learned that the Serial Object is used ,
That Object has Sub Instructions, 2 of which are print and println
.. print prints on one line and when it reaches a ; does not start a new line
.. println prints on one line and when it reaches a ; it goes to the next line
Got that ?
Simple
so... Tech Info Warning...
When you create Text Strings like Serial.print(" "); and Serial.println(" ");
You are using your Arduino Memory, called (SRAM)
when you do this you are very quickly going to flood your SRAM and get errors
SO... THE SOLUTION.... F macro .... Or is it ?
The popular consensus is to Use the F macro
"but i already said...."
Lets start with "macro" it is a command or series of commands that are used
to get things done automatically , and they can be re-used
an F macro is just a command called "F" You use it like this
Serial.print(F(""));
Basically you insert it before the text string and WHAT IT DOES IS...
it says to the compiler....
DO NOT PUT THIS IN SRAM
(this will solve the problem of chewing up your SRAM)
What is says is... Put the following line / text string into PROGRAM MEMORY
Because it has to be stored somewhere
The problem here is.. You are taking a lot of crap from one memory and dumping it in the other , It achieves a little
BUT.... I HAVE A BETTER IDEA
Your problem is really that when you compile the code, if the compiler SEE'S SOMETHING AS "A TEXT STRING" it allocates a tonne of memory to it
WHAT IF WE COULD CHANGE THAT ?
so that the compiler compiled things like normal code and used minimal memory
then we could change that thing when we needed it so that it only stored in memory the line that it's using at that time.
THAT !! would save a lot of memory wouldn't it ?
EXPLANATION :
We need to create a new object because when the object Serial.print(""); is seen
this where the problem starts.
I'm going to call this new Object "AltText" (Alternative Print Text) You can call it whatever you want , You can call it BigBird for all i care
so this line
#define AltText 1
This defines the name of the object and gives it a value of 1
we are using 1 as True/On and we can use 0 as False/Off.
I'm going to give you the ability to turn this feature On and Off WHENEVER YOU LIKE.
all you need to do is change the 1 to a 0 and anything that contains the term
"AltText" will not be compiled at all
This is useful when you have 200 Lines of Text Strings and you don't want to uncomment them all
Next
#if AltText == 1
We put in an IF Statement and say.... If "AltText" is 1 (True/On)
so... if you see something that reads as "AltText"
then we have to do something with that..
THIS IS THE GOLDEN KEY TO EVERYTHING
so it's saying, it "AltText" is true then
define the an object called singleline(x) You can name this whatever you want as well.
and then whenever you see this object CHANGE IT TO Serial.print(x)
In this way you are only using memory when you need to.
FYI, the X is just there in case you have a value in the field , it's a placeholder.
if you take out the x you will get an error
although you can change the x to whatever you want
so you're using your own object that doesn't chew up memory at compile time.
then when it's needed you are telling it to change it to the usual Serial.print objects
THIS WILL DRASTICALLY REDUCE THE AMOUNT OF MEMORY YOU ARE CONSUMING
and this part
#else
#define singleline(x)
#define newline(x)
This just accounts for what happens to your code when you set
.. #define AltText 1 to 0
if you like, Try the code without this section then change the define AltText to 0
and see what happens
The #endif just closes the IF Statement
so.. Use that and change all the Serial.print() in your code to singleline(x)
and change all the Serial.println() to newline()
or.. make up your own names
don't worry about the F macro
don't worry about print or println
it will work in the same way , You've just not used text strings everywhere at compile time''
If you problem is bloated memory
then this should fix your problem
Ohh ?? well there you go then LOL
thanks Mate
Truth be told i never actually looked that up, but i noticed when we were trying
to perform formatting on a text string we would use F for that purpose.
i can see the logic in FLASH
and that they do different things.
i was under the understanding that both did the same thing. that being both can print text strings as in the case of Serial.print("");
but when you add the F macro you get additional formatting features and options.
Exactly, which is obviously what i was addressing
Fair enough, so.. You don't think that my proposed solution will work in this situation.
for me, I've tested it and it works and it greatly reduces how much SRAM is used.
i just figured i'd throw it up since not many people mention it