Programm bleibt in ISR hängen?

OP #2079192
Lesenswert?

Hallo,

ich hab ein Problem mit folgendem Programm, ich weiß nicht wirklich was 
da falsch läuft. Schaltung ist diegleiche wie aus dem Thread 
Beitrag "pnp schaltet nicht richtig ab?".


1
#ifndef F_CPU
2
#define F_CPU 3686400
3
#endif
4

5
#include <avr/io.h>
6
#include <stdint.h>
7
#include <avr/interrupt.h> 
8

9
uint8_t interrupt_flag = 0;
10
uint8_t n_digit = 0;
11

12
  
13

14
void ef_out(uint8_t digit)
15
{
16
  switch (digit)
17
  {
18
    case 0:
19
    PORTD = 0xFF;  // Alle digits aus
20
    PORTB = 0xC6;  // "E" an Port B anlegen
21
    PORTD = 0xFE;  // Digit 0 an
22
    break;
23
  
24
    case 1:
25
    PORTD = 0xFF;  // Alle digits aus
26
    PORTB = 0xCE;  // "F" an Port B anlegen
27
    PORTD = 0xFD;  // Digit 1 an
28
    break;  
29

30
    case 2:
31
    PORTD = 0xFF;  // Alle digits aus
32
    PORTB = 0xFF;  // Alle Segmente aus
33
    PORTD = 0xFB;  // Digit 2 an
34
    break;
35
  }
36
}
37

38
int main(void)
39
{
40
  DDRB = 0xFF;  // Port B Ausgang
41
  DDRD = 0xFF;  // Port D Ausgang
42

43
  TCCR0 = 0x03;      // Timer 0 normal mode, prescaler 64
44

45
  TIMSK = (1<<TOIE0);  // Overflow Interrupt aktivieren
46

47
  
48
  sei();      // Interrupts global aktivieren
49

50
  while (1)
51
  {
52
    if (interrupt_flag)
53
    {
54
      ef_out(n_digit);
55
      
56
      n_digit++;
57
      if (n_digit > 2)
58
        n_digit = 0;
59
      
60
      interrupt_flag = 0;
61
    }
62
  }
63

64
  return 0;
65
}
66

67
ISR(TIMER0_OVF_vect) // ISR für Timer0 Overflow
68
{
69
  interrupt_flag = 1;
70
}

In dem anderen Thread hatte ich ja schon ein lauffähiges Programm, 
welches ne Variable hochzählt und ausgibt, deswegen versteh ich nicht, 
warum diese einfachere Version auf einmal nicht funktioniert.

Ich will einfach nur auf der ersten Anzeige ein "E" ausgeben und auf der 
zweiten ein "F", die dritte soll einfach "aus" sein.

Wenn ich das jetzt simuliere, springt das Programm nach der Abfrage des 
interrupt_flags direkt in die ISR und kommt dort scheinbar nicht mehr 
raus, d.h. sobald die ISR beendet wird springt das Programm sofort 
wieder rein.

Ich kann mir das nicht erklären, weiß jemand von euch was da los ist?
#2079280
Lesenswert?

Hi Chris,
vermutlich wird deine Main-Routine ständig von der 
Interrupt-Service-Routine unterbrochen (Dazu ist die ISR berechtigt). 
Ist das Grundprinzip von Interrupts klar?
Wenn Du was interrupt-getriggertes außerhalb der zugehörigen ISR machen 
möchtest, dann schalte dafür die Interrupts ab.
Macht man eigentlich aber nicht so.
Gruß
Andi
OP #2079283
Lesenswert?

Ah, danke für den Hinweis, ich hatte den Artikel zwar schonmal gelesen, 
diese Tatsache aber anscheinend wieder vergessen.

Komisch nur, dass folgendes Programm mit zwei Timern und zwei derartigen 
Flags funktioniert:
1
#ifndef F_CPU
2
#define F_CPU 3686400
3
#endif
4

5
#include <avr/io.h>
6
#include <stdint.h>
7
#include <util/delay.h>
8
#include <avr/interrupt.h> 
9

10
uint8_t interrupt_flag = 0;
11
uint8_t timer_flag = 0;  
12

13

14
// Legt das entsprechende Bitmuster der Ziffer ziff an PORTB an
15
void ziff_out(uint8_t ziff)
16
{
17
...
18
}
19

20
// Gibt die Stelle digit der Zahl num an der entsprechenden 7Segment Anzeige aus
21
void num_out(uint8_t num, uint8_t digit)
22
{
23
...
24
}
25

26
int main(void)
27
{
28
  DDRB = 0xFF;  // Port B Ausgang
29
  DDRD = 0xFF;  // Port D Ausgang
30

31
  TCCR0 = 0x03;      // Timer 0 normal mode, prescaler 64
32

33
  TCCR1A = 0x00;
34
  TCCR1B = 0x03;      // Timer 1 normal mode, prescaler 64
35

36
  TIMSK |= (1<<TOIE0) | (1<<TOIE1);  // Overflow Interrupt aktivieren
37

38
  
39
  sei();      // Interrupts global aktivieren
40

41
  uint8_t value = 123;
42
  uint8_t n_digit = 0;
43

44
  while (1)
45
  {
46
    if (interrupt_flag)
47
    {
48
      n_digit++;
49
      if (n_digit > 2)
50
        n_digit = 0;
51
      num_out(value, n_digit);
52

53
      interrupt_flag = 0;
54
    }
55

56
    if (timer_flag)
57
    {
58
      value++;
59

60
      timer_flag = 0;
61
    }
62
  }
63

64
  return 0;
65
}
66

67
ISR(TIMER0_OVF_vect) // ISR für Timer0 Overflow
68
{
69
  interrupt_flag = 1;
70
}
71

72
ISR(TIMER1_OVF_vect) // ISR für Timer1 Overflow
73
{
74
  timer_flag = 1;
75
}
#2081165
Lesenswert?

Die Abarbeitung der Main-Routine wird abgebrochen, wenn irgendwo ein 
Interrupt auftritt. Dann arbeitet der Controller die zugehörige ISR ab 
und kehrt nach Abschluß an die Stelle in der Mainroutine zurück, an der 
er abgebrochen hat. Das sollte klar sein.

http://www.mikrocontroller.net/articles/AVR-Tutorial:_Interrupts
http://www.mikrocontroller.net/articles/Interrupt

Vermutung:
1.
Wenn jetzt die "Interruptfrequenz" zu hoch ist, hast Du den 
beschriebenen "Fehler". Er springt zu häufig aus der Mainroutine raus. 
Dein Programm funktioniert sobald Du ohne das Flag arbeitest und den 
auszuführenden Programmteil direkt in die ISR reinmachst. Die ISR wird 
nämlich nicht unterbrochen.

Vielleicht mal den Prescaler hochsetzen.

Oder in der Serviceroutine das Interruptflag in TIMSK wegnehmen und nach 
Abarbeitung in der Mainroutine wieder setzen. Damit schaltest Du die 
Interupts während der Abarbeitung in der Mainroutine aus. Zur 
Fehlersuche ist das i.O., allerdings machst Du dir die Zeitbasis, die 
mit den regelmäßigen Interrupts schaffst kaputt. Wie oben schon gesagt 
ist das kein guter Stil.
1
int main(void)
2
{
3
  DDRB = 0xFF;  // Port B Ausgang
4
  DDRD = 0xFF;  // Port D Ausgang
5

6
  TCCR0 = 0x03;      // Timer 0 normal mode, prescaler 64
7

8
  TIMSK = (1<<TOIE0);  // Overflow Interrupt aktivieren
9

10
  
11
  sei();      // Interrupts global aktivieren
12

13
  while (1)
14
  {
15
    if (interrupt_flag)
16
    {
17
      ef_out(n_digit);
18
      
19
      n_digit++;
20
      if (n_digit > 2)
21
        n_digit = 0;
22
      
23
      interrupt_flag = 0;
24
      TIMSK |= (1<<TOIE0); /INT ein
25
    }
26
  }
27

28
  return 0;
29
}
30

31
ISR(TIMER0_OVF_vect) // ISR für Timer0 Overflow
32
{
33
  interrupt_flag = 1;
34
  TIMSK &= ~(1<<TOIE0); //INT aus
35
}

2.
wie meine Vorredner schon sagten -> Optimierung

Fehlersuche:
Mal mit Setzen von Portpins die Dauer der relevanten Programmteile 
prüfen und mit der Interruptfrequenz vergleichen.

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