Pages: [1]   Go Down
Author Topic: Sleep-Library für ATTiny84?  (Read 724 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Full Member
***
Karma: 0
Posts: 116
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,

ich bastel gerade an Funksensoren mit 433 Mhz und scheitere am Sleepmode ...
Ich wollte dafür eigentlich die Jeelib verwenden, den - man ist ja faul - muss ich mich um nichts kümmern; sondern einfach "LooseSomeTime" statt Delay nutzen.

Nun knallt die JeeLib mit der VirtualWire-Lib - ich bekomme Fehler beim Kompilieren:
Code:
C:\Program Files (x86)\Arduino\libraries\jeelib\RF12.cpp: In function 'void rf12_interrupt()':
C:\Program Files (x86)\Arduino\libraries\jeelib\RF12.cpp:301: error: '_crc16_update' was not declared in this scope
C:\Program Files (x86)\Arduino\libraries\jeelib\RF12.cpp:311: error: '_crc16_update' was not declared in this scope
C:\Program Files (x86)\Arduino\libraries\jeelib\RF12.cpp: In function 'void rf12_recvStart()':
C:\Program Files (x86)\Arduino\libraries\jeelib\RF12.cpp:350: error: '_crc16_update' was not declared in this scope
C:\Program Files (x86)\Arduino\libraries\jeelib\RF12.cpp: In function 'void rf12_sendStart(uint8_t)':
C:\Program Files (x86)\Arduino\libraries\jeelib\RF12.cpp:440: error: '_crc16_update' was not declared in this scope
C:\Program Files (x86)\Arduino\libraries\jeelib\RF12.cpp: In function 'uint8_t rf12_config(uint8_t)':
C:\Program Files (x86)\Arduino\libraries\jeelib\RF12.cpp:656: error: '_crc16_update' was not declared in this scope

Google-Suche war ergebnislos. Ich habe mich auch nicht rangetraut, den "Sleep-Code" aus der Lib zu extrahieren.
Und so habe ich mich auf die Suche nach einer einfachen Möglichkeit gemacht, meinen ATTiny84 in den SChlafzustand zu schicken.

Fertige Libs habe ich ausprobiert - also, RocketStream & Co - die kompilieren aber auf dem ATTiny84 nicht.

Versuche, "händisch" eine Sleep-Lib zu schreiben, scheitern an mangelnder Fachkenntnis smiley

Gibt es den keinen 10-Zeiler um den ATTiny84 in den Schlaf zu schicken und über den Watchdog wieder zu wecken?

Ja, ich habe gegoogelt, und jetzt 2h irgendwelche Codeschnipsel versucht zusammenzuführen, aber ich krieg's nicht hin :/
Logged

Offline Offline
Faraday Member
**
Karma: 120
Posts: 3979
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hier gibt es massig Code wie man das per Hand macht:
http://www.gammon.com.au/forum/?id=11497

Schau aber vielleicht im Datenblatt nach ob die Register genauso funktionieren.

In den AVR Libs gibt es auch Funktionen, die das etwas vereinfachen:
http://www.nongnu.org/avr-libc/user-manual/group__avr__power.html
http://www.nongnu.org/avr-libc/user-manual/group__avr__sleep.html
http://www.nongnu.org/avr-libc/user-manual/group__avr__watchdog.html

Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 116
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
danke für die Info.
Den ersten Link habe ich soweit studiert und wollte einfach mal ein Example auf meinen ATTiny84 flashen.
Dabei sollte eine angeschlossene LED ein paar mal blinken und der ATTiny danach für 1 Sekunde schlafen gehen.

Das Ergebnis sieht aber wie folgt aus: Die LED flasht unaufhörlich; offenkundig geht der AVR nicht in den Sleep. Warum weiß ich nicht - bin auch etwas ratlos, wie ich das jetzt näher analysieren kann?

Code:
#include <avr/sleep.h>
#include <avr/wdt.h>

const byte LED = 7;
 
// watchdog interrupt
ISR (WDT_vect)
{
   wdt_disable();  // disable watchdog
}  // end of WDT_vect
 
void setup () { }

void loop ()
{
 
  pinMode (LED, OUTPUT);
  digitalWrite (LED, HIGH);
  delay (100);
  digitalWrite (LED, LOW);
  pinMode (LED, INPUT);
 
  // disable ADC
  ADCSRA = 0; 

  // clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset
  WDTCSR = bit (WDCE) | bit (WDE);
  // set interrupt mode and an interval
  WDTCSR = bit (WDIE) | bit (WDP2) | bit (WDP1);    // set WDIE, and 1 second delay
  wdt_reset();  // pat the dog
 
  set_sleep_mode (SLEEP_MODE_PWR_DOWN); 
  sleep_enable();
 
  // turn off brown-out enable in software
  MCUCR = bit (BODS) | bit (BODSE);
  MCUCR = bit (BODS);
  sleep_cpu (); 
 
  // cancel sleep as a precaution
  sleep_disable();
 
  } // end of loop
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 116
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ich habe mir "irgendwie" selbst geholfen.
Der Fehler kam wohl daher, dass die VirtualWire-Lib die crc16.h included - das selbe macht auch die JeeLib.
Der Unterschied: Die JeeLib nutzt die crc16.h im /avr/avr/utils-Verzeichnis, wohingegen die VirtualWire-Lib eine eigene crc16.h mitbringt, die aber 3-4 x kleiner ist.

Ich habe also die "normale" crc16.h von C:\Program Files (x86)\Arduino\hardware\tools\avr\avr\include\util nach C:\Program Files (x86)\Arduino\libraries\VirtualWire\util kopiert und die bestehende Datei vorher umbenannt.

Nun klappt auch mein Sleep einwandfrei...
Logged

Offline Offline
Faraday Member
**
Karma: 120
Posts: 3979
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

smiley

Wo du bei sowas auch wie gesagt auch aufpassen musst ist, dass die Register genauso funktionieren. Der Code oben ist eigentlich für den Atmega328. Das geht im Prinzip auf dem ATTiny genauso, aber je nach Prozessor-Typ sind da Funktionen abgespeckt. Da gibt es dann mal das eine oder andere Bit nicht, oder es steht in einem anderen Register.
Logged

Cologne
Offline Offline
God Member
*****
Karma: 11
Posts: 506
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,
wenn du den Sleep Modus direkt über die Register steuern willst, kann ich dir ein Beispiel geben.
In meinem Canon Zeitraffer Timer geht ein ATTiny84 zwischen den Auslösungen immer wieder in den Sleep Mode. Das Projekt ist hier http://glaskugelsehen.wordpress.com/2013/07/16/zeitraffersteuerung-fur-canon-kamera/ beschrieben. Ich häng den Code mal hier mit rein.
Code:
/* Programm löst eine Canon 550D programmgesteuert aus. Über einen Drehkodierschlater lassen sich 15
verschiedene Zeiten einstellen. Kodierer an D0-3 angeschlossen (PA0..3)
Focus und Auslöser werden über FET geschaltet, Focus über D9, Auslöser über D10 (PB0, PB1)
Im Bulb Modus muss bei Reset der Focus Button gedrückt gehalten werden.
Der Prozessor bleibt die meiste Zeit im Sleep Modus. Timing ist erprobt bei 8MHz Takt
Dieses Programm wurde von Reinhard Nickels (rnickels@web.de) erstellt und steht unter GNU GPL.
*/
#include <avr/sleep.h>
#include <avr/wdt.h>

#define POWER 7  // stellt die Messspannung für den Drehkodierer bereit
#define FOCUS 9
#define SHOT 10
#define BULB 4
byte wdtime;     // Variable für Schlafzyklus
byte mode;
boolean first=true;


volatile boolean f_wdt = true;
int wd_counter = 0;
/*
Schalter-
stellung 0 1 2 3 4 5 6 7 8 9 A B C D E F
Zeit AUS 3 sec 5 sec 10 sec 15 sec 30 sec 1 min 5 min 15 min 30 min 1 h 2 h 3 h 4 h 5 h 6 h
Fokus-
Vorlaufzeit - |1 sec -> |4 sec ->
 */
//                         0  1  2   3   4   5   6   7    8    9     10(A) 11(B) 12(C)  13(D)  14(E)  15(F)
// unsigned int Shot[16]= {0, 3, 5,  10, 15, 30, 60, 300, 900, 1800, 3600, 7200, 10800, 14400, 18000, 21600}; 
   unsigned int Shot[16]= {0, 7, 15, 33,  4,  7, 13,  68, 205,  410,  820, 1640,  2460,  3280,  4100,  4920}; 

void setup() {
  pinMode(FOCUS,OUTPUT);
  pinMode(SHOT,OUTPUT);
  pinMode(POWER,OUTPUT);
  pinMode(BULB, INPUT);
  if (!digitalRead(BULB)) {
    while (!digitalRead(BULB)) {
    }  // warte auf HIGH
    digitalWrite(FOCUS, HIGH);
    digitalWrite(SHOT, HIGH);
    while(1) {    // stay to next RESET
    }
  }
  for (int i=0;i<4;i++) {
    pinMode(i, INPUT);
    digitalWrite(i, HIGH);  // Pullups
  }
   
  digitalWrite(POWER, HIGH);
  delay(200);  // zur Stabilisierung der Spannung- hier als Testausgang, kann im endgültigen Prog entfallen
//  mode=kodierer();
  mode = ~PINA & B0001111;
  digitalWrite(POWER, LOW);
  if (mode==0) {
    for (int i=0;i<4;i++) {
      digitalWrite(i, LOW);  // damit kein Strom an den Pullups verbraucht wird
    }
    system_sleep();    // ohne Watchdog init warte auf Reset
  }
  else if (mode<=3) wdtime=4;     // 250ms
  else wdtime=8;                  // 4s
  setup_watchdog(wdtime);
}

void loop() {
  if (f_wdt) {  // wait for timed out watchdog / flag is set when a watchdog timeout occured
    f_wdt=false;       // reset flag
    digitalWrite(FOCUS, HIGH);
    if (mode<=5) delay(1000);
    else delay(4000);
    digitalWrite(SHOT, HIGH);
    delay(100);
    digitalWrite(SHOT, LOW);
    digitalWrite(FOCUS, LOW);
  }
  pinMode(FOCUS,INPUT);       // Ausgänge für Schlafen vorbereiten
  pinMode(SHOT,INPUT);
  pinMode(POWER,INPUT); 
  for (int i=0;i<4;i++) {
    digitalWrite(i, LOW);
  }

  while (wd_counter < Shot[mode]) {    // x-1 * 4s bei Mode 8
    system_sleep();          // hier gehts zum schlafen und ab hier gehts weiter
    wd_counter++;
  }
  wd_counter=0;
  pinMode(FOCUS,OUTPUT);
  pinMode(SHOT,OUTPUT);
  pinMode(POWER,OUTPUT);
  for (int i=0;i<4;i++) {
    digitalWrite(i, HIGH);
  }

}

// set system into the sleep state
// system wakes up when wtchdog is timed out
void system_sleep() {
  ADCSRA &= ~(1<<ADEN);        // switch Analog to Digitalconverter OFF
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
  sleep_enable();
  sleep_mode();                        // System sleeps here
  // continue from here
  sleep_disable();                     // System continues execution here when watchdog timed out
  ADCSRA |= (1<<ADEN);                 // switch Analog to Digitalconverter ON
}

void setup_watchdog(int ii) {   
// ii: 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms,6=1s,7=2s,8=4s,9=8s
  byte bb;
  if (ii > 9 ) ii=9;   // 1001
  bb=ii & 7;           // xxxx & 0111  =  0aaa
  if (ii > 7) bb|= (1<<5);   // xx1xxaaa
  bb|= (1<<WDCE);    // WDCE is BIT4       xx11xaaa
  MCUSR &= ~(1<<WDRF);    // Watchdog Reset Flag wird gelöscht
  // start timed sequence
  WDTCSR |= (1<<WDCE) | (1<<WDE);     //   WDE Watchdog enable, WDCE Watchdog Change Enable (must be set by prescaler use)
  // set new watchdog timeout value
  WDTCSR = bb;     // ??
  WDTCSR |= (1<<WDIE);      // Watchdog Timeout INT enable
}
 
// Watchdog Interrupt Service / is executed when watchdog timed out
ISR(WDT_vect) {
  f_wdt=true;  // set global flag
}
Das Programm ist gut kommentiert, die entsprechenden Initialisierungen des Sleep Mode sind ziemlich übersichtlich.

Reinhard
Logged

Pages: [1]   Go Up
Jump to: