Forum: Mikrocontroller und Digitale Elektronik Problem mit Zähler


von Phillip H. (philharmony)


Lesenswert?

Hi, ich habe hier eine Funktion um den ADC 10 mal auszulesen, den 
Mittelwert abzuspeichern und dem MUX auf den nächsten Kanal zu stellen.
Für die 10 Messungen soll der conversion_counter je um eins 
incrementiert werden.
Zum testen gebe ich den Wert des Zählers mit var_out bei jedem Aufruf 
aus.
Und hier ist das Problem: der Zähler hat IMMER den Wert 1. Ich habe den 
ganzen Code durchsuchen lassen ob ich den Wert aus versehen irgendwo 
nochmal benutze oder resette, negativ. Er Zählt ihn einfach nicht hoch.
Sollte die If-Condition betreten werden soll ein "in" gesendet werden, 
auch das passiert nie, also wird der Zähler auch da nicht zurückgesetzt.
Andere Zähler im Code Funktionieren, jemand eine Idee warum das nicht 
klappt?
AVR-Studio und Atmega8535.
1
//Globale Variablen
2
#define ADC_CYCLES 10 //Umläufe Genauigkeit <-> Zeit
3
unsigned char admux_counter; //Zähler für ADC Kanal
4
unsigned char conversion_counter; //Zähler für Umläufe im ADC für höhere Genauigkeit
5
int adc_buffer;  //Pufferspeicher des ADC
6
7
void convert_adc_channels()
8
{
9
  adc_buffer + =ADCW; //Wert zu Pufferspeicher Addieren
10
  if (conversion_counter >= ADC_CYCLES) //wenn Wandlungszähler gleich Zahl der Umläufe ist
11
  {
12
/**/uart_puts("in\n");
13
    conversion_counter = 0; //Wandlungszähler zurücksetzen
14
    virtual_adc[admux_counter] = (adc_buffer / ADC_CYCLES);  //Wert durch Zahl d. Wandlungen teilen und speichern
15
    admux_counter = ((admux_counter + 1) % NUMBER_OF_ADC_CHANNELS); //Kanalzähler erhöhen
16
    ADMUX = ((ADMUX & 0xe0) | adc_used_pins[admux_counter]); //Nächsten Kanal setzen
17
  }
18
  conversion_counter++; //Wandlungszähler erhöhen
19
  /**/var_out(conversion_counter); //Zum Prüfen
20
  (ADCSRA |= 1<<ADSC); //nächste Wandlung einleiten
21
}

von Benjamin S. (recycler)


Lesenswert?

schreib mal da hardcore 10 rein. vlt gehts dann
1
if (conversion_counter >= ADC_CYCLES)

von Matthias (Gast)


Lesenswert?

evtl. volatile?

von Phillip H. (philharmony)


Lesenswert?

Hatte es vorher auch als volatile deklariert weil ich das erst per ISR 
machen wollte. Gleiches Ergebnis. Hardcoded ändert auch nichts, hatte 
ich auch schon versucht.
Ist conversion_counter vielleicht irgendwie von GCC reserviert oä?
Hehe, scheint so, bin grade auf die Idee gekommen den Namen mal zu 
ändern. mit adc_conversion_counter gehts plötzlich...???

von kurz (Gast)


Lesenswert?

Quatsch: volatile

Benjamin hat die Anzwort doch schon gegeben.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Wenn der Zähler nur in der Funktion benötigt wird kannst du ihn auch 
dort lokal anlegen.
1
void convert_adc_channels()
2
{
3
  const unsigned char conversion_counter = 0;
4
  adc_buffer + = ADCW; //Wert zu Pufferspeicher Addieren
5
  if (conversion_counter >= ADC_CYCLES) {
6
    //wenn Wandlungszähler gleich Zahl der Umläufe ist
7
    uart_puts("in\n");
8
    conversion_counter = 0; //Wandlungszähler zurücksetzen
9
    virtual_adc[admux_counter] = (adc_buffer / ADC_CYCLES);  //Wert durch Zahl d. Wandlungen teilen und speichern
10
    admux_counter = ((admux_counter + 1) % NUMBER_OF_ADC_CHANNELS); //Kanalzähler erhöhen
11
    ADMUX = ((ADMUX & 0xe0) | adc_used_pins[admux_counter]); //Nächsten Kanal setzen
12
  } else {
13
    conversion_counter++; //Wandlungszähler erhöhen
14
  }
15
  var_out(conversion_counter); //Zum Prüfen
16
  (ADCSRA |= 1<<ADSC); //nächste Wandlung einleiten
17
}

von Benjamin S. (recycler)


Lesenswert?

