Forum: Mikrocontroller und Digitale Elektronik Atmega8 hängt nach Interrupt


von Kaito C. (kaitocross)


Lesenswert?

Guten Abend :) Dieses mal habe ich ein Problem mit meinem Programm für 
den Atmega8. Wenn PortC >= 11 ist und der Interrupt ausgelöst wird, 
hängt sich das Programm auf und reagiert nicht auf interrupts.
Ich bitte euch mir weiterzuhelfen :) LG
1
uint8_t segcodeB[11];
2
bool segcodeD[11];
3
uint8_t temp = 0;
4
uint8_t darstellzahl[4] = {0,0,0,0};
5
uint16_t Zeitwert = 0;
6
uint8_t displaycounter = 0;
7
bool triggermove = false;
8
int main(void)
9
{
10
  //welche Zahl welche leuchtenden Segmente
11
  //      = 0b00gfedcb
12
  segcodeB[0] = 0b00011111;
13
  segcodeB[1] = 0b00000011;
14
  segcodeB[2] = 0b00101101;
15
  segcodeB[3] = 0b00100111;
16
  segcodeB[4] = 0b00110011;
17
  segcodeB[5] = 0b00110110;
18
  segcodeB[6] = 0b00111110;
19
  segcodeB[7] = 0b00000011;
20
  segcodeB[8] = 0b00111111;
21
  segcodeB[9] = 0b00110111;
22
  segcodeB[10] = 0b00011111;
23
      //  = a
24
  segcodeD[0] = 1;
25
  segcodeD[1] = 0;
26
  segcodeD[2] = 1;
27
  segcodeD[3] = 1;
28
  segcodeD[4] = 0;
29
  segcodeD[5] = 1;
30
  segcodeD[6] = 1;
31
  segcodeD[7] = 1;
32
  segcodeD[8] = 1;
33
  segcodeD[9] = 1;
34
  segcodeD[10] = 1;
35
  
36
  DDRD &=~(1<<PD3)|(1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7);
37
  DDRB &=~(1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)|(1<<PB5);
38
  PORTD|=(1<<PD2);
39
  PORTC |=(1<<PC0)|(1<<PC1)|(1<<PC2)|(1<<PC3);
40
  MCUCR=0b00000011;
41
  GICR=0b01000000;
42
  sei();
43
44
    while(1)
45
    {
46
    if (triggermove)
47
    {
48
        darstellzahl[0]=darstellzahl[1];
49
        darstellzahl[1]=darstellzahl[2];
50
        darstellzahl[2]=darstellzahl[3];
51
        darstellzahl[3]=temp;
52
        triggermove=false;
53
    }
54
    if (temp<11)
55
    {
56
    PORTD=(1<<PD3)|(0<<PD4)|(0<<PD5)|(0<<PD6)|(segcodeD[darstellzahl[0]]<<PD7);
57
    PORTB=segcodeB[darstellzahl[0]];
58
    _delay_ms(10);
59
    PORTD=(0<<PD3)|(1<<PD4)|(0<<PD5)|(0<<PD6)|(segcodeD[darstellzahl[1]]<<PD7);
60
    PORTB=segcodeB[darstellzahl[1]];
61
    _delay_ms(10);
62
    PORTD=(0<<PD3)|(0<<PD4)|(1<<PD5)|(0<<PD6)|(segcodeD[darstellzahl[2]]<<PD7);
63
    PORTB=segcodeB[darstellzahl[2]];
64
    _delay_ms(10);
65
    PORTD=(0<<PD3)|(0<<PD4)|(0<<PD5)|(1<<PD6)|(segcodeD[darstellzahl[3]]<<PD7);
66
    PORTB=segcodeB[darstellzahl[3]];
67
    _delay_ms(10);
68
    }
69
    }
70
71
}
72
ISR(INT0_vect)
73
{
74
  temp = PINC & 0x0F;
75
  if (temp<11)
76
  {
77
  triggermove = true;
78
  }
79
  else
80
  {
81
    triggermove=false;
82
  }
83
  /*if (temp==12)//wenn #
84
  {
85
    Zeitwert = darstellzahl[0]*1000+darstellzahl[1]*100+darstellzahl[2]*10+darstellzahl[3];
86
  }*/
87
//  _delay_ms(10);
88
}

: Bearbeitet durch User
von Chefkoch (Gast)


Lesenswert?

Korrigiert miche wenn ich mich irre, aber müsste die in der ISR 
verwendete Variable "triggermove" nicht als volatile deklariert werden 
wenn diese im Hauptprogramm zur Verfügung stehen soll bzw. temp für die 
ISR in der ISR?

von Der kleine Nils (Gast)


Lesenswert?

Moin Christian,

Christian H. schrieb:
1
DDRD &=~(1<<PD3)|(1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7);
2
DDRB &=~(1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)|(1<<PB5);


auch wenn das nicht direkt zu deiner Problemlösung beiträgt solltest du 
der Negierung ~ eine kusätzliche Klammer spendieren. Du setzt ja erst 
das Datenwort aus den veroderungen zusammen und willst dann das 
komplette Wort invertieren.
1
DDRD &=~((1<<PD3)|(1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7));
2
DDRB &=~((1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)|(1<<PB5));

Die Zeile und ff. werden nicht funktionieren. Die altbekannte & und | 
Problematik. Was ist denn, wenn in PD4 eine 1 steht? 1 | 0 = 1. Du wirst 
den Wert in PD4 mit dieser Zeile nie wieder verändern, sobald eine 1 
steht. Die Null bekommst du nur durch das &.
1
    PORTD=(1<<PD3)|(0<<PD4)|(0<<PD5)|(0<<PD6)|(segcodeD[darstellzahl[0]]<<PD7);

Vielleicht solltest du diese Zeilen erstmal korrigieren und mal gucken, 
ob's dann läuft.

Gruß
Nils

von Gecko (Gast)


Lesenswert?

Chefkoch schrieb:
> Korrigiert miche wenn ich mich irre, aber müsste die in der ISR
> verwendete Variable "triggermove" nicht als volatile deklariert werden
> wenn diese im Hauptprogramm zur Verfügung stehen soll bzw. temp für die
> ISR in der ISR?

http://www2.informatik.uni-halle.de/lehre/c/c_volat.html

von Karl H. (kbuchegg)


Lesenswert?

Christian H. schrieb:
> Guten Abend :) Dieses mal habe ich ein Problem mit meinem Programm für
> den Atmega8. Wenn PortC >= 11 ist und der Interrupt ausgelöst wird,
> hängt sich das Programm auf und reagiert nicht auf interrupts.

Woran machst du das fest?

Hintergrund: In deinem Programm stimmt so einiges nicht. Und das beginnt 
schon mal damit, dass du keinen einzigen Portpin auf Ausgang gestellt 
hast. Offenbar hängt am PORTB bzw. PORTD/7 irgendetwas, das du steuern 
möchtest (LED?). Dazu müssen die Pins aber auf Ausgang gestellt sein!

Hier
1
  PORTD=(1<<PD3)|(0<<PD4)|(0<<PD5)|(0<<PD6)|(segcodeD[darstellzahl[0]]<<PD7);
schaltest du dir den Pullup Widerstand am Pin PD2 ab. Ich weiss jetzt 
nicht, was an deinem Interrupt Pin hängt, aber da du in der 
Initialisierungsphase den Pullup einschaltest, gehe ich mal davon aus, 
dass du den brauchst.


In Summe: da fehlt es an Verständnis für recht grundlegende Sachen in 
der AVR-Programmierung. Kann es sein, dass du gerade den 10-ten Schritt 
vor dem ersten machst?

: Bearbeitet durch User
von Kaito C. (kaitocross)


Lesenswert?

Habe auf den DDR das ganze nun mit ner dirketzuweisung gelöst, das 
scheint wohl abhilfe geschaffen zu haben. Ich sollte meinen Kopf nochmal 
ins Lehrbuch stecken :D

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Kaito C. schrieb:
> Habe auf den DDR das ganze nun mit ner dirketzuweisung gelöst, das
> scheint wohl abhilfe geschaffen zu haben. Ich sollte meinen Kopf nochmal
> ins Lehrbuch stecken :D


