Hallo in die Runde,
ich möchte euch gleich warnen.... ich bin noch absoluter Anfänger!! Ich
hoffe Ihr habt dafür Verständnis ;-)
Mein Ziel ist es mit einem PIR-Sensor Funksteckdosen zu schalten, dies
funktioniert auch ohne Probleme allerdings ist der Stromverbrauch doch
recht hoch ohne den Sleep-Modus und genau hier ist auch mein Problem,
ich bekomme den Attiny85 leider nicht mehr aus dem Schlaf-Modus.
Hier mal mein bisheriger Code:
1
include <avr/sleep.h>
2
#include <avr/power.h>
3
#include <RCSwitch.h>
4
RCSwitch mySwitch = RCSwitch();
5
6
void setup()
7
{
8
mySwitch.enableTransmit(3);
9
mySwitch.setPulseLength(320);
10
pinMode(bewegung, INPUT);
11
attachInterrupt(0, interrupt, RISING);
12
}
13
14
void loop()
15
{
16
bewegungsstatus = digitalRead(bewegung);
17
18
if (status != bewegungsstatus)
19
{
20
21
if (bewegungsstatus == HIGH)
22
{
23
mySwitch.send(4433, 24);
24
delay(500);
25
status = bewegungsstatus;
26
enterSleep();
27
}
28
29
else
30
{
31
mySwitch.send(4436, 24);
32
delay(500);
33
status = bewegungsstatus;
34
enterSleep();
35
}
36
}
37
}
38
39
void interrupt() {
40
//leere Interruptfunktion
41
}
42
43
void enterSleep(){
44
set_sleep_mode(SLEEP_MODE_PWR_DOWN); //festlegen des Schlafmoduses
45
sleep_enable(); //ermoeglichen der angegebenen Schlaffunktion
46
sleep_mode(); //starten der Schlaffunktion
47
//hier geht es nach dem Interrupt weiter
48
sleep_disable(); //deaktivieren der Schlaffunktion
49
power_all_enable(); //reaktivieren aller Chips/Funktionen
50
}
Der Bewegungssensor gibt einen HIGH ab sobald er eine Bewegung
feststellt. Dieser sollte doch eigentlich den Attiny85 wieder aus dem
schlaf holen (Dachte ich jedenfalls).
Der Data Pin des Bewegungs- Sensor liegt am Pin2 des Attinys. Ein
"Schaltplan" habe ich hier im Anhang
Hat jemand noch mal einen Tipp oder eine Idee woran es liegen kann?
Viele Grüße
Torsten
Soweit ich das sehe, musst du noch Interrupts Global aktivieren mit
sei();
Ich weiß aber nicht, ob eine deiner Libraries das nicht schon macht,
dann hättest einen andren Fehler noch drin.
Danke für die Antworten
S. Landolt schrieb:> Ich verstehe nicht viel von alledem, aber:>> //hier geht es nach dem Interrupt weiter> Wo wird dieser zugelassen?
Ich dachte mit "attachInterrupt(0, interrupt, RISING);" wird dies
zugelassen.... bin mir da aber auch nicht sicher. :-(
Jan H. schrieb:> Soweit ich das sehe, musst du noch Interrupts Global aktivieren mit> sei();>> Ich weiß aber nicht, ob eine deiner Libraries das nicht schon macht,> dann hättest einen andren Fehler noch drin.
Muss ich das im Setup Bereich machen? Sorry für die Fragen.
Viele Grüße
Torsten
...weitere Fragestellungen deren Antworten du dir selber sehr gut über
das WWW beantworten kannst sind:
- du verwendest du Arduine IDE: unsterstützt diese den ATtiny korrekt?
(im Sinne von Pinzuordnung)
- das Datenblatt vom ATtiny hast du studiert? INT-ports sind PB0 bis
PB2, das sind die Pinne 5, 6 und 7 physikalisch.
- weißt du, was deine Zeile "attachInterrupt(0, interrupt, RISING);"
macht? Und viel wichtiger, welcher pyhsikalische Pin sich hinter der "0"
verbirgt?
Hallo,
CBF schrieb:> Noch eine dumme Frage: der Code läuft tatsächlich auf dem 85er und nicht> auf dem im Schaltbild gezeigten Arduino-board?
Der Adruino dient hier nur als Stromversorgng
CBF schrieb:> Torsten W. schrieb:>> pinMode(bewegung, INPUT);>> Wer oder was ist "bewegung"? Hier fehlt eine Deklaration.
Stimmt, ich habe leider die Deklaration vergessen. Sorry!
int bewegung = 2;
int bewegungsstatus = 0;
int status = 0;
"pinMode(bewegung, INPUT);" soll auf Pin zwei
CBF schrieb:> - das Datenblatt vom ATtiny hast du studiert? INT-ports sind PB0 bis> PB2, das sind die Pinne 5, 6 und 7 physikalisch
Das ist gar nicht so einfach... leider gab es zur meiner Schulzeit kein
Englisch und somit ist dies mehr schlecht als recht... Ich werde aber da
noch mal einen tieferen Blick drauf werfen müssen.
Wenn ich es richtig verstanden habe müsste
*PB0 = PCINT0 = physikalisch 5
*PB1 = PCINT1 = physikalisch 6
*PB" = PCINT2 = physikalisch 7
sein, oder?
CBF schrieb:> - weißt du, was deine Zeile "attachInterrupt(0, interrupt, RISING);"> macht?
Wenn ich es richtig verstanden habe geht es hier um den Pin PB0 = PCINT0
= physikalisch 5 dieser springt zum void interrupt () wenn der Pin 5
Volt Eingang bekommt?
Bitte korrigiere mich wenn was nicht stimmt
CBF schrieb:> Und viel wichtiger, welcher pyhsikalische Pin sich hinter der "0"> verbirgt?
Das müsste ja Pin 5 sein wenn ich es oben richtig verstanden habe.
CBF schrieb:> du verwendest du Arduine IDE: unsterstützt diese den ATtiny korrekt?> (im Sinne von Pinzuordnung)
Das muss ich jetzt erst mal weiter testen und suchen.
Vielen Dank schon mal für eure Hilfe.... das bringt mich doch schon ein
Stück weiter.
VG
Torsten
PS: Gibt es ein gute Anleitung auf Deutsch? Ich habe bis jetzt leider
noch nicht wirklich was gefunden.
CBF schrieb:> - das Datenblatt vom ATtiny hast du studiert?
Und du?
> INT-ports sind PB0 bis> PB2, das sind die Pinne 5, 6 und 7 physikalisch.
Beim Tiny85 ist jeder Pin interruptfähig. PCINT0..5, wobei PCINT5
natürlich erst nutzbar wird, wenn man den Reset-Pin zu einem IO-Pin
umgefused hat.
Und was die "klassischen" INTx betrifft: davon hat der Tiny85 nur genau
einen, INT0. Und der liegt auf dem gleichen physischen Pin wie
PCINT2/PB2, also auf Pin7.
Hast du irgendwo deklariert, welche Pins als Interrupt gebraucht werden?
Im Register GIMSK musst du das PCIE-Bit setzen. Sonst sind die
Interrupts ausgeschaltet.
Kämpf dich mal durch all die Register(ab Seite 51 des Datenblattes) und
siehe, welche du alles benötigst.
Hallo,
die normalen Interrupts beziehen sich meines Wissens nur auf die
Hardwareinterruts, PinChange muß man selber einbinden (mal nach googlen,
falls sich das geändert hat).
Beim Tiny85 wäre das also nur PB2 (Pin7), in der ArduinoIDE gemappt auf
Pinnummer 2.
// ATMEL ATTINY45 / ARDUINO
//
// +-\/-+
// Ain0 (D 5) PB5 1| |8 Vcc
// Ain3 (D 3) PB3 2| |7 PB2 (D 2) Ain1
// Ain2 (D 4) PB4 3| |6 PB1 (D 1) pwm1
// GND 4| |5 PB0 (D 0) pwm0
// +----+
Hänge also Deinen Sensor an 2 (PB2, Pin 7), dann müßte es klappen.
Gruß aus Berlin
Michael
Deine gezeigte Irq-Routine ist leer. Bei mir wird der Attiny85
periodisch geweckt über den watchdog-timer. Die zugehörige Irq-routine
sieht dann so aus:
ISR(WDT_vect){ // watchdog interrupt service routine
sleep_disable(); // wakeup!
WDTCR |= (1<<WDIE); // wdt irq re-enable = avoid reset
}
avr schrieb:> Avrs kann man im Powerdown nur durch lowlevel Interrupts wecken. Dein> Sensor kann den avr also gar nicht wecken.
Der INT0 und Pin Change Interrupt gehört dazu. Kannst du unter dem
Kapitel "Power Management and Sleep modes" im Datenblatt nachlesen.
Aus dem Datenblatt:
TM F. schrieb:> avr schrieb:>> Avrs kann man im Powerdown nur durch lowlevel Interrupts wecken. Dein>> Sensor kann den avr also gar nicht wecken.>> Der INT0 und Pin Change Interrupt gehört dazu. Kannst du unter dem> Kapitel "Power Management and Sleep modes" im Datenblatt nachlesen.
Ich dachte avr hätte von sich selbst gesprochen.
TM F. schrieb:> avr schrieb:> Avrs kann man im Powerdown nur durch lowlevel Interrupts wecken. Dein> Sensor kann den avr also gar nicht wecken.>> Der INT0 und Pin Change Interrupt gehört dazu.
Der int0 Interrupt muss trotzdem ein Level Interrupt sein. Wenn
AttachInterrupt diesen nutzt kann es mit rising nicht funktionieren.
> Kannst du unter dem> Kapitel "Power Management and Sleep modes" im Datenblatt nachlesen.
Ja Schlaumeier, das mit dem levelinterrupt solltest du vielleicht auch
noch mal nachlesen. Das ist wahrscheinlich hier das Problem.
> Aus dem Datenblatt:Only an External Reset, a Watchdog Reset, a Brown-out> Reset, USI start condition> interupt, an external level interrupt on INT0 or a pin change interrupt> can wake up the MCU.
Naja meine Zeit mit den avrs ist schon etwas her. Die tinys haben wohl
mehr Möglichkeiten als der atmega48. Auf diesen trifft meine Aussage zu.
Der Levelinterrupt wird nur gebraucht, wenn PB2 explizit als INT0
verwendet wird. Wird PB2 als "normale" I/O gebraucht, fährt der uC aus
dem Sleep-Mode hoch, wenn ein Interrupt kommt.
Oder sehe ich etwas falsch?
Hallo,
erst mal vielen Dank für die vielen Antworten. Das hat mir schon mal
sehr viel weiter geholfen.
Ich habe meinen Code ein wenig "Vereinfacht"
1
#include <avr/sleep.h>
2
#include <avr/power.h>
3
#include <avr/interrupt.h>
4
5
int bewegung = 0;
6
int interrupta = 2;
7
8
// the setup function runs once when you press reset or power the board
9
void setup() {
10
11
pinMode(3, OUTPUT); //für die LED
12
pinMode(bewegung, INPUT);
13
14
15
// the loop function runs over and over again forever
16
void loop() {
17
for (int i=0; i<5; i++){
18
digitalWrite(3, HIGH); // turn the LED on (HIGH is the voltage level)
19
delay(1000); // wait for a second
20
digitalWrite(3, LOW); // turn the LED off by making the voltage LOW
21
delay(1000); // wait for a second
22
}
23
enterSleep();
24
}
25
26
void enterSleep(){
27
attachInterrupt(0,interrupt, LOW); //PIR Sensor an PIN2
28
set_sleep_mode(SLEEP_MODE_PWR_DOWN); //festlegen des Schlafmoduses
29
sleep_enable(); //ermoeglichen der angegebenen Schlaffunktion
30
sleep_mode(); //starten der Schlaffunktion
31
//hier geht es nach dem Interrupt weiter
32
sleep_disable(); //deaktivieren der Schlaffunktion
33
power_all_enable(); //reaktivieren aller Chips/Funktionen
34
}
35
36
void interrupt() {
37
detachInterrupt(0);
38
}
Michael U. schrieb:> Hänge also Deinen Sensor an 2 (PB2, Pin 7), dann müßte es klappen.
Ja, endlich ein Licht am Ende des Tunnels :-) Sobald der Bewegungsmelder
keine Bewegung mehr erkennt (also von HIGH auf LOW geht) wacht mein
Attiny85 wieder auf und die LED blinkt 5 mal. Danach legt er sich wieder
schlafen... Jetzt wacht er allerdings nicht wieder auf :-(
1
attachInterrupt(0,interrupt, CHANGE);
funktioniert leider nicht.
Wie bekomme ich jetzt den Attiny85 wieder wach wenn er eine Bewegung
erkennt (also von LOW auf HIGH wechselt)
avr schrieb:> Avrs kann man im Powerdown nur durch lowlevel Interrupts wecken.
Sei mir bitte nicht böse aber ich hoffe du hast nicht recht auch wenn es
im Moment nicht danach aussieht. Dann wären einige Stunden in den Sand
gesetzt.
TM F. schrieb:> Der Levelinterrupt wird nur gebraucht, wenn PB2 explizit als INT0> verwendet wird. Wird PB2 als "normale" I/O gebraucht, fährt der uC aus> dem Sleep-Mode hoch, wenn ein Interrupt kommt.
Sorry, das verstehe ich (noch) nicht. Was meinst du damit?
Ich hoffe Ihr habt noch ein paar Ideen für mich und könnt mich noch ein
Stück weiterbringen
Viele Grüße
Torsten
PCMSK |= (1<<PB2); // enable PB2 which PCINT2 is on
20
//sei(); // set Enable Interrupts
21
}
22
23
// the loop function runs over and over again forever
24
void loop() {
25
for (int i=0; i<5; i++){
26
digitalWrite(3, HIGH); // turn the LED on (HIGH is the voltage level)
27
delay(1000); // wait for a second
28
digitalWrite(3, LOW); // turn the LED off by making the voltage LOW
29
delay(1000); // wait for a second
30
}
31
enterSleep();
32
}
33
34
35
void enterSleep(){
36
set_sleep_mode(SLEEP_MODE_PWR_DOWN); //festlegen des Schlafmoduses
37
sleep_enable(); //ermoeglichen der angegebenen Schlaffunktion
38
sleep_mode(); //starten der Schlaffunktion
39
//hier geht es nach dem Interrupt weiter
40
sleep_disable(); //deaktivieren der Schlaffunktion
41
power_all_enable(); //reaktivieren aller Chips/Funktionen
42
}
43
44
void interrupt() {
45
//nichts
46
}
TM F. schrieb:> ISR(PCINT0_vect)> {> // Deine Interruptroutine> }
Bei mir funktioniert es erstaunlicherweise ohne. Könnt ihr mir bitte
noch erklären was hier üblicherweise rein kommt bzw. Ist die die Routine
die direkt nach dem Interrupt ausgeführt wird?
Vielen Dank an alle für die Geduld und die super Hilfe
Gruß
Torsten
Torsten W. schrieb:> vielen lieben Dank an alle, es funktioniert jetzt so wie es soll! :-)
Das tut's aber auch nur, weil Arduino einen Timer mit ISR für millis()
uind delay() aufsetzt und deswegen Interrupts global einschaltet. Sonst
würde ein sei() am Anfang fehlen.
> Bei mir funktioniert es erstaunlicherweise ohne.
Üblicherweise zeigen in C die Interruptvektoren von nicht deklarierten
ISRs auf einen bad vector, der, falls nicht anders bestimmt, einen Reset
auslöst. Kann einfach sein, dass Du den Reset nicht bemerkst.
Für eine leere ISR gibt's sowas:
EMPTY_INTERRUPT (PCINT0_vect);
Da dürfte dann ein RETI in der IVT stehen.
Torsten W. schrieb:> TM F. schrieb:>> ISR(PCINT0_vect)>> {>> // Deine Interruptroutine>> }>> Bei mir funktioniert es erstaunlicherweise ohne. Könnt ihr mir bitte> noch erklären was hier üblicherweise rein kommt bzw. Ist die die Routine> die direkt nach dem Interrupt ausgeführt wird?
Üblicherweise kommt da rein die Deaktivierung des Interrupts, der zum
Erwachen führen soll (und in der Folge erstmal zu nichts mehr). Nötig
wird das i.A. bei prellenden mechanischen Kontakten oder bei
Level-getriggertem Interrupt.
Die ISR selber ist aber natürlich unbedingt nötig, denn sie wird
tatsächlich als erstes nach dem Aufwachen durchlaufen.
Fehlt sie, kommt's auf die Laufzeitumgebung an, was passiert. Beim gcc
wird also letztlich Adresse 0 angesprungen, das ganze Programm startet
also neu, fast wie nach PowerOn.
Aaaaber: es hat kein echter Reset stattgefunden, d.h.: im ersten Lauf
initialisierte Hardware bleibt initialisiert und könnte u.U. über daran
gekoppelte ISRs "erstaunliche" Folgeschäden nach dem Aufwachen
verursachen.
Wenn du also noch alle Latten am Zaun hast, gönnst du deinem Programm
wenigstens die leere ISR. Zumindest bis du das Ganze wirklich im Schlaf
in Assembler beherrschst (was voraussichtlich niemals passieren wird...)
Torsten W. schrieb:>> Der Levelinterrupt wird nur gebraucht, wenn PB2 explizit als INT0>> verwendet wird. Wird PB2 als "normale" I/O gebraucht, fährt der uC aus>> dem Sleep-Mode hoch, wenn ein Interrupt kommt.>> Sorry, das verstehe ich (noch) nicht. Was meinst du damit?
Der Levelinterrupt bedeutet, dass wenn deine Eingangsspannung einen
festen Referenzwert(ca. 1,1V, siehe Datenblatt) überschreitet wird ein
Interrupt ausgelöst.
Ein "normaler" I/O löst einen Interrupt aus, wenn das Eingangssignal das
Level eines logischen 1 (oder 0, je nach Konfiguration) erreicht hat.