Forum: Mikrocontroller und Digitale Elektronik Interrupt während While-Loop


von Rico H. (Firma: FHNW) (2she)


Lesenswert?

Guten Tag allerseits!

Kleines Problem hier!
Ich mache 6 Temperaturmessungen mittels Thermoelementen und ATMega2561, 
welche auf einem Display angezeigt und aktualisiert werden.

Die Routine sieht folgendermassen aus:
1
while(1){
2
  LCD_Print("test",90,120,2,1,1,red,red);
3
  delay_ms(300);
4
  LCD_Print("test",90,120,2,1,1,blue,blue);
5
  delay_ms(300);
6
}  
7
8
ISR(INT4_vect)
9
{
10
  delay_ms(100);
11
  key = key_press(pos, site);
12
  LCD_Print("test",90,100,1,1,1,red,green);
13
  delay_ms(100);
14
  LCD_Print("test",90,100,1,1,1,black,green);
15
}

im Beispiel wird die while-schleife durch einen Tasteninterrupt 
unterbrochen. Mittels key_press() ermittle ich noch die genaue Taste, da 
nur die Kolonnen auf Interruptleitungen hängen. Was soweit auch 
funktioniert, die while-Schleife wird unterbrochen und danach 
weitergeführt, was auch mein Ziel ist.
Jetz zu meinem Problem.
Wenn ich in der selben Struktur die Temperaturmessung vornehme, das 
heisst in der while-Schleife verschiedene berechnungen mache, häng ich 
irgendwo im Programm fest, die while-Schleife wird jedoch nicht weiter 
durchlaufen und die Werte nicht aktualisiert...woran kann das liegen?

Hier noch die erwähnte Temperaturberechnungs-Schleife:
1
while(1){
2
    // TEMP ================================================
3
    /*measurement with temp sensor 1*/
4
    y = 0;
5
    temp2strg(meas_Temp(ADC1_ON), strg_temp);
6
    LCD_write_Temp(strg_temp, y);
7
    /*measurement with temp sensor 2*/
8
    y = 18;
9
    temp2strg(meas_Temp(ADC2_ON), strg_temp);
10
    LCD_write_Temp(strg_temp, y);
11
    /*measurement with temp sensor 3*/
12
    y = 36;
13
    temp2strg(meas_Temp(ADC3_ON), strg_temp);
14
    LCD_write_Temp(strg_temp, y);
15
    /*measurement with temp sensor 4*/
16
    y = 54;
17
    temp2strg(meas_Temp(ADC4_ON), strg_temp);
18
    LCD_write_Temp(strg_temp, y);
19
    /*measurement with temp sensor 5*/
20
    y = 72;
21
    temp2strg(meas_Temp(ADC5_ON), strg_temp);
22
    LCD_write_Temp(strg_temp, y);
23
    /*measurement with temp sensor 6*/
24
    y = 90;
25
    temp2strg(meas_Temp(ADC6_ON), strg_temp);
26
    LCD_write_Temp(strg_temp, y);
27
  }

von Peter II (Gast)


Lesenswert?

du kannst nicht in der ISR und in dem hauptprogramm auf den Display 
rumschreiben. Das führt immer zu Problemen.

Auch ein Delay hat nicht in der ISR verloren.

Ändere erstmal diese punkte und zeige uns dann das komplette Programm.

von Rico H. (Firma: FHNW) (2she)


Lesenswert?

Peter II schrieb:
> du kannst nicht in der ISR und in dem hauptprogramm auf den Display
> rumschreiben. Das führt immer zu Problemen.
1
while(1){
2
  LCD_Print("test",90,120,2,1,1,red,red);
3
  delay_ms(300);
4
  LCD_Print("test",90,120,2,1,1,blue,blue);
5
  delay_ms(300);
6
}  
7
8
ISR(INT4_vect)
9
{
10
  delay_ms(100);
11
  key = key_press(pos, site);
12
}

> Auch ein Delay hat nicht in der ISR verloren.

dieser Delay von 100ms ist noch dazu da um die Taste zu entprellen. 
Führt das auch schon zu Problemen?


Und hier noch ke_press():
1
  #include <avr/io.h>
2
  #include <avr/interrupt.h>
3
  #include "../header/MMI/matrix_keyboard.h"
4
5
  void Init_Key_Port()
6
  {
7
    /* All Ports input of the matrix keyboard */
8
    DDRE = ( (0<<DDE7) | (0<<DDE6) | (0<<DDE5) | (0<<DDE4));
9
    DDRD = ( (0<<DDD7) | (0<<DDD4) );
10
    DDRG = ( (0<<DDG3) | (0<<DDG0) );
11
    /* Pullup resistance active for keyboard ports*/
12
    PORTE = ( (1<<PE7) | (1<<PE6) | (1<<PE5) | (1<<PE4));
13
    PORTD = ( (1<<PD7) | (1<<PD4) );
14
    PORTG = ( (1<<PG3) | (1<<PG0) );
15
  }
16
17
  char key_press(int pos, int site)
18
  {
19
    char number=0;
20
    int keycode, keyflag = 4;
21
    Init_Key_Port();                  // make sure all keyboard ports are initialized
22
23
    /* check line D */
24
    PORTD = (0<<PD4);                   // PORT D4 at pullup desactive
25
    DDRD = (1<<DDD4);                   // PORT D4 in input
26
    keycode = 0x08 &0x0F;                // line code
27
    /* check column */
28
    if ((PINE &(1<<PINE7)) == 0) ;            // faking condition
29
    else if ((PINE &(1<<PINE5)) == 0) keycode += 0x10 &0xF0;
30
    else if ((PINE &(1<<PINE4)) == 0) keycode += 0x20 &0xF0;
31
    else if ((PINE &(1<<PINE6)) == 0) keycode += 0x40 &0xF0;
32
    else keyflag --;
33
    PORTD = (1<<PD4);                   // PORT D4 at pullup active
34
    DDRD = (0<<DDD4);                   // PORT D4 in output
35
36
    if (keyflag == 3)
37
    {
38
      /* check line C */
39
      PORTD = (0<<PD7);                 // PORT D7 at pullup desactive
40
      DDRD = (1<<DDD7);                 // PORT D7 in input
41
      keycode = 0x04 &0x0F;              // line code
42
      /* check column */
43
      if ((PINE &(1<<PINE7)) == 0) ;          // faking condition
44
      else if ((PINE &(1<<PINE5)) == 0) keycode += 0x10 &0xF0;
45
      else if ((PINE &(1<<PINE4)) == 0) keycode += 0x20 &0xF0;
46
      else if ((PINE &(1<<PINE6)) == 0) keycode += 0x40 &0xF0;
47
      else keyflag --;
48
      PORTD = (1<<PD7);                 // PORT D7 at pullup active
49
      DDRD = (0<<DDD7);                 // PORT D7 in output
50
    }
51
52
    if (keyflag == 2)
53
    {
54
      /* check line B */
55
      PORTG = (0<<PG0);                 // PORT G0 at pullup desactive
56
      DDRG = (1<<DDG0);                 // PORT G0 in input
57
      keycode = 0x02 &0x0F;              // line code
58
      /* check column */
59
      if ((PINE &(1<<PINE7)) == 0) ;          // faking condition
60
      else if ((PINE &(1<<PINE5)) == 0) keycode += 0x10 &0xF0;
61
      else if ((PINE &(1<<PINE4)) == 0) keycode += 0x20 &0xF0;
62
      else if ((PINE &(1<<PINE6)) == 0) keycode += 0x40 &0xF0;
63
      else keyflag --;
64
      PORTG = (1<<PG0);                 // PORT G0 at pullup active
65
      DDRG = (0<<DDG0);                 // PORT G0 in output
66
    }
67
    
68
    if (keyflag == 1)
69
    {
70
      /* check line A */
71
      PORTG = (0<<PG3);                 // PORT G3 at pullup desactive
72
      DDRG = (1<<DDG3);                 // PORT G3 in input
73
      keycode = 0x01 &0x0F;              // line code
74
      /* check column */
75
      if ((PINE &(1<<PINE7)) == 0) ;          // faking condition
76
      else if ((PINE &(1<<PINE5)) == 0) keycode += 0x10 &0xF0;
77
      else if ((PINE &(1<<PINE4)) == 0) keycode += 0x20 &0xF0;
78
      else if ((PINE &(1<<PINE6)) == 0) keycode += 0x40 &0xF0;
79
      else keyflag --;
80
      PORTG = (1<<PG3);                // PORT G3 at pullup active
81
      DDRG = (0<<DDG3);                 // PORT G3 in output
82
    }
83
84
    /* Interrupt Ports input */
85
    DDRE = ( (0<<DDE7) | (0<<DDE6) | (0<<DDE5) | (0<<DDE4));
86
    /* Ports output */
87
    DDRD = ( (1<<DDD7) | (1<<DDD4) );
88
    DDRG = ( (1<<DDG3) | (1<<DDG0) );
89
    /* Pullup resistance Interrupt Ports active */
90
    PORTE = ( (1<<PE7) | (1<<PE6) | (1<<PE5) | (1<<PE4));
91
    /* Pullup resistance output Ports inactive */
92
    PORTD = ( (0<<PD7) | (0<<PD4) );
93
    PORTG = ( (0<<PG3) | (0<<PG0) );
94
    sei();
95
    /* Switch table which return the value of the pressed key */
96
    /****************************************************************************/
97
    /* Change the following code lines to attribute some action for each button */
98
    /****************************************************************************/
99
    switch (keycode)
100
    {
101
      case 0x21 :  number = '0';
102
      break;
103
      case 0x18 : number = '1';
104
      break;
105
      case 0x28 : number = '2';
106
      up();
107
      break;
108
      case 0x48 : number = '3';
109
      break;
110
      case 0x14 : number = '4';
111
      break;
112
      case 0x24 : number = '5';
113
            if (site==0)
114
            {
115
              if (pos==1)
116
              {
117
                Sensoren();
118
                break;
119
              }
120
              if (pos==2)
121
              {
122
                DiffMess();
123
                break;
124
              }
125
              if (pos==3)
126
              {
127
                Logger();
128
                break;
129
              }
130
              if (pos==4)
131
              {
132
                Abgleich();
133
                break;
134
              }
135
              if (pos==5)
136
              {
137
                Settings();
138
                break;
139
              }
140
              if (pos==6)
141
              {
142
                Credits();
143
                break;
144
              }
145
            }
146
      break;
147
      case 0x44 : number = '6';
148
      break;
149
      case 0x12 :  number = '7';
150
      break;
151
      case 0x22 : number = '8';
152
      down();
153
      break;
154
      case 0x42 : number = '9';
155
      break;
156
      case 0x00 :  number = 'N';
157
      break;
158
      case 0x81 :  number = 'S';
159
      
160
      break;
161
      case 0x41 : number = 'E';
162
163
              if (site==1)
164
              {
165
                Menu();
166
                break;
167
              }
168
              if (site==2)
169
              {
170
                Menu();
171
                break;
172
              }
173
              if (site==3)
174
              {
175
                Menu();
176
                break;
177
              }
178
              if (site==4)
179
              {
180
                Menu();
181
                break;
182
              }
183
              if (site==5)
184
              {
185
                Menu();
186
                break;
187
              }
188
              if (site==6)
189
              {
190
                Menu();
191
                break;
192
              }
193
            
194
      break;
195
    }
196
    
197
    return number;
198
  }

von Felix P. (fixxl)


Lesenswert?

Ja, der Delay in der ISR kann zu Problemen führen. Dort sollte auch kein 
Aufruf externer Programme stehen.

Ich handhabe das so, dass ich in der ISR Flags setze und die dann im 
Hauptprogramm auswerte und nach Ausführung der entsprechenden Routine 
wieder lösche.

von Rico H. (Firma: FHNW) (2she)


Lesenswert?

Felix Pflaum schrieb:
> Ja, der Delay in der ISR kann zu Problemen führen. Dort sollte auch kein
> Aufruf externer Programme stehen.
>
> Ich handhabe das so, dass ich in der ISR Flags setze und die dann im
> Hauptprogramm auswerte und nach Ausführung der entsprechenden Routine
> wieder lösche.

Das Problem ist, dass die Temperaturmessungen eine gewisse Zeit (~5sec) 
benötigen, was beim setzen eines Flags dann auch Verzögerungen 
verursacht.. Oder seh ich das falsch?

von Peter II (Gast)


Lesenswert?

was hat das sei(); in der ISR der key_press verloren?

> dieser Delay von 100ms ist noch dazu da um die Taste zu entprellen.
> Führt das auch schon zu Problemen?
früher oder später auf jeden Fall, dann in der Zeit geht nichts anders 
mehr.

von Rico H. (Firma: FHNW) (2she)


Lesenswert?

Peter II schrieb:
> was hat das sei(); in der ISR der key_press verloren?
ist raus, da habich was getestet


> früher oder später auf jeden Fall, dann in der Zeit geht nichts anders
> mehr.
ok, aber soweit ich bis jetzt testen konnte sind mir dadurch noch keine 
probleme aufgetreten.
Ich häng immernoch an der Ausgabe der Temperaturwerte. Manchmal 
funktioniert es sogar:=)...aber ich kann mir nicht vorstellen wo sich 
das Programm festsetzt.

von Peter II (Gast)


Lesenswert?

Rico H. schrieb:
> aber ich kann mir nicht vorstellen wo sich
> das Programm festsetzt.

du rufst ja noch tausend andere dinge in der key_press auf

Sensoren();
DiffMess();

das hat alles dort nichts zu suchen, key_press sollte nur eine 
zurückliefern welche Taste gedrückt wurden ist.

von Rico H. (Firma: FHNW) (2she)


Lesenswert?

Peter II schrieb:

> das hat alles dort nichts zu suchen, key_press sollte nur eine
> zurückliefern welche Taste gedrückt wurden ist.

was soviel heisst, dass ich doch mittels Flags arbeiten muss und z.b 
nach jeder einzelnen Messung die Flags abfragen muss, was die 
Reaktionszeit erheblich verkleinert?!

von Peter II (Gast)


Lesenswert?

Rico H. schrieb:
> was soviel heisst, dass ich doch mittels Flags arbeiten muss und z.b
> nach jeder einzelnen Messung die Flags abfragen muss,
Ja!!!

> was die
> Reaktionszeit erheblich verkleinert?!
ja, das system kann dann auch noch andere dinge erledigen.

von Rico H. (Firma: FHNW) (2she)


Lesenswert?

Peter II schrieb:
> Ja!!!
Ok dann werde ich mich mal hinter die Flags setzen..Fragen werden früher 
oder später wieder auftauchen, ich bin froh über solch kompetente Leute, 
danke vielmas

> ja, das system kann dann auch noch andere dinge erledigen.
andere Dinge?

Ziel ist für mich jetzt folgende implementation, richtig?:

while(1){
Messung 1
Abfrage Flags //falls ein Flag gesetzt, Funktionsaufruf (und jmp 
zurück?)
Messung 2
Abfrage Flags
...
Messung 6
Abrage Flags
}

von Karl H. (kbuchegg)


Lesenswert?

Rico H. schrieb:

> Ziel ist für mich jetzt folgende implementation, richtig?:
>
> while(1){
> Messung 1
> Abfrage Flags //falls ein Flag gesetzt, Funktionsaufruf (und jmp
> zurück?)
> Messung 2
> Abfrage Flags
> ...
> Messung 6
> Abrage Flags
> }


Im Prinzip ja.
Nur kannst du dir ja auch selbst das Leben einfacher machen, indem du 
auf COde-Duplizierungen verzichtest, indem du realisierst, dass deine 
'Messungen' im Grund ja immer gleich sind, nur mit anderen Zahlenwerten. 
Und diese Zahlenwerte kann man zb auch in ein Array stecken, bzw. die 
für eine relevante Messung notwendigen Zahlenwerte zuerst in einer 
Struktur zusammenfassen und dann davon ein Array machen
1
// was ist alles für EINE Messung an Wissen notwendig?
2
struct tempMeasurment {
3
  uint8_t  ADC_Code;
4
  uint8_t  LCDLine;
5
};
6
7
// und hier sind sie dann. Diese Sensoren (ADC_Code) sind abzufragen
8
// und das Ergebnis ist wo (LCDLine) auszugeben
9
#define MEASUREMENT_COUNT 6
10
struct tempMeasurement Measurements[MEASUREMENT_COUNT] =
11
{
12
  { ADC1_ON,  0 },
13
  { ADC2_ON, 18 },
14
  { ADC3_ON, 36 },
15
  { ADC4_ON, 54 },
16
  { ADC5_ON, 72 },
17
  { ADC6_ON, 90 }
18
};
19
20
....
21
22
int main()
23
{
24
25
....
26
27
  uint8_t nrMeas = 0;
28
29
....
30
31
  while(1) {
32
33
    // die Messung vornehmen
34
    temp2strg( meas_Temp(Measurements[nrMeas].ADC_Code), strg_temp );
35
    LCD_write_Temp( strg_temp, Measurements[nrMeas].LCDLine );
36
37
    // beim nächsten Schleifendurchlauf kommt dann der nächste Sensor drann
38
    // welcher ist das?
39
    nrMeas++;
40
    if( nrMeas == MEASUREMENT_COUNT )
41
      nrMeas = 0;
42
43
44
    
45
    // hier dann deine Tastenauswertung
46
    Abfrage Flags
47
48
  }
49
}

So werden reihum ebenfalls alle Sensoren abgefragt und zwischendurch die 
Flags ausgewertet. Bei jedem Durchgang durch die while-Hauptschleife 
wird EIN Sensor abgefragt und ausgewertet. Aber eben jedesmal ein 
anderer.

Und ... du hast keine Codeduplizierung mehr!

von Rico H. (Firma: FHNW) (2she)


Lesenswert?

Karl Heinz Buchegger schrieb:

> So werden reihum ebenfalls alle Sensoren abgefragt und zwischendurch die
> Flags ausgewertet. Bei jedem Durchgang durch die while-Hauptschleife
> wird EIN Sensor abgefragt und ausgewertet. Aber eben jedesmal ein
> anderer.
>
> Und ... du hast keine Codeduplizierung mehr!

VIELEN DANK!! Das macht das ganz schon viel Übersichtlicher!! Habe gar 
nicht daran gedacht, da ich mich irgendwie völlig im Code verloren 
habe..
Ist es sinnvoller die Abfrage der Flags durch IF-Schleifen oder einen 
SWITCH zu machen?

von Falk B. (falk)


Lesenswert?

Siehe auch Multitasking, Interrupt und [[Strukturierte 
Programmierung auf Mikrocontrollern]].

von Karl H. (kbuchegg)


Lesenswert?

Rico H. schrieb:

> Ist es sinnvoller die Abfrage der Flags durch IF-Schleifen oder einen
> SWITCH zu machen?

a) es gibt keine if - "Schleifen"
   eine Schleife ist ein Codestück, in dem etwas wiederholt wird.
   Bei einem if wird nichts wiederholt. Ein if ist eine Auswahl
   aus 2 Möglickeiten

b) Kann man generell nicht sagen.
   Ob man
1
   if( Variable == 1 )
2
     ....1
3
4
   else if( Variable == 2 )
5
     ....2
6
7
   else if( Variable == 5 )
8
     ....3
9
10
   else
11
     ....4
schreibt, oder ob man da ein
1
   switch( Variable )
2
   {
3
     case 1:
4
       ....1
5
       break;
6
7
     case 2:
8
       ....2
9
       break;
10
11
     case 5:
12
       ....3
13
       break;
14
15
     default:
16
       ....4
17
   }
    draus macht, wird sich nicht viel reissen. Bei einem switch kann
    der Compiler besser optimieren und der Wert von 'Variable' wird
    nur einmalig ausgewertet. Aber ansonsten ist da auch viel
    persönliche Vorliebe dabei.

von Falk B. (falk)


Lesenswert?


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.