Grüßt euch,
ich wollte gerade eine einfach Interrupt-Routine in C programmieren,
jedoch will der uC nicht so wie ich :/
Ausgangssituation:
An Port D0 ist ein Signalgeber angeschlossen. An Port D3 (INT0) und Port
D4 (INT1) ist jeweils ein Schalter gegen Vcc angeschlossen. Bei einer
Flanke an einem der beiden Interrupt-Anschlüssen, soll nun die Methode
alarm() ausgeführt werden.
1
#include<avr/io.h>
2
#include<util/delay.h>
3
#include<avr/interrupt.h>
4
5
voidalarm()
6
{
7
for(intk=0;k<5;k++){
8
for(inti=0;i<500;i++){
9
PORTD=0x00;
10
_delay_ms(10);
11
PORTD=0x01;
12
_delay_ms(10);
13
}
14
_delay_ms(500);
15
}
16
17
}
18
19
intmain(void)
20
{
21
sei();
22
23
// Set Port D0 pin as output
24
DDRD=0x01;
25
26
while(1){
27
}
28
29
return1;
30
}
31
32
ISR(INT0_vect)
33
{
34
//_delay_ms(5000);
35
alarm();
36
}
37
38
39
ISR(INT1_vect)
40
{
41
//_delay_ms(15000);
42
alarm();
43
}
Hab ich was vergessen oder warum funktioniert das nicht?
PS: Die Ports haben alle einen Pull-Up Widerstand. Muss ich dann die
Schalter der Interrups mit GND verbinden, dass eine Flanke entsteht?
Vielen Dank schonmal für eure Hilfe!
Grüße Sebastian
SeppElek schrieb:> int main(void)> {> sei();>> // Set Port D0 pin as output> DDRD = 0x01;>> while(1) {> }>> return 1;> }> Hab ich was vergessen oder warum funktioniert das nicht?
Ähm.
Im µC gibt es viele Interrupt Quellen.
Wenn du eine benutzen willst, dann musst du die Quelle dafür auch
freigeben.
sei ist ein Rundumschlagschalter, mit dem alle überhaupt möglichen
Interrupts unterdrückt bzw. eigentlich freigegeben werden. Das hat aber
ncihts damit zu tun, dass man einer INterruptquelle selber auch die
Freigabe erteilen muss.
PS:
Schalter, der nach Vcc schaltet ist eine ganz schlechte Idee.
Da muss man dann einen externen Pulldown Widerstand an den Pin
anschliessen.
Würde man den Schalter anders rum verdrahten (schaltet nach GND), dann
könnte man den internen Pullup Widerstand benutzen.
Taster oder Schalter über Interrupts abzufragen ist auch keine so gute
Idee. Reines Polling reicht da dicke.
AVR-TutorialAVR-GCC-Tutorial
> Hab ich was vergessen oder warum funktioniert das nicht?
Ja, vergessen hast du die komplette Initialisierung der beiden
Interrupts INT0 und INT1. Ohne Schaltplan und AVR-Typ ist es schwer, da
genauer etwas zu schreiben.
Die lange Funktion alarm() aus den ISR heraus zu starten ist
gewöhnungsbedürfig. Du musst bedenken, dass während eine ISR
abgearbeitet wird andere ISRs gesperrt sind! Deine Variante alarm()
aufzurufen zählt als innerhalb der ISR. Üblicher ist eher diese Art der
Programmierung mit einem globalen Flag:
Helfer schrieb:> Ja, vergessen hast du die komplette Initialisierung der beiden> Interrupts INT0 und INT1. Ohne Schaltplan und AVR-Typ ist es schwer, da> genauer etwas zu schreiben.
Der uC ist ein Atmel ATtiny88, Schaltplan ist im Anhang. Was genau muss
ich denn bei den externen Interrupts initialisieren? Bei
Timer-Interrupts ist klar, da gibts ja einiges zu initialisieren. Aber
bei den externen..?
Danke für eure Antworten!
> Was genau muss ich denn bei den externen Interrupts initialisieren?
Zum Beispiel musst du die Interrupt Enable Maske passend für die beiden
Interrupts setzen, damit die auch berücksichtigt werden. Und du musst
dich entscheiden auf was die Interrupts reagieren sollen. Also auf LOW
Pegel, Pegelwechsel, steigende Flanke oder fallende Flanke. Das sind
beim Atmega88 zwei Register EIMSK und EICRA mit ihren entsprechenden
Bits, die im Datenblatt im Abschnitt 12. External Interrupts beschrieben
sind.
Im Schaltplan hast du ja die beiden Pins zu INT0 und INT1 universell zu
der Klemme gezogen. Ohne externe Pull-up oder Pull-Down widerstände, die
einen Ruhepegel festlegen. Kann man machen, wenn das Bauteil an der
Klemme von allein saubere Logikpegel ausgibt. Wenn dort nur ein Taster
oder ein Transistorschalter fehlt da noch was. OK, man kann durch die
internen Pull-ups externe ersetzen, aber das wäre z.B. auch ein Teil der
Initialisierung.
Okay, also die Daten zur Initialisierung hab ich im Datenblatt gefunden
und auch angewandt. Zu meiner Schande muss ich allerdings zugeben, dass
ich es einfach nicht hinbekommen habe :/
Auch beim nächsten Versuch, das Problem per pollying zu lösen, scheitere
ich kläglich :/
1
voidalarm()
2
{
3
for(intk=0;k<5;k++){
4
for(inti=0;i<500;i++){
5
PORTD&=(0<<6);
6
_delay_ms(10);
7
PORTD|=(1<<6);
8
_delay_ms(10);
9
}
10
_delay_ms(2000);
11
}
12
}
13
14
intmain(void)
15
{
16
17
// PortD6 (Buzzer) output, alles andere input
18
DDRD=0x40;
19
20
while(1){
21
if(PORTD2==1){
22
alarm();
23
}
24
}
25
26
return1;
27
}
Die Methode alarm() in der while-Schleife wird einfach nie ausgefüht,
obwohl PortD2 zu Vcc verbunden wurde. Kann mir hier jemand helfen? :-$
SeppElek schrieb:> Auch beim nächsten Versuch, das Problem per pollying zu lösen, scheitere> ich kläglich :/AVR-GCC-Tutorial
Ist weiter oben schon mal gefallen.
> while(1) {> if (PORTD2==1) {
Autsch!
Das sidn Grundlagen. Umsomehr: Blick ins AVR-GCC-Tutorial
Hab die zweite Lösung nun übernommen, jedoch kommt es mir so vor, als
wäre der interne Pull-Up Widerstand defekt. Denn sobald ich den Schalter
einmal umgelegt habe, führt er alarm() aus, wenn ich ihn zurück schalte,
hört er aber nicht auf. Also sprich: PIND2 bleibt auf GND.
Der Pull-Up Widerstand wurde mit
1
PORTD|=(1<<PD2);
aber korrekt aktiviert, oder nicht?
1
#include<avr/io.h>
2
#include<util/delay.h>
3
4
voidalarm()
5
{
6
for(intk=0;k<1;k++){
7
for(inti=0;i<500;i++){
8
PORTD&=(0<<6);
9
_delay_ms(10);
10
PORTD|=(1<<6);
11
_delay_ms(10);
12
}
13
_delay_ms(2000);
14
}
15
16
_delay_ms(5000);
17
}
18
19
intmain(void)
20
{
21
22
// PortD6 (Buzzer) output, alles andere input
23
DDRD|=(1<<PD6);
24
25
PORTD|=(1<<PD2);
26
27
28
while(1){
29
if(!(PIND&(1<<PD2))){
30
alarm();
31
}
32
}
33
34
return1;
35
}
Tut mir nochmals leid, dass ich euch zur späten Stunde mit meinen
Anfängerfragen quälen muss :/
> PORTD &= (0<<6);
So löscht mein kein einzelnes Bit. Gratulation, damit hast du gerade den
Pullup ausgeschaltet.
Tu dir selbst einen Gefallen und schau ins AVR-GCC-Tutorial !
Es macht nicht wirklich Sinn, wenn wir dir hier das Tutorial in Auszügen
noch einmal vorbeten müssen nur weil du selbst nicht nachlesen willst.
PORTD &= ~(1<<6);