Forum: Compiler & IDEs fleurys I2C + UART lib halten in Kombination die Hauptschleife an!


von M. H. (dbzwerg)


Angehängte Dateien:

Lesenswert?

Hallo,

ich möchte mehrere Bytes mittels I2C von meiner Masterbaugruppe (mega32)
zu meinem Slave (mega8) senden.

Prinzipiell funktioniert dies, allerdings bleiben sowohl master als auch
Slave nach erfolgter Übetragung von  z.b. 8 Byte vom Master zum Slave 
für mehrere Sekunden
einfach hängen bzw. die Hauptschleifen werden nicht mehr ausgeführt, 
mein z.B. Timerinterrupt läuft aber weiter.

Wenn ich nun sowohl im Master und auch dem Slave code nahezu alle UART 
Ausgaben lösche, funktoniert das ganze wieder.

Nun meine Frage: Warum stört die UART die Funktion der I2C Ss bzw. warum 
bleibt meine Hauptschleife hängen?

Ich benutze für den Master die I2C + UART lib von fleury, für den Slave 
die I2Clib von
jtronics.de und die UART wiederrum von fleury.


Die libs hab ich als anhang angefügt

Hier das main master Programm:
1
 
2
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3
4
// Hauptprogramm für den ClockClock Master
5
6
// µC :ATmega32
7
8
// CPU Takt : 16MHz
9
10
// Funktionsbeschreibung:
11
12
//------------------------------
13
14
// Version: V0.1
15
// Datum: 07.08.12
16
17
18
19
//------------------------------
20
21
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
22
23
#include <avr/io.h>
24
#include <avr/interrupt.h> 
25
#include "uart.h" //Enthällt uart funktionen (Achtung uart.c muss in makefile eingetragen werden, wenn dies nicht von der ide gemacht wird)
26
#include <stdlib.h> // enthällt die Umwandlung von int zu char (itoa)
27
#include <util/delay.h> // Enthällt delay funktionen
28
#include <avr/wdt.h>  // Enthält Watchdog Funktionen
29
#include <cc_com.h> // Definitionen für die I2C Kommunikation zwischen den Baugruppen
30
31
#include <avr/pgmspace.h>
32
#include "i2cmaster.h"
33
34
// Definitionen
35
36
  #ifndef F_CPU
37
  #define F_CPU         16000000UL  // CPU Takt in Hz
38
  #endif
39
  #define UART_BAUD_RATE    9600  
40
41
  
42
43
//Deklaration der Variablen
44
45
  volatile unsigned char count_100ms       =  0;
46
  volatile unsigned char count_500ms       =   0;
47
  volatile unsigned char count_1s       =   0;
48
  volatile unsigned char count_2s       =   0;
49
  volatile unsigned char timestamp       =  0;     // Zeitstempel byte
50
                                //( Bit3 = 100ms; Bit4 =  500ms; Bit5= 1s;Bit6 = 2s)                    
51
  volatile unsigned char ccs_data        =  0;    // Buffer zur Speicherung der vom Slave emfpangenen Daten  
52
53
//Deklaration der Funktionsprototypen
54
55
  void send_int_uart(int value); // Deklaration für UART INt SEND Unterfunktion
56
  
57
  
58
  void I2CWrite_CCS(uint8_t ADDR, uint8_t CMD, uint8_t DATA) // Funktion zum senden von Daten an I2C Slave ( CCS = ClocClock Slave)
