come on, don't "piss away" :) memory! a month will be 2 digits, add a '\0' at the end and that's 3... no need to save 50 bytes for that, right? and you could probably even read that as a byte for month number...
Yes, I know that! But I thought that I should consider the WHOLE buffer (date, time, reading, various symbols here and there, etc.)
This is the output, absolutely not what I expected
well read again what the first param of strtok() should be once you've done the initialization. Also, you are searching for commas, do you see a lot of those into your buffer?
// Code for receiving the data from my analytical scale through RS232 with parsing
// Libraries
#include <LiquidCrystal.h>
#include <SPI.h>
#include <SD.h>
// Interface and Objects definitions
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // Creates a LCD LiquidCrystal object
const int chipSelect = 10; // Assigns the pin for the SPI-SD chip selection
const byte bufferSize = 50; // enough for your max length of a message
static byte bufferPosition = 0;
char inputBuffer[bufferSize]; // my array of the data from the scale
char tempBuffer[bufferSize]; // temporary array for use when parsing
// variables to hold the parsed data
char date_month[bufferSize] = {0};
char date_day[bufferSize] = {0};
char date_year[bufferSize] = {0};
char time_hour[bufferSize] = {0};
char time_min[bufferSize] = {0};
char time_sec[bufferSize] = {0};
float reading = 0.0;
boolean newData = false;
//============
void setup()
{
Serial.begin(9600, SERIAL_7N1); // Includes the scale parameters
pinMode(chipSelect, OUTPUT); // Ensures that the SPI-SD selection pin is an output
lcd.begin(16, 2); // Initialises the interface to the LCD screen
lcd.clear(); // // Clears the LCD screen and positions the cursor in the upper-left corner
if (!SD.begin(chipSelect)) // Checks if the SD card is working
{
lcd.println("SD failed!");
delay(2000);
return;
}
bufferPosition = 0;
inputBuffer[0] = '\0'; // initialize with empty string
}
//============
void loop() {
recvWithEndMarker();
if (newData == true) {
strcpy(tempBuffer, inputBuffer);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
parseData();
saveData();
newData = false;
}
}
//============
void recvWithEndMarker() {
char endMarker = 'OK';
char receivedData;
while (Serial.available() > 0 && newData == false) {
receivedData = Serial.read();
if (receivedData != endMarker) {
inputBuffer[bufferPosition] = receivedData;
bufferPosition++;
if (bufferPosition >= bufferSize) {
bufferPosition = bufferSize - 1;
}
}
else {
inputBuffer[bufferPosition] = '\0'; // terminate the string
bufferPosition = 0;
newData = true;
}
}
}
//============
void parseData() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(tempBuffer,","); // get the first bit
strcpy(date_month, strtokIndx); // copy it to month variable
strtokIndx = strtok(tempBuffer,","); // carry on...
strcpy(date_month, strtokIndx); // carry on copy this byte in the same variable
strtokIndx = strtok(tempBuffer,",");
strcpy(date_day, strtokIndx); // copy it to month variable
strtokIndx = strtok(tempBuffer,",");
strcpy(date_day, strtokIndx); // carry on copy this byte in the same variable, etc.
strtokIndx = strtok(tempBuffer,",");
strcpy(date_year, strtokIndx);
strtokIndx = strtok(tempBuffer,",");
strcpy(date_year, strtokIndx);
strtokIndx = strtok(NULL, ","); // I do the same with the time...
strcpy(time_hour, strtokIndx);
strtokIndx = strtok(NULL, ",");
strcpy(time_hour, strtokIndx);
strtokIndx = strtok(NULL, ",");
strcpy(time_min, strtokIndx);
strtokIndx = strtok(NULL, ",");
strcpy(time_min, strtokIndx);
strtokIndx = strtok(NULL, ",");
strcpy(time_sec, strtokIndx);
strtokIndx = strtok(NULL, ",");
strcpy(time_sec, strtokIndx);
strtokIndx = strtok(NULL, ",");
reading = atof(strtokIndx); // convert this part to a float for the reading cell
}
//============
void saveData()
{
// **********************************************************************
// here the inputBuffer has a full line, you could parse it for content
// I'm just saving the full line to the SD card
// **********************************************************************
File readings = SD.open("readings.csv", FILE_WRITE); // Opens the file on the SD card
if (readings) // If the file opened OK, write to it on SD card
{
readings.print(date_month);
readings.print(',');
readings.print(date_day);
readings.print(',');
readings.print(date_year);
readings.print(',');
readings.print(time_hour);
readings.print(',');
readings.print(time_min);
readings.print(',');
readings.print(time_sec);
readings.print(',');
readings.println(reading);
readings.close(); // Closes the file to save the data on the SD card
} else { // If the file didn't open, print an error
lcd.println("FILE NOT OPEN");
delay(2000);
lcd.clear();
}
}
I changed the end marker:
char endMarker = 'OK';
So I think it will build the buffer until the "OK".
Anyway, I will have a look again on that strtok() then but I am quite struggling
Thanks for finding the time to troubleshoot/change my code when you have a bit of time. really appreciated mate.
the code you have only test for a char, not a string...
Notice something here (besides looking for a comma)
strtokIndx = strtok(tempBuffer,","); // get the first bit
strtokIndx = strtok([color=red]tempBuffer[/color],","); // carry on...
...
strtokIndx = strtok([color=red]NULL[/color], ",");
warning: overflow in implicit constant conversion [-Woverflow]
I believe it is better to wait for your proper troubleshoot instead of me guessing here and there, because it seems there is LOADS of issue there In the meanwhile, I will study again that instruction, promised
well read again what the first param of strtok() should be once you've done the initialization. Also, you are searching for commas, do you see a lot of those into your buffer?
I should look for ":" and "/" actually right? Those are the separators for date and time
I will change again the code and understand what param to put in that instruction I am struggling with
I started reading your thread while it was still in the project forum. You are ahead of me with arduinos but I have a suggestion for your goal to post the data in the cloud.
I put together some python code on a RasPi that would read a sensor and post in a google spreadsheet. The access to google spreadsheets was in a project named "gspread". I see there is (or maybe) a version for the Arduino. It might be worth your time to look at it when you get to that point.
Thanks for the note - I'm unsure which project you are talking about
(Also I prefer not using google consumer services for storing data because of their advertising sponsored data collection practice which they then resell. I don't like being the product - I prefer to pay a bit for my own hosting service and domain and keep my privacy and not help them know too much about me - even if it's for storing the temperature of my cellar - of course everyone is free to do what they choose).
ptr = strtok(NULL, anyDelimiters); // will be empty
Serial.print(++i); Serial.print("\t["); Serial.print(ptr); Serial.println("]");
ptr = strtok(NULL, anyDelimiters);// will be empty
Serial.print(++i); Serial.print("\t["); Serial.print(ptr); Serial.println("]");
}
void loop() {
}
then once you understand what happens, consider the function `[url=http://www.cplusplus.com/reference/cstdlib/atoi/]atoi()[/url]`
Thanks I used your code and I understood what is doing (hopefully) It has been very helpful.
OK, let's tidy up the ideas: for what I understood if I need to gather data from a serial device I need to:
build a buffer
parse the data the way I like
Use the parsed data in variables that I can use for my scope.
First insight: Here I have 2 lines, so I should build 2 buffers: inputBuffer1, inputBuffer2 perhaps
Second insight: I am definying the variable for date and time as char...if I use ATOI I can simply save memory and define them as integer
Third insight: in the parse data function I could actually iterate and build an array {hour, min, sec, month, day, year, reading} and use it with the proper index, for example parseddata etc. Right? Anyway, all this "thinking is for AFTER. ATM, here is my new code: ```
*// Code for receiving the data from my analytical scale through RS232 with parsing
// Interface and Objects definitions
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // Creates a LCD LiquidCrystal object
const int chipSelect = 10; // Assigns the pin for the SPI-SD chip selection
const byte bufferSize = 50;
static byte bufferPosition = 0; // Initialises the buffer index
char inputBuffer[bufferSize]; // Array of the data from the scale
char tempBuffer[bufferSize]; // Temporary array for use when parsing
// Variables to hold the parsed data (and initialisation) - the char can become int once I use ATOI
char date_month[2] = {0};
char date_day[2] = {0};
char date_year[2] = {0};
char time_hour[2] = {0};
char time_min[2] = {0};
char time_sec[2] = {0};
float reading = 0.0; // For the samples weight
boolean newData = false; // Our flag
//============
void setup()
{
Serial.begin(9600, SERIAL_7N1); // Includes the scale parameters
pinMode(chipSelect, OUTPUT); // Ensures that the SPI-SD selection pin is an output
lcd.begin(16, 2); // Initialises the interface to the LCD screen
lcd.clear(); // // Clears the LCD screen and positions the cursor in the upper-left corner
if (!SD.begin(chipSelect)) // Checks if the SD card is working
{
lcd.println("SD failed!");
delay(2000);
return;
}
// bufferPosition = 0; // We already initialise it
inputBuffer[0] = '\0'; // Initialises with empty string
}
//============
void loop() {
recvWithEndMarker();
if (newData == true) {
strcpy(tempBuffer, inputBuffer); // Temporary copy to protect the original data
parseData();
saveData();
newData = false; // Resets the flag so the process can start again
}
}
while (Serial.available() > 0 && newData == false) {
receivedData = Serial.read(); // reads the data from the scale
// Now we copy the data into the buffer until we do not find \n:
if (receivedData != endMarker) {
inputBuffer[bufferPosition] = receivedData;
bufferPosition++;
// Let's avoid overflow:
if (bufferPosition >= bufferSize) {
bufferPosition = bufferSize - 1;
}
}
else {
inputBuffer[bufferPosition] = '\0'; // Terminates the string
bufferPosition = 0; // Resets the buffer index
newData = true; // We have new data read now
}
}
}
//============
void parseData() { // split the data into its parts
char * ptr; // this is used by strtok() as a pointer
const char anyDelim[] = " :/"; // Defines the delimiters fpr strtok()
ptr = strtok(tempBuffer, anyDelim); // our 1st token extracted from the buffer
strcpy(time_hour, ptr); // Copies the token to the appropriate variable
ptr = strtok(NULL, anyDelim); // NULL carries on from previous token's end
strcpy(time_min, ptr);
ptr = strtok(NULL, anyDelim);
reading = atof(ptr); // convert this part to a float for the reading cell
}
//============
void saveData()
{
File readings = SD.open("readings.csv", FILE_WRITE); // Opens the file on the SD card
if (readings) // If the file opened OK, write to it on SD card
{
readings.println(inputBuffer); // This is to check the actual buffer
readings.println(tempBuffer); // This is to check the actual temp buffer
readings.print(date_month);
readings.print(',');
readings.print(date_day);
readings.print(',');
readings.print(date_year);
readings.print(',');
readings.print(time_hour);
readings.print(',');
readings.print(time_min);
readings.print(',');
readings.print(time_sec);
readings.print(',');
readings.println(reading);
readings.close(); // Closes the file to save the data on the SD card
} else { // If the file didn't open, print an error
lcd.println("FILE NOT OPEN");
delay(2000);
lcd.clear();
}
}* ``` here is the output:
I cannot see the buffer printed out and also I do not understand why is catching the hour "12", the year "17" and the month "3" and few "0" around.... Hope I am going OK
I think you still don't get that the way you build the buffer is you capture 1 line at a time - and as I tried to depict in the image above, your buffer won't look the same every time you call parseData(). That's a challenge because your parsing function expects both the date and floating point value.
--> your parsing function needs to be smarter. for example you could check if the length of the buffer is < 5 (for example) by using the function strlen() - in which case you can ignore parsing as it's likely not either the time or the value. then you could check if the buffer contains "G OK" (using the strstr() function). if the "G OK" exists, then you know your buffer starts with the floating point and if not you can probably assume it's the time/date.
checking that strtok() does not return a NULL pointer would also help your code be more robust.
last but not least, may be to get started you could ignore the first few input until you got a line with the "G OK" to make sure you are synchronized on date/time/value
I understood the different buffers, but it is getting complicated...that output is not at all what I ecxpected
Trying to improve it:
// Code for receiving the data from my analytical scale through RS232 with parsing
// Libraries
#include <LiquidCrystal.h>
#include <SPI.h>
#include <SD.h>
// Interface and Objects definitions
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // Creates a LCD LiquidCrystal object
const int chipSelect = 10; // Assigns the pin for the SPI-SD chip selection
const byte bufferSize = 50;
static byte bufferPosition = 0; // Initialises the buffer index
char inputBuffer[bufferSize]; // Array of the data from the scale
char tempBuffer[bufferSize]; // Temporary array for use when parsing
// Variables to hold the parsed data (and initialisation) - the char can become int once I use ATOI
char date_month[2] = {0};
char date_day[2] = {0};
char date_year[2] = {0};
char time_hour[2] = {0};
char time_min[2] = {0};
char time_sec[2] = {0};
float reading = 0.0; // For the samples weight
boolean newData = false; // Our flag
//============
void setup()
{
Serial.begin(9600, SERIAL_7N1); // Includes the scale parameters
pinMode(chipSelect, OUTPUT); // Ensures that the SPI-SD selection pin is an output
lcd.begin(16, 2); // Initialises the interface to the LCD screen
lcd.clear(); // // Clears the LCD screen and positions the cursor in the upper-left corner
if (!SD.begin(chipSelect)) // Checks if the SD card is working
{
lcd.println("SD failed!");
delay(2000);
return;
}
// bufferPosition = 0; // We already initialise it
inputBuffer[0] = '\0'; // Initialises with empty string
}
//============
void loop() {
recvWithEndMarker();
if (newData == true) {
strcpy(tempBuffer, inputBuffer); // Temporary copy to protect the original data
parseData();
saveData();
newData = false; // Resets the flag so the process can start again
}
}
//============
void recvWithEndMarker() {
char endMarker = '\n';
char receivedData;
while (Serial.available() > 0 && newData == false) {
receivedData = Serial.read(); // reads the data from the scale
// Now we copy the data into the buffer until we do not find \n:
if (receivedData != endMarker) {
inputBuffer[bufferPosition] = receivedData;
bufferPosition++;
// Let's avoid overflow:
if (bufferPosition >= bufferSize) {
bufferPosition = bufferSize - 1;
}
}
else {
inputBuffer[bufferPosition] = '\0'; // Terminates the string
bufferPosition = 0; // Resets the buffer index
newData = true; // We have new data read now
}
}
}
//============
void parseData() { // split the data into its parts
char * ptr; // this is used by strtok() as a pointer
const char anyDelim[] = " :/"; // Defines the delimiters fpr strtok()
int sizeBuffer = strlen (tempBuffer);
if (sizeBuffer > 5) {
ptr = strtok(tempBuffer, anyDelim); // our 1st token extracted from the buffer
strcpy(time_hour, ptr); // Copies the token to the appropriate variable
ptr = strtok(NULL, anyDelim); // NULL carries on from previous token's end
strcpy(time_min, ptr);
ptr = strtok(NULL, anyDelim);
strcpy(time_sec, ptr);
ptr = strtok(NULL, anyDelim);
strcpy(date_month, ptr);
ptr = strtok(NULL, anyDelim);
strcpy(date_day, ptr);
ptr = strtok(NULL, anyDelim);
strcpy(date_year, ptr);
}
else {
ptr = strtok(tempBuffer, anyDelim);
reading = atof(ptr); // convert this part to a float for the reading cell
}
}
//============
void saveData()
{
File readings = SD.open("readings.csv", FILE_WRITE); // Opens the file on the SD card
if (readings) // If the file opened OK, write to it on SD card
{
readings.println(inputBuffer); // This is to check the actual buffer
readings.println(tempBuffer); // This is to check the actual temp buffer
readings.print(date_month);
readings.print(',');
readings.print(date_day);
readings.print(',');
readings.print(date_year);
readings.print(',');
readings.print(time_hour);
readings.print(',');
readings.print(time_min);
readings.print(',');
readings.print(time_sec);
readings.print(',');
readings.println(reading);
readings.close(); // Closes the file to save the data on the SD card
} else { // If the file didn't open, print an error
lcd.println("FILE NOT OPEN");
delay(2000);
lcd.clear();
}
}
I got that, that's why in the following code (not posted below) I put > 15 but same output
Now I put the condition re the presence or not of "OK". So if we do not have "OK" (buffDevid is NULL), it is the date/time and parse the way I did, if we do, then just consider the buffer with the floating point reading....
// Code for receiving the data from my analytical scale through RS232 with parsing
// Libraries
#include <LiquidCrystal.h>
#include <SPI.h>
#include <SD.h>
// Interface and Objects definitions
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // Creates a LCD LiquidCrystal object
const int chipSelect = 10; // Assigns the pin for the SPI-SD chip selection
const byte bufferSize = 50;
static byte bufferPosition = 0; // Initialises the buffer index
char inputBuffer[bufferSize]; // Array of the data from the scale
char tempBuffer[bufferSize]; // Temporary array for use when parsing
// Variables to hold the parsed data (and initialisation) - the char can become int once I use ATOI
char date_month[2] = {0};
char date_day[2] = {0};
char date_year[2] = {0};
char time_hour[2] = {0};
char time_min[2] = {0};
char time_sec[2] = {0};
float reading = 0.0; // For the samples weight
boolean newData = false; // Our flag
//============
void setup()
{
Serial.begin(9600, SERIAL_7N1); // Includes the scale parameters
pinMode(chipSelect, OUTPUT); // Ensures that the SPI-SD selection pin is an output
lcd.begin(16, 2); // Initialises the interface to the LCD screen
lcd.clear(); // // Clears the LCD screen and positions the cursor in the upper-left corner
if (!SD.begin(chipSelect)) // Checks if the SD card is working
{
lcd.println("SD failed!");
delay(2000);
return;
}
// bufferPosition = 0; // We already initialise it
inputBuffer[0] = '\0'; // Initialises with empty string
}
//============
void loop() {
recvWithEndMarker();
if (newData == true) {
strcpy(tempBuffer, inputBuffer); // Temporary copy to protect the original data
parseData();
saveData();
newData = false; // Resets the flag so the process can start again
}
}
//============
void recvWithEndMarker() {
char endMarker = '\n';
char receivedData;
while (Serial.available() > 0 && newData == false) {
receivedData = Serial.read(); // reads the data from the scale
// Now we copy the data into the buffer until we do not find \n:
if (receivedData != endMarker) {
inputBuffer[bufferPosition] = receivedData;
bufferPosition++;
// Let's avoid overflow:
if (bufferPosition >= bufferSize) {
bufferPosition = bufferSize - 1;
}
}
else {
inputBuffer[bufferPosition] = '\0'; // Terminates the string
bufferPosition = 0; // Resets the buffer index
newData = true; // We have new data read now
}
}
}
//============
void parseData() { // split the data into its parts
char * ptr; // this is used by strtok() as a pointer
const char anyDelim[] = " :/"; // Defines the delimiters fpr strtok()
char * bufDivider;
bufDivider = strstr (tempBuffer, "OK"); // Checks if the string "OK" is in the buffer
if (bufDivider == NULL) { // If not, then it is the date/time buffer...
ptr = strtok(tempBuffer, anyDelim); // our 1st token extracted from the buffer
strcpy(time_hour, ptr); // Copies the token to the appropriate variable
ptr = strtok(NULL, anyDelim); // NULL carries on from previous token's end
strcpy(time_min, ptr);
ptr = strtok(NULL, anyDelim);
strcpy(time_sec, ptr);
ptr = strtok(NULL, anyDelim);
strcpy(date_month, ptr);
ptr = strtok(NULL, anyDelim);
strcpy(date_day, ptr);
ptr = strtok(NULL, anyDelim);
strcpy(date_year, ptr);
}
else { // otherwise, it is the samples weight buffer
ptr = strtok(tempBuffer, anyDelim);
reading = atof(ptr); // convert this part to a float for the reading cell
}
}
//============
void saveData()
{
File readings = SD.open("readings.csv", FILE_WRITE); // Opens the file on the SD card
if (readings) // If the file opened OK, write to it on SD card
{
readings.println(inputBuffer); // This is to check the actual buffer
readings.println(tempBuffer); // This is to check the actual temp buffer
readings.print(date_month);
readings.print(',');
readings.print(date_day);
readings.print(',');
readings.print(date_year);
readings.print(',');
readings.print(time_hour);
readings.print(',');
readings.print(time_min);
readings.print(',');
readings.print(time_sec);
readings.print(',');
readings.println(reading);
readings.close(); // Closes the file to save the data on the SD card
} else { // If the file didn't open, print an error
lcd.println("FILE NOT OPEN");
delay(2000);
lcd.clear();
}
}
here is another piece of code to run (with console at 115200) and see the output. then go read the code and try to understand how it works (it is what I explained above)
(hopefully that works, just typed it in)
char tmpBuffer1[] = "17:35:52 03/21/17\r";
char tmpBuffer2[] = "15.0091 G OK\r";
char tmpBuffer3[] = "\r";
const char anyDelimiters[] = " :/";
void parseTime(char * buffer)
{
int i = 0;
byte h, m, s, M, D, Y;
char * ptr;
ptr = strtok(buffer, anyDelimiters);
if (ptr) {
h = atoi(ptr);
Serial.print(++i); Serial.print("\t["); Serial.print(h); Serial.println("]");
}
ptr = strtok(NULL, anyDelimiters);
if (ptr) {
m = atoi(ptr);
Serial.print(++i); Serial.print("\t["); Serial.print(m); Serial.println("]");
}
ptr = strtok(NULL, anyDelimiters);
if (ptr) {
s = atoi(ptr);
Serial.print(++i); Serial.print("\t["); Serial.print(s); Serial.println("]");
}
ptr = strtok(NULL, anyDelimiters);
if (ptr) {
M = atoi(ptr);
Serial.print(++i); Serial.print("\t["); Serial.print(M); Serial.println("]");
}
ptr = strtok(NULL, anyDelimiters);
if (ptr) {
D = atoi(ptr);
Serial.print(++i); Serial.print("\t["); Serial.print(D); Serial.println("]");
}
ptr = strtok(NULL, anyDelimiters);
if (ptr) {
Y = atoi(ptr);
Serial.print(++i); Serial.print("\t["); Serial.print(Y); Serial.println("]");
}
}
void parseVal(char * buffer)
{
double v = strtod(buffer, NULL); // see http://www.atmel.com/webdoc/avrlibcreferencemanual/group__avr__stdlib_1ga5ee4d110a3bb55d2eadda05e3ebedf8a.html
Serial.print("Value="); Serial.print("\t["); Serial.print(v, 5); Serial.println("]");
}
void scanBufferType(char * buffer)
{
Serial.print("\n---------------------\nAnalysing Buffer["); Serial.print(buffer); Serial.println("]\n---------------------");
if (strlen(buffer) < 5) {
Serial.println("Not a meaningful entry");
} else if (strstr(buffer, "G OK")) { // see http://www.cplusplus.com/reference/cstring/strstr/
Serial.println("it's a value");
parseVal(buffer);
} else {
Serial.println("it's a time");
parseTime(buffer);
}
}
void setup() {
Serial.begin(115200);
scanBufferType(tmpBuffer1);
scanBufferType(tmpBuffer2);
scanBufferType(tmpBuffer3);
}
void loop() {}
I understood and appreciated all your teaching..this is my code (I adapted from yours):
// Code for receiving the data from my analytical scale through RS232 with parsing
// Libraries
#include <LiquidCrystal.h>
#include <SPI.h>
#include <SD.h>
// Interface and Objects definitions
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // Creates a LCD LiquidCrystal object
const int chipSelect = 10; // Assigns the pin for the SPI-SD chip selection
const byte bufferSize = 50;
static byte bufferPosition = 0; // Initialises the buffer index
char inputBuffer[bufferSize]; // Array of the data from the scale
char tempBuffer[bufferSize]; // Temporary array for use when parsing
const char anyDelimiters[] = " :/";
boolean newData = false; // Our flag
byte D, M, Y, h, m, s; // Defines the variable for date/time
double reading; // Defines the variable for the weight reading
//============
void setup()
{
Serial.begin(9600, SERIAL_7N1); // Includes the scale parameters
pinMode(chipSelect, OUTPUT); // Ensures that the SPI-SD selection pin is an output
lcd.begin(16, 2); // Initialises the interface to the LCD screen
lcd.clear(); // // Clears the LCD screen and positions the cursor in the upper-left corner
if (!SD.begin(chipSelect)) // Checks if the SD card is working
{
lcd.println("SD failed!");
delay(2000);
return;
}
inputBuffer[0] = '\0'; // Initialises with empty string
}
//============
void loop() {
recvWithEndMarker();
if (newData == true) {
strcpy(tempBuffer, inputBuffer); // Temporary copy to protect the original data
scanBufferType(tempBuffer);
saveData();
newData = false; // Resets the flag so the process can start again
}
}
//============
void recvWithEndMarker() {
char endMarker = '\n';
char receivedData;
while (Serial.available() > 0 && newData == false) {
receivedData = Serial.read(); // reads the data from the scale
// Now we copy the data into the buffer until we do not find \n:
if (receivedData != endMarker) {
inputBuffer[bufferPosition] = receivedData;
bufferPosition++;
// Let's avoid overflow:
if (bufferPosition >= bufferSize) {
bufferPosition = bufferSize - 1;
}
}
else {
inputBuffer[bufferPosition] = '\0'; // Terminates the string
bufferPosition = 0; // Resets the buffer index
newData = true; // We have new data read now
}
}
}
//============
void scanBufferType(char * buffer)
{
if (strlen(buffer) < 5) {
return;
} else if (strstr(buffer, "G OK")) {
parseVal(buffer);
} else {
parseDateTime(buffer);
}
}
//============
void parseDateTime(char * buffer)
{
int i = 0;
byte h, m, s, M, D, Y;
char * ptr;
ptr = strtok(buffer, anyDelimiters);
if (ptr) {
h = atoi(ptr);
}
ptr = strtok(NULL, anyDelimiters);
if (ptr) {
m = atoi(ptr);
}
ptr = strtok(NULL, anyDelimiters);
if (ptr) {
s = atoi(ptr);
}
ptr = strtok(NULL, anyDelimiters);
if (ptr) {
M = atoi(ptr);
}
ptr = strtok(NULL, anyDelimiters);
if (ptr) {
D = atoi(ptr);
}
ptr = strtok(NULL, anyDelimiters);
if (ptr) {
Y = atoi(ptr);
}
}
//============
void parseVal(char * buffer)
{
double v = strtod(buffer, NULL);
}
//============
void saveData()
{
File readings = SD.open("readings.csv", FILE_WRITE); // Opens the file on the SD card
if (readings) // If the file opened OK, write to it on SD card
{
readings.println(inputBuffer); // This is to check the actual buffer
readings.println(tempBuffer); // This is to check the actual temp buffer
readings.print(D);
readings.print(',');
readings.print(M);
readings.print(',');
readings.print(Y);
readings.print(',');
readings.print(h);
readings.print(',');
readings.print(m);
readings.print(',');
readings.print(s);
readings.print(',');
readings.println(reading);
readings.close(); // Closes the file to save the data on the SD card
} else { // If the file didn't open, print an error
lcd.println("FILE NOT OPEN");
delay(2000);
lcd.clear();
}
}
You have these as global and local to the parsing functions so global variables are never set (or not the same variable for the weight)
byte D, M, Y, h, m, s; // Defines the variable for date/time
double reading; // Defines the variable for the weight reading
and saveData() again writes everything every time whereas you are receiving time and weight separately.. you need to call saveData() only after you have received the sentence with "G OK". this way you know you've read a time before and a value.
You have these as global and local to the parsing functions so global variables are never set (or not the same variable for the weight)
"Local variables are not known to functions outside their own" that's why they are all "0" right?
J-M-L:
byte D, M, Y, h, m, s; // Defines the variable for date/time
double reading; // Defines the variable for the weight reading
and `saveData()` again writes everything every time whereas you are receiving time and weight separately.. you need to call `saveData()` only after you have received the sentence with "G OK". this way you know you've read a time before and a value.
So I should call that function straight after the parsing:
You need to "CALL SAVEDATA" only once which is after reading the weight (ie when you have received the "G OK" after parsing the weight), you know that when you get there you had received first the time in the previous buffer and now the weight, so you are good to go for printing out everything.
Yes for variable scope; so don't re-declare them in the parsing functions, just use the globals