Forum: Compiler & IDEs uint32_t Problem


von Markus Wien (Gast)


Lesenswert?

Hallo zusammen!
Zunächst einmal vielen Dank für dieses Forum. Konnte in den letzten 
Jahre immer wieder auf jede Menge nützliche Tips zurückgreifen und viel 
lernen.
Jetzt komme ich aber nicht mehr weiter. Ich möchte gerne eine Art "Uhr" 
in den Controller einbauen. Jede Millisekunde wird die ISR aufgerufen 
und inkrementiert die Variable __Time_ms um 1. In der 
Haupt-While-Schleife wird überprüft, ob 500ms vergangen sind. Ist dem 
so, dann wird eine LED aktiviert bzw. deaktiviert.

Jedoch blinkt die LED nicht regelmäßig. Ab und zu sind es nicht die 
veranschlagten 500ms, sondern weniger, bis sich der Status der LED 
ändert. Hab ich was offensichtliches übersehen?

Anbei der Code:
1
/****************/
2
/* Bibliotheken */
3
/****************/
4
5
#include <avr/io.h>
6
#include <avr/interrupt.h>
7
#include <util/delay.h>
8
#include "clock.h"
9
#include "led.h"
10
11
12
/****************/
13
/*  Prototypen  */
14
/****************/
15
16
void initAll (void);
17
18
19
20
/*********************/
21
/* Globale Variablen */
22
/*********************/
23
24
volatile uint32_t __Time_ms = 0;
25
26
27
28
/********************************************/
29
/*-------PROGRAMMCODE-----------------------*/
30
/********************************************/
31
32
/*****************/
33
/* MAIN-Funktion */
34
/*****************/
35
36
int main (void)
37
{
38
  uint32_t oldTime=0;
39
  uint8_t ledStatus=0;
40
41
42
  initAll();
43
44
  
45
  while (1)
46
  {
47
    if ((oldTime + 500) < CLOCK_SystemTime())
48
    {
49
      if (ledStatus)
50
      {
51
        LED_OnOff(0);
52
        ledStatus = 0;
53
      }
54
      else
55
      {
56
        LED_OnOff(1);
57
        ledStatus = 1;
58
      }
59
      oldTime = CLOCK_SystemTime();
60
    }    
61
  }
62
63
  return 1;
64
}
65
66
67
68
/****************/
69
/*  Funktionen  */
70
/****************/
71
72
void initAll (void)
73
{  
74
  LED_Init();
75
  
76
  TIMSK0|=1<<TOIE0);
77
  TCCR0A |= (1<<CS01) | (1<<CS00); //Set Timer0 prescaler 64
78
79
  sei();
80
}
81
82
83
84
85
86
/***********************************************************/
87
/*-------------INTERRUPT SERVICE ROUTINEN------------------*/
88
/***********************************************************/
89
90
ISR (TIMER0_OVF_vect)
91
{
92
  __Time_ms++;
93
  TCNT0 = 5;
94
}

von Johannes M. (johnny-m)


Lesenswert?

Erstens ist in obigem Code ein Syntaxfehler drin, weshalb das so sicher 
gar nicht kompiliert. Außerdem hast Du als Anwender keine Bezeichner zu 
vergeben, die mit Unterstrichen beginnen (und erst recht keine, die mit 
zwei Unterstrichen beginnen). Diese Bezeichner sind für das System 
(Compiler und lib) reserviert!

Abgesehen davon ist es für sinnvolle Hilfe essentiell erforderlich, zu 
wissen, um welchen Controller es überhaupt geht. Das gehört in den 
Betreff und steht auch in den Forenregeln, deren Kenntnis auch Du vor 
dem Absenden bestätigen musstest!

von Johannes M. (johnny-m)


Lesenswert?

Dass das ungenau wird (wenn es denn überhaupt funktioniert), wundert 
mich übrigens nicht wirklich. Timer-Reload macht man beim AVR einfach 
nicht. Jeder AVR hat mindestens einen Timer, der mindestens eine 
Compare-Einheit besitzt. Und wenn man die im CTC-Modus betreibt, dann 
wird das ganze auch genau.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Johannes M. wrote:

