Go Down

Topic: Reading DS1307 RTC after sleeping (Read 1 time) previous topic - next topic

Eheran

I updated the code, replaced the big string with the buffer and im also using the 2nd char, byte 177 (tho its false but thats what arduino reads right after wakeup with clock initialization), to start mark the new linke eg. add the datestring.
But I run into problems while compiling:
Code: [Select]
read-rs232-log-13:29: error: 'buffer' does not name a type

 buffer[0] = 0; // terminating null byte

 ^

C:\Users\Leo\Documents\Arduino\read-rs232-log-13\read-rs232-log-13.ino: In function 'void recvoneChar()':

read-rs232-log-13:143: error: cannot convert 'String' to 'const char*' for argument '2' to 'char* strncat(char*, const char*, size_t)'

       strncat(buffer, datestring, 25); //Output would be "buffer" combined with "This is the string to add"

                                     ^

exit status 1
'buffer' does not name a type


Isnt "buffer" defined as "char"?
New code:
Code: [Select]
#include <Wire.h>
#include <Time.h>
#include <TimeLib.h>
#include <DS1307RTC.h>

#include <SdFat.h>
#include <SPI.h>
#include <LowPower.h>
const int chipSelect = 10;
SdFat SD;
int val = 0;

const int dPin = 2; // interrupt 0


String inputString = "";         // a string to hold incoming data
String datestring = "";          // strong for date assembly
boolean stringComplete = false;  // whether the string is complete
bool fertig = 1;
int warten = 0;
bool linefeed = 0;
bool an = 1;
int num;

char inChar;
boolean newData = false;

char buffer[350];
buffer[0] = 0; // terminating null byte

bool plusminus = 0;



void setup()  {
  Serial.begin(9600);

  //  inputString.reserve(312);         // reserve 312 bytes for the inputString
  datestring.reserve(32);
  delay(250);

  pinMode(5, OUTPUT);         //power to SD
  digitalWrite(5, LOW);
  pinMode(dPin, INPUT);       //interruptpin
  pinMode(8, OUTPUT);         //power for RTC
  digitalWrite(8, HIGH);
  pinMode(9, OUTPUT);
  digitalWrite(9, LOW);
  Serial.println("an");
  Serial.flush();

}

void loop() {
  //  recvoneChar();


  if (an) {         //on first start up sleep and wait for signal
    attachInterrupt(0, interrupt, CHANGE);
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
    detachInterrupt(0);
    an = 0;
  }

  if ((millis() - warten) > 50) {    //dont sleep while the data comes in
    val++;
    if (val == 10) {    //count 10x data for lower SD-card access -> lower power consumption
      stringComplete = true;
      val = 0;
    }
    if (stringComplete) {   //print the 10 records to the SD-card
      digitalWrite(5, HIGH);
      if (!SD.begin(chipSelect)) {                            // see if the card is present and can be initialized:
        Serial.println("Card failed or not present");
        delay(50);
        return;
      }
      File dataFile = SD.open("log.txt", FILE_WRITE);
      dataFile.print(buffer);
      dataFile.close();
      //      Serial.println();
      Serial.print(buffer);
      //      Serial.println();
      Serial.flush();
      inputString = "";                  // clear the string:
      stringComplete = false;
      digitalWrite(5, LOW);
    }


    //    Serial.println(",  sl");  //debug to see what happens when
    //    Serial.flush();
    digitalWrite(9, HIGH);
    attachInterrupt(0, interrupt, LOW);
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
    detachInterrupt(0);
    digitalWrite(9, LOW);
    warten = millis();
    //    Serial.print("wk  ,");
    linefeed = 0;
    num = 0;
    plusminus = 0;
  }


}


void recvoneChar() {


  while (Serial.available()) {
    inChar = Serial.read();
    num++;

    tmElements_t tm;
    if (RTC.read(tm)) {
      datestring = String(tmYearToCalendar(tm.Year)) + "." + String(tm.Month) + "." + String(tm.Day) + " " + String(tm.Hour) + ":" + String(tm.Minute) + ":" + String(tm.Second);
      //      Serial.print(datestring);
    }    else {
      if (RTC.chipPresent()) {  //this never shows up, so the I2C itself failed
        Serial.println(F("The DS1307 is stopped.  Please run the SetTime"));
        Serial.println(F("example to initialize the time and begin running."));
        Serial.println();
      } else {
        Serial.println(F("DS1307 read error!  Please check the circuitry."));
        Serial.println();
      }
      delay(2000);
    }

    int l = strlen(buffer);   //defines the lenght of the string(?!) to be l, eg. add one char
    buffer[l++] = inChar;          //Counts up l position in "buffer" and puts "c" into this position, I would put my "inChar" here
    //    buffer[l] = 0;             // terminating null byte, but why fixed at position 1?
    if ( (byte) inChar == 177) {
      plusminus = 1;
      buffer[l++] = '\r';
      buffer[l++] = '\n';
      strncat(buffer, datestring, 25); //Output would be "buffer" combined with a max of 25 chars of "datestring"
      buffer[l++] = ',';
    }
    if (plusminus) {
      buffer[l++] = inChar;          //Counts up l position in "buffer" and puts "c" into this position, I would put my "inChar" here
      buffer[l] = 0;             // terminating null byte
    }

    Serial.println(inChar);
  }
}



