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
volatileuint16_tg_dimmdauer=10;
2
3
voidmain(void){
4
//ADC zur Dimmgeschwindigkeitseinstellung per Poti an PC2 / ADC2
//Hier kommen noch Tasterabfragen, die allerdings funktionieren, wenn ich den ADC auskommentiere oder der µC nicht einfriert.
26
}
27
28
voidbuntflackern(void){
29
staticuint16_ti=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
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.
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
volatileuint16_tg_dimmdauer=10;
2
3
voidmain(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
staticuint16_tADC_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.
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?
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.
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
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.
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!