> Dass das ungenau wird (wenn es denn überhaupt funktioniert), wundert
> mich übrigens nicht wirklich. Timer-Reload macht man beim AVR einfach
> nicht.

Derartige Codeschnipsel stammen vermutlich noch aus der Zeit vor 10
Jahren, da der AT90S1200 in der Tat noch kein CTC hatte...

Wenn überhaupt, dann sollte der timer reload übrigens die erste
Operation innerhalb der ISR sein.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Markus Wien wrote:
> volatile uint32_t __Time_ms = 0;
>
> ISR (TIMER0_OVF_vect)
> {
>   __Time_ms++;
>   ...
> }

Race condition auf __Time_ms? Wo/wie das gelesen ist, kann man nur 
raten...

Johann

von Peter (Gast)


Lesenswert?

@Johann L.
>Race condition
kannst du das etwas genauer erleutern? Denn innerhalb der ISR kann das 
Programm ja nicht uterbrochen werden, wo soll da ein Problem entstehen?

von Johannes M. (johnny-m)


Lesenswert?

Peter wrote:
> @Johann L.
>>Race condition
> kannst du das etwas genauer erleutern? Denn innerhalb der ISR kann das
> Programm ja nicht uterbrochen werden, wo soll da ein Problem entstehen?
Das Problem ensteht dann, wenn im Hauptprogramm auf die Variable 
zugegriffen wird und während des Zugriffs ein Interrupt 
dazwischenhaut. Der Zugriff auf eine 32-Bit-Variable ist eine ziemlich 
langwierige Sache.

Ich verstehe auch absolut nicht, wozu Du bei den Zeiten einen 
32-Bit-Integer brauchst.

Die Frage nach dem Controller-Typ ist übrigens immer noch offen...



EDIT:
Sorry, hatte nicht gesehen, dass Du nicht der OP bist...

von (prx) A. K. (prx)


Lesenswert?

Johannes M. wrote:

> Ich verstehe auch absolut nicht, wozu Du bei den Zeiten einen
> 32-Bit-Integer brauchst.

Wenn man Zeitabhängigkeiten wie beispielsweise Timeouts über eine 
System-Uptime implementiert, dann ist das durchaus sinnvoll.

Man sollte dann allerdings für den Lesezugriff auf diese Variable eine 
eigene kleine Zugriffsfunktion implementieren, die den Zugriff bei 
abgeschalteten Interrupts durchführt.

von Peter (Gast)


Lesenswert?

@Johann L.
> Das Problem ensteht dann, wenn im Hauptprogramm auf die Variable
> zugegriffen wird und während des Zugriffs ein Interrupt
> dazwischenhaut. Der Zugriff auf eine 32-Bit-Variable ist eine ziemlich
> langwierige Sache.
Und wo wird im Hauptprogramm auf die Variable zugegriffen? Ich kann 
nicht sehen wo die Variable überhaupt verwendet wird. Also kann es auch 
gut möglich sein das er vor dem zugriff die interups ausschaltet und 
dann wieder einschaltet.

von Karl H. (kbuchegg)


Lesenswert?

Peter wrote:
> @Johann L.
>> Das Problem ensteht dann, wenn im Hauptprogramm auf die Variable
>> zugegriffen wird und während des Zugriffs ein Interrupt
>> dazwischenhaut. Der Zugriff auf eine 32-Bit-Variable ist eine ziemlich
>> langwierige Sache.
> Und wo wird im Hauptprogramm auf die Variable zugegriffen? Ich kann
> nicht sehen wo die Variable überhaupt verwendet wird.

Genau deswegen hat es Johann L. ja auch als Frage formuliert.

von Johannes M. (johnny-m)


Lesenswert?

A. K. wrote:
>> Ich verstehe auch absolut nicht, wozu Du bei den Zeiten einen
>> 32-Bit-Integer brauchst.
>
> Wenn man Zeitabhängigkeiten wie beispielsweise Timeouts über eine
> System-Uptime implementiert, dann ist das durchaus sinnvoll.
Hast natürlich Recht, ich hatte mir das Programm grad nicht noch mal 
angeschaut...

von Johannes M. (johnny-m)


Lesenswert?