Nope.
Du solltest erst mal die Bitmanipulationen sicher beherrschen.
Genau dazu dienen die ersten Übungen in der µC-Programmiererei. 
Überraschung! Da geht es in wirklichkeit nicht darum, dass ein paar LED 
vor sich hin leuchten oder nicht leuchten oder blinken oder ein 
Lauflicht bilden. Das Ergebnis ist nur Mittel zum Zweck, eine fundierte 
Basis für Bitoperationen zu schaffen

Bit setzen (auf 1)
1
    xy |= ( 1 << bit );
2
    abc |= ( 1 << bit1 ) | ( 1 << bit2 );

bit löschen (auf 0)
1
    xy &= ~( 1 << bit );
2
    abc &= ~( ( 1 << bit1 ) | ( 1 << bit2 ) );

bit abfragen
1
    if( xy & ( 1 << bit ) )

solange das nicht im Schlaf sitzt, machen weiterführende Themen keinen 
Sinn. Und genau dazu dienen diese LED-Übungen: damit das im Schlaf sitzt 
und man in der Lage ist, genau 1 Bit (oder mehrere) an einem Port so zu 
beeinflussen, wie man das braucht und nicht immer auf die 
Rundumschlagmethode 'Oooch, da weise ich einfach dem Port als ganzes was 
zu; passt schon' zurückzufallen.

Genauso wie diese Übungen das Verständnis für Eingang/Ausgang/Pullup 
etablieren sollen.
Im DDRx bedeutet ein 1 Bit, dass der Pin auf Ausgang geschaltet ist. Ein 
0 Bit hingegen bedeutet, dass der Pin auf Eingang geschaltet ist.
Ist ein Pin auf Eingang geschaltet, dann schaltet ein 1 Bit an 
korrespondierender Stelle im PORTx Register den Pullup Widerstand dazu 
bzw. ein 0 Bit schaltet ihn wieder weg.

Und da auf einem Port üblicherweise mehrere Dinge hängen, die logisch 
betrachtet voneinander unabhängig sind (wie zb eine LED und ein Taster), 
ist es unumgänglich, dass man die Einzelbitoperationen beherrscht. Denn 
ansonsten beeinflusst man mit kompletten Portzuweisungen immer auch alle 
anderen Dinge, die an diesem Port hängen. Womit man bei einfachen 
Porgrammen, wie zb einem Lauflicht bei dem an einem Port nichts anders 
als die LED hängen, noch durchkommt, wächst sich nämlich sonst zu einem 
Albtraum aus, weil kein Mensch mehr verfolgen kann, welche anderen Bits 
an diesem Port wie stehen müssen und das auch erhalten bleiben muss, 
obwohl man doch eigentlich nur eine LED einschalten wollte.

: Bearbeitet durch User
von stefanus (Gast)


Lesenswert?

Noch ein Tip:
1
  segcodeB[0] = 0b00011111;
2
  segcodeB[1] = 0b00000011;
3
  segcodeB[2] = 0b00101101;
4
  segcodeB[3] = 0b00100111;
5
  segcodeB[4] = 0b00110011;
6
  segcodeB[5] = 0b00110110;
7
  segcodeB[6] = 0b00111110;
8
  segcodeB[7] = 0b00000011;
9
  segcodeB[8] = 0b00111111;
10
  segcodeB[9] = 0b00110111;
11
  segcodeB[10] = 0b00011111;

Solche Konstrukte führen dazu, dass die gazen Konstanten doppelt 
Speicher belegen, nämlich einmal im Flash und dann nochmal im RAM. Durch 
die Verwednungen von PROGMEM sparst Du Dir das Ram.
1
const uint8_t segcodeB[] PROGMEM = {
2
  0b00011111,0b00000011, ...,0b00011111
3
};

Lesezugriffe darauf müssen dann etwas anders gestaltet werden. Beispiel:
1
uint8_t value=pgm_read_byte(&segcodeB[index]);

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.