Externer Interrupt 0 am ATMEGA88

#3332497
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
}
Gast #3332560
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
Gast #3332563
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.
#3332746
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. :)
#3333140
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren