Go Down

Topic: Sleep and wake up with DS3231 (Read 10891 times) previous topic - next topic

novakkry

Nov 09, 2015, 08:26 pm Last Edit: Nov 22, 2015, 12:32 am by novakkry
Hello,
the first problem with the sim800l was solved. Now I am dealing with sleeping and waking up the arduino. My goal is send data once a day at specific time and then the rest of the time sleep.


I am a total newbie so sorry for dumb questions.

I'd like to make a gadget that will measure level of water and temperature of air and send these data to mysql database on server via SIM800 module.

I bought and make work both sensors, but the SIM800 module (http://cdn1.shopium.ua/d/arduino/c/s/6c414f36-bb29-4bc3-9a61-44bb3be1e79b.jpg) I am able to only send sms.

I found on the internet (http://arduinodev.com/arduino-library-for-gprshttp-communication-with-sim800/) similar problem solved, but I can't make the code work. In the library on GitHub (https://github.com/stanleyhuangyc/Freematics/tree/master/libraries/SIM800) there is written "Change SIM_SERIAL definition to the serial UART which SIM800 is attached to". I am not sure what exactly should I change and in which file.

For example I've got the SIM 800 connected
TX to pin 6
RX to pin 7
And example of adress that would save water level 50cm and air temperature 20 celsius:
http://10.10.10.10:80/add.php?level=50&temperature=20

Thank you a lot for help.

Krystof

PaulS

Quote
I am not sure what exactly should I change and in which file.
The code that the comment was located in, obviously.

geologic

As said in the configuration section, you should change in the SIM800.h file

I use the same library with arduino uno, i changed that line to

#define SIM_SERIAL Serial

If you use the example code, remove this part, because it freezes the sim800 module

Code: [Select]


 // show position
  GSM_LOCATION loc;
  if (gprs.getLocation(&loc)) {
    con.print("LAT:");
    con.print(loc.lat, 6);
    con.print(" LON:");
    con.print(loc.lon, 6);
    con.print(" TIME:");
    con.print(loc.hour);
    con.print(':');
    con.print(loc.minute);
    con.print(':');
    con.println(loc.second);
  }

novakkry

#3
Nov 16, 2015, 12:40 pm Last Edit: Nov 16, 2015, 02:38 pm by novakkry
Thank you people so much for advices.
So I changed the Serial1 to Serial and little bit modifed the code. The problem was that the rx and tx pin has to be switched. And it is working now! I am able to send data to mysql database. Huraaa! :))

But I have another problem. I need to read the data from the sensor and send them once a day at a certain time. The whole project will be running on a big capacity battery and has to last at least for one year without any interference (I will build custom pcb, this is just prototype.). I tried to use the delay function for one day (86 400 000 miliseconds), but the connection and setting up the network take from 30 seconds to two minutes, so the arduino would be delayed ca. 30 minutes every month and thats too much.

So my question is: Do you know or do you have some example how to implement some real clock time module so the module at certain time will wake up the arduino from low power mode, arduino does the specific task and then put the arduino into low power mode again?

Here is my code. If you will see something that would be helpful to modife, let me please know!
Code: [Select]

#include "SIM800.h"
#define APN "internet"

#define con Serial
#include <NewPing.h>

//utlrasonic settings------
int trig_pin = 8;
int echo_pin = 9;
int max_vzdalenost = 500; //vzdalenost = distance in czech; max distance is set up for 500cm
NewPing metr(trig_pin, echo_pin, max_vzdalenost);
float vzdalenost;
//------ultrasonic settings

CGPRS_SIM800 gprs;

//example of get request 109.81.197.40/add.php?id=xx&level=xx

void setup()
{
  con.begin(9600);
 
}

void loop()
{
//setting up the connection-----
while (!con);

  for (;;) {
    con.print("Resetting...");
    while (!gprs.init());
    con.println("OK");
   
    con.print("Setting up network...");
    byte ret = gprs.setup(APN);
    if (ret == 0)
      break;
    con.print("Error code:");
    con.println(ret);
  }
  con.println("OK");

  for (;;) {
    if (gprs.httpInit()) break;
    con.println(gprs.buffer);
    gprs.httpUninit();
    delay(1000);
  }

//---- setting up the connection

  static char* url = "http://109.81.197.40/add.php"; //core addres without data
  char mydata[16]; //array for data

  //read from ultrasonic sensor-----
  int x;
do
{
  delay(50);          // wait for sensors to stabilize
  x = metr.ping_cm();;  // check the sensors

} while (x == 0);
//-----read form the ultrasonic sensor

  sprintf(mydata, "id=1&level=%i", x); //data itself

  //get request
  gprs.httpConnect(url,mydata);
  while (gprs.httpIsConnected() == 0) {
    // can do something here while waiting
  }
  if (gprs.httpState == HTTP_ERROR) {
    con.println("Connect error");
    return;
  }
  con.println();

delay(600000); //10 min delay and all over agein

}

Thank you a lot for advices.

Krystof

PaulS

Quote
I tried to use the delay function
Wrong answer. An RTC is the correct answer.

Quote
Do you know or do you have some example how to implement some real clock time module so the module at certain time will wake up the arduino from low power mode, arduino does the specific task and then put the arduino into low power mode again?
Which RTC? Several are able to generate external interrupts. Some have alarms that can generate the external interrupt. Set the alarm to trigger the interrupt which will wake the Arduino which will then collect and send the data and then go back to sleep.

Quote
If you will see something that would be helpful to modife, let me please know!
Well, I doubt your code actually looks like that. Learn to post code properly. There IS a code icon. Learn what it does.

novakkry

PaulS>
I didn't see the "code" icon because I answered through quick reply, sorry. I edited the post. Does it look OK?

I was thinking about DS3231 or DS1307, which do you think is more suitable? Don't you have some code examples or articles to learn how to do it? I am really keen to learn, but I have to start somewhere and I have no idea how to start.

Thank you

PaulS

Quote
I have no idea how to start.
The two RTCs you listed are good choices. There are Arduino libraries for using either one. The 3231 is more accurate, and probably does everything you want. The 1307 is a decent clock, but that's about all that it is.

novakkry

So I am buying 3231. Will updadate this thread.


novakkry

I finally got DS3231 module. Don't you have some example code that does the sleep mode, interrupt and sleep mode again? I am learning fast, but I don't think I am capable to do it by myself without any help.

Thank you.

dannable

Power saving techniques: http://www.gammon.com.au/forum/?id=11497

Connect the alarm pin of the DS3231 to an interrupt pin on the Arduino and use that to wake it up.

Clemens

Perhaps this code helps. I used the DS3231 lib from the Seeeduino Stalker that supports IRQ:
http://www.seeedstudio.com/wiki/images/c/c9/SeeeduinoStalkerV2.1_Software%28Arduino_1.0%29.zip

and the rocketscream LowPower lib:
https://github.com/rocketscream/Low-Power

Code: [Select]

// pins hard coded
// D2  RTC IRQ
// D13 debug LED

// libraries
// RTC
#include <Wire.h>    // I2C (for RTC)
#include <DS3231.h>  // RTC itself

DS3231 RTC;                     // create RTC object for DS3231
static DateTime interruptTime;  // next interrupt time 

// power saving
#include <LowPower.h>


// we need some variable as char to pass it to payload easily
char timestampChar[20];  // should handle yyyy/mm/dd hh:mm:ss and null terminator


void setup () {
  // debug
  Serial.begin(9600);
  pinMode(13, OUTPUT);  // debug led

  // rtc, irq
  Wire.begin();
  RTC.begin();
 
  pinMode(2, INPUT_PULLUP);  // initialize INT0 (D2 on the most Arduino's) to accept external interrupts
 
  // set periodic interrupt intervals
  //RTC.enableInterrupts(EveryMinute); // options: EverySecond, EveryMinute, EveryHour

  // or specify only the first interrupt time in case EverySecond, EveryMinute, EveryHour
  // does not fit your needs, then specify it also in void INT0_ISR()
  DateTime start = RTC.now();
  // add x seconds (interval time) to start time
  interruptTime = DateTime (start.get() + 60);
}