void interrupt() {
}



For the wake-up glitch: I changed the code a little, so there is only one sleep that can only happen after at least 50ms passed since wake-up. The glitch is a little different that way, its wake up after 1,5ms of signals and is up for 1,75ms. Then back to sleep and back up etc.

Code: [Select]
  if ((millis() - warten) > 50) {    //dont sleep while the data comes in
[blabla other code]
    digitalWrite(9, HIGH);
    attachInterrupt(0, interrupt, LOW);  //sleep after printing it and/or the buffer of 10 is not full yet
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
    detachInterrupt(0);
    digitalWrite(9, LOW);
    warten = millis();
}

152: Still working, no bug
153: zoomed in on the working part
155: glitched part
154: zoomed in on the glitched part

pylon

Quote
Isnt "buffer" defined as "char"?
Yes, buffer is, but datestring is still a String object and the C function don't know how to handle C++ objects.

The last parameter of strcat() is the size of the buffer in the first parameter!

To get that string formatted easily you should take a look at the snprintf(). To print directly to your result string without wasting memory you can use pointer arithmetic:

Code: [Select]

  uint16_t len = strlen(buffer);
  snprintf(buffer + len, 350 - len, "myformat is %d", decimal_var);


Quote
For the wake-up glitch: I changed the code a little, so there is only one sleep that can only happen after at least 50ms passed since wake-up. The glitch is a little different that way, its wake up after 1,5ms of signals and is up for 1,75ms. Then back to sleep and back up etc.
My guess is that you ran out of memory the "an" variable got overwritten (or "warten" if you removed that part) so it didn't react like you would with enough memory.

After writing "buffer" to the file you should reset it to the empty string:

Code: [Select]

buffer[0] = 0;


And remove all usages of the String class.

Eheran

In post #5 I did measure the free RAM and printed it. It didnt change and was about 500byte.


Quote
To get that string formatted easily you should take a look at the snprintf(). To print directly to your result string without wasting memory you can use pointer arithmetic:
Im simply unable to follow you at this point and am unable to use pointer arithmetic or buffers so far.
Code: [Select]
uint16_t len = strlen(buffer);
snprintf(buffer + len, 350 - len, "myformat is %d", decimal_var);

"len" gives the current lenght of "buffer".
In ur link a integer is set to be the result of snprinf instead of that beeing on its own?
Where do I even put these 2 lines, how do I use them, for what?
Please try to explain the code in a few words.



And im still stuck at the error:
Code: [Select]

read-rs232-log-13:29: error: 'buffer' does not name a type

 buffer[0] = 0; // terminating null byte

 ^

PaulS

Code: [Select]
[blabla other code]
When you post ALL of your code, then we can help.
The art of getting good answers lies in asking good questions.

pylon

And im still stuck at the error:
Code: [Select]

read-rs232-log-13:29: error: 'buffer' does not name a type

 buffer[0] = 0; // terminating null byte

 ^

Move that line

Code: [Select]
buffer[0] = 0; // terminating null byte

inside the setup routine. Although your code is correct as you wrote it the Arduino IDE does some magic before handing over to the compiler and that magic is not compatible with what you had.

Quote
In ur link a integer is set to be the result of snprinf instead of that beeing on its own?
Where do I even put these 2 lines, how do I use them, for what?
Please try to explain the code in a few words.
Yes the snprintf() function returns an integer but in this case you don't need it so you don't have to assign it to a variable.

These two lines cannot be inserted verbosely in your code, I posted them to show you how to add a (C) string with snprintf() to the end of an existing string without allocating a second buffer just for the snprintf() call.
The first parameter to snprintf() is a character pointer pointing to the start of your character array aka C string. We add the length of the current string to the porinter pointing to the start of the buffer. The result of this calculation points to the end of the current string. So the resulting string from snprintf is appended to the end of your current string using no other temporary buffer.
Please read the linked manual page for snprintf(). You can then replace your String object addition line:

Code: [Select]
      datestring = String(tmYearToCalendar(tm.Year)) + "." + String(tm.Month) + "." + String(tm.Day) + " " + String(tm.Hour) + ":" + String(tm.Minute) + ":" + String(tm.Second);


which is just a waste of memory.

Quote
In post #5 I did measure the free RAM and printed it. It didnt change and was about 500byte.
You did that in one point in your code. But you allocate some variables in routines that are hold locally and other constructs and libraries may also need temporary memory. You can do a lot with 512 bytes but the way you are wasting memory in the rest of your code it won't last long for you.


Eheran

This is the code including my trys to get the buffer working. Not compiling.

Code: [Select]
#include <Wire.h>
#include <Time.h>
#include <TimeLib.h>
#include <DS1307RTC.h>

