Externer Interrupt 0 am ATMEGA88

OP #3332497
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
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
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.
OP #3332746
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. :)
OP #3333140
@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
Gast #3333157
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

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 13 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.