Forum: Mikrocontroller und Digitale Elektronik Atmega328P Interrupt löst dauerhaft aus


von Waldkauz (Gast)


Lesenswert?

Moin,

Ich bin gerade dabei meinen Controller für eine Rotierende Uhr(ähnlich 
einer Propeller-Clock) zu Programmieren. Zur ermittlung der Drehzahl 
nutze ich einen Hallsensor vom Typ A3144 und einen kleinen Magneten. Nun 
habe ich folgendes Problem: Der Interrupt löst solange aus, wie der 
Magnet über dem Sensor ist, obwohl ich eigentlich deklariert habe, dass 
er nur bei steigender Flanke auslösen soll. Anbei schicke ich mal die 
entsprechenden Passagen, vielleicht hat ja jemand von euch eine Idee.

Danke im voraus, Waldkauz

1
 #define F_CPU   16000000UL
2
3
#include <asf.h>
4
#include <avr/sfr_defs.h>
5
#include <avr/io.h>
6
#include <stdio.h>
7
#include <stdlib.h>
8
#include <inttypes.h>
9
#include <util/delay.h>
10
#include <avr/interrupt.h>
11
12
#define setbit(P,BIT)  ((P) |= (1<<(BIT)))    
13
#define clearbit(P,BIT)  ((P) &= ~(1<<(BIT)))  
14
15
int main (void)
16
{  
17
        MCUCR = 1<<ISC01 | 1<<ISC00;
18
  EIMSK |= (1 << INT0);
19
20
        while(testvariable == 1)
21
        {
22
        }
23
}
24
25
26
ISR(INT0_vect)
27
{
28
  setbit(PORTD, 7);
29
  _delay_ms(50);
30
  clearbit(PORTD, 7);
31
  _delay_ms(50);
32
}

von Waldkauz (Gast)


Lesenswert?

Bevor ich es vergesse: Ich habe schon die Spannung am Pin gemessen, die 
liegt wenn der Sensor auslöst bei ca. 0,1 Volt

von Peter II (Gast)


Lesenswert?

Waldkauz schrieb:
> vielleicht hat ja jemand von euch eine Idee.

ist es wirklich der echte code?

testvariable gibt es nicht. Nicht das wir einen Fehler suchen, der gar 
nicht da ist.

von Waldkauz (Gast)


Angehängte Dateien:

Lesenswert?

Ich hänge den echten code mal eben mit an, habe das jetzt mit der 
Testvariable so geschrieben, da die Hauotschleife funktioniert und nur 
der Interrupt probleme macht. Der Code ist auch nooch nicht wirklich 
aufgeräumt ^^

von Bastian W. (jackfrost)


Lesenswert?

Ohne sei(); werden auch keine Interrupte ausgeführt. Es fehlt auch das 
PD7 als Ausgang gesetzt wurde.Ist das dein ganzer Code ?

Gruß JackFrost

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Waldkauz schrieb:
> setbit(PORTD, 7);
>   _delay_ms(50);
>   clearbit(PORTD, 7);
>   _delay_ms(50);

Du kannst nicht ganze 100ms (eine ganze zehntel Sekunde) in der ISR() 
mit Nichtstun vertrödeln. Bis dahin tritt ja schon wieder der nächste 
Interrupt auf. Oder drehst Du den Propeller in Ultra-Zeitlupe? Delays in 
ISRs gehen zu 99% in die Hose.

Setze lediglich ein Flag in der ISR, toggle das Bit PD7 in der 
Hauptschleife. Am besten letzteres über einen Timer, denn auch das 
Warten einer ganzen zehntel Sekunde in der Hauptschleife hat meist 
weitere unerwünschte Nebeneffekte.

Merke:

Vermeide Delays. delay_ms() kann man ja mal für kleine Tests verwenden, 
wenn man weiß, was man tut. Praxistauglich ist es meistens nicht. 
delay_us() kann man in seltenen Fällen durchgehen lassen, wenn es sich 
um sehr kleine Zeitspannen handelt, wo man sowieso nichts zwischendurch 
zu tun hat. Aber sonst sind Flags und Timer die richtige Wahl. Dafür 
sind sie da.

: Bearbeitet durch Moderator
von Stefan P. (form)


Lesenswert?

Ersetze mal
MCUCR = 1<<ISC01 | 1<<ISC00;
durch
MCUCR = (1<<ISC01) | (1<<ISC00);

von Peter II (Gast)


Lesenswert?

Stefan P. schrieb:
> Ersetze mal
> MCUCR = 1<<ISC01 | 1<<ISC00;
> durch
> MCUCR = (1<<ISC01) | (1<<ISC00);

das dürfte es nicht sein. << bindest höher als |

von Thomas E. (thomase)


Lesenswert?

Waldkauz schrieb:
> MCUCR = 1<<ISC01 | 1<<ISC00;
Warum versuchst du die Interruptvektoren zu verbiegen? Klappt aber 
nicht, da es sich um eine "Timed Sequence" handelt. Stattdessen steht 
der Eingang auf Low Level und produziert solange Interrupts, bis der Pin 
auf High geht. Alles richtig also. Oder ein typischer Fall von 
Copy&Paste-Programmierung, ohne weiteres Nachdenken und Nichtbenutzung 
des Datenblattes.

Daß der Atmega328 kein GIMSK hat, hast du ja mittels Fehlermeldung des 
Compilers noch rausgefunden. Nur liefert das vorhandene MCUCR natürlich 
keine Fehlermeldung. Leider hat es eine vollkommen andere Bedeutung.

Guck ins Datenblatt unter Register Description bei den Externen 
Interrupts.

Kleiner Tip: Dein Freund heißt EICRA.

: Bearbeitet durch User
von Waldkauz (Gast)


Lesenswert?

Danke Thomas, das war der Fehler!
Hatte den Teil aus einem anderen Code von mir übernommen, wo ich aber 
einen anderen Controller damals verwendet hatte. Jetzt klappt es.

von Waldkauz (Gast)


Lesenswert?

Frank M. schrieb:
> Du kannst nicht ganze 100ms (eine ganze zehntel Sekunde) in der ISR()
> mit Nichtstun vertrödeln. Bis dahin tritt ja schon wieder der nächste
> Interrupt auf. Oder drehst Du den Propeller in Ultra-Zeitlupe? Delays in
> ISRs gehen zu 99% in die Hose.

Moin Frank!
Die Delays kommen da wieder raus, die hatte ich nur testweise drin um zu 
gucken ob und wie der Interrupt auslöst. Der Propeller lief dabei 
wirklich in Zeitlupe, da ich ihn nur mit dem Finger gedreht hatte.

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.