Forum: Mikrocontroller und Digitale Elektronik Pin-Change-Interrupt/ATmega328p


von Felix (Gast)


Lesenswert?

Hallo, Ich habe folgendes Problem: Ich habe eine ATmega328p und habe an 
den PINS PINB0,PINB1,PIND6,PIND7 jeweils einen Taster gegen Masse 
hängen.Wenn ich jetzt einen der Taster betätige, soll eine LED leuchten. 
Wenn ich ihn ein zweites mal betätige, soll die LED wieder ausgehen. (Es 
ist übrigens immer die gleiche LED (1 Stück) zu testzwecken).
Wenn ich die Taster von PINB0 oder PINB1 drücke, dann funktioniert alles 
klaglos. Wenn ich allerdings die Taster von PIND6 oder PIND7 drücke, 
fängt meine LED nicht zu leuchten an. Wenn Sie aber, bevor ich einen der 
2 Taster von PORTD drücke, bereits eingeschalten ist, dann geht sie aus. 
Aber wie gesagt, ich kann sie nicht einschalten.
Hier ist mal mein Code...
Danke vielmals schon im Voraus,
1
#define F_CPU 8000000UL
2
#include <avr/io.h>
3
#include <util/delay.h>
4
#include <avr/interrupt.h>
5
 
6
 
7
 
8
void init_PinChangeInterrupts(void);
9
 
10
bool t1_pressed = false;
11
bool t2_pressed = false;
12
bool t3_pressed = false;
13
bool t4_pressed = false;
14
 
15
 
16
int main(void)
17
{
18
DDRD = 0b00100000;                                        //PIND5 = Ausgang für LED, PIND6 und PIND7 sind 2 Taster-Eingänge
19
DDRB = 0b00000000;                                        //PINB0 und PINB1 sind zwei weitere Taster-Eingänge
20
 
21
PORTB = (1<<PINB0) | (1<<PINB1);                        //Hier werden die PULLUPS aktiviert
22
PORTD = (1<<PIND6) | (1<<PIND7);                        //Hier werden die PULLUPS aktiviert
23
 
24
init_PinChangeInterrupts();                                //Hier werden die Interrupts initialisiert          
25
sei();                                                    //Aktivieren der Interrupts
26
                                                       
27
while (1);
28
}
29
 
30
 
31
ISR(PCINT0_vect)
32
{  
33
    if (!(PIND & (1<<PIND7)))                //Taster von PIND7 wurde gedrückt
34
    {
35
        if (t1_pressed == false)            //Wenn die LED zuvor ausgeschalten war
36
            {  
37
                PORTD |= (1<<PIND5);
38
                t1_pressed = true;
39
                _delay_ms(100);
40
            }
41
        else if (t1_pressed == true)        //Wenn die LED zuvor eingeschalten war
42
            {
43
                PORTD &= ~(1<<PIND5);
44
                t1_pressed = false;
45
                _delay_ms(100);
46
            }
47
    }
48
 
49
    if (!(PIND & (1<<PIND6)))                //Taster von PIND6 wurde gedrückt
50
    {
51
        if (t2_pressed == false)            //Wenn die LED zuvor ausgeschalten war
52
            {
53
                PORTD |= (1<<PIND5);
54
                t2_pressed = true;
55
                _delay_ms(100);
56
            }
57
        else if (t2_pressed == true)        //Wenn die LED zuvor eingeschalten war
58
            {
59
                PORTD &= ~(1<<PIND5);
60
                t2_pressed = false;
61
                _delay_ms(100);
62
            }
63
    }
64
 
65
    if (!(PINB & (1<<PINB0)))                //Taster von PIND6 wurde gedrückt
66
    {
67
        if (t3_pressed == false)            //Wenn die LED zuvor ausgeschalten war
68
            {
69
                PORTD |= (1<<PIND5);
70
                t3_pressed = true;
71
                _delay_ms(100);
72
            }
73
        else if (t3_pressed == true)        //Wenn die LED zuvor eingeschalten war
74
            {
75
                PORTD &= ~(1<<PIND5);
76
                t3_pressed = false;
77
                _delay_ms(100);
78
            }
79
    }
80
 
81
    if (!(PINB & (1<<PINB1)))                //Taster von PINDB1 wurde gedrückt
82
    {
83
        if (t4_pressed == false)            //Wenn die LED zuvor ausgeschalten war
84
            {  
85
                PORTD |= (1<<PIND5);
86
                t4_pressed = true;
87
                _delay_ms(100);
88
            }
89
        else if (t4_pressed == true)        //Wenn die LED zuvor eingeschalten war
90
            {
91
                PORTD &= ~(1<<PIND5);
92
                t4_pressed = false;
93
                _delay_ms(100);
94
            }
95
    }
96
}
97
 
98
void init_PinChangeInterrupts(void)
99
{
100
    PCICR  |= (1<<PCIE2) | (1<<PCIE0);            //Die Pins 23 bis 16 werden als Interrupts hergenommen, als auch die pins 0 bis 7
101
    PCMSK2 |= (1<<PCINT23) | (1<<PCINT22);        //Hier werden die Interrupts für die jeweiligen Pins enabled
102
    PCMSK0 |= (1<<PCINT0) | (1<<PCINT1);        //Hier das gleiche wie obige Zeile
103
}

von Einer K. (Gast)


Lesenswert?

Solange der AVR nicht schlafen soll, dürfte PinChange die falsche Kanone 
sein.

von Max M. (jens2001)


Lesenswert?

Felix schrieb:
> #include <util/delay.h>

Wenn ich das lese geht bei mir die Warnlampe an und ich suche nur noch 
nach...

Felix schrieb:
> ISR(PCINT0_vect)
> ...
> _delay_ms(100);

Hast du mal irgend ein HowTo zum Thema Interuptprogramierung gelesen?

von Matthias (Gast)


Lesenswert?

Wie (um Himmels willen) kommt man auf die Idee "_delay_ms()" in einer 
ISR zu verwenden? Ist Dir der Sinn und Zweck einer ISR bekannt?

Wenn das Programm nix anderes tut, als ein paar Taster abzufragen, dann 
kannst Du Dir die Interrupts sparen und das gleich per "polling" lösen.
Dann kannst Du auch die delay-Funktion verwenden.

Bei deinem Code würde es mich wundern, wenn es überhaupt tut und der uC 
nicht beim Drücken der "falschen" Taste einen Reset ausführt.
Dir fehlt mindestzens ein ISR(PCINT2_vect) Block mit den entsprrechenden 
Tasten drin. Die 8-Bit AVR haben für jeden PORT[A,B,C,....] einen 
eigenen "Sammel-IRQ" für Pinchange. Daher brauchst Du auch für jeden 
Port eine ISR.

Der Compiler, den ich normalerweise verwende, hat für alle IRQs, für die 
keine ISR definiert wurde eine Dummy-Funktion, die zu einem Reset führt.
Glaub der AVR-GCC macht das ähnlich (hab mit dem schon lange nix mehr 
gemacht).

von Felix (Gast)


Lesenswert?

Supi, danke Matthias, hat echt geholfen, hab nicht daran gedacht, dass 
jeder Port über eine extra ISR-Routine verfügt...Ps: Das mit dem Delay 
in der ISR hab ich nur zu Testzwecken drinnen, wollte damit eigentlich 
Tasterprellen verhindern.
Danke vielmals, LG

von Andreas H. (ahz)


Lesenswert?

Felix schrieb:
> Ps: Das mit dem Delay
> in der ISR hab ich nur zu Testzwecken drinnen, wollte damit eigentlich
> Tasterprellen verhindern.

Das einzige was man so testet ist die Widerstandsfägigkeit der Tastatur 
gegen Reinbeissen.

Rule of thumb: Deine ISR's solletn so wenig Zeit verbrauchen wie irgend 
möglich. Denn IN der ISR werden neue IRQs evtl. anders behandelt als in 
der normalen Programmausführung. Und die dabei entstehenden Fehler sind 
schwer zu debuggen.

/regards

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.