Läubi .. schrieb:
> Wenn der Zähler nur in der Funktion benötigt wird kannst du ihn auch
> dort lokal anlegen.
 ich glaube das ist falsch, weil wenn ich die funktion aufrufe, bekomme 
ich genau das resultat mit der 1 und weiter zählt er nicht. wenn dann 
musst du die das in einer while schleife machen, aber soweit ich mir das 
vorstellen kann, kommen die daten von einer interruptquelle und darin 
wird die fkt aufgerufen.

such mal in deinem quelltext, wo die variable sonst noch 
gebraucht/benutz/geschrieben wird.

von Phillip H. (philharmony)


Lesenswert?

@Läubi:
Du meinst static oder? Ja kann ich auch machen, allerdings wundert es 
mich trotzdem warum es mit adc_conversion_counter geht und mit 
conversion_counter nicht.
Das ELSE hat da nichts zu suchen, er soll IMMER einen weiter zählen.

@Kurz: Wasn das schon wieder für ein Gezicke? War ein Vorschlag, und der 
von Benjamin hat ja leider auch nichts gebracht.

@Benjamin, nene das ist schon richtig, mit STATIC (nicht const) kann ich 
dem Compiler sagen, er soll die Variable nach Funktinsende  nicht 
löschen (Speicher nicht Freigeben) sondern beim nächsten Aufruf mit dem 
vorhandenen Wert weiter arbeiten.
An anderer Stelle im Text wird die Variable nicht mehr verwendet, habe 
eben schon eine textsuche laufen lassen um das auszuschliessen.

von Benjamin S. (recycler)


Lesenswert?

kommt mir komisch vor.
das mit static stimmt :) mit const gehts nicht.

von Phillip H. (philharmony)


Lesenswert?

Noch ne Korrektur meinerseits, Läubi hatte recht mit dem ELSE.
Sonst macht er ja einen Durchgang zu wenig...

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Phillip Hommel schrieb:
> @Läubi:
> Du meinst static oder? Ja kann ich auch machen, allerdings wundert es
> mich trotzdem warum es mit adc_conversion_counter geht und mit
> conversion_counter nicht.
> Das ELSE hat da nichts zu suchen, er soll IMMER einen weiter zählen.
ja static... sorry. Ich vermute/befürchte das sich da irgenwas 
überlagert, daher sollten Variablen halt einen so klein wie möglichen 
Gültigkeitsbereich haben, dann ist die Gefahr geringer das was schief 
geht.
Vieleicht mal mit nem Clean des Projektes versuchen?

> Das ELSE hat da nichts zu suchen, er soll IMMER einen weiter zählen.
Ja aber nur wenn er nicht auf 0 gesezt wird, sonst ist die zählung 
nämlich:

0 1 2 ... 9, 1 ... 9, 1... 9, 1....9 weil sofort wieder erhöht wird.

von Phillip H. (philharmony)


Lesenswert?

Also jetzt geht es ja, hab die Variable einfach umbenannt.
Nochmal zur sicherheit, da ich es jetzt doch per interrupt machen 
möchte:
Ich kann innerhalb des ISR auch static volatile definieren oder?
Dann würde ich den code mal dahingehend aufräumen und alles etwas 
übersichtlicher machen.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Phillip Hommel schrieb:
> Also jetzt geht es ja, hab die Variable einfach umbenannt.
> Nochmal zur sicherheit, da ich es jetzt doch per interrupt machen
> möchte:
> Ich kann innerhalb des ISR auch static volatile definieren oder?
> Dann würde ich den code mal dahingehend aufräumen und alles etwas
> übersichtlicher machen.

volatile bracuhst du nur wenn Interupt UND Hauptprogramm auf die 
Variable zugreifen ODER sich der Wert auserhalb des Sichtbereiches des 
Compilers ändern könnte (z.B. weil es sich um ein Hardwareregister 
handelt)

von Phillip H. (philharmony)


Lesenswert?

Stimmt, so war das. Dh einfach im ISR die variablen static 
initialisieren und gut is?
Nächstes kleines Problem ist, daß das ganze jetzt per interrupt läuft, 
hab den ADC Prescaler auf 64 gestellt damit kommen ca 58kHz raus.
Der ADC liefert jetzt aber seltsame Werte.
Habe mal nur einen Kanal, ADC0 in Benutzung. Wenn ich ihn testweise an 
gnd lege dann liefert er brav die 0, lege ich ihn aber an AVCC  (kommt 
vom USB-Port und ist die Versorgungssannung des Controllers) dann 
schickt er abwechselnd 768 und 1022/1023. Ne Idee wo die 768 herkommen?
Habe inzwischen den o.g. Code noch dahingehend ergänzt, daß in der 
If-Condition der ADC Buffer natürlich noch geleert wird.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

AVCC ausreichend abgeblockt mit Spule+100nF? Kondesator an AREF?, ggf 
nen kleinen Kondesator an den ADC Pin gegen GND.
Ansonstent soltest du auch besser über 8 oder 16 Werte mitteln dann kann 
das der Compiler ggf. in einen Schift anstelle einer Division umsetzen.

von Phillip H. (philharmony)


Lesenswert?

Hardwaremäßig habe ich gar nichts abgesichert da es grade nur ums testen 
geht (nich schimpfen ;)).
Das Problem scheint aber wo anders zu liegen da er immer exakt 1022 und 
768 in ganz periodischer Sequenz sendet...Immer 8mal 768, dann einmal 
1022. Irgendwo im Code muß da noch was hängen, ich suche weiter...

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Vieleicht schwankt einfach deine Spannungsversorgung, häng das ganze mal 
ans Labornetzteil.

von Karl H. (kbuchegg)


Lesenswert?

Phillip Hommel schrieb:
> Also jetzt geht es ja, hab die Variable einfach umbenannt.

Du hast das Symptom beseitigt, aber nicht die Ursache :-)
Dein Programmfehler, der nach deiner Schilderung ganz woanders steckt, 
ist immer noch im Programm. Wahrscheinlich irgendwo ein Arrayüberlauf, 
so wie in 95% aller Fälle, in denen es zu solch seltsamen Symptomen 
kommt.


Edit: Deine weitere Schilderung der Ereignisse bestärkt mich eigentlich 
in meiner Vermutung, dass du den 'Fehler' durch Umbenennen der Variable 
nicht behoben hast :-)

von Phillip H. (philharmony)


Lesenswert?

Naja, ich habe ja jetzt ein ganz anderes Problem. Das eine war daß er 
partout einen Zähler nicht incrementieren wollte, das zweite scheint 
jetzt ein Anderes Problem zu sein:
Da ich ein Timer-interrupt und das ADC interrupt benutze, vermute ich 
mal daß genau dort das problem liegen könnte.
Und zwar ist das ADCW ja eignetlich zweiteilig.
Die 768 sind genau 11 00 00 00 00. Also genau der High-Part von 1023.
Eventuell funkt jedes mal (ausser jedes 8. mal, da hab ich nämlich 
1023))der Timer genau beim auslesen des ADCW dazwischen und der Low Part 
geht verloren.
Beim Initialisiren, also der first conversion braucht er ja etwas länger 
(25 anstatt 13 cycles) und da sind es auch keine 8 mal...
Mal schauen ob und wie ich das geregelt kriege...

von Karl H. (kbuchegg)


Lesenswert?

Phillip Hommel schrieb:
> Naja, ich habe ja jetzt ein ganz anderes Problem. Das eine war daß er
> partout einen Zähler nicht incrementieren wollte,

Das ist Blödsinn.
Das ist das Symptom, welches du gesehen hast. Die Ursache war aber mit 
Sicherheit etwas anderes.
Was du getan hast war nichts anderes, als den Zähler an eine andere 
Stelle im Speicher zu lanzieren. Dadurch wirkt sich dein Programmfehler 
nicht mehr an diesem Zähler aus. Stattdessen wird halt irgendeine andere 
Variable unzulässig verändert. Dein ursprüngliches Symptom ist weg, 
dafür hast du ein anderes Symptom.
Und solange du das eigentliche Problem nicht behebst, wird das immer so 
weitergehen. Solange bis du entweder das Problem behebst oder aber bis 
du zufällig eine Konfiguration hast, in der das Problem eine 
Speicherstelle verändert, die ansonsten keiner braucht und daher das 
Problem etwas anstellt, was sich nicht mehr auswirkt. Aber wehe, du 
veränderst dein Programm dann noch einmal. Dann ist er ganz plötzlich 
wieder da :-)

Poste mal das komplette Programm, wenn es nicht zu lang ist (unter 300 
Zeilen hat). Ich wette, da findet sich irgendwo ein zu klein 
dimensinoiertes Array.

von Phillip H. (philharmony)


Lesenswert?

Sorry, das sollte gar nicht so sehr nach Widerspruch klingen wie es tut. 
Eher als Gegenfrage ob diese beiden Phänomene wirklich zusammenhängen 
können, aber das hast Du ja schon erklärt.
Habt Ihr nen Tip wie ich bei der Fehlersuche Vorgehen könnte? Da steh 
ich nämlich grade echt im Wald.
Aufgetreten ist das ganze ab dem Moment wo ich das ADC-Interrupt ins 
Spiel gebracht habe...Ich nehme das ganze nochmal aus dem ISR raus und 
lass die Funkt mal in der Main laufen, mal sehn wie es dann aussieht. 
Ich meld mich gleich nochmal.
Das Programm hat über 700 Zeilen plus config.h, das will ich Euch nicht 
antun. Aber ich werde mal alle arrays checken.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

1
uart_puts("in\n");
2
virtual_adc[admux_counter] = (adc_buffer / ADC_CYCLES);
3
admux_counter = ((admux_counter + 1) % NUMBER_OF_ADC_CHANNELS);
All sowas ist arg Böswillig im Interupt!
Uart ausgaben dauern je nach Baudrate extrem lange, ebenso die Division 
und Modulo mit nicht 2er Potenzen...
Außerdem solltest du deine Arrays/Zähler überprüfen auf das gleiche 
Problem was du eben schon hattest mit dem zurücksetzen.

von Karl H. (kbuchegg)


Lesenswert?

Phillip Hommel schrieb:
> Das Programm hat über 700 Zeilen plus config.h, das will ich Euch nicht
> antun.

Das ginge zur Not auch noch, wenn es nicht zu chaotisch ist.

von Phillip H. (philharmony)


Lesenswert?

@ Läubi.
Die Ausgabe über den uart hatte ich nur drin um zu checken was er macht. 
Die kommt in der eigentlichen Anwendung natürlich nicht vor.
Werde die Cycle-Zahl mal auf 8 setzen.
Arrays sehen eigentlich alle ok aus.

von Phillip H. (philharmony)


Lesenswert?

Ich habs!
In tiefster Ehrfurcht verneige ich mich vor Karl Heinz' 7.Sin inkl 
seiner Erfahrung.
Danke natürlich auch an alle anderen die geholfen haben.
Problem lag hier
1
#define NUMBER_OF_ADC_CHANNELS (sizeof adc_used_pins / sizeof adc_used_pins[0]) 
2
volatile unsigned char adc_used_pins[] = {0};
3
volatile int virtual_adc[NUMBER_OF_ADC_CHANNELS];
Geändert in
1
#define NUMBER_OF_ADC_CHANNELS (sizeof adc_used_pins / sizeof adc_used_pins[0]) 
2
volatile unsigned char adc_used_pins[1] = {0};
3
volatile int virtual_adc[1] = {0};
Verstehe jetzt zwar noch nicht ganz warum das vorher nicht geklappt hat, 
aber vielleicht nachdem ich ne runde an der frischen Luft war... ;)

von Karl H. (kbuchegg)


Lesenswert?

Phillip Hommel schrieb:

>
1
> #define NUMBER_OF_ADC_CHANNELS (sizeof adc_used_pins / sizeof
2
> adc_used_pins[0])
3
> volatile unsigned char adc_used_pins[] = {0};
4
> volatile int virtual_adc[NUMBER_OF_ADC_CHANNELS];
5
>
> Geändert in
>
1
> #define NUMBER_OF_ADC_CHANNELS (sizeof adc_used_pins / sizeof
2
> adc_used_pins[0])
3
> volatile unsigned char adc_used_pins[1] = {0};
4
> volatile int virtual_adc[1] = {0};
5
>

Hmm.
Das kanns aber noch nicht gewesen sein.
Rein formal besteht zwischen den beiden Formen kein Unterschied.

von Phillip H. (philharmony)


Lesenswert?

Dachte ich eigentlich auch, Problem is: wie finde ich den Fehler wenn 
das Symptom nicht mehr auftritt?
Edit: Habe die 2. wieder auf die erste Version zurück-geändert und das 
alte Problem taucht wieder auf...
Optimierung steht auf -Os.
Zusatzinfo, die o.g. Zuweisung mache ich in einem eingebundenen 
Header-file, könnte es damit zusammenhängen?

von Phillip H. (philharmony)


Lesenswert?

Aaaaaah, verflixte 0-Indizierung.
Wenn ich
1
int zantralspeicher[6]
definiere, und dann auf die
1
Zentralspeicher[0]...Zentralspeicher[6]
zugreife dann geht das natürlich schief.

von Karl H. (kbuchegg)


Lesenswert?

Phillip Hommel schrieb:
> Aaaaaah, verflixte 0-Indizierung.
> Wenn ich
>
1
> int zantralspeicher[6]
2
>
> definiere, und dann auf die
>
1
> Zentralspeicher[0]...Zentralspeicher[6]
2
>
> zugreife dann geht das natürlich schief.

Ja. Das sieht als Ursache schon viel besser aus.

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.