59
    {
60
    int connect;
61
    
62
    connect = i2c_start(ADDR+I2C_WRITE);   // set device address and write mode
63
    /*  switch(connect)
64
      {
65
      case 0:
66
          uart_puts("Verbindung zu Slave:");
67
          send_int_uart(ADDR);  
68
          uart_puts("\n\r");
69
          break;
70
      case 1:
71
          uart_puts("KEINE Verbindung zu Slave:");
72
          send_int_uart(ADDR);  
73
          uart_puts("\n\r"); 
74
          break;
75
      }
76
    */  
77
    connect = i2c_write(CMD);                 // write command
78
    /*  switch(connect)
79
      {
80
      case 0:
81
          uart_puts("Folgendes Kommando uebertragen:");
82
          send_int_uart(CMD);  
83
          uart_puts("\n\r");
84
          break;
85
      case 1:
86
          uart_puts("Folgendes Kommando NICHT uebertragen:");
87
          send_int_uart(CMD);  
88
          uart_puts("\n\r");
89
          break;
90
      }
91
    */  
92
    connect = i2c_write(DATA);                  // write data
93
    /*  switch(connect)
94
        {
95
        case 0:
96
            uart_puts("Folgenden Inhalt gesendet:");
97
            send_int_uart(DATA);  
98
            uart_puts("\n\r");
99
            break;
100
        case 1:
101
            uart_puts("Folgenden Inhalt NICHT uebertragen:");
102
            send_int_uart(DATA);  
103
            uart_puts("\n\r");
104
            break;
105
        }
106
    */    
107
    i2c_stop();                       // set stop conditon = release bus
108
    //uart_puts(" I2C BUS released");
109
    }
110
  
111
  
112
  unsigned char I2CRead_CCS(uint8_t ADDR, uint8_t CMD) // Funktion zum lesen von Daten aus I2C Slave ( CCS = ClocClock Slave)
113
  {   
114
    int data;
115
    int connect;
116
    connect = i2c_start(ADDR+I2C_WRITE);   // set device address and write mode
117
  /*  switch(connect)
118
    {
119
    case 0:
120
        uart_puts("Verbindung zu Slave:");
121
        send_int_uart(ADDR);  
122
        uart_puts("\n\r");
123
        break;
124
    case 1:
125
        uart_puts("KEINE Verbindung zu Slave:");
126
        send_int_uart(ADDR);  
127
        uart_puts("\n\r");
128
        break;
129
    }
130
  */  
131
    connect = i2c_write(CMD);                 // write command, sendet Startpostion der Leseadresse an Slave
132
  /*  
133
      switch(connect)
134
      {
135
      case 0:
136
          uart_puts("Verbindung zu Slave:");
137
          send_int_uart(ADDR);  
138
          uart_puts("\n\r");
139
          break;
140
      case 1:
141
          uart_puts("KEINE Verbindung zu Slave:");
142
          send_int_uart(ADDR);  
143
          uart_puts("\n\r");
144
          break;
145
      }
146
  */    
147
    connect = i2c_rep_start   (ADDR+I2C_READ);   // Repeated Start
148
  /*  
149
          switch(connect)
150
      {
151
      case 0:
152
          uart_puts("Verbindung zu Slave:");
153
          send_int_uart(ADDR);  
154
          uart_puts("\n\r");
155
          break;
156
      case 1:
157
          uart_puts("KEINE Verbindung zu Slave:");
158
          send_int_uart(ADDR);  
159
          uart_puts("\n\r");
160
          break;
161
      }
162
  */    
163
    data = i2c_readNak();      // Liest akutelle Bufferposition vom Slave aus und schrebit sie in die variable "ccs_data"
164
    i2c_stop();            // set stop conditon = release bus
165
  //  uart_puts(" I2C BUS released");
166
  //  uart_puts("\n\r");
167
    return data;            // Gibt das gelesene Byte an funktion zurück  
168
  }
169
  
170
171
//Interrupts
172
173
174
// Aktion bei Timer 1 Overflow (alle 100ms)
175
ISR (TIMER1_OVF_vect)
176
{
177
178
  PORTD ^=(1<<PD5); //LED 1 Toggeln
179
180
  
181
  ++count_100ms;      // Intervallzähler inkrementieren
182
  TCNT1 = 40536; // Timer1 vorladen damit er  nach 100ms überläuft
183
  
184
}
185
186
// Hauptschleife
187
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
188
  int main (void) // Start Hauptschleife
