Komisches Verhalten des ADC bei Funktionsaufruf / µC friert ein

Gast #2730484
Guten Abend,
ATMega8, 8MHz
Ich habe ein für mich unverständliches und auch komisches Problem. Ich 
initialisiere den ADC, löse eine einmalkonvertierung in einem Interrupt 
aus, speichere den ADC-Wert in einer globalen Variable und greife in 
einer Unterfunktion in einer if-Abfrage auf diese Variable zu.
1
volatile uint16_t g_dimmdauer = 10;
2

3
void main (void) {
4
//ADC zur Dimmgeschwindigkeitseinstellung per Poti an PC2 / ADC2
5
ADMUX |= (1 << REFS0) | (1 << MUX1);
6
//ADC Enable und Vorteiler 64
7
ADCSRA |= (1 << ADEN) | (1 << ADPS1) | (1 << ADPS2);
8
ADCSRA |= (1 << ADSC);
9

10
  while (1) {
11
    buntflackern();
12
  }
13
}
14

15
ISR (TIMER2_OVF_vect) {
16
static uint16_t ADC_neu = 0;
17

18
//ADC Auswerten
19
while (!(ADCSRA & (1 << ADIF)));
20
ADC_neu = ADC/10;
21
//Zittern beseitigen
22
if ((ADC_neu < g_dimmdauer - 5) || (ADC_neu > g_dimmdauer +5))
23
  g_dimmdauer = ADC_neu;
24

25
//Hier kommen noch Tasterabfragen, die allerdings funktionieren, wenn ich den ADC auskommentiere oder der µC nicht einfriert.
26
}
27

28
void buntflackern(void) {
29
static uint16_t  i =0;
30
i++;
31
  if(i >= g_dimmdauer) {
32
    i=0;
33
    g_farbwahl++;
34
    g_menue_gesetzt=0;
35
  }
36
  if (g_farbwahl > 6)
37
    g_farbwahl =0;
38
  
39
  standfarbe();
40
}

Ok, soweit so klar. Was passiert? Ich stelle den Poti so, dass der ADC 
mir Werte nahe 0 ausgibt. Drehe ich am Poti, erhöhe ich den Wert, das 
buntflackern wird langsamer, da g_dimmdauer größer wird. Drehe ich jetzt 
allerdings in die andere Richtung, also verringere ich den ADC und damit 
g_dimmdauer, friert der µC ein. Er reagiert nicht mehr auf das Poti und 
auf Tastereingaben.

Ideen, wodran es liegt?

Grüße
#2730521
CDA_verwirrt schrieb:

> Ok, soweit so klar. Was passiert? Ich stelle den Poti so, dass der ADC
> mir Werte nahe 0 ausgibt. Drehe ich am Poti, erhöhe ich den Wert, das
> buntflackern wird langsamer, da g_dimmdauer größer wird.

Das kann ich so nicht nachvollziehen, da ich nirgends sehe, wo der ADC 
jemals neu gestartet werden würde. Und auf Autorun steht er auch nicht.

> while (!(ADCSRA & (1 << ADIF)));

Nimm halt nicht das Interrupt Flag her.

Du setzt das ADSC Bit um den ADC zu starten und wenn der ADC fertig ist, 
nimmt er es wieder auf 0 zurück. Einfach, simpel, geschmacklos und 
funktioniert perfekt.

Ein Interrupt Flag (ADIF) hingegen musst du explizit löschen, wenn du 
keine ISR dafür hast. Und auch das kann ich in deinem Code nicht 
feststellen.


Edit: Im Grunde kannst du dir das Abfragen auch sparen. Wenn du den ADC 
zum Ende der ISR neu startest, dann ist der mit Sicherheit beim nächsten 
Timeroverflow, mindestens 256 Takte später, schon längst mit der 
Wandlung fertig.
Gast #2730546
Ok blöd. Hab das mal geändert, aber kein Erfolg. Der Fehler ist nach wie 
vor da, der Atmega friert ein.

Ich habe den Code jetzt mal auf folgendes geändert:
1
volatile uint16_t g_dimmdauer = 10;
2

3
void main (void) {
4
//ADC zur Dimmgeschwindigkeitseinstellung per Poti an PC2 / ADC2
5
ADMUX |= (1 << REFS0) | (1 << MUX1);
6
//ADC Enable und Vorteiler 64
7
ADCSRA |= (1 << ADEN) | (1 << ADPS1) | (1 << ADPS2);
8
ADCSRA |= (1 << ADSC);
9

10
  while (1) {
11
    buntflackern();
12
  }
13
}
14

15
ISR (TIMER2_OVF_vect) {
16
static uint16_t ADC_neu = 0;
17

18
//ADC Auswerten
19
ADC_neu = ADC/10;
20
  g_dimmdauer = ADC_neu;
21

22
ADSCRA |= (1 << ADSC);
23

24
//Hier kommen noch Tasterabfragen, die allerdings funktionieren, wenn ich den ADC auskommentiere oder der µC nicht einfriert.
25
}
26

27
void buntflackern(void) {
28
static uint16_t  i =0;
29
i++;
30
  if(i >= g_dimmdauer) {
31
    i=0;
32
    g_farbwahl++;
33
    g_menue_gesetzt=0;
34
  }
35
  if (g_farbwahl > 6)
36
    g_farbwahl =0;
37
  
38
  standfarbe();
39
}
Gast #2730719
Ich hab mir das jetzt nochmal genau angeguckt. Sobald ich die Zeile
1
g_dimmdauer = ADC_neu;

auskommentiere, macht der µC alles, was ich möchte. Nur, dass sich die 
g_dimmdauer eben nicht per Poti verändern lässt. Heißt also, dass der 
Timer das ja auch alles schafft. Ich würd deswegen jetzt auf ein Problem 
mit

volatile uint16_t g_dimmdauer tippen. Hab ich das was nicht beachtet, 
was man nicht mit globalen Variablen tun darf? Oder sollte ich 
vielleicht den Poti seltener Abfragen und Verändern?
#2730825
volatile ist nur die halbe Miete. Du musst auch die Variable atomar 
auslesen (d.h. unter Interruptschutz), weil es eine 16 Bit Variable ist.

Ich würde das ganze ehrlich gesagt auch anders machen.
Ich würde mir in der ISR nur ein Flag setzen, dass es wieder mal was am 
ADC zu tun gibt. Die komplette Logik, die den ADC ausliest und 
auswertet, würde ich dann in die Hauptschleife verlagern, getriggert von 
diesem Flag.
Gast #2730906
Mensch... das heißt, wenn ich den ADC nur als 8-Bitter nehme, sollte es 
da keine Probleme geben? Ich teile ja sowieso den ADC-Wert durch 10.

Idee: Ich setze das ADLAR-Bit und damit wird der ADC-Wert von Links 
ausgelesen. Und dann lese ich nur ADCH aus. Netter Nebeneffekt: Ich 
brauche keine "Zitterabfrage" mehr, weil die unteren 2 Bits eh nichts 
zählen. Dann setze ich g_dimmdauer noch als 8-Bit Variable, weil der eh 
nur Werte bis Maximal 255 durch den ADC kriegen kann.

Stimmt der Gedankengang so? Testen und programmieren kann ich leider 
erst heute Abend zu Hause...

Grüße
#2731486
CDA_verwirrt schrieb:
> Mensch... das heißt, wenn ich den ADC nur als 8-Bitter nehme, sollte es
> da keine Probleme geben?

Das weiß ich nicht.

Denn: Das schlimmste was dir passieren kann, ist das du mit falschen 
Werten rechnest. Aber hängen sollte das Programm deswegen ja nicht.

Auf der anderen Seite werde ich das Gefühl nicht los, dass du nicht 
deinen kompletten Code herzeigst. Da sind ein paar Kommentare in deinem 
Code, die mich das glauben lassen bzw. es fehlen ganz offensichtlich 
Teile. Ob und wie diese Dinge da jetzt noch zusätzlich mit reinspielen 
kann kein Mensch sagen, solange er nicht den kompletten Code sieht.
Gast #2732299
Guten morgen :-)

Ich hab gestern noch das Problem gelöst gekriegt. Als ich erstmal alle 
variablen auf 8 Bit umgestellt hatte, lief der ATMega8 und machte genau 
das, was er sollte. Ich hatte in einem anderen Programmteil noch eine 
kleine Plausibilitätsabfrage, über die er mit falschen 16 Bit Werten 
vielleicht nicht kam. Glaube ich. Sicher bin ich mir an der Stelle nicht 
und will das auch nicht weiter ausprobieren. Jetzt tut er ja wieder das, 
was ich von ihm will und der 8 Bit ADC ist immernoch mehr als 
ausreichend.

Den kompletten Code hab ich tatsächlich nicht hergezeigt. Sind immerhin 
mittlerweile über 700 Zeilen Code... Also hab ich das aufs Wesentliche 
begrenzt. Man verzeihe mir.

Danke für die Lösungshilfe!

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 14 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.