#include <SdFat.h>
#include <SPI.h>
#include <LowPower.h>
const int chipSelect = 10;
SdFat SD;
int val = 0;

const int dPin = 2; // interrupt 0


String inputString = "";         // a string to hold incoming data
String datestring = "";          // strong for date assembly
boolean stringComplete = false;  // whether the string is complete
bool an = 1;                     //marker for first startup

// a few markers (un)used to signal when the new temp. reading is complete
bool fertig = 1;
int warten = 0;
bool linefeed = 0;
int num;
char inChar;
boolean newData = false;
bool plusminus = 0;


char buffer[350];
uint16_t len = strlen(buffer);
snprintf(buffer + len, 350 - len, "myformat is %d", decimal_var);




void setup()  {
  Serial.begin(9600);

  //inputString.reserve(312);         //replaced by buffer - reserve 312 bytes for the inputString
  buffer[0] = 0; // terminating null byte
  datestring.reserve(32);
  delay(250);

  pinMode(5, OUTPUT);         //power to SD
  digitalWrite(5, LOW);
  pinMode(dPin, INPUT);       //interruptpin
  pinMode(8, OUTPUT);         //power for RTC
  digitalWrite(8, HIGH);
  pinMode(9, OUTPUT);         //debug pin sleep
  digitalWrite(9, LOW);
  Serial.println("an");
  Serial.flush();

}

void loop() {
  //  recvoneChar();


  if (an) {         //on first start up sleep and wait for signal
    attachInterrupt(0, interrupt, CHANGE);
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
    detachInterrupt(0);
    an = 0;
  }

  if ((millis() - warten) > 50) {    //dont sleep while data comes in
    val++;
    if (val == 10) {    //count 10x data for lower SD-card access -> lower power consumption
      stringComplete = true;
      val = 0;
    }
    if (stringComplete) {   //print the 10 records to the SD-card
      digitalWrite(5, HIGH);    //power SD-card (MOSFET)
      if (!SD.begin(chipSelect)) {                            // see if the card is present and can be initialized:
        Serial.println("Card failed or not present");
        delay(50);
        return;
      }
      File dataFile = SD.open("log.txt", FILE_WRITE);
        dataFile.print(buffer);
      dataFile.close();
      Serial.print(buffer);
      Serial.flush();
      buffer[0] = 0;
      inputString = "";                  // clear the string:
      stringComplete = false;
      digitalWrite(5, LOW);
    }


    //    Serial.println(",  sl");  //debug
    //    Serial.flush();
    digitalWrite(9, HIGH);     //debug
    attachInterrupt(0, interrupt, LOW);
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
    detachInterrupt(0);
    digitalWrite(9, LOW);    //debug
    warten = millis();
    //    Serial.print("wk  ,");  //debug
    linefeed = 0;
    num = 0;
    plusminus = 0;
  }


}


void recvoneChar() {


  while (Serial.available()) {
    inChar = Serial.read();
    num++;

    tmElements_t tm;
    if (RTC.read(tm)) {
      datestring = String(tmYearToCalendar(tm.Year)) + "." + String(tm.Month) + "." + String(tm.Day) + " " + String(tm.Hour) + ":" + String(tm.Minute) + ":" + String(tm.Second);
    }    else {
      if (RTC.chipPresent()) {  //this never shows up, so the I2C itself failed
        Serial.println(F("The DS1307 is stopped.  Please run the SetTime"));
        Serial.println(F("example to initialize the time and begin running."));
        Serial.println();
      } else {
        Serial.println(F("DS1307 read error!  Please check the circuitry."));
        Serial.println();
      }
      delay(2000);
    }

    int l = strlen(buffer);        //defines the lenght of the string(?!) to be l, eg. add one char
    buffer[l++] = inChar;          //Counts up one position in "buffer" and puts the inChar into this position
    //    buffer[l] = 0;           // terminating null byte, but why fixed at position 1?
    if ( (byte) inChar == 177) {
      plusminus = 1;      //this is the false (due to wakeup) symbol, but its consistent, so its used to toggle new data
      buffer[l++] = '\r';
      buffer[l++] = '\n';
      strncat(buffer, datestring, 350); //Output would be "buffer" combined with "datestring", max lenght 350
      buffer[l++] = ',';
    }
    if (plusminus) {            //new data is coming in, now just put it into the buffer
      buffer[l++] = inChar;     //Counts up l position in "buffer" and puts the inChar into this position
      buffer[l] = 0;            // terminating null byte
    }

    Serial.println(inChar);     //debug print to serial
  }
}



void interrupt() {
}

Code: [Select]
read-rs232-log-13a:33: error: expected constructor, destructor, or type conversion before '(' token

 snprintf(buffer + len, 350 - len, "myformat is %d", decimal_var);

         ^

C:\Users\Leo\Documents\Arduino\read-rs232-log-13a\read-rs232-log-13a.ino: In function 'void recvoneChar()':