189
  {
190
  
191
    // Eingänge definieren
192
    
193
194
195
    // Ausgänge definieren
196
      DDRD |=(1<< PD1);       //UART Tx
197
      DDRD |=(1<< PD5);       //Test Led1
198
      DDRD |=(1<< PD6);       //Test Led2
199
    
200
    // UART initialisieren
201
202
      uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );   
203
204
    
205
    // Startkonfig Timer 1 
206
  
207
      TCCR1B |= (1<<CS10);   // Prescaler /64 = Overflow alle 100ms und Timer starten
208
      TCCR1B |= (1<<CS11);   //
209
      
210
      TIMSK |= (1<<TOIE1);   // Overlfow ISR erlauben
211
212
      
213
      TCNT1 = 40536;      // TImer1 vorladen damit er  nach 100ms überläuft
214
    
215
    // I2C initialisieren
216
    
217
      i2c_init();
218
    
219
    
220
    // Global Interrupts aktivieren
221
      sei();  
222
223
      
224
225
  while(1)  // Start Dauerschleife
226
  {
227
      
228
    //Zeit setzen
229
      if ( count_100ms == 1) // 100ms
230
        {
231
          timestamp |= ((1 << 3));
232
          ++count_500ms;
233
          count_100ms = 0;
234
        }
235
236
      if ( count_500ms == 5) // 500ms
237
        {
238
          timestamp |= ((1 << 4));
239
          ++count_1s;
240
          count_500ms = 0;
241
        }
242
243
      if ( count_1s ==2) // 1s
244
        {
245
246
          timestamp |= ((1 << 5));
247
          ++count_2s;
248
          count_1s = 0;
249
        }
250
251
      if ( count_2s ==2) // 1s
252
        {
253
254
          timestamp |= ((1 << 6));
255
          
256
          count_2s = 0;
257
        }
258
259
  // Test Taster
260
261
    if((PIND &(1<<PD2)))
262
    {
263
    
264
    
265
    }
266
    
267
    
268
  //Zeitgesteuerte Aktionen
269
      
270
    //100ms
271
      if ((timestamp & (1<<3))) 
272
      {
273
274
        
275
        
276
        timestamp &= ~((1 << 3)); // Zetistempelbit 100ms löschen
277
      }
278
279
    //500ms
280
      if ((timestamp & (1<<4)))   
281
      {
282
        PORTD ^=(1<<PD6); //LED 2 Toggeln
283
        
284
        
285
        timestamp &= ~((1 << 4)); // Zetistempelbit 500ms löschen
286
      }
287
  
288
    //1s
289
      if ((timestamp & (1<<5)))   
290
      {
291
        
292
        
293
        
294
        timestamp &= ~((1 << 5)); // Zetistempelbit 1s löschen      
295
      }
296
      
297
    //2s
298
      if ((timestamp & (1<<6))) 
299
        {
300
        for(int address = CCS_ADDRESS_START ; address<= CCS_ADDRESS_END;address++)
301
              {  
302
                  
303
                ccs_data = I2CRead_CCS(address, CCS_STATUS); //Statusbyte auslesen
304
                //uart_puts("CCS STATUS:");
305
                //send_int_uart(ccs_data);
306
307
                if ((ccs_data & (CCS_NEW_DATA))==0)
308
                {
309
                  int data = 0;
310
                      
311
                    uart_puts("Neue Daten werden an Slave gesendet...Adresse");
312
                    send_int_uart(address);
313
                    uart_puts("\n\r");
314
                        
315
                  for (int i = CC_DATA_START; i<= CC_DATA_END; i++)  
316
                  {
317
                    ++data;              // Testdaten
318
                  /*  
319
                    I2CWrite_CCS(address, i, data);
320
                    uart_puts("Block Nr.");
321
                    send_int_uart(i);
322
                    uart_puts(", Inhalt:");
323
                    send_int_uart(data);
324
                    uart_puts("\n\r");
325
                  */
326
                  }
327
                  
328
                  I2CWrite_CCS(address, CCS_STATUS, CCS_NEW_DATA);  // Für Slave markieren das neue Daten da sind
329
                  
330
                }
331
                      
332
                else if(ccs_data & CCS_NEW_DATA)
333
                      
334
                {
335
                // Wenn noch Daten vom Slave verarbeitet werden passiert nix
336
                /*
337
                  uart_puts("Slaveadresse:");
338
                  send_int_uart(address);
339
                  uart_puts("verarbeit noch alte Daten");
340
                  uart_puts("\n\r");
341
                */  
342
                }
343
344
              }        
345
            timestamp &= ~((1 << 6)); // Zetistempelbit 1s löschen
346
347
348
  
349
        }
350
    
351
352
    
353
    
354
  }//Ende Dauerschleife
