hallo zusammen, ich suche den fehler in diesem code, den ich (möglichst
einfach) zum lernen mit Interrupts umzugehen geschrieben habe.
Es sollte passieren:
Blinken der led in ihrer 1. frequenz bis taster gedrückt wird, dann in
der 2., bis er erneut gedrückt wird (wieder die erste) usw.
es wird immer der erste teil der schleife ausgeführt, dh die led blinkt
immer in der selben frequenz.
wo ist der fehler?
irgendwie bekomme ich es nicht hin, eine globale bool variable über die
isr funktion zu verändern (siehe code) - auch wenn sie jetzt volatile
deklariert ist. was ich auch mache im code, die variable bleibt die
selbe.
kann mir da irgendjemand einen ansatz geben?
Wie löst du den PCINT0 aus?
Wenn mit einem Taster, dann denke daran, dass Taster prellen, d.h. du
bekommst nicht voraussagbar viele PCINT0s pro Tastendruck.
In diesem Fall würde ich mir zunächst einen prellfreien Digitaltaster
aufbauen, um die PCINT Funktionalität zu erforschen.
In der Praxis macht man i.d.R. keine Tastenauswertung mit einem externen
Interrupt, sondern nutzt ein Pollingverfahren per Software oder Timer
(s. Artikel entprellung). Die Ausnahme: Wecken des µC aus einem
Sleepmodus.
1
// Target: Attiny13 @ 9.6 MHz
2
// Debugstand: Simulation
3
#include<stdbool.h>
4
#include<stdlib.h>
5
#include<stdint.h>
6
7
#include<avr/io.h>
8
#include<avr/interrupt.h>
9
10
#define F_CPU 9.6E6
11
#include<util/delay.h>
12
13
volatileboolonoff1=1;// <===
14
volatileboolonoff2=0;// <===
15
16
ISR(PCINT0_vect)
17
{
18
if(onoff1)
19
{
20
onoff1=0;
21
onoff2=1;
22
}
23
else
24
{
25
onoff1=1;
26
onoff2=0;
27
}
28
}
29
30
voidblinken(uint8_tnum)
31
{
32
uint8_ti,j;
33
for(i=0;i<20;i++)
34
{
35
for(j=0;j<num;j+=50)
36
_delay_ms(50);
37
PORTB^=(1<<PB1);
38
}
39
}
40
41
intmain(void)
42
{
43
DDRB=(1<<PB1);// PB1 Ausgabe
44
45
GIMSK|=(1<<PCIE);
46
PCMSK|=(1<<PCINT0);
47
sei();
48
49
while(1)
50
{
51
if(onoff1)
52
blinken(50);
53
elseif(onoff2)
54
blinken(200);
55
else// !onoff1 && !onoff2 sollte nie erreicht werden!
hallo stefan
ja, den PCINT0 löse ich per taster aus, den ich hardwareentprellt habe
mit einem 33kohm widerstand und 0,33µF.
wie gut das funktioniert habe ich allerdings noch nicht mit dem oszi
angeschaut.
Um genau den sleepmodus geht es mir - ich möchte den µC über den selben
taster ein bzw ausschalten (dh in bzw aus dem sleepmode holen) - und
wollte das über eine boolvariable machen, die ich bei jeder
tasteraktivierung ändere - und damit in der main steuern, ob der
controller sleepen soll oder seine funktion ausführen.
wie würde man das denn (sonst) umsetzen?
grüße
Mit dem PCINT habe ich das noch nicht gemacht.
Mit dem INT0 Interrupt ist ein Beispiel im Wiki
http://www.mikrocontroller.net/articles/Sleep_Mode#Aufwachen_per_Tastendruck
und ich habe auf dem Pollin Board mit INT0 bei meinem Suppentimer
experimentiert
http://www.mikrocontroller.net/articles/Pollin_Funk-AVR-Evaluationsboard#Suppentimer
Das Prellen spielt dort keine Rolle, weil nur das einfache Wecken per
Interrupt implementiert wird. Dann ist es egal, ob die Wecktaste prellt.
Wach ist wach. Das Schlafenlegen kann dann mit einer regulären
Tasteneingabe oder mit einem Timeout (Suppentimer) gemacht werden.
Allerdings ist das Wecken per Interrupt auch empfindlich gegen
Spikes/Störungen auf der Leitung am Interruptpin. Man kann das
berücksichtigen indem man nach dem Wecken zusätzlich den Tastenzustand
pollt und wenn die Mindestgedrücktdauer nicht erfüllt ist direkt wieder
pennen geht.
ich wurde eben darauf aufmerksam gemacht, dass ich ja beim drücken des
tasters zwei pinchanges ausführe und damit meine boolvariablen danach
wieder genauso aussehen wie vorher.. logisch.
wie kann ich das verhindern? ich erinnere mich dunkel daran, dass man
irgendwo die flanke für den interrupt auswählen kann(?) oder anders?
ich bin auf dem gebiet noch seeeehr grün hinter den ohren...
Am einfachsten?
Du kannst den PCINT0 Pin abfragen, ob z.B. ein HIGH Pegel anliegt, d.h.
ein Wechsel von LOW nach HIGH der Auslöser war. Und nur dann die Aktion
machen.
> Du kannst den PCINT0 Pin abfragen, ob z.B. ein HIGH Pegel anliegt, d.h.> ein Wechsel von LOW nach HIGH der Auslöser war. Und nur dann die Aktion> machen.
Nachteil bzw. Beschränkung der Einfachmethode: Der Tastendruck muss
länger dauern als die Aufrufzeit der ISR, damit der Pegel innerhalb der
ISR noch ansteht und gemessen werden kann. Die Methode ist daher nix bei
sehr schnellen Signalen z.B. von Sensoren für eine Drehzahlmessung
War grad im Datenblatt des Attiny13 unterwegs. Dort sieht es so aus,
dass man beim PCINT nicht einstellen kann, auf welche Flanke reagiert
wird.
Das ist aber beim INT0 Interrupt möglich.
Wenn der Sleepmodus dazu kommt gilt weiter, dass nur bestimmte externe
Interrupts den µC aufwecken können und auch nur bestimmte Ereignisse wie
z.B. LOW Pegel am externen Interruptpin. Näheres im Datenblatt.