read-rs232-log-13a:141: error: cannot convert 'String' to 'const char*' for argument '2' to 'char* strncat(char*, const char*, size_t)'

       strncat(buffer, datestring, 350); //Output would be "buffer" combined with "datestring", max lenght 350

                                      ^

exit status 1
expected constructor, destructor, or type conversion before '(' token

Eheran

And this is working code (for >48h or >1 million chars to collect).
The main difference is the sleep mode "idle" with USART still active instead of "power.down".
The differences in "void serialEvent()" are due to the differece in the incoming data (its beeing false at the first interrupt out of power.down). And of course me trying to use buffers now too, but the string would have been identical otherwise.

Code: [Select]
#include <Wire.h>
#include <Time.h>
#include <TimeLib.h>
#include <DS1307RTC.h>

#include <SdFat.h>
#include <SPI.h>
#include <LowPower.h>
const int chipSelect = 10;
SdFat SD;
int val = 0;

const int dPin = 2; // interrupt 0


String inputString = "";         // a string to hold incoming data
String datestring = "";          // strong for date assembly
boolean stringComplete = false;  // whether the string is complete
bool fertig = 1;
int warten = 0;
bool linefeed = 0;
bool an = 1;
int num;

char inChar;
boolean newData = false;


void setup()  {
  Serial.begin(9600);

  inputString.reserve(312);         // reserve 312 bytes for the inputString
  datestring.reserve(32);
  delay(250);

  pinMode(5, OUTPUT);         //power to SD
  digitalWrite(5, LOW);
  pinMode(dPin, INPUT);       //interruptpin
  pinMode(8, OUTPUT);         //power for RTC
  digitalWrite(8, HIGH);
  pinMode(9, OUTPUT);
  digitalWrite(9, LOW);
  Serial.println("an");
  Serial.flush();

}

void loop() {
  //  recvoneChar();


  if (an) {         //on first start up sleep and wait for signal
    attachInterrupt(0, interrupt, CHANGE);
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
    detachInterrupt(0);
    an = 0;
  }

  if ((millis() - warten) > 50) {    //dont sleep while the data comes in
    //    val++;
    //    if (val == 10) {    //count 10x data for lower SD-card access -> lower power consumption
    //      stringComplete = true;
    //      val = 0;
    //    }
    if (stringComplete) {   //print the 10 records to the SD-card
      digitalWrite(5, HIGH);
      if (!SD.begin(chipSelect)) {                            // see if the card is present and can be initialized:
        Serial.println("Card failed or not present");
        delay(50);
        return;
      }
      File dataFile = SD.open("log.txt", FILE_WRITE);
      dataFile.print(inputString);
      dataFile.close();
      //      Serial.println();
      Serial.print(inputString);
      //      Serial.println();
      Serial.flush();
      inputString = "";                  // clear the string:
      stringComplete = false;
      digitalWrite(5, LOW);
    }


    //    Serial.println(",  sl");  //debug to see what happens when
    //    Serial.flush();
    digitalWrite(9, HIGH);
    //   attachInterrupt(0, interrupt, LOW);  //sleep after printing it and/or the buffer of 10 is not full yet
    //  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
    LowPower.idle(SLEEP_FOREVER, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF,  //timer0 für millis()
                  SPI_OFF, USART0_ON, TWI_OFF);
    //    detachInterrupt(0);
    digitalWrite(9, LOW);

    warten = millis();
    //    Serial.print("wk  ,");
    linefeed = 0;
    num = 0;

  }


}


void serialEvent() {
  while (Serial.available()) {
    char inChar = (char)Serial.read();       // get the new byte:

    tmElements_t tm;
    if (RTC.read(tm)) {
      datestring = String(tmYearToCalendar(tm.Year)) + "." + String(tm.Month) + "." + String(tm.Day) + " " + String(tm.Hour) + ":" + String(tm.Minute) + ":" + String(tm.Second);
      //      Serial.print(datestring);
    }
    else {
      if (RTC.chipPresent()) {  //this never shows up, so the I2C itself failed
        Serial.println("The DS1307 is stopped.  Please run the SetTime");
        Serial.println("example to initialize the time and begin running.");
        Serial.println();
      } else {
        Serial.println("DS1307 read error!  Please check the circuitry.");
        Serial.println();
      }
      delay(2000);
    }

    if (inChar == 'C') {                    // if the incoming character is a newline, set a flag
      inputString += datestring;                   // add timestamp
      inputString += ",";                   // add timestamp
    }
    inputString += inChar;                   // add it to the inputString:


    if (inChar == '\n') {                    // if the incoming character is a newline, set a flag
      val++;
    }
    if (val == 10) {
      stringComplete = true;                 // so the main loop can do something about it:
      val = 0;
    }
    Serial.println(inChar);
  }
}
void interrupt() {
}

pylon

You cannot copy example code, paste it at a random location in your code and expect it to compile. You have to understand what the example code does, adapt it to your sketch and insert it at the right location.