355
}//Ende Hauptschleife
356
357
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
358
359
//Unterfunktion Integerwert über uart ausgeben
360
  void send_int_uart(int value)
361
  {
362
    char buffer [33];
363
    itoa (value,buffer,10);
364
    uart_puts(buffer);
365
  }





Hier das Slave Prog.


1
 
2
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3
4
// Demoprogramm für den ClockClock Slave
5
6
// µC :ATmega8
7
8
// CPU Takt : 8MHz
9
10
// Funktionsbeschreibung:
11
12
//------------------------------
13
14
// Version: V0.1
15
// Datum: 05.08.12
16
17
18
19
//------------------------------
20
21
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
22
23
#include <avr/io.h>
24
#include <avr/interrupt.h> 
25
#include "uart.h"         //Enthällt uart funktionen (Achtung uart.c muss in makefile eingetragen werden, wenn dies nicht von der ide gemacht wird)
26
#include <stdlib.h>       // enthällt die Umwandlung von int zu char (itoa)
27
#include <util/delay.h>     // Enthällt delay funktionen
28
#include <avr/wdt.h>        // Enthält Watchdog Funktionen
29
#include <cc_com.h>       // Definitionen für die I2C Kommunikation zwischen den Baugruppen
30
31
#include <avr/pgmspace.h>
32
33
#include "twislave.h"
34
35
// Definitionen
36
37
  #define TIMER1_preload     53036
38
39
  #ifndef F_CPU
40
  #define F_CPU         8000000UL  // CPU Takt in Hz
41
  #endif
42
  #define UART_BAUD_RATE    9600  
43
  #define SLAVE_ADRESSE 0x40                 // Slave-Adresse, wenn niederwertigstes Bit = 1 ist, 
44
                              // sind General Call Anfragen erlaubt 
45
46
47
//Deklaration der Variablen  
48
49
volatile unsigned char count_100ms       =  0;
50
volatile unsigned char count_500ms       =   0;
51
volatile unsigned char count_1s       =   0;  
52
volatile unsigned char timestamp       =  0;     // Zeitstempel byte
53
//( Bit3 = 100ms; Bit4 =  500ms; Bit5= 1s) 
54
                               
55
56
//Deklaration der Funktionsprototypen
57
58
void send_int_uart(int value); // Deklaration für UART INt SEND Unterfunktion
59
60
61
void Initialisierung(void)
62
  {
63
  cli();
64
65
  init_twi_slave(SLAVE_ADRESSE);      //TWI als Slave mit Adresse slaveadr starten 
66
  
67
  sei();
68
  }
69
70
71
//Interrupts
72
73
74
// Aktion bei Timer 1 Overflow (alle 100ms)
75
ISR (TIMER1_OVF_vect)
76
{
77
  ++count_100ms;      // Intervallzähler inkrementieren
78
  TCNT1 = 53036;       // Timer1 vorladen damit er  nach 100ms überläuft
79
}
80
81
82
83
84
85
// Hauptschleife
86
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
87
  int main (void) // Start Hauptschleife
88
  {
89
  
90
  
91
  
92
  
93
    // Eingänge definieren
94
    
95
96
97
    // Ausgänge definieren
98
      DDRD |=(1<< PD1);       //UART Tx
99
      DDRD |=(1<< PD5);       //Test Led1
100
      DDRD |=(1<< PD6);       //Test Led2
101
    
102
    // UART initialisieren
103
104
      uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );   