void loop () {
  // output timestamp
  getTimestamp();
  Serial.println(timestampChar);

  // do other things here, e.g. reading sensors

  // debug
  // blink LED to indicate sensor reading is done
  // delet this after prototyping to save power
  digitalWrite(13, HIGH);
  Serial.flush();  // flush serial before sleeping
  LowPower.powerDown(SLEEP_60MS, ADC_OFF, BOD_OFF); // delay 60 ms
  digitalWrite(13, LOW);
   
  // prepare next interrupt time
  RTC.clearINTStatus();  // this function call is a must to bring INT pin high after an interrupt
  RTC.enableInterrupts(interruptTime.hour(),interruptTime.minute(),interruptTime.second());  // set the interrupt (h,m,s)
  attachInterrupt(0, wakeUp, LOW);  // enable INT0, required to handle level triggered interrupts
 
  // go sleeping
  // debug
  Serial.print("\nSleeping ... ");
  Serial.flush();  // flush serial before sleeping
  // power down with ADC and BOD disabled
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
  // waiting for the next interrupt
  // tzzzzz ... tzzzzz ...
 
  // wakeup
  detachInterrupt(0);
  // calculate next interrupt time
  interruptTime = DateTime(interruptTime.get() + 5); 
 
  delay(10); // this delay is required to allow CPU to stabilize
  Serial.println("Awake from sleep.\n");
}


// timestamp
void getTimestamp() {   
  DateTime currentTime = RTC.now();  // get the current date-time   
  snprintf(timestampChar, sizeof(timestampChar), "%d/%02d/%02d %02d:%02d:%02d", currentTime.year(), currentTime.month(), currentTime.date(), currentTime.hour(), currentTime.minute(), currentTime.second());  // write to char array
}


// interrupt service routine for external interrupt on INT0 triggered from RTC
// keep this as short as possible, possibly avoid using function calls
void wakeUp() {
   // handler for the pin interrupt
}



A RTC is the best solution of cause, in case you do not have it the TimeAlarms lib can do a similar but not so precise job (without power saving): https://www.pjrc.com/teensy/td_libs_TimeAlarms.html Unfortunately the TimeAlarms lib can not deal with IRQs that would be a nice feature.

In case your logging intervals must not be super accurate and can differ +/- some seconds the Narcoleptic lib can help. Nice thing vs rocketscream LowPower lib https://code.google.com/p/narcoleptic/ is that you can specify free time slots and you have not to divide up in 8s pieces as you have to do it with the rocketscream lib.

novakkry

#11
Nov 20, 2015, 07:24 pm Last Edit: Nov 20, 2015, 07:27 pm by novakkry
I am kind of lost and desperate...

I am able to sleep the arduino and wake it up with interrupt manual signal (push button connected to PIN2). But I don't know how to do it using ds3231. This is the code to put it asleep. While not sleeping, I want to blink the LED couple times (function "blikani").
Code: [Select]
#include <avr/sleep.h>

const byte LED = 13;
 
void wake ()
{
  // cancel sleep as a precaution
  sleep_disable();
  // precautionary while we do other stuff
  detachInterrupt (0);
}  // end of wake

void setup ()
  {
  digitalWrite (2, HIGH);  // enable pull-up
  }  // end of setup

void loop ()
{
  blikani();
 
  // disable ADC
  ADCSRA = 0; 
 
  set_sleep_mode (SLEEP_MODE_PWR_DOWN); 
  sleep_enable();

  // Do not interrupt before we go to sleep, or the
  // ISR will detach interrupts and we won't wake.
  noInterrupts ();
 
  // will be called when pin D2 goes low 
  attachInterrupt (0, wake, FALLING);
  EIFR = bit (INTF0);  // clear flag for interrupt 0
 
  // turn off brown-out enable in software
  // BODS must be set to one and BODSE must be set to zero within four clock cycles
  MCUCR = bit (BODS) | bit (BODSE);
  // The BODS bit is automatically cleared after three clock cycles
  MCUCR = bit (BODS);
 
  // We are guaranteed that the sleep_cpu call will be done
  // as the processor executes the next instruction after
  // interrupts are turned on.
  interrupts ();  // one cycle
  sleep_cpu ();   // one cycle

  } // end of loop

  void blikani(){
    pinMode (LED, OUTPUT);

    for(int i = 0; i<=20;i++){
  digitalWrite (LED, HIGH);
  delay (50);
  digitalWrite (LED, LOW);
  delay (50);
    }
  pinMode (LED, INPUT);

  }
 