I fixed the first code for you. I expect you that read it and try to understand what it does (use the linked manual page above).

Code: [Select]
#include <Wire.h>
#include <DS1307RTC.h>

#include <SdFat.h>
#include <SPI.h>
#include <LowPower.h>
const int chipSelect = 10;
SdFat SD;
int val = 0;

const int dPin = 2; // interrupt 0


boolean stringComplete = false;  // whether the string is complete
bool an = 1;                     //marker for first startup

// a few markers (un)used to signal when the new temp. reading is complete
bool fertig = 1;
int warten = 0;
bool linefeed = 0;
int num;
char inChar;
boolean newData = false;
bool plusminus = 0;


char buffer[350];




void setup()  {
  Serial.begin(9600);

  buffer[0] = 0; // terminating null byte
  delay(250);

  pinMode(5, OUTPUT);         //power to SD
  digitalWrite(5, LOW);
  pinMode(dPin, INPUT);       //interruptpin
  pinMode(8, OUTPUT);         //power for RTC
  digitalWrite(8, HIGH);
  pinMode(9, OUTPUT);         //debug pin sleep
  digitalWrite(9, LOW);
  Serial.println("an");
  Serial.flush();

}

void loop() {
  //  recvoneChar();


  if (an) {         //on first start up sleep and wait for signal
    attachInterrupt(0, interrupt, CHANGE);
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
    detachInterrupt(0);
    an = 0;
  }

  if ((millis() - warten) > 50) {    //dont sleep while data comes in
    val++;
    if (val == 10) {    //count 10x data for lower SD-card access -> lower power consumption
      stringComplete = true;
      val = 0;
    }
    if (stringComplete) {   //print the 10 records to the SD-card
      digitalWrite(5, HIGH);    //power SD-card (MOSFET)
      if (!SD.begin(chipSelect)) {                            // see if the card is present and can be initialized:
        Serial.println("Card failed or not present");
        delay(50);
        return;
      }
      File dataFile = SD.open("log.txt", FILE_WRITE);
      dataFile.print(buffer);
      dataFile.close();
      Serial.print(buffer);
      Serial.flush();
      buffer[0] = 0; // clear the string
      stringComplete = false;
      digitalWrite(5, LOW);
    }


    //    Serial.println(",  sl");  //debug
    //    Serial.flush();
    digitalWrite(9, HIGH);     //debug
    attachInterrupt(0, interrupt, LOW);
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
    detachInterrupt(0);
    digitalWrite(9, LOW);    //debug
    warten = millis();
    //    Serial.print("wk  ,");  //debug
    linefeed = 0;
    num = 0;
    plusminus = 0;
  }


}


void recvoneChar() {


  while (Serial.available()) {
    inChar = Serial.read();
    num++;

    tmElements_t tm;
    if (! RTC.read(tm)) {
      if (RTC.chipPresent()) {  //this never shows up, so the I2C itself failed
        Serial.println(F("The DS1307 is stopped.  Please run the SetTime"));
        Serial.println(F("example to initialize the time and begin running."));
        Serial.println();
      } else {
        Serial.println(F("DS1307 read error!  Please check the circuitry."));
        Serial.println();
      }
      delay(2000);
    }

    int l = strlen(buffer);        //defines the lenght of the string(?!) to be l, eg. add one char
    buffer[l++] = inChar;          //Counts up one position in "buffer" and puts the inChar into this position
    buffer[l] = 0;
    //    buffer[l] = 0;           // terminating null byte, but why fixed at position 1?
    if ( (byte) inChar == 177) {
      plusminus = 1;      //this is the false (due to wakeup) symbol, but its consistent, so its used to toggle new data
      buffer[l++] = '\r';
      buffer[l++] = '\n';
      l += snprintf(buffer + l, 350 - l, "%d.%d.%d %d:%d:%d", tmYearToCalendar(tm.Year), tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second);
      buffer[l++] = ',';
      buffer[l] = 0;
    }
    if (plusminus) {            //new data is coming in, now just put it into the buffer
      buffer[l++] = inChar;     //Counts up l position in "buffer" and puts the inChar into this position
      buffer[l] = 0;            // terminating null byte
    }

    Serial.println(inChar);     //debug print to serial
  }
}



void interrupt() {
}



Quote
The main difference is the sleep mode "idle" with USART still active instead of "power.down".
In sleep mode "powerDown" the UART hardware is not enabled so you cannot receive any information from there. If that is key to your application you must change the sleep mode (p.e. to 'idle') to let the Arduino wake up if the serial interface gets active.

Eheran

I had some time to test it now.
After adding <Time.h> and <TimeLib.h> to your code and uncommenting "recvoneChar();"  I was able to get it working. After about 30s it stops working. Here is the output when failing:
Code: [Select]
h
±
2
2
.
6
6
7
4
h
±
2
2
.
6
5
8
9
h
±
2
2
.
6
4
9
2

