Forum: Mikrocontroller und Digitale Elektronik ATMega32 Langzeitbetrieb


von Timm S. (atrocty)


Lesenswert?

Guten Morgen,

ich habe da mal ein kleines Anliegen. Zurzeit arbeite ich an meiner 
Abschlussprüfung als Systeminformatiker. Das Programm, welches wir 
programmieren sollten, ist eine Überwachungskamerasteuerung.

Das Programm an sich ist nicht die Problematik, es ist schon fertig 
geschrieben und die gewünschten Funktionen sind alle einwandfrei.
(OSD  Sensoren  UART ...)

Allerdings hat der Mikrocontroller (ATmega32) Probleme bei 
Langzeitbetrieb. Sobald der Mikrocontroller länger als 20 Minuten 
arbeitet hört die main-Routine auf zu arbeiten. In dieser Routine sollen 
die Kameras im 5-Sekunden Takt wechseln.

Als Funktion sollte eine Heartbeat-Anzeige über einen Timer laufen. 
Diese funktioniert einwandfrei, selbst nach stundenlangem Betrieb.

Die Sensoren haben allerdings dann keinen Einfluss mehr auf das 
Programm, ebenso hört der automatische Wechsel der Kameras auf.

Hier also die Frage:
Was ist da sinnvoller: Den µC über den Timer immer wieder neustarten zu 
lassen, oder den Speicher hzu säubern im Betrieb? Bei zweiterem wüsste 
ich nicht wie das funktionieren sollte...

Meinen Code poste ich noch nicht, da ich nicht weiß, ob es auch wirklich 
erlaubt ist. Das Programm wurde schon zur Bewertung abgegeben, nächste 
Woche erfolgt ein Änderungsauftrag des Programms.

Vielen dank für eure Hilfe und Grüße aus dem Norden!

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Timm S. schrieb:
> Was ist da sinnvoller: Den µC über den Timer immer wieder neustarten zu
> lassen, oder den Speicher hzu säubern im Betrieb?

Weder noch.
Du mußt schon den Fehler suchen und beseitigen.
Vermutlich ein Atomicity Problem oder ein Deadlock.

von Martin S. (tungl)


Lesenswert?

Das Programm so schreiben, dass nicht nach 20 Minuten der Speicher voll 
laeuft? Das muss ja irgendeinen Grund haben.

Da du den Code nicht posten willst/kannst, musst du dich wohl selber auf 
die Suche nach dem Problem begeben.

von spess53 (Gast)


Lesenswert?

Hi

>Was ist da sinnvoller: Den µC über den Timer immer wieder neustarten zu
>lassen, oder den Speicher hzu säubern im Betrieb?

Keins von beiden. Dein Programm hat Fehler. Die musst du finden und 
beheben.

MfG Spess

von Uli der Troll (Gast)


Lesenswert?

Ihr habt moeglicherweise ein Software problem, moeglicherweise ein EMV 
Problem. Ich verwende auch Mega32, und die laufen jahrelang durch, ohne 
reboot.

Boevor ich eine reboot massnahmen andenken und testen wuerde, wuerde ich 
versuchen den Fehler beheben. Das einzige was man periodisch neu 
initialisierent kann/sollte ist allenfalls ein LCD, da diese EMV 
empfindlich sind. Sobald die eingestrahlte Welle in den LCD Ausschnitt 
passt., dh gegen 1GHz und drueber. Ja, die EMV Vorschriften gehen bis 
3GHz. Jeden will ja mit einem Mobiltelephon rumlaufen ... das sendet 
wahlweise bei 800, 900, 1800, 1900MHz. Dann kommt WLAN bei 2.4GHz und 
5GHz.
Als ersten nimmt man den Watchdog raus. Mit dem sieht man nichts. Dann 
baut man eine Laufzeit messung ein, dh einen Zaehler, der per timer 
incrementiert, und den fragt man per kommunikation periodisch ab. Und 
dann sucht man den Zustand, wo der Controller abstuerzt.

von Timm S. (atrocty)


Lesenswert?

1
#ifndef F_CPU
2
#define F_CPU 16000000UL
3
#endif
4
5
#include <avr/interrupt.h>
6
#include <avr/io.h>
7
#include <stdlib.h>
8
#include <stdbool.h>
9
#include <util/delay.h>  
10
#include "pal.h"
11
#include "uart.h"
12
13
//----------------------------------------------------------------------
14
// Eigene Definitionen
15
//----------------------------------------------------------------------
16
17
#define UART_BAUD_RATE      9600
18
19
//----------------------------------------------------------------------
20
// Globale Variablen
21
//----------------------------------------------------------------------
22
23
volatile bool CamSelect = true;      // true = Kamera 2, false = Kamera 1
24
volatile bool Heartbeat = true;
25
volatile bool Interrupted = false;
26
27
//----------------------------------------------------------------------
28
// Interrupt-Routinen
29
//----------------------------------------------------------------------
30
ISR(INT0_vect)
31
{
32
  Interrupted = true;          // Setzt den Schalter "Interrupted" auf HIGH für Delay Funktion (siehe unten)
33
}
34
35
ISR(INT1_vect)
36
{
37
  Interrupted = true;
38
}
39
40
ISR(TIMER1_COMPA_vect)
41
{  
42
  Heartbeat = !Heartbeat;        // Invertiert den Schalter "Heartbeat" bei jedem Timer-Überlauf
43
  display_memory_address = 393;    // Position auf dem Bildschirm für OSD
44
  if (Heartbeat == true)
45
    pal_write_char(0xF8);      // Zeichne das gewählte Heartbeat-Symbol auf dem Bildschirm wenn Heartbeat ein ist...
46
  else
47
    pal_write(" ");          // ... ansonsten lösche es
48
}
49
50
//----------------------------------------------------------------------
51
// Initialisieren der Eingänge/Ausgänge und Interrupts
52
//----------------------------------------------------------------------
53
54
void init()
55
{
56
  DDRA = 0xA7;            // Kamera
57
  DDRC |= (1<<PC0);          // Ausgangspin für Aufnahmegerät
58
  DDRD = 0x00;            // Eingang für Sensoren
59
  
60
  PORTC |= (1<<PC0);          // Setze Aufnahme auf HIGH (Low-Aktiv)
61
  PORTD |= (1<<PD2);          // Setze internen Pull-Up
62
  
63
  GICR  |= (1<<INT0)  | (1<<INT1);
64
  MCUCR |= (1<<ISC00) | (1<<ISC10);
65
}
66
67
//----------------------------------------------------------------------
68
// Initialisieren des Timers
69
//----------------------------------------------------------------------
70
71
void initTimer()
72
{
73
  TCCR1B |= (1<<WGM12) | (1<<CS12);  // Compare-Match-Mode (CTC), Prescaler 256
74
  TIMSK  |= (1<<OCIE1A);        // Aktivierung CTC
75
  OCR1A  = 62499;          // Setze Zeit, bis Timer überlaufen ist (1 Sekunde)
76
}
77
78
//----------------------------------------------------------------------
79
// Anzeige Variable über UART
80
//----------------------------------------------------------------------
81
82
void uart_putv(int Variable)
83
{
84
  char Buffer[20];
85
  itoa( Variable, Buffer, 10 );
86
  uart_puts( Buffer );
87
}
88
89
//----------------------------------------------------------------------
90
// VT100 Code über UART
91
//----------------------------------------------------------------------
92
93
void uart_vt100(const char *s )
94
{
95
  //-------------------------------------------------------------------------
96
  // VT100-Code. Dieser wird mit der ESC-Taste initialisiert (ASCII-Wert: 27)
97
  // Referenz: http://thoughtmountain.com/VT100_codes.html
98
  //-------------------------------------------------------------------------
99
100
  uart_putc(27);
101
  while (*s)
102
  uart_putc(*s++);
103
}
104
105
//----------------------------------------------------------------------
106
// Delay, der mit Interrupt abgebrochen werden kann
107
//----------------------------------------------------------------------
108
109
void myDelay(int ms)
110
{
111
  for (int i = 0; i < ms; i++)
112
  {
113
    _delay_ms(1);
114
    if(Interrupted == true)      // Wird durch Interrupt ausgelöst
115
      break;
116
  }
117
}
118
119
//======================================================================
120
//   Main-Funktion
121
//======================================================================
122
123
int main (void)
124
{
125
  // Initialisierungen durchführen (I/O, OSD,...)
126
  init();
127
  pal_init();
128
  initTimer();
129
  // Freigabe der Interrupts/Timer
130
  sei();
131
  
132
  // Initialisierung von UART
133
  uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );
134
  uart_vt100("[2J");                  // [UART] Lösche aktuellen Terminal-Bildschirm
135
  
136
  while(1)
137
  {
138
    Interrupted = false;              // Rücksetzung des Interrupt-Schalters
139
      
140
    if ((PIND & (1<<PD2) ) && !(PIND & (1<<PD3) ))  // Wenn Sensor 1 HIGH und Sensor 2 LOW ist, schalte auf Kamera 2 (halten)
141
      CamSelect = true;
142
    if (!(PIND & (1<<PD2) ) && (PIND & (1<<PD3) ))  // Wenn Sensor 1 LOW und Sensor 2 HIGH ist, schalte auf Kamera 1
143
      CamSelect = false;
144
      
145
    if (CamSelect == true)              // Wenn Kamera 2 geschaltet
146
    {
147
      PORTA |= 0x20;                // Schalte Kamera 2 auf Video Kanal -X6
148
      display_memory_address = 413;
149
      pal_write("Cam2 ");              // [OSD] Gebe "Cam2" auf Bildschirm aus
150
    }
151
    else if (CamSelect == false)          // Wenn Kamera 1 geschaltet
152
    {
153
      PORTA &= ~(0x20);              // Schalte Kamera 1 auf Video Kanal -X6
154
      display_memory_address = 413;
155
      pal_write("Cam1 ");              // [OSD] Gebe "Cam1" auf Bildschirm aus
156
    }
157
    
158
    if ((PIND & (1<<PD2) ) || (PIND & (1<<PD3) ))
159
    {
160
      uart_vt100("[31m");              // [UART] Schrift Rot
161
      uart_vt100("[2;3f");            // [UART] Zeile 2, Position 3
162
      uart_puts("  Aufnahme!    ");        // [UART] Ausgabe "Aufnahme"
163
      display_memory_address = 43;
164
      pal_write("ALARM");              // [OSD] Gebe "ALARM" auf Bildschirm aus
165
      PORTC &= ~(1<<PC0);              // Aufnahmepin LOW (Low-Aktiv!!!)
166
    }
167
    else
168
    {
169
      uart_vt100("[0m");              // [UART] Schrift zuruecksetzen
170
      uart_vt100("[2;3f");
171
      uart_puts("Einsatzbereit");
172
      display_memory_address = 43;
173
      pal_write("Ruhe ");
174
      PORTC |= (1<<PC0);              // Aufnahmepin HIGH (Low-Aktiv!!!)
175
    }
176
    uart_vt100("[1;1f");
177
    uart_vt100("[?25l");              // [UART] Cursor unsichtbar schalten
178
    uart_vt100("[33m");                  // [UART] Gelbe Schrift
179
    uart_puts("-----------------");          // [UART] Zeichne Rahmen
180
    uart_vt100("[3;1f");
181
    uart_puts("-----------------");
182
    myDelay(5000);                  // Warte 5 Sekunden (Kann per Interrupt abgebrochen werden)
183
    CamSelect = !CamSelect;              // Wechsle aktuelle Kamera
184
  }
185
}

Das wäre der aktuelle Code ohne Treiber...
Die Sensoren sind hierbei an den beiden Interrupts angeschlossen.

: Bearbeitet durch User
von Uli der Troll (Gast)


Lesenswert?

die variable interrupted wird von zwei interrupts gespiesen ?

Uart ist blockierend ? Sollte man nie machen... ist nicht mehr debugbar. 
In welchem Zustand ist das programm? Nimm eine Zustandsmaschine.

von Timm S. (atrocty)


Lesenswert?

Von Zustandsmaschine hatte ich vorher noch nichts gehört, habe 
eigentlich nur mit Struktogrammen und PAP's gearbeitet.

Das 2 Interrupts für 1 Varriable verwendet wird ist bedingt durch die 
vordefinierte Hardware, zu der wir das Programm schreiben sollten.
(Jeder Interrupt = 1 Sensor)

UART ist hier allerdings Nebensache, habe das Programm auch ohne UART 
laufen lassen und das gleiche Resultat erhalten.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Was mir im Programm auffällt:

PD2 und PD3 werden als Eingang benutzt. Aber  nur für PD2 wird ein 
Pullup eingeschaltet.

Dann natürlich und nicht zu übversehen: pal_write bzw. die 
Adressumschaltung wird von main UND von der ISR aufgerufen.
Ist das Zulässig? ist pal_write reentrant? Was passiert, wenn gerade die 
Funktion pal_write läuft und der Interrupt ausgelöst wird, der 
seinersseits pal_write aufruft?

Auch interessant: was passier, wenn hier
1
      display_memory_address = 413;
2
      pal_write("Cam2 ");              // [OSD] Gebe "Cam2" auf Bildschirm aus
genau nach dem Zuweisen der neuen Adresse und vor dem Aufruf von 
pal_write ein Interrupt auftritt, der seinerseits
1
ISR(TIMER1_COMPA_vect)
2
{  
3
  Heartbeat = !Heartbeat;        // Invertiert den Schalter "Heartbeat" bei jedem Timer-Überlauf
4
  display_memory_address = 393;    // Position auf dem Bildschirm für OSD
5
...
die Adresse wieder umsetzt?


Alles das sind genau die Dinge, die bei ersten Tests gut gehen, die aber 
irgendwann zeitlich sich genau so ausgehen, dass es zu Fehlsituationen 
kommt.

Warum habt ihr euch denn nicht an eine der Grundregeln gehalten: In 
einer ISR werden keine Ausgaben gemacht. Oder, wenn schon, dann NUR in 
dieser ISR. Bei "Shared Resourcen" also Dingen, die sich mehrere 
Programmteile 'teilen', muss man ein wenig vorsichtig sein! Das führt 
sonst ganz schnell zu massiven Synchronisations bzw. Reentrance 
Problemen.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Genau, darum klassische mit Flags, siehe Interrupt.
Und eine Statemachine MUSS man auch als Systeminformatiker kennen!
Das ist das KLEINE 1x1!

von Karl H. (kbuchegg)


Lesenswert?

Das hier
1
    if ((PIND & (1<<PD2) ) && !(PIND & (1<<PD3) ))  // Wenn Sensor 1 HIGH und Sensor 2 LOW ist, schalte auf Kamera 2 (halten)
2
      CamSelect = true;
3
    if (!(PIND & (1<<PD2) ) && (PIND & (1<<PD3) ))  // Wenn Sensor 1 LOW und Sensor 2 HIGH ist, schalte auf Kamera 1
4
      CamSelect = false;

ist sowieso seltsam.
Wenn PD2 immer das Gegenteil von PD3 sein muss, dann frage ich mich: 
wozu überhaupt 2 Eingänge? Offenbar tut es ja auch einer. Dann erhebt 
sich dann auch nicht die Frage: was passiert, wenn PD2 und PD3 den 
gleichen Pegel haben? (ok, in dem Fall ändert dann CamSelect seinen 
Zustand nicht. Aber: ist das auch so gewollt?)

von Timm S. (atrocty)


Lesenswert?

Zuerst mal danke für die konstruktiven Beiträge!

Der Pullup war eigentlich nicht nötig, da Hardwaremäßig ein Widerstand 
verbaut wurde. Wird also bei meiner nächsten Revision entfernt.

Bei den rare occurrences wie du beschrieben hast ist die Formatierung 
teils durcheinander... bin schon dabei das zu beheben.

Ich probiere mal den Code umzuschreiben und dies aus der Timer-Routine 
zu entfernen, melde mich wenn es geklappt hat.

von Matthias X. (current_user)


Lesenswert?

Hast du einen Debugger? Wo bleibt der stehen?

Ich erkenne hier kein Speicherleck.
Dein Heartbeat kommt weiter regelmäßig?
Hast du sonst irgendwo eine While Schleife oder ähnliches in den 
Treibern?

Wenn du keinen Debugger hast, dann erstelle einen Zähler in der 
Hauptschleife. Stürzt das Programm dann immer exakt nach xxx durchläufen 
ab? Erstelle an verschiedenen Punkten der Hauptschleife eine UART 
Ausgabe. Wo stürzt er ab.
Wie sehen die PAL-write Rountinen aus. Kann es sein dass er dort hängen 
bleibt?

von Karl H. (kbuchegg)


Lesenswert?

Die ganze Sache mit dem 5 Sekunden Delay, der durch Interrupt 
abgebrochen werden kann ... man kann es so machen, mit etwas Bauchweh. 
Aber so richtig 'nach den Regeln der Kunst' ist das nicht wirklich.

Letzten Endes ist das doch ein: wenn einer von 2 Eingängen eine Flanke 
aufweist, dann bewerte die Schalterstellungen (bzw. Sensorstellung) neu 
und schalte gegebenenfalls die Kameras um, spätestens aber alle 5 
Sekunden.
Man würde das anders programmieren. Das Stichwort Statemachine ist ja 
schon gefallen.
Der Grund dafür ist einfach: mit dem delay verbaut ihr euch zukünftige 
Erweiterungen massiv. Damit da in diesen Zeittakt noch was anderes 
reinpasst, muss man sowieso das Programm umbauen. Da kann man das auch 
jetzt gleich nach den Regeln der Kunst machen.

von Timm S. (atrocty)


Lesenswert?

Karl Heinz schrieb:
> Das hier ist sowieso seltsam.
> ist das auch so gewollt?

Das ist so gewollt. Wenn exklusiv ein Sensor aktiv ist, soll die Kamera 
explizit auf den zugewiesenen Sensor zugewiesen werden. Sind beide 
Sensoren aktiv, soll wie bei inaktiven Sensoren hin- und hergeschaltet 
werden. Nur die Aufnahme soll dann noch erfolgen.

von Timm S. (atrocty)


Lesenswert?

Habe nun relativ simpel die Heartbeat-Funktion in meine Delay-Funktion 
eingebaut. Bisher läuft die Platine einwandfrei. (15 Minuten läuft er 
bereits)

Wenn nicht mit Delay, wie dann? Wie soll ich "in den Regeln der Kunst" 
einen 5-Sekunden-Takt erzeugen, wobei die Kamerastellung wechselt ?

Groß erweitert soll das Programm eh nicht mehr. (Auch wenn diese 
Einstellung nicht gerade löblich ist, das weiß ich)

Ich denke, dass beim Änderungsauftrag nur noch zusätzlich der 
Watchdog-Sensor angeschlossen werden soll, der fehlt noch bei der 
fertigen Platine. Den Code dafür habe ich mir auch schon vorgeschrieben.

von Falk B. (falk)


Lesenswert?

@ Timm S. (atrocty)

>Wenn nicht mit Delay, wie dann? Wie soll ich "in den Regeln der Kunst"
>einen 5-Sekunden-Takt erzeugen, wobei die Kamerastellung wechselt ?

Siehe Statemachine

>Groß erweitert soll das Programm eh nicht mehr. (Auch wenn diese
>Einstellung nicht gerade löblich ist, das weiß ich)

Mag sein, aber du willst ja was Gescheites für deine berufliche Zukunft 
lernen und nicht in BASCOM-Arduino-Style was zusammenfrickeln.

von Karl H. (kbuchegg)


Lesenswert?

Timm S. schrieb:
> Habe nun relativ simpel die Heartbeat-Funktion in meine Delay-Funktion
> eingebaut. Bisher läuft die Platine einwandfrei. (15 Minuten läuft er
> bereits)
>
> Wenn nicht mit Delay, wie dann? Wie soll ich "in den Regeln der Kunst"
> einen 5-Sekunden-Takt erzeugen, wobei die Kamerastellung wechselt ?

Du hast einen Timer laufen, der den Heartbeat erzeugt.
Die 5 Sekunden kann man auch als 'Anzahl von aufgetretenen Heartbeats' 
ausdrücken.
Wann immer in einem Programm Zeiten (hinreichender Größe, alles über ein 
paar µs) vorkommen, dann kannst du deinen Allerwertesten darauf 
verwetten, dass die Lösung über Timer führt und nicht über delays. 
Delays sind oft nicht die Lösung, sie sind aber oft das Problem.

In deinem Fall musstest du zu einem Kunstgriff greifen, indem du den 
Delay mittels Interrupt von hinten durch die Brust ins Auge abwürgen 
musstest, nur damit du auch zeitnah auf das Ansprechen eines Sensors 
reagieren kannst. Drückst die die Umschaltzeiten als Anzahl von 
Heartbeats aus und schaltest du in main nur dann um, wenn diese Anzahl 
erreicht ist, dann fällt der delay flach und damit auch die ganze 
Interrupt Geschichte, die du nur brauchtest um den Delay vorzeitig 
abwürgen zu können. Das Programm wird also eigentlich sogar einfacher, 
auch wenn sich das bei dir nicht viel schenken wird.
Aber: da du die externen Interrupts gar nicht mehr brauchst, hast du 
auch die Einschränkung auf lediglich 2 von ihnen weg. Du kannst also 
beliebig viele (im Rahmen der Pins deines µC) derartige Kameras und 
Sensoren anhängen, ohne dass sich an der Programmstruktur groß was 
ändert.
So arbeiten Profis: sie lassen sich Optionen für die Zukunft offen, wenn 
ihnen das in der Programmstruktur praktisch nichts kostet.


> Groß erweitert soll das Programm eh nicht mehr. (Auch wenn diese
> Einstellung nicht gerade löblich ist, das weiß ich)

Ist kein Argument. Du bist kein Bastler, sondern das ist deine 
Abschlussarbeit, die dir bescheinigt, dass du eine Fachkraft bist. 
Schlimm genug, dass dir der Begriff Statemachine (oder das deutsche 
Zustandsautomat) nichts sagt.

: Bearbeitet durch User
von Timm S. (atrocty)


Lesenswert?

Karl Heinz schrieb:
> Ist kein Argument. Du bist kein Bastler, sondern das ist deine
> Abschlussarbeit, die dir bescheinigt, dass du eine Fachkraft bist.
> Schlimm genug, dass dir der Begriff Statemachine (oder das deutsche
> Zustandsautomat) nichts sagt.

Dem stimme ich auch vollkommen zu.
Leider wird meist nur nach IHK-Richtlinien gelehrt, und dabei haben wir 
hier noch das Glück, dass wir einige Sachen lernen, die nicht unbedingt 
direkt was mit dem Berufsfeld zu tun haben. Und in den IHK-Richtlinien 
gabs wohl die Zustandsautomaten nicht. (Auch nicht in vielen Jahren 
vorher laut den Prüfungen, haben Sommer/Winter von 2004-2013 
durchgearbeitet)
Mal schauen ob sich einiges ändert sobald das Studium losgeht...

Zum Programm: Ich gehe davon aus, dass du meinst, wenn ich ohne delays 
arbeite die Interrupts nicht brauche.
Bin am überlegen:
Gehen wir mal davon aus ich entferne den delay. Der Timer ist auf exakt 
1 Hz getaktet.
Um ein Flackern durch OSD und UART zu verhindern wird ein Schalter als 
Bedingung gesetzt, der immer nur bei Änderungen schaltet.
Ist das so der richtige Ansatz?

von Falk B. (falk)


Lesenswert?

@

>Zum Programm: Ich gehe davon aus, dass du meinst, wenn ich ohne delays
>arbeite die Interrupts nicht brauche.

Nein, den Timer-Interrupt brauchst du auf jeden Fall. Aber die Externen 
Interrupts nicht.

>Gehen wir mal davon aus ich entferne den delay. Der Timer ist auf exakt
>1 Hz getaktet.

Kann man machen, ist aber eher zu langsam. Praktisch wird man eher 
10-1000Hz anstreben.

>Um ein Flackern durch OSD und UART zu verhindern wird ein Schalter als
>Bedingung gesetzt, der immer nur bei Änderungen schaltet.
>Ist das so der richtige Ansatz?

So in etwa.

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.