Attiny84 Power Saving Interrupt Problem

Hallo in die Runde!

An einem Attiny84 verwende ich 5 Buttons. Beim betätigen eines Buttons sende ich über ein 433 MHz Modul eine entsprechende Information. Das ganze funktioniert wundern. Leider musste ich feststellen, dass der Attiny gute 5 bis 6 mA zieht. Da das ganze mal als batteriebetriebene Fernbedienung ausgelegt werden soll, ist der Verbrauch viel zu hoch.

Meine Vorstellung ist, dass der Attiny schläft und beim drücken eines Buttons kurz aufgeweckt wird, seine Information sendet und wieder schläft.

Das power Saving habe ich folgendermaßen umgesetzt. Testweise habe ich erstmal nur einen Button als Interrupt eingebracht. Beim Kompilieren erhalte ich jedoch folgenden Error:

“PCMSK was not declared in this scope”.

Geflasht wird der Attiny84 über einen Arduino Nano.

Hier mein Code. Kann einer weiterhelfen? ich bedanke mich schonmal recht herzlich :slight_smile:

#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <RCSwitch.h>

RCSwitch mySwitch = RCSwitch();

const long senderId = 55412;
const int rxPin = 6;
const int pinReset = 5;
const int pinButtonOK = 4;
const int pinButtonC1 = 3;
const int pinButtonC2 = 2;
const int pinButtonC3 = 1;
long sendData = 0;
const int pinLED = 7;

void setup() {
  mySwitch.enableTransmit(rxPin);
  pinMode(pinReset, INPUT);
  pinMode(pinButtonOK, INPUT);
  pinMode(pinButtonC1, INPUT);
  pinMode(pinButtonC2, INPUT);
  pinMode(pinButtonC3, INPUT);
  pinMode(pinLED, OUTPUT);
  digitalWrite(pinLED, LOW);
}

void sleep() {

    GIMSK |= _BV(PCIE);                     
    PCMSK |= _BV(PCINT4);                  
    ADCSRA &= ~_BV(ADEN);                   
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);    

    sleep_enable();                         
    sei();                                  
    sleep_cpu();                           

    cli();                                 
    PCMSK &= ~_BV(PCINT4);                  
    sleep_disable();                        
    ADCSRA |= _BV(ADEN);                    

    sei();                                  
    } // sleep

ISR(PCINT0_vect) {
    // This is called when the interrupt occurs, but I don't need to do anything in it
    }

void loop() {

  if (digitalRead(pinReset) == HIGH) {
    digitalWrite(pinLED, HIGH);
    sendData = senderId * 100;
    sendData = sendData + 0;
    mySwitch.send(sendData, 24);
    digitalWrite(pinLED, LOW);
  } else if (digitalRead(pinButtonOK) == HIGH) {
    digitalWrite(pinLED, HIGH);
    sendData = senderId * 100;
    sendData = sendData + 1;
    mySwitch.send(sendData, 24);
    digitalWrite(pinLED, LOW);
  } else if (digitalRead(pinButtonC1) == HIGH) {
    digitalWrite(pinLED, HIGH);
    sendData = senderId * 100;
    sendData = sendData + 2;
    mySwitch.send(sendData, 24);
    digitalWrite(pinLED, LOW);
  } else if (digitalRead(pinButtonC2) == HIGH) {
    //digitalWrite(pinLED, HIGH);
    sendData = senderId * 100;
    sendData = sendData + 3;
    mySwitch.send(sendData, 24);
    digitalWrite(pinLED, LOW);
  } else if (digitalRead(pinButtonC3) == HIGH) {
    digitalWrite(pinLED, HIGH);
    sendData = senderId * 100;
    sendData = sendData + 4;
    mySwitch.send(sendData, 24);
    digitalWrite(pinLED, LOW);
  }

}

Hallo,

kennt deine IDE den ATtiny84 überhaupt?
Die Registernamen unterscheiden sich zwischen ATmega und ATtiny teilweise.
Und wo hast du den Code her?
Selbst mit Datenblatt geschrieben?
Oder von einer Arduino Seite? Dann würde das ersteres bestätigen.
Der Ablauf selbst ist gleich, nur die Namen sind anders und wenn du das aus der IDE heraus schreibst, dann muß diese den ATtiny kennen.
Tipp von combie: GitHub - damellis/attiny: ATtiny microcontroller support for the Arduino IDE
Möglicherweise sind die Namen der Interrupts Pins auch noch verschieden.
Weiß jetzt nicht ob und wie weit du das für den ATtiny angepaßt hast.

Und was meinst du mit Button 5?
Welche Pinnummer vom ATtiny84 ist das?

Hallo,

ja die Arduino IDE kennt meinen Attiny grundlegend. Ich verwende den arduino-attiny-core: Google Code Archive - Long-term storage for Google Code Project Hosting.

Das vorherige Programm ohne die Zeilen für das Power Saving konnte ich problemlos kompilieren und auf dem Attiny84 übertragen. Dabei verwende ich auch die "normale" Pinbezeichnung: Also z.B. D6 anstatt des physischen Pins.