105
106
    
107
      // Startkonfig Timer 1 
108
  
109
        TCCR1B |= (1<<CS10);   // Prescaler /64 = Overflow alle 100ms und Timer starten
110
        TCCR1B |= (1<<CS11);   //
111
        
112
        TIMSK |= (1<<TOIE1);   // Overlfow ISR erlauben
113
114
        
115
        TCNT1 = 53036;      // TImer1 vorladen damit er  nach 100ms überläuft
116
        
117
        
118
      Initialisierung();  //I2C init
119
    
120
    
121
    // Global Interrupts aktivieren
122
      sei();  
123
124
      
125
126
  while(1)  // Start Dauerschleife
127
  {
128
      
129
    //Zeit setzen
130
      if ( count_100ms == 1) // 100ms
131
        {
132
          timestamp |= ((1 << 3));
133
          ++count_500ms;
134
          count_100ms = 0;
135
        }
136
137
      if ( count_500ms == 5) // 500ms
138
        {
139
          timestamp |= ((1 << 4));
140
          ++count_1s;
141
          count_500ms = 0;
142
        }
143
144
      if ( count_1s ==2) // 1s
145
        {
146
          timestamp |= ((1 << 5));
147
          count_1s = 0;
148
        }
149
150
    
151
    //Zeitgesteuerte Aktionen
152
    
153
    //100ms
154
    if ((timestamp & (1<<3))) 
155
    {
156
157
      timestamp &= ~((1 << 3)); // Zetistempelbit 100ms löschen
158
    }
159
160
    //500ms
161
    if ((timestamp & (1<<4)))   
162
    {
163
164
165
    PORTD ^=(1<<PD6); //LED 2 Toggeln
166
167
      timestamp &= ~((1 << 4)); // Zetistempelbit 500ms löschen
168
    }
169
170
171
172
    //1s
173
    if ((timestamp & (1<<5))) 
174
    {
175
176
      timestamp &= ~((1 << 5)); // Zetistempelbit 1s löschen  
177
    }
178
179
    
180
    if(rxbuffer[CCS_STATUS] & CCS_NEW_DATA  ) //
181
    
182
      
183
    {
184
      txbuffer[CCS_STATUS] |= CCS_NEW_DATA;    // Master mitteilen das der Slave beschäftigt ist
185
      rxbuffer[CCS_STATUS] &= ~(CCS_NEW_DATA);
186
      
187
      uart_puts("Daten von Master erhalten:");
188
      uart_puts("\n\r");
189
            
190
      for (int i = CC_DATA_START; i<= CC_DATA_END; i++)
191
      {
192
      /*
193
        uart_puts("Datenblock Nr:");
194
        send_int_uart(i);uart_puts("\t");
195
        uart_puts("Inhalt:");
196
        send_int_uart(rxbuffer[i]);
197
        uart_puts("\n\r");
198
      */  
199
      }
200
    
201
      txbuffer[CCS_STATUS] &= ~(CCS_NEW_DATA);  // Mastermitteilen das neue Daten empfangen werden können
202
      uart_puts("Bereit fuer neue Daten...");
203
      uart_puts("\n\r");
204
    }
205
206
207
    if((PIND &(1<<PD2)))
208
    {
209
      
210
      
211
      
212
213
    }
214
    
215
      
216
217
  }//Ende Dauerschleife
218
  }//Ende Hauptschleife
219
220
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
221
222
//Unterfunktion Integerwert über uart ausgeben
223
  void send_int_uart(int value)
224
  {
225
    char buffer [33];
226
    itoa (value,buffer,10);
227
    uart_puts(buffer);
228
  }

von Karl H. (kbuchegg)


Lesenswert?

Weil deien UART Ausgaben viel zu lang sind!

Es stimmt zwar, dass die Fleury Lib interruptgesteuert ist, aber 
irgendwann ist auch in der besten Lib der Ausgabepuffer voll und die 
Ausgabefunktion wird dazu gezwungen Däumchen zu drehen, bis durch den 
UART Interrupt genügend Platz im Buffer geschaffen wird, damit auch noch 
der Rest von "Krieg und Frieden" per UART versendet werden kann.


Entweder in den UART Funktionen die Puffergröße hochschrauben (was 
allerdings nichts daran ändert, dass die UART Übertragung seine Zeit 
braucht) oder ein etwas weniger geschwätziges Programm schreiben.

Zb.: Anstelle von
1
  uart_puts("Daten von Master erhalten:");

kann man auch
1
  uart_puts("Received ");
schreiben. Hat die gleiche Aussagekraft und ist um mehr als die Hälfte 
kürzer (und wird daher auch schneller per UART übertragen)

von Karl H. (kbuchegg)


Lesenswert?

Ausserdem sind mir deine ganzen 'timestamp' Sachen nicht geheuer.
1
ISR (TIMER1_OVF_vect)
2
{
3
4
  PORTD ^=(1<<PD5); //LED 1 Toggeln
5
6
  
7
  ++count_100ms;      // Intervallzähler inkrementieren
8
  TCNT1 = 40536; // Timer1 vorladen damit er  nach 100ms überläuft
9
  
10
}
11
12
...
13
14
    //Zeit setzen
15
      if ( count_100ms == 1) // 100ms
16
        {
17
          timestamp |= ((1 << 3));
18
          ++count_500ms;
19
          count_100ms = 0;
20
        }

in der ISR wird count_100ms erhöht. Dauert die Hauptschleife zu lange 
(länger als 200 ms), dann erwischt die Hauptschleife count_100ms nicht 
mehr mit dem Wert 1, sondern der Wert ist bereits höher. Als Folge davon 
wird der ganze timestamp Mechanismus nicht mehr getriggert und es muss 
gewartet werden, bis count_100ms dann irgendwann überläuft und wieder 
bei 0 beginnt.

IMHO sollte die ganze Zeitzählerei komplett in die ISR verfrachtet 
werden, so wie bei jeder Uhr. Uhrzeiten (oder wie hier bei dir 
Timestamps) sind als eine Einheit zu betrachten und nicht als eine 
Sammlung von getrennten Variablen. In der ISR muss die Uhrzeit erhöht 
werden, damit das ganze Sinn macht und nichts verloren geht. Dann mach 
das aber auch und erhöhe die Uhrzeit und nicht nur einen Teil davon. 
Nur so ist sicher gestellt, dass keine Zeittakte verloren gehen, solange 
die Interrupts aktiviert sind - egal was die Hauptschleife in der 
Zwischenzeit macht.

von M. H. (dbzwerg)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Weil deien UART Ausgaben viel zu lang sind!
>
> Es stimmt zwar, dass die Fleury Lib interruptgesteuert ist, aber
> irgendwann ist auch in der besten Lib der Ausgabepuffer voll und die
> Ausgabefunktion wird dazu gezwungen Däumchen zu drehen, bis durch den
> UART Interrupt genügend Platz im Buffer geschaffen wird, damit auch noch
> der Rest von "Krieg und Frieden" per UART versendet werden kann.
>

Naja das meine TExte evtl. nen bissle lang seh ich ja ein...allerdings 
werden die texte ja komplett ausgespuckt und an meinem PC terminal 
angeziegt und erst DANACH passiert nix mehr...

von Karl H. (kbuchegg)


Lesenswert?

Da spielen mehrere Dinge zusammen.

Deine zu langen Ausgaben mit deiner Timestamp-Steuerung.
Das alles beeinflusst sich gegenseitig und führt zu dem Effekt den du 
siehst.

Beitrag "Re: fleurys I2C + UART lib halten in Kombination die Hauptschleife an!"

von M. H. (dbzwerg)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Ausserdem sind mir deine ganzen 'timestamp' Sachen nicht geheuer.
>