A
A
.6828h±
2017.2.5 15:50:19,±2222..66880000h±
2017.2.5 15:50:21,±2222..66776699h±
2017.2.5 15:50:22,±2222..66778877h±
2017.2.5 15:50:24,±2222..66880077h±
2017.2.5 15:50:25,±2222..66779900h±
2017.2.5 15:50:27,±2222..66774422h±
2017.2.5 15:50:28,±2222..66667744h±
2017.2.5 15:50:30,±2222..66558899h±
2017.2.5 15:50:32,±2222..66449922h±
2017.2.AA2 Z2
2
.
j9ÿ
Cÿ
HR




Quote
If that is key to your application you must change the sleep mode (p.e. to 'idle') to let the Arduino wake up if the serial interface gets active.
Thats how I did it in the working example. Now I just want so save some more power.

pylon

We didn't implement a length check and the buffer is to small to hold 10 records (each record holds 35 characters plus carriage return and newline, so for 10 records the buffers must be at least 371 bytes in size, if you don't want to loose characters, it must be 406 characters.

Quote
Thats how I did it in the working example. Now I just want so save some more power.
You cannot save power that way without loosing functionality.

Eheran

#25
Feb 08, 2017, 11:52 pm Last Edit: Feb 09, 2017, 12:45 am by Eheran
Corrected code, removed a double line printing the inChar.
Increased the Buffer to 400 Bytes anyways, but theoretical maximum should be 300.

Code: [Select]
#include <Wire.h>
#include <Time.h>
#include <TimeLib.h>
#include <DS1307RTC.h>

#include <SdFat.h>
#include <SPI.h>
#include <LowPower.h>
const int chipSelect = 10;
SdFat SD;
int val = 0;

const int dPin = 2; // interrupt 0


boolean stringComplete = false;  // whether the string is complete
bool an = 1;                     //marker for first startup

// a few markers (un)used to signal when the new temp. reading is complete
bool fertig = 1;
int warten = 0;
bool linefeed = 0;
int num;
char inChar;
boolean newData = false;
bool plusminus = 0;


char buffer[400];




void setup()  {
  Serial.begin(9600);

  buffer[0] = 0; // terminating null byte
  delay(250);

  pinMode(5, OUTPUT);         //power to SD
  digitalWrite(5, LOW);
  pinMode(dPin, INPUT);       //interruptpin
  pinMode(8, OUTPUT);         //power for RTC
  digitalWrite(8, HIGH);
  pinMode(9, OUTPUT);         //debug pin sleep
  digitalWrite(9, LOW);
  Serial.println("an");
  Serial.flush();

}

void loop() {
  recvoneChar();


  if (an) {         //on first start up sleep and wait for signal
    attachInterrupt(0, interrupt, CHANGE);
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
    detachInterrupt(0);
    an = 0;
  }

  if ((millis() - warten) > 50) {    //dont sleep while data comes in
    val++;
    if (val == 10) {    //count 10x data for lower SD-card access -> lower power consumption
      stringComplete = true;
      val = 0;
    }
    if (stringComplete) {   //print the 10 records to the SD-card
      digitalWrite(5, HIGH);    //power SD-card (MOSFET)
      if (!SD.begin(chipSelect)) {                            // see if the card is present and can be initialized:
        Serial.println("Card failed or not present");
        delay(50);
        return;
      }
      File dataFile = SD.open("log.txt", FILE_WRITE);
      dataFile.print(buffer);
      dataFile.close();
      Serial.print(buffer);
      Serial.flush();
      buffer[0] = 0; // clear the string
      stringComplete = false;
      digitalWrite(5, LOW);
    }


    //    Serial.println(",  sl");  //debug
    //    Serial.flush();
    digitalWrite(9, HIGH);     //debug
    attachInterrupt(0, interrupt, LOW);
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
    detachInterrupt(0);
    digitalWrite(9, LOW);    //debug
    warten = millis();
    //    Serial.print("wk  ,");  //debug
    linefeed = 0;
    num = 0;
    plusminus = 0;
  }


}


void recvoneChar() {


  while (Serial.available()) {
    inChar = (char)Serial.read();       // get the new byte:
    num++;

    tmElements_t tm;
    if (! RTC.read(tm)) {
      if (RTC.chipPresent()) {  //this never shows up, so the I2C itself failed
        Serial.println(F("The DS1307 is stopped.  Please run the SetTime"));
        Serial.println(F("example to initialize the time and begin running."));
        Serial.println();
      } else {
        Serial.println(F("DS1307 read error!  Please check the circuitry."));
        Serial.println();
      }
      delay(2000);
    }

    int l = strlen(buffer);          //defines the lenght of the string "buffer" to be int L
    //    buffer[l++] = inChar;          //Counts up one position in "buffer" and puts the inChar into this position
    //    buffer[l] = 0;                 // terminating null byte, at position L
    if ( (byte) inChar == 177) {
      plusminus = 1;      //this is the false (due to wakeup) symbol, but its consistent, so its used to toggle new data
      buffer[l++] = '\r';
      buffer[l++] = '\n';
      l += snprintf(buffer + l, 400 - l, "%d.%d.%d %d:%d:%d", tmYearToCalendar(tm.Year), tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second);
      buffer[l++] = ',';
      buffer[l] = 0;
      inChar = '\0';
    }
    if (plusminus) {            //new data is coming in, now just put it into the buffer
      buffer[l++] = inChar;     //Counts up l position in "buffer" and puts the inChar into this position
      buffer[l] = 0;            // terminating null byte
    }

    Serial.println(inChar);     //debug print to serial
  }
}