Don't you know how to wake it up at specific time once or twice a day? If the ds3231 is powered only from battery, is it able to do the interrupt or it needs Vcc from arduino? The interrupt alarm information is saved in arduino or in ds3231 module?

I have found code from Mr. JChristensen, which does the interrupt at specific time, but I can't implement the alarm into previous code. This code does the alarm interrupt, but doesn't sleep the arduino. Here is the link: https://github.com/JChristensen/DS3232RTC/issues/5

I tried all day at least hundered times, but I just couldn't make it work...

Any specific help would be gift from heaven.

Thank you.

Krystof

novakkry

This is what I have so far. The problem is, that the ran only twice and then it fall asleep forever. Don't you know where could be mistake? Maybe the code is total bullshit, I am trying...

Code: [Select]
#include <DS3232RTC.h>        //http://github.com/JChristensen/DS3232RTC
#include <Streaming.h>        //http://arduiniana.org/libraries/streaming/
#include <Time.h>             //http://playground.arduino.cc/Code/Time
#include <Wire.h>             //http://arduino.cc/en/Reference/Wire
#include <avr/sleep.h>                                 

#define SQW_PIN 2

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

    //setSyncProvider() causes the Time library to synchronize with the
    //external RTC by calling RTC.get() every five minutes by default.
    setSyncProvider(RTC.get);
    Serial << "RTC Sync";
    if (timeStatus() != timeSet){
        Serial << " FAIL!";
    }
    Serial << endl;

    printDateTime( RTC.get() );
    Serial << " --> Current RTC time." << endl;

    //Disable the default square wave of the SQW pin.
    RTC.squareWave(SQWAVE_NONE);

    //Attach an interrupt on the falling of the SQW pin.
    //digitalWrite(SQW_PIN, HIGH);    //redundant with the following line
    pinMode(SQW_PIN, INPUT_PULLUP);
   

    //Set an alarm at every 20th second of every minute.
    RTC.setAlarm(ALM1_MATCH_SECONDS, 20, 0, 0, 1);    //daydate parameter should be between 1 and 7
    RTC.alarm(ALARM_1);                   //ensure RTC interrupt flag is cleared
    RTC.alarmInterrupt(ALARM_1, true);

}

//volatile boolean alarmIsrWasCalled = false; don't think we need it

void alarmIsr()
{
    Serial.println("alarmIsr"); // to get know whether the fuction ran or not
   // alarmIsrWasCalled = true; don't think we need it

}

void sleepNow() { 
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // sleep mode is set here 
    sleep_enable();                         // enables the sleep bit in the mcucr register 
      // use interrupt 0 (pin 2) and run function
      attachInterrupt(0,alarmIsr, CHANGE);// here the device is actually put to sleep!!   
      sleep_mode();
      Serial.println("SleepNow"); //to get know whether the fuction ran or not
     
    // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP 
   

  //  sleep_disable();         // first thing after waking from sleep: disable sleep... 
   // detachInterrupt(0);      // disables interrupt 0 on pin 2 so the wakeUpNow code will not be executed during normal running time. 



int i = 1; //to get know how many times the loop went

void loop(void)
{
// alarmIsrWasCalled = false; don't think we need it
delay(100);
Serial.println(i);
delay(100);
i++;
sleepNow();
}

void printDateTime(time_t t)
{
    Serial << ((day(t)<10) ? "0" : "") << _DEC(day(t)) << ' ';
    Serial << monthShortStr(month(t)) << " " << _DEC(year(t)) << ' ';
    Serial << ((hour(t)<10) ? "0" : "") << _DEC(hour(t)) << ':';
    Serial << ((minute(t)<10) ? "0" : "") << _DEC(minute(t)) << ':';
    Serial << ((second(t)<10) ? "0" : "") << _DEC(second(t));
}

Go Up