>
> IMHO sollte die ganze Zeitzählerei komplett in die ISR verfrachtet
> werden, so wie bei jeder Uhr. Uhrzeiten (oder wie hier bei dir
> Timestamps) sind als eine Einheit zu betrachten und nicht als eine
> Sammlung von getrennten Variablen. In der ISR muss die Uhrzeit erhöht
> werden, damit das ganze Sinn macht und nichts verloren geht. Dann mach
> das aber auch und erhöhe die Uhrzeit und nicht nur einen Teil davon.

Das klingt logisch...danke für den Tipp werde es mal probieren, 
allerdings ist mir das mit "Uhrzeiten als Einheit" noch nicht klar.
Könntest du mir ein beispiel geben?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

M. H. schrieb:
> allerdings ist mir das mit "Uhrzeiten als Einheit" noch nicht klar.

count_100ms
count_500ms
count_1s
count_2s

All diese sollten in der ISR "an einem Stück" aktualisiert werden und 
nicht in der Hauptschleife. Dann bilden sie auch die gewünschte Einheit.

von Karl H. (kbuchegg)


Lesenswert?

> allerdings ist mir das mit "Uhrzeiten als Einheit" noch nicht
> klar. Könntest du mir ein beispiel geben?


Sieht man oft
1
ISR( ... )
2
{
3
  ++Sekunden;
4
}
5
6
int main()
7
{
8
  ...
9
10
  while( 1 )
11
    if( Sekunden == 60 )
12
      Minuten++;
13
14
    ...

und das ist QUatsch. Dauert die Aktion in der Hauptschleife in Summe 
länger als 2 Sekunden, dann wird der 60-er Overflow zu spät gemacht, 
weil eine 1 Sekunde verloren geht.

Die Uhrzeit besteht aus Sekunden + Minuten + Stunden. Also erhöh das 
auch so in der ISR
1
ISR( ... )
2
{
3
  Sekunden++;
4
  if( Sekunden == 60 ) {
5
    Sekunden = 0;
6
    Minuten++;
7
    if( Minuten == 60 ) {
8
      Minuten = 0;
9
      Stunden++;
10
      if( Stunden == 24 )
11
        Stunden = 0;
12
    }
13
  }
14
}

Solange die ISR nur läuft, KANN keine Erhöhung verloren gehen oder zu 
spät erfolgen - egal was die Hauptschleife macht (und nicht schreibend 
auf die Variablen zugreift). Und wenn die Hauptschleife 3 Stunden lang 
_delay_ms macht geht trotzdem keine Zeitzählung verloren. Denn hier wird 
in der ISR die Uhrzeit als Ganzes erhöht und nicht nur ein Teil davon.

Bei dir dann eben
1
ISR (TIMER1_OVF_vect)
2
{
3
  TCNT1 = 40536; // Timer1 vorladen damit er  nach 100ms überläuft
4
5
  PORTD ^=(1<<PD5); //LED 1 Toggeln
6
7
  ++count_100ms;      // Intervallzähler inkrementieren
8
  timestamp |= ((1 << 3));
9
10
  ++count_500ms;
11
  if ( count_500ms == 5) // 500ms
12
  {
13
    count_500ms = 0;
14
    timestamp |= ((1 << 4));
15
    ++count_1s;
16
17
    if ( count_1s ==2) // 1s
18
    {
19
      count_1s = 0;
20
      timestamp |= ((1 << 5));
21
      ++count_2s;
22
23
      if ( count_2s ==2) // 1s
24
      {
25
        count_2s = 0;
26
        timestamp |= ((1 << 6));
27
      }
28
    }
29
  }
30
}

Hier kann nichts mehr verloren gehen! Solange der Timer läuft und die 
ISR aufgerufen wird, werden auch die Bits zuverlässig in den 
Zeitintervallen gesetzt.

(Nur musst du beim Abfragen der Bts ein wenig aufpassen! Atomarer 
Zugriff und sofortiges Zurücksetzen der Bits sind selbstverständlich.)

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.