void interrupt() {
}

This glitches after about 8 min:
Code: [Select]
2
3
.
4
1
4
8

2017.2.8 19:42:48,23.3928
2017.2.8 19:42:50,23.3919
2017.2.8 19:42:52,23.3926
2017.2.8 19:42:53,23.3938
2017.2.8 19:42:55,23.4004
2017.2.8 19:42:56,23.4057
2017.2.8 19:42:58,23.4103
2017.2.8 19:42:59,23.4111
2017.2.8 19:43:1,23.4126
2017.2.8 19:43:3,23.4148ú
j
h
{{{

2017.2.8 19:43:6,)
ù
2
3
.
4
3
4
3
h}}}
The part in {{{}}} then repeats with the correct temp. and date values


Since I still think this issue has nothing to do with strings or now the buffer I removed everything out of the code. Only sleep, wake up and print the data. Nothing else.
Code: [Select]
void loop() {
  recvoneChar();


  if (an) {         //on first start up sleep and wait for signal
    attachInterrupt(0, interrupt, CHANGE);
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
    detachInterrupt(0);
    an = 0;
  }

  if ((millis() - warten) > 50) {    //dont sleep while data comes in
    Serial.println(",  sl");  //debug
    Serial.flush();
    digitalWrite(9, HIGH);     //debug
    attachInterrupt(0, interrupt, LOW);
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
    detachInterrupt(0);
    digitalWrite(9, LOW);    //debug
    warten = millis();
    Serial.print("wk  ,");  //debug
  }


}


void recvoneChar() {
  while (Serial.available()) {
    inChar = (char)Serial.read();       // get the new byte:
    Serial.println(inChar);     //debug print to serial
  }
}



void interrupt() {
}


Tested for 1h and no problems.
Tested again with a timestamp in front of every char, no logging or buffer etc.
The output changed after a few minutes, there was another wakeup + sleep right befor the data comes in. The 50ms rule was compromised here, the scope shows that pin 9 is back to high (aka sleeping) after only ~13ms.
Code: [Select]
void loop() {
  recvoneChar();


  if (an) {         //on first start up sleep and wait for signal
    attachInterrupt(0, interrupt, CHANGE);
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
    detachInterrupt(0);
    an = 0;
  }

  if ((millis() - warten) > 50) {    //dont sleep while data comes in

    Serial.println(",  sl");  //debug
    Serial.flush();
    digitalWrite(9, HIGH);     //debug
    attachInterrupt(0, interrupt, LOW);
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
    detachInterrupt(0);
    digitalWrite(9, LOW);    //debug
    warten = millis();
    Serial.println("wk  ,");  //debug
  }


}


void recvoneChar() {


  while (Serial.available()) {
    inChar = (char)Serial.read();       // get the new byte:

    tmElements_t tm;
    if (! RTC.read(tm)) {
      if (RTC.chipPresent()) {  //this never shows up, so the I2C itself failed
        Serial.println(F("The DS1307 is stopped.  Please run the SetTime"));
        Serial.println(F("example to initialize the time and begin running."));
        Serial.println();
      } else {
        Serial.println(F("DS1307 read error!  Please check the circuitry."));
        Serial.println();
      }
      delay(2000);
    }
    Serial.print(tmYearToCalendar(tm.Year));     //debug print to serial
    Serial.print(".");
    Serial.print(tm.Month);
    Serial.print(".");
    Serial.print(tm.Day);
    Serial.print(" ");
    Serial.print(tm.Hour);
    Serial.print(":");
    Serial.print(tm.Minute);
    Serial.print(":");
    Serial.print(tm.Second);
    Serial.print("  ");
    Serial.println(inChar);     //debug print to serial
  }
}

void interrupt() {
}



Now I wanted to know whats going on and only removed the RTC parts out of your code to see if the RTC causes the problem. And... it worked. No glitch for tested 30min.
Then I removed the RTC power from pin 8 and onto the 5V rail to see if maybe that screws up the RTC or I2C. Failed after 8min.
So I dont know how or why, but its the RTC and/or its implementation. Since its currently a DS1307 and that always had to be replaced with a DS3231... and those should have been here 2 weeks ago... I will update this when I finally get them.

Eheran

Installed the DS3231.
Glitches after 8min.
No idea what to do.
Take a look at the scope pictures (reminder: Thats pin9).

Code: [Select]
#include <Wire.h>
#include <DS3231.h>
DS3231 clock;
RTCDateTime dt;

#include <SdFat.h>
#include <SPI.h>
#include <LowPower.h>
const int chipSelect = 10;
SdFat SD;
int val = 0;


const int dPin = 2; // interrupt 0


// a few markers used to signal when the new temp. reading is complete etc.
boolean stringComplete = false;  // whether the string is complete
bool an = 1;                     //marker for first startup
int num;
bool plusminus = 0;
char inChar;
int warten = 0;


char buffer[300];




void setup()  {
  Serial.begin(9600);

  buffer[0] = 0; // terminating null byte
  delay(250);

  clock.begin();
  clock.setDateTime(__DATE__, __TIME__);  // Set sketch compiling time
  dt = clock.getDateTime();
  Serial.println(clock.dateFormat("Y.m.d H:i:s", dt));

  pinMode(5, OUTPUT);         //power to SD
  digitalWrite(5, LOW);
  pinMode(dPin, INPUT);       //interruptpin
  pinMode(8, OUTPUT);         //power for RTC
  digitalWrite(8, HIGH);
  pinMode(9, OUTPUT);         //debug pin sleep
  digitalWrite(9, LOW);
  Serial.println(F("an"));
  Serial.flush();

}

void loop() {
  recvoneChar();


  if (an) {         //on first start up sleep and wait for signal
    attachInterrupt(0, interrupt, CHANGE);
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
    detachInterrupt(0);
    an = 0;
  }

  if ((millis() - warten) > 50) {    //dont sleep while data comes in
    val++;
    if (val == 10) {    //count 10x data for lower SD-card access -> lower power consumption
      stringComplete = true;
      val = 0;
    }
    if (stringComplete) {   //print the 10 records to the SD-card
      digitalWrite(5, HIGH);    //power SD-card (MOSFET)
      if (!SD.begin(chipSelect)) {                            // see if the card is present and can be initialized:
        Serial.println(F("SD fail"));
        delay(50);
        return;
      }
      File dataFile = SD.open("log.txt", FILE_WRITE);
      dataFile.print(buffer);
      dataFile.close();
      Serial.print(buffer);
      Serial.flush();
      buffer[0] = 0; // clear the string
      stringComplete = false;
      digitalWrite(5, LOW);
    }


    //    Serial.println(",  sl");  //debug
    //    Serial.flush();
    digitalWrite(9, HIGH);     //debug
    attachInterrupt(0, interrupt, LOW);
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
    detachInterrupt(0);
    digitalWrite(9, LOW);    //debug
    warten = millis();
    Serial.println();
    //    Serial.print("wk  ,");  //debug
    linefeed = 0;
    num = 0;
    plusminus = 0;
  }


}


void recvoneChar() {


  while (Serial.available()) {
    inChar = (char)Serial.read();       // get the new byte:
    num++;




    int l = strlen(buffer);          //defines the lenght of the string "buffer" to be int L
    //    buffer[l++] = inChar;          //Counts up one position in "buffer" and puts the inChar into this position
    //    buffer[l] = 0;                 // terminating null byte, at position L
    if ( (byte) inChar == 177) {
      plusminus = 1;      //this is the false (due to wakeup) symbol, but its consistent, so its used to toggle new data
      buffer[l++] = '\r';
      buffer[l++] = '\n';
      dt = clock.getDateTime();
      l += snprintf(buffer + l, 400 - l, clock.dateFormat("Y.m.d H:i:s", dt));
      buffer[l++] = ',';
      buffer[l] = 0;
      inChar = '\0';
    }
    if (plusminus) {            //new data is coming in, now just put it into the buffer
      buffer[l++] = inChar;     //Counts up l position in "buffer" and puts the inChar into this position
      buffer[l] = 0;            // terminating null byte
    }

    Serial.print(inChar);     //debug print to serial
  }
}



void interrupt() {
}

pylon

Am I correct in the interpretation of the scope images that the spikes are about 40µs long?

I cannot find any information in the ATmega328 datasheet about what behaviour the chips has on it's GPIOs during power down. The term "power down" would lead me to the assumption that a HIGH value is not guaranteed during power down but as I wrote I cannot find any information about that.

I would try to reverse the polarity of pin 9, so let it be low during power down and high in the active state. It might be completely unrelated but it's worth a try.

What are glitches in your current context? The spikes in the scope or do you get wrong output on the serial?

Eheran

Yes, 40µs. As long as the program is running correct this could never be less than 50ms.
It fails to wake up (or falls asleep right away) so the collected data is garbage.
Quote
I would try to reverse the polarity of pin 9, so let it be low during power down and high in the active state. It might be completely unrelated but it's worth a try.
You mean what the output on the scope would be? Its not related to the problem, its only for debugging.

pylon

Quote
You mean what the output on the scope would be? Its not related to the problem, its only for debugging.
You thinkt that the spikes in the scope output are wake-ups that don't work correctly. I think they might be spikes during sleep, the processor don't awake that often. That's why I would change the polarity and pull the pin externally down to eliminate fake output of a floating pin.


Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy