Den Arduino schlafen schicken und von der RealTimeClock wieder aufweckenFreitag, 10 April, 2015 11:07

Der Arduino soll ja mal mit Batterie laufen und deswegen (und überhaupt, nicht wahr?) sind stromsparende Zustände neben der Hauptfunktion ein zweiter Hauptfaktor in der Arduino Programmierung. Wie üblich waren durch Google bereits bekannt gewordene und auch neue Webseiten diesbezüglich auskunftsfreudig.

Dass es zuerst nicht klappen wollte, den Arduino wieder auf zu wecken - schlafen schicken ging ganz wunderbar und prompt, schien zunächst undurchsichtig zu sein. Aber auch hier hatten andere Leute dasselbe Problem und so kam ich der Ursache auf die Spur. - Meine naive Annahme, wenn ich die RTC anweise, den Interrupt zu aktivieren, mit dem sie den Arduino wieder aufwecken soll, dann funktionert das auch war falsch. Vorher putzen quasi muss schon sein :)

Und eine Seite stach aus allen anderen Seiten besonders hervor, weswegen ich sie gerne hier besonders erwähne:

Gammon Forum : Electronics : Microprozessors: Power saving techniques for microprozessors 

Und hier präsentiere ich mein Labor-Script, das funktioniert (Update, für das neue LED-Display und mit 2-stelligen Ausgaben überall :) ):

    
#include <LiquidCrystal_I2C.h>
#include <DS3232RTC.h> 
#include <Time.h>
#include <Wire.h>
#include <avr/sleep.h>
#include <avr/power.h>

// old LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
int counter=0;
int pin2 = 2;

unsigned long(starttime)=2;
unsigned long(sleeptime)=1;

void setup()
{
  Serial.begin(9600);
  pinMode(pin2, INPUT); 
  lcd.begin(20, 4);
  lcd.setCursor(0,0);
  setSyncProvider(RTC.get);
  if(timeStatus() != timeSet) {
lcd.print("Unlucky - no RTC");
Serial.println("Unlucky - no RTC");
  }  
  else {
lcd.print("lucky - got RTC");
Serial.println("lucky - got RTC");
starttime=now();
sleeptime=starttime+30;
delay(2000);
  unsigned long alarmtime=sleeptime+30;
  Serial.print("Sleep time: ");
  SerialDigits(hour(sleeptime));
  Serial.print(":");
  SerialDigits(minute(sleeptime));
  Serial.print(":");
  SerialDigits(second(sleeptime));
  Serial.println("");
  Serial.print("Alarm time: ");
  SerialDigits(hour(alarmtime));
  Serial.print(":");
  SerialDigits(minute(alarmtime));
  Serial.print(":");
  SerialDigits(second(alarmtime));
  Serial.println("");
  RTC.squareWave(SQWAVE_NONE);
  RTC.alarm(1);
  RTC.alarm(2);
  RTC.alarmInterrupt(ALARM_1, true);
  RTC.alarmInterrupt(ALARM_2, false);
  RTC.setAlarm(ALM1_MATCH_HOURS, second(alarmtime), minute(alarmtime), hour(alarmtime), 0);
  Serial.println("Waiting for sleep");
  lcd.clear();
  } 
}

void loop(void)
{
  unsigned long(current)=now();
  unsigned long(soon)=current;
//  do {
 digitalClockDisplay();
//     delay(200);
 if ( (sleeptime > 1 ) and ( sleeptime = soon ) ) {
   enterSleep();
 }
//     soon=now();
//  } while ( soon  current +6);
//  do {
 digitalAlarmsDisplay();
 delay(200);
 if ( (sleeptime > 1 ) and ( sleeptime = soon ) ) {
   enterSleep();
 }
 soon=now();
//   } while ( soon   current +10);
}

void wake () {
 sleep_disable();
}
void enterSleep(void)
{
  lcd.setCursor(0,1);
  lcd.print("... entering sleep                ");
  lcd.setCursor(0,2);
  lcd.print("S1: ");
  LedDigits(hour(sleeptime));
  lcd.print(":");
  LedDigits(minute(sleeptime));
  lcd.print(":");
  LedDigits(second(sleeptime));
  lcd.setCursor(0,3);
  lcd.print("A1: ");
  LedHexes(RTC.readRTC(ALM1_HOURS));
  lcd.print(":");
  LedHexes(RTC.readRTC(ALM1_MINUTES));
  lcd.print(":");
  LedHexes(RTC.readRTC(ALM1_SECONDS));
  delay(2000);
  lcd.noBacklight();
  delay(2000);
  lcd.off();
  // disable ADC
  ADCSRA = 0;
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  noInterrupts ();
  // This is triggered by interrupt
  attachInterrupt (0, wake, LOW);
  // turn off brown-out enable in software
  // turn on brown-out enable select
  MCUCR = bit (BODS) | bit (BODSE);
  // this must be done within 4 clock cycles of above
  MCUCR = bit (BODS);
  interrupts ();
  sleep_mode();
  
  /* After wake up continue from here. */
  
  detachInterrupt (0); 
  power_all_enable();
  lcd.on();
  sleeptime=1;
  setSyncProvider(RTC.get);
  RTC.alarmInterrupt(ALARM_1, false);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("..just woke up!!");
  delay(2000);
}

void setAlarmOnce() {
  unsigned long alarmtime=sleeptime+60;
  Serial.print("Sleep time: ");
  SerialDigits(hour(sleeptime));
  Serial.print(":");
  SerialDigits(minute(sleeptime));
  Serial.print(":");
  SerialDigits(second(sleeptime));
  Serial.println("");
  SerialDigits(hour(alarmtime));
  Serial.print(":");
  SerialDigits(minute(alarmtime));
  Serial.print(":");
  SerialDigits(second(alarmtime));
  Serial.println("");
}

void digitalClockDisplay(void)
{
  lcd.setCursor(0,0);
  LedDigits(hour());
  lcd.print(':');
  LedDigits(minute());
  lcd.print(':');
  LedDigits(second());
  lcd.print(' ');
  char tempF[6];
  int t = RTC.temperature();
  float celsius = t / 4.0;
  dtostrf(celsius, 5, 1, tempF);
  lcd.print(celsius);
  lcd.print((char)223);
  lcd.print('C');
  lcd.setCursor(0,1);
  LedDigits(day());
  lcd.print('.');
  LedDigits(month());
  lcd.print('.');
  lcd.print(year());
  lcd.print("  ");
}

void digitalAlarmsDisplay() {
lcd.setCursor(0,2);
lcd.print("S1: ");
LedDigits(hour(sleeptime));
lcd.print(":");
LedDigits(minute(sleeptime));
lcd.print(":");
LedDigits(second(sleeptime));
lcd.setCursor(0,3);
lcd.print("A1: ");
LedHexes(RTC.readRTC(ALM1_HOURS));
lcd.print(":");
LedHexes(RTC.readRTC(ALM1_MINUTES));
lcd.print(":");
LedHexes(RTC.readRTC(ALM1_SECONDS));
lcd.print("       ");

}

void LedDigits (int digits)
{
  if(digits < 10)
lcd.print('0');
  lcd.print(digits);
}

void SerialDigits (int digits)
{
  if(digits < 10)
Serial.print('0');
  Serial.print(digits);
}

void LedHexes (int digits)
{
  if(digits < 16)
lcd.print('0');
  lcd.print(digits, HEX);
}

Etwas lang geworden :)

Categories:

[ [1] Kommentar ]