Peter wrote:
> @Johann L.
>> Das Problem ensteht dann, wenn im Hauptprogramm auf die Variable
>> zugegriffen wird und während des Zugriffs ein Interrupt
>> dazwischenhaut. Der Zugriff auf eine 32-Bit-Variable ist eine ziemlich
>> langwierige Sache.
> Und wo wird im Hauptprogramm auf die Variable zugegriffen? Ich kann
> nicht sehen wo die Variable überhaupt verwendet wird.
Möglicherweise in der geheimen Funktion "CLOCK_SystemTime()"...

von Markus Wien (Gast)


Lesenswert?

Herzlichen Dank für die vielen hilfreichen Tips.
Den Interrupt der Uhr hab ich nun umgestellt (Danke an Jörg und 
Johannes). Macht die Sache etwas leichter und es spart Zeit.
Zugegebenermaßen hab ich das mit dem Code-Beispiel etwas verbockt. Ist 
z.T. aus anderen Files entnommen (daher auch die __Time_ms und die 
"geheimnisvolle" Funktion CLOCK_SystemTime) und zusammengebastelt. Hab 
es danach nicht mehr versucht zu kompilieren (mea culpa).

Den entscheidenden Hinweis gab schließlich Johann mit "race_condition". 
Die Lösung kam dann von Peter, A.K. Johannes und all den anderen.
Hab jetzt vor der Abfrage der SystemZeit den Interrupt deaktiviert und 
siehe da, es läuft. Kein zufälliges Flackern der LED mehr.

Werde das ganze jetzt noch etwas aufhübschen und wieder in den alten 
Code einbetten. Tausend Dank an alle.

Zu guter letzt: Es war ein AT90CAN128-Controller und die Uhr brauche ich 
zur exakten Abfrage von ms-Zeiten, die z.T. größer als 64 Sekunden sind. 
Daher kein uint16.


Anbei noch der Code:
1
////////////////////////////
2
/**************************/
3
/*                        */
4
/*      TEST              */
5
/*                        */
6
/**************************/
7
////////////////////////////
8
9
10
11
/****************/
12
/* Bibliotheken */
13
/****************/
14
15
#include <avr/io.h>
16
#include <avr/interrupt.h>
17
#include "led.h"
18
19
20
/****************/
21
/*  Prototypen  */
22
/****************/
23
24
void initAll (void);
25
uint32_t CLOCK_SystemTime2(void);
26
27
28
/*********************/
29
/* Globale Variablen */
30
/*********************/
31
32
volatile uint32_t systemTime_ms;
33
34
35
/********************************************/
36
/*--------PROGRAMMCODE----------------------*/
37
/********************************************/
38
39
/*****************/
40
/* MAIN-Funktion */
41
/*****************/
42
43
int main (void)
44
{
45
46
  uint8_t ledStatus=0;
47
  uint32_t oldTime=0;
48
49
50
  initAll();
51
52
  
53
  while (1)
54
  {
55
    if ((oldTime + 400) <= CLOCK_SystemTime2())
56
    {
57
      if (ledStatus)
58
      {
59
        LED_OnOff(0);
60
        ledStatus = 0;
61
      }
62
      else
63
      {
64
        LED_OnOff(1);
65
        ledStatus = 1;
66
      }
67
      oldTime = CLOCK_SystemTime2();
68
    }
69
  }
70
71
  return 1;
72
}
73
74
75
76
/****************/
77
/*  Funktionen  */
78
/****************/
79
80
void initAll (void)
81
{  
82
  LED_Init();  
83
84
  
85
  TCCR0A |= (1<<WGM01);
86
  TIMSK0 |= (1<<OCIE0A);
87
  TCCR0A |= (1<<CS01) | (1<<CS00);
88
  OCR0A = 250;
89
90
  systemTime_ms = 0;
91
92
  sei();
93
}
94
95
uint32_t CLOCK_SystemTime2(void)
96
{
97
  uint32_t buffer;
98
  cli();
99
  buffer = systemTime_ms;
100
  sei();
101
  return buffer;
102
}
103
104
105
106
107
/**************************************************/
108
/*----------INTERRUPT SERVICE ROUTINEN------------*/
109
/**************************************************/
110
111
ISR (TIMER0_COMP_vect)
112
{
113
  systemTime_ms++;
114
}

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.