Forum: Mikrocontroller und Digitale Elektronik Externer Interrupt 0 am ATMEGA88


von Andre S. (dg2mmt)


Lesenswert?

Ich komme grad nicht weiter, sehe vermutlich den Fehler nicht:
In meiner Anwendung will ich einen Drehgeber auswerten. Also habe ich 
den einen Kanal am ATMEGA88 auf Port D.1 und den anderen an Port D.2 
gehängt.
D.2 ist ja mit INT0 verbunden, ich will also beim Auslösen des 
Interrupts (L->H) die ISR aufrufen und die Richtung abfragen und 
entsprechende Reaktion auslösen.

Schon im Simulator (Atmel Studio 6) bekomme ich keinen Sprung in die 
ISR, wenn ich PIND2 toggle.
Leider habe ich bisher meinen Fehler selbst nicht finden können, 
vielleicht hat ja hier jemand nen Tipp.

Hier die relevanten Abschnitte:
1
#ifndef F_CPU
2
#define F_CPU 1000000UL //factory default clock value
3
#endif
4
5
#include <avr/io.h>
6
#include <avr/iomx8.h>
7
#include <avr/interrupt.h>
8
#include <stdint.h> /** unsigned data types */
9
10
/** struct for setting single port bits
11
source: [http://www.mikrocontroller.net/attachment/27445/SBIT.C] */
12
struct bits {
13
uint8_t b0:1;
14
uint8_t b1:1;
15
uint8_t b2:1;
16
uint8_t b3:1;
17
uint8_t b4:1;
18
uint8_t b5:1;
19
uint8_t b6:1;
20
uint8_t b7:1;
21
} __attribute__((__packed__));
22
23
#define SBIT(port,pin) ((*(volatile struct bits*)&port).b##pin)
24
25
/** ports for incremental encoder, inputs */
26
#define VOL_A SBIT( PIND, 1 ) /** incremental encoder output A */
27
#define VOL_B SBIT( PIND, 2 ) /** incremental encoder output B */
28
29
#define DDRD_SETTING 0x00 /** Port D direction setting iiii_iiii */
30
31
void init_ports(void)
32
{
33
    DDRD = DDRD_SETTING;
34
    
35
    EICRA |= 0x03;  /** set external interrupt 0 at rising edge */
36
    EIMSK |= 0x01;  /** activate external interrupt 0 */
37
    EIFR |= 0x01;  /** activate execution of interrupt 0 */
38
}
39
void init_timer(void)
40
{
41
    TCCR0A |= 0x02;  /** set CTC mode */
42
    TCCR0B |= 0x04;  /** set prescaler to 256 */
43
    OCR0A = 39;  /** at 1 MHz clock: (1000000 Hz)/ 256 / (100 Hz) = 39 counter tics */
44
    TIMSK0 |= 0x02;  /** activate timer compare match A interrupt */
45
46
}
47
int main(void)
48
{
49
    init_ports();
50
    init_timer();
51
    sei();  /** global enabling of interrupts */
52
    while(1)
53
    {
54
        //TODO:: Please write your application code
55
    }
56
}
57
ISR (TIMER0_COMPA_vect)
58
{
59
     /** code der ausgeführt wird */
60
}
61
62
ISR (INT0_vect) /** interrupt is activated at rising edge of VOL_B */
63
{
64
    if(VOL_A)  /** clock wise turn */
65
        get_volume(1,0);  /** increase volume */
66
    else  /** VOL_A is 0, counter clock wise turn */
67
        get_volume(-1,0); /** decrease volume */
68
}

von katastrophenheinz (Gast)


Lesenswert?

INT0 ist an PD2, INT1 ist an PD3,
du fragst in der ISR aber PD1 ab.
Ist das so gewollt?

Ich kenne den AVR-Sim nicht. Bist du sicher, daß der in der Lage ist,
auf PinChange-Interrupts zu reagieren?

>EIMSK |= 0x01;  /** activate external interrupt 0 */
>EIFR |= 0x01;  /** activate execution of interrupt 0 */
Reihenfolge falsch, Kommentar falsch, Bitzuweisung schlecht lesbar
EIFR = (1 << INTF0 );    /** Clear Pending INT0*/
EIMSK |= ( 1 << INT0 );  /** activate external interrupt 0 */

Gruss, Heinz

von katastrophenheinz (Gast)


Lesenswert?

katastrophenheinz schrieb:
> INT0 ist an PD2, INT1 ist an PD3,
> du fragst in der ISR aber PD1 ab.
> Ist das so gewollt?

Sorry, wer lesen kann, ist klar im Vorteil. Du wolltest das so.
Meine kleinen Korrekturen werden das Verhalten deines Programms nicht
gravierend verändern, also bleibt di Frage, ob der AVR-Sim in der Lage 
ist, INT0 auszulösen, wenn du am PIND2 rumwackelst.

von katastrophenheinz (Gast)


Lesenswert?

Vielleicht guckst du auch mal hier:

Beitrag "Drehgeber/Encoder 1-, 2- oder 4-schrittig"

Da gibt es einen fertigen/getesteen Codeschnipsel zum Auslesen eines 
Drehgebers.

von Andre S. (dg2mmt)


Lesenswert?

Danke für die Tipps.
Ich habs mal geändert. Im Simulator hab ich in Einzelschrittbetrieb zwar 
noch immer keinen Erfolg gehabt, aber wenn ich den Pin toggle und dann 
auf Run gehe, wird der Interrupt aufgerufen... komisches Verhalten.
Nachdem ich jetzt also in der ISR mal direkt noch ein paar LEDs hab 
blitzen lassen, weiß ich jetzt zumindest, dass die ISR aufgerufen wird.
Muss dann also noch wo anders nen Bug haben. :)

von Thomas E. (thomase)


Lesenswert?

Was soll das mit dem Interrupt? Das wird auch dir nicht gelingen, damit 
einen Drehgeber einzulesen. Guck dir die Routine von PeDa an. Da steht 
wie man das richtig macht.

mfg.

von Andre S. (dg2mmt)


Lesenswert?

@Thomas Eckmann:
Nur weil du das noch nicht gesehen hast, heißt nicht, dass es nicht 
funktionieren kann.
Ich hatte in einer aufgerufenen Funktion noch einen logischen Fehler, 
aber funktionieren tut das hervorragend.
Schau dir mal nen Drehgeben an: zwei um 90° versetzte Rechteck-Kurven 
kommen da raus.
Wenn du auf die (steigende) Flanke des einen Rechtecksignals triggerst 
(Interrupt) und dann schaust, welchen Pegel das andere Signal zu diesem 
Zeitpunkt hat, kannst du sauber feststellen, ob jetzt nach links oder 
rechts gedreht wurde.
Da ich das Signal in Hardware entprelle, muss ich das in der Software 
nicht beachten.
   __,  .__,  .__,  .__,  .__
A:   |__|  |__|  |__|  |__|
   _,  .__,  .__,  .__,  .__
B:  |__|  |__|  |__|  |__|
    ^  ^
    |  |- Interrupt bei Linksdrehung: A == 0
    |---- Interuupt bei Rechtsdrehung: A == 1

: Bearbeitet durch User
von spess53 (Gast)


Lesenswert?

Hi

>Nur weil du das noch nicht gesehen hast, heißt nicht, dass es nicht
>funktionieren kann.

Mit diesen Ansatz kommen Anfänger hier öfters. Also nichts unbekanntes.

MfG Spess

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.