Den Code zum Power Saving habe ich grundlegend von hier: ATTiny85 Wake from Sleep on Pin State Change Code Example | Big Dan the Blogging Man

Ich habe nur PCMSK |= _BV(PCINT3); zu PCMSK |= _BV(PCINT4); angepasst um Pin 9 (physisch) für den Interrupt zu nutzen.

Welche Pinbezeichnung wäre denn für den Attiny84 die richtige in meinem Fall? Wäre es sinnvoll statt dem arduino-attiny-core auf die von die verlinkte Bibliothek zu wechseln?

Gruß,
Tony

Habe ich was übersehen oder rufst du die Sleep-Funktion gar nicht auf? In deiner Loop müsste die If-Schleife einmal durchlaufen werden, und danach der Attiny wieder schlafen gelegt werden.

Wäre es sinnvoll statt dem arduino-attiny-core auf die von die verlinkte Bibliothek zu wechseln?

Das hilft dir bei den Registerbezeichnern nicht weiter.

Schau ins Datenblatt des Prozessors.
Da sind alle Register des Prozessors aufgelistet!
Zumindest die, die er hat.
z.B. "PCMSK0" und "PCMSK1".
(mannnnooo....)

Laut Datenblatt lese ich die von dir genannten Register "PCMSK0" und "PCMSK1" heraus für Interrupts (Punkt 9.2): http://www.atmel.com/images/doc8183.pdf

Jedoch ist mir nicht klar, wie ich den Code dazu jetzt anpassen muss.

ja die Arduino IDE kennt meinen Attiny grundlegend. Ich verwende den arduino-attiny-core: Google Code Archive - Long-term storage for Google Code Project Hosting.

Wenn du da rein schaust, siehst du, dass die pcint Dinger fein deklariert sind.
Wird also voll unterstützt. (soweit ich das erkennen kann)
http://playground.arduino.cc/Main/PinChangeInt

Okay, das mit PinChangeInt mag ja funktionieren, aber inwieweit hilft mir das bei meiner Fehlermeldung in Bezug auf das Power Saving weiter: "PCMSK was not declared in this scope". ?

aber inwieweit hilft mir das bei meiner Fehlermeldung in Bezug auf das Power Saving weiter: "PCMSK was not declared in this scope". ?

Hmmm...

Da du offensichtlich nicht aus dem Datenblatt, und auch nicht aus anderen Quellen herauslesen kannst, wie man diese Register setzt, dachte ich, ich biete dir eine Lib an, die das automatisch für dich im Hintergrund erledigt.

Leider kann ich dir nicht 100%ig garantieren, dass die Lib funktioniert.

Die Alternative wäre, dass ich dir das Datenblatt vorlese, und vielleicht in Deutsch übersetze. Nunja, dafür bin ich allerdings heute zu faul.

Ich denke ich hab es gefunden. Die Register heißen PCMSK0 und PCIE0.

Hallo,

ich versuch es mal.
Zuerst muß geklärt werden, was ist bei dir Pin 9 genau?

Laut Arduino Beschriftung wäre Pin 9 der IC Pin 3 welcher den Interruptnamen PCINT9 hat.
Hängt dort ein Quarz dran, dann wäre der nicht verwendbar.
Meinst du den IC Pin 9, dann lautet der Interruptname PCINT4. Das wäre Arduino Pin 4!
Ich nehme jetzt mal an du meinst letzteres?

Wenn du das geklärt hast, mußte 2 Register setzen.
Jetzt gehört PCINT4 zum Interrupt Trigger PCI0.
Darum mußte das GIMSK Register setzen mit

GIMSK |= (1<<PCIE0);

Damit wird nur festgelegt das die Gruppe der Interrupts von PCINT0 bis PCINT7 aktiviert werden. Damit später ein Interrupt Flag ausgelöst werden kann. Generell gesehen.
Und im PCMSK0 Register wird festgelegt welcher Interrupt von PCINT0 bis PCINT7 überhaupt abgefragt wird.

PCMSK0 |= (1<<PCINT4);

Der Interrupt Vector der bei eintreffen eines Interrupts aktiv wird lautet

ISR(PCINT4_vect)    // Interrupt Handler PCINT4
{
    
}

Wenn dir das alles zu umständlich ist, mußte die Arduino Komfort Variante verwenden wie von combie erwähnt. Und Spexx hatte schon erwähnt das du deine sleep Funktion gar nicht aufrufst. Vielleicht vergessen oder bewußt noch ausgeklammert. Auch wäre es vielleicht ratsam die gesamte Interrupt Geschichte alleine zu testen. Also mit schlanken Code ohne den “Sleep Kram”. Zum Verständnis entwickeln wie das funktioniert. Danach kannste sleep einbauen.

ISR(PCINT4_vect)

Nicht eher: ISR(PCINT0_vect) ?

Hier ist in der Mitte eine schöne Tabelle:
http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html

Hallo,

ja natürlich, richtig erkannt. :wink: Danke für die Korrektur.

ISR(PCINT0_vect)    // Interrupt Handler PCINT0 für PCINT7:0