Forum: Mikrocontroller und Digitale Elektronik USART_Polling_oder_Interrupt


von AVR_Beginner (Gast)


Lesenswert?

Hallo!

Habe da ein Problem:
Ich will mit folgendem Code den USART betreiben.
Unglücklicherweise las ich, dass bei Auftreten von mehreren ISRs dieser 
Sourcecode ungeeignet ist (sprich: Der Stack wird zusammengehaut) etc.

Wie man ersehen kann benutzt der Code schon einen Timer overflow 
interrupt. Meine Frage an euch Experten ist es, ob ich vl. evtl. evtl. 
doch nicht noch den USART-Recieve_ISR einfügen kann? (=Ich habe in 
dieser Routine nichts anderes vor, als UDR in eine andere Variable 
umzuspeichern und ein Flagbyte zu setzen?
Durch Abfrage des Flags in TestC soll dann der Wert abgearbeitet werden.
Eine Alternative ist die Pollingmethode,  jedoch befürchte ich, dass die 
Variable überschrieben werden könnte?
Mein MCU ist ein atmega32.
1
/// Includes //////////
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
5
/// Data Types /////////
6
typedef unsigned char u8;
7
typedef unsigned int u16;
8
typedef struct task
9
{
10
   // pointer to a function
11
   void (*pfunc) (void);
12
   // delay before the first call
13
   u16 delay;
14
   // interval between subsequent runs
15
   u16 period;
16
   // flag indicating time to run
17
   u8 run;
18
}task;
19
20
struct USART
21
{ unsigned char empfangen;
22
unsigned char wert;
23
}
24
25
/// Defines ///////////
26
// 25msec period 256-180 
27
// 7.3728MHz and /1024 prescaler
28
#define StartFrom       76
29
// maximum number of tasks
30
#define MAXnTASKS       20
31
32
/// Globals ///////////
33
volatile task TaskArray[MAXnTASKS];
34
35
/// Prototypes ////////
36
void InitUART (u16 baud);
37
void TransmitByte (u8 data);
38
void InitScheduler (void);
39
void UpdateScheduler(void);
40
void DeleteTask (u8 index);
41
void AddTask (void (*taskfunc)(void), u16 taskdelay, u16 taskperiod);
42
void DispatchTask (void);
43
44
void TestA (void);
45
void TestB (void);
46
void TestC (void);
47
48
/// Main //////////////
49
int main(void)
50
{
51
   InitUART (23);
52
   InitScheduler();
53
        
54
   // populate task array       
55
   AddTask (TestA, 0, 3);
56
   AddTask (TestB, 1, 4);
57
   AddTask (TestC, 4, 0);
58
        
59
   // enable interrupts
60
   sei();
61
        
62
   while (1) 
63
   {
64
      DispatchTask();
65
   }            
66
}
67
68
void InitUART (u16 baud)
69
{
70
   UBRRH = (u8)(baud>>8);                                                        
71
   UBRRL = (u8)baud;
72
   UCSRB = (1<<RXEN)|(1<<TXEN);              
73
   UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
74
//hier ist noch der Recieveinterrupt zu aktivieren
75
}
76
77
78
79
void InitScheduler (void)
80
{
81
   u8 i;
82
   
83
   // timer prescaler clock/1024
84
   TCCR0 |= (1<<CS02)|(1<<CS00);
85
   // clear pending interrupts
86
   TIFR = 1<<TOV0;
87
   // enable timer0 overflow interrupt
88
   TIMSK |= 1<<TOIE0;
89
    // load timer0
90
   TCNT0 = StartFrom;
91
92
   // clear task array
93
   for (i=0; i<MAXnTASKS; i++) DeleteTask(i);
94
}
95
96
void DeleteTask (u8 j)
97
{
98
   TaskArray[j].pfunc = 0x0000;
99
   TaskArray[j].delay = 0;
100
   TaskArray[j].period = 0;
101
   TaskArray[j].run = 0;
102
}
103
104
void AddTask (void (*taskfunc)(void), u16 taskdelay, u16 taskperiod)
105
{
106
   u8 n=0;
107
108
   // find next available position
109
   while ((TaskArray[n].pfunc != 0) && (n < MAXnTASKS)) n++;
110
111
   // place task
112
   if (n < MAXnTASKS)
113
   {
114
      TaskArray[n].pfunc = taskfunc;
115
      TaskArray[n].delay = taskdelay;
116
      TaskArray[n].period = taskperiod;
117
      TaskArray[n].run = 0;   
118
   }
119
}
120
121
SIGNAL(SIG_OVERFLOW0)
122
{
123
   u8 m;
124
125
  
126
   
127
   // load timer
128
   TCNT0 = StartFrom;
129
   
130
   for (m=0; m<MAXnTASKS; m++)
131
   {
132
      if (TaskArray[m].pfunc)
133
      {   
134
         if (TaskArray[m].delay == 0) 
135
         {
136
            TaskArray[m].run = 1;
137
            TaskArray[m].delay = TaskArray[m].period;
138
         }
139
         else TaskArray[m].delay--;
140
      }
141
   }
142
}
143
ISR(USART_RECv_vect)
144
{
145
USART.empfangen=1;
146
USART.wert=UDR;
147
}
148
void DispatchTask (void)
149
{
150
   u8 k;
151
   
152
   for (k=0; k<MAXnTASKS; k++)
153
   {
154
      if (TaskArray[k].run == 1)
155
      {
156
         // run task
157
         (*TaskArray[k].pfunc)();
158
         // clear run flag
159
         TaskArray[k].run = 0;
160
      }
161
   }
162
163
}
164
165
void TestA (void)
166
{
167
   
168
}
169
170
void TestB (void)
171
{
172
   
173
}
174
175
void TestC (void)
176
{
177
  //Abfrage, ob was Empfangen
178
179
if(USART.empfangen){
180
// hier geschieht die Verarbeitung
181
182
183
//Ende der Verarbeitung
184
USART.empfangen=0;
185
}
186
}


mfg

PS: Freu mich auf die Antworten

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Wenn der Timerinterrupt absolut zeitkritisch ist und nicht verzögert 
werden darf, polle die UART. Wenn dem nicht so ist, nimm den Interrupt. 
Es gibt keine allgemeingültige Formel für den Ablauf eines Programms.

von Martin V. (oldmax)


Lesenswert?

Hi
ich finde den Weg, (trotz keiner allgemein gültigen Formel) den UART 
Empfang per ISR zu händeln, völlig richtig. Es geht auch nix verloren, 
wenn der empfangene Wert in einen Ringpuffer eingetragen wird. Wenn der 
Timer nicht grad im µS-bereich liegt, dürfte er höchstens mal kurz 
holpern, aber er dürfte nicht verloren gehen. Ist aber ein wenig 
abhängig von der Taktfrequenz.
Gruß oldmax

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.