Forum: Mikrocontroller und Digitale Elektronik ADC gibt kein Wert aus


von Denis B. (tulip_denis)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich habe ein Programm, was die eingelesene Spannung in Lux ausgeben 
soll.
Ich kann zwischen 3 Bereiche umschalten. Jenach bereich wird mit 25000, 
2500 oder 250 multipliziert.
Ich bekomme aber komischerweise kein Wert ausgegen.
Startanzeige etc. geht.
Danke im voraus.

: Bearbeitet durch User
von uff basse (Gast)


Angehängte Dateien:

Lesenswert?

Denis B. schrieb:
> Danke im voraus.

Fuck!

Was ist an dem Text der bei jedem zu postenden Beitrag steht
nicht zu verstehen?

Oder gilt der Text nicht für dich?

von Denis B. (tulip_denis)


Lesenswert?

Sorry, die datei angehängt.

von uff basse (Gast)


Lesenswert?

Denis B. schrieb:
> Angehängte Dateien:
>
>           Code.docx (21 KB)

Sourcecode in Office-Dokument? Echt jetzt?

von Wolfgang (Gast)


Lesenswert?

Denis B. schrieb:
> Ich bekomme aber komischerweise kein Wert ausgegen.

Vielleicht versteht der ADC bzw. der Compiler kein docx

von Denis B. (tulip_denis)


Angehängte Dateien:

Lesenswert?

Code ist im Anhang.

von uff basse (Gast)


Lesenswert?

<takt100ms> wird nie auf TRUE gesetzt, vermutlich immer null.

Dann wird auch doAdc() und calculateLux() nie aufgerufen.

sei() bewirkt nichts da keine Interrupts definiert sind
und keine ISRs angelegt sind.

von Dieter (Gast)


Lesenswert?

Wolfgang schrieb:
> Vielleicht versteht der ADC bzw. der Compiler kein docx

Vielleicht hängt am ADC-Eingang auch gar nichts dran?
Der Pin hängt zum Beispiel in der Luft oder die Leiterbahn geht im Layer 
ins Nirwana. Dann kannst Du noch Jahrzehnte weiter im Code suchen.

von uff basse (Gast)


Lesenswert?

<takt1s> wird auch nie auf TRUE gesetzt, es sei denn du verheimlichst
irgendwelchen Code.

von uff basse (Gast)


Lesenswert?

Dieter schrieb:
> Vielleicht hängt am ADC-Eingang auch gar nichts dran?

Denis B. schrieb:
> Ich bekomme aber komischerweise kein Wert ausgegen.

von Georg M. (g_m)


Lesenswert?

> lcd_putc(tempValue/100 + ASC_NULL);

Funktioniert es auch mit einem Integer?

von Denis B. (tulip_denis)


Angehängte Dateien:

Lesenswert?

Danke für die Tipps,
ISR und Timer hat gefehlt.
Habe jetzt angepasst.
Bekomme aber beispielsweise 10 anstatt 100 Lux.

von N. M. (mani)


Lesenswert?

Denis B. schrieb:
> Danke für die Tipps,
> ISR und Timer hat gefehlt.
> Habe jetzt angepasst.

Dann lese dir auch noch durch wann man volatile verwenden sollte:
AVR-GCC-Tutorial: Datenaustausch mit Interrupt-Routinen

>float index;

Da ich vermute dass du einen Controller ohne Floating Point Unit 
verwendest würde ich mir die ganzen floats sparen.

Denis B. schrieb:
> Bekomme aber beispielsweise 10 anstatt 100 Lux.

Dein Erwartungswert weicht um einen Faktor 10 ab. Deine 
Messwertumschaltung hat pro Stufe einen Faktor 10.
Da liegt die Vermutung nahe dass die nicht richtig funktioniert.
Setze sie Mal auf einen festen Wert und schau ob Erwartungswert und 
Messwert zusammenpassen.

Allgemein passt an mehreren Stellen Code und Kommentar nicht zusammen. 
Evtl ist das dein Problem dass dein Faktor nicht richtig berechnet wird:
1
DDRD = DDRD & 0b11110000;       // Port B auf Eingabe schalten

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Denis B. schrieb:
> Ich bekomme aber komischerweise kein Wert ausgegen.
wie wäre es, wenn du im allerersten Anlauf gar nichts "korrigierst", 
sondern einfach direkt den ADC-Wert auf das Display ausgibst? Und 
gleichzeitig mit dem Multimeter die Spannung am ADC-Pin nachmisst und 
nachrechnest, ob der angezeigte Wert passt?

Oder andersrum: es funktioniert nicht, die Mondrakete von der Idee weg 
komplett fertig zu machen und dann das komplett neu aufgebaute Ding in 
Richtung Mond zu starten. Stattdessen nimmt man nacheinander einzelne 
Teile der Mondrakete in Betrieb und untersucht, ob der jeweilige Teil 
wie geplant funktioniert. Und wenn jedes Teil für sich tut, dann wird 
die Mondrakete Stück für Stück zusammengefügt und dabei immer wieder 
getestet.

Ersetze im obigen Text das Wort "Mondrakete" durch irgend eine andere 
Gerätebezeichnung wie z.B. "Luxmeter".

Denis B. schrieb:
> ISR und Timer hat gefehlt.
Ist hier überhaupt eine ISR und ein Timer nötig? Wofür?

Ein "Interrupt" ist eine "Unterbrechung" im Programmablauf, weil etwas 
Wichtiges dringend dazwischenkommt. Bei deiner Anwendung ist 1. nichts 
schnell oder dringend und 2. muss nichts unterbrochen werden.

Und ein Timer wird benötigt, wenn etwas in konstanten Zeitabständen 
passieren soll. Auch das ist in deiner Anwendung unnötig.

: Bearbeitet durch Moderator
von N. M. (mani)


Lesenswert?

Lothar M. schrieb:
> Ist hier überhaupt eine ISR und ein Timer nötig?

Prinzipiell kann man das zwar überlegen, aber ganz verkehrt empfinde ich 
den Timer hier nicht. Ob mit ISR oder ohne.

Was wäre die Alternative? Ein SW-Zähler der die Main Durchläufe zählt? 
Das ist in meinen Augen aus mehreren Gründen hässlich:

Man kann allgemein die Zeiten nur schätzen weil man nicht genau weiß wie 
lange ein Durchlauf ist.

Die Zeiten verändern sich mit jeder Zeile Code die er hinzufügt.
Ist zwar momentan nicht kritisch, aber trotzdem unschön.

Mit dem richtigen Timer + ISR kann er am Ende der while sogar noch ein 
Sleep einfügen falls notwendig.

Allgemein ist ein Timer meist nicht verkehrt für Anzeige, Entprellen, 
ADC (äquidistante Abtastung), ... usw.
Und der Interrupt tut selbst in einem anspruchsvollen Programm (was das 
hier ja eindeutig nicht ist) meist nicht weh, wenn er kurz genug ist.

: Bearbeitet durch User
von Teo D. (teoderix)


Lesenswert?

N. M. schrieb:
> Lothar M. schrieb:
>> Ist hier überhaupt eine ISR und ein Timer nötig?
>
> Prinzipiell kann man das zwar überlegen, aber ganz verkehrt empfinde ich
> den Timer hier nicht. Ob mit ISR oder ohne.
>
> Was wäre die Alternative?

Eine (dämliche) Warteschleife, in der das ADC-Flag abgefragt wird.

von N. M. (mani)


Lesenswert?

Teo D. schrieb:
> Eine (dämliche) Warteschleife, in der das ADC-Flag abgefragt wird.

Und dann mit 20kHz das Display aktualisieren?
Zahl nur beispielhaft. Je nach dem wie schnell der ADAC wandelt.

: Bearbeitet durch User
von STK500-Besitzer (Gast)


Lesenswert?

N. M. schrieb:
> Teo D. schrieb:
>> Eine (dämliche) Warteschleife, in der das ADC-Flag abgefragt wird.
>
> Und dann mit 20kHz das Display aktualisieren?
> Zahl nur beispielhaft. Je nach dem wie schnell der ADAC wandelt.

Wenn das Display das macht?!
Aber wozu braucht man den ADAC dabei?

von N. M. (mani)


Lesenswert?

STK500-Besitzer schrieb:
> Wenn das Display das macht?!

Geil, wild zappelnde Werte bis man nichts mehr lesen kann. Top.

STK500-Besitzer schrieb:
> Aber wozu braucht man den ADAC dabei?

Herzlichen Glückwunsch, du hast einen Typo gefunden.

: Bearbeitet durch User
von Teo D. (teoderix)


Lesenswert?

N. M. schrieb:
> Teo D. schrieb:
>> Eine (dämliche) Warteschleife, in der das ADC-Flag abgefragt wird.
>
> Und dann mit 20kHz das Display aktualisieren?

Wow, du hast aber schnelle Augen....
Du hast nach Alternativen gefragt, nicht nach einer passenden Lösung 
deines Problems. Ich nannte sie dir und gab dir sogar einen Hinweis, 
dass das dämlich ist. .... Mir scheint, du bist schlau genug, um das 
selbstständig zu erarbeiten. BB :)

von STK500-Besitzer (Gast)


Lesenswert?

N. M. schrieb:
> STK500-Besitzer schrieb:
>> Wenn das Display das macht?!
>
> Geil, wild zappelnde Werte bis man nichts mehr lesen kann. Top.
Das ist doch ein ganzh anderes Problem.
Die Display-Refresh-Routine sieht nicht so aus, als würde sie 
non-blocking funktionieren.
Ergo, bremmst die den Messprozess auch noch aus.
Ich gebe dir aber Recht, dass das momentan noch nicht optimal ist.

> STK500-Besitzer schrieb:
>> Aber wozu braucht man den ADAC dabei?
>
> Herzlichen Glückwunsch, du hast einen Typo gefunden.
Sehr gerne... Einfach mal drüber lachen und gut.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

N. M. schrieb:
> Allgemein ist ein Timer meist nicht verkehrt für Anzeige, Entprellen,
> ADC (äquidistante Abtastung), ... usw.
Ich habe nirgends was anderes behauptet. Er ist aber eben für genau 
diese "fortgeschrittenen" Anwendungen nötig. Und nicht für die 
urschleimige Inbetriebnahme und das Debuggen eines ADC.

N. M. schrieb:
> Und dann mit 20kHz das Display aktualisieren?
Für solche Programme auf Bastelinbetriebnahmeniveau tue ich mir eben 
genau den Schuh nicht an, erst mal das komplette Framework mit 
Interrupts und Timer zum laufen zu bekommen und dann an die Lösung der 
eigentlichen Aufgabe zu gehen.

Für solche Programme auf Bastelinbetriebnahmeniveau verplempere ich dann 
einfach wissentlich Rechenzeit und nehme ein delay(). Wohl wissend, dass 
man das hinterher noch "richtig" machen muss (weil in meinem Programm 
sowieso ein 1ms-Zähler laufen wird).

STK500-Besitzer schrieb:
> dass das momentan noch nicht optimal ist.
Wir sind hier noch weit weg vom "Optimieren". Zum "Optimieren" müsste 
das Programm ja erst mal überhaupt das tun, was es soll.

: Bearbeitet durch Moderator
von N. M. (mani)


Lesenswert?

Teo D. schrieb:
> Mir scheint, du bist schlau genug, um das selbstständig zu erarbeiten.
> BB :)

Ich schon. Aber ich bin auch nicht der TO :-)

Die Frage habe ich gestellt da man einem Anfänger den bereits laufenden 
Timer Ausreden möchte. Ich finde den Timer gut, deshalb die Frage wie er 
es ohne Timer machen soll.

von N. M. (mani)


Lesenswert?

Lothar M. schrieb:
> Für solche Programme auf Bastelinbetriebnahmeniveau verplempere ich dann
> einfach wissentlich Rechenzeit und nehme ein delay().

Klar, mache ich teilweise auch.
Der Timer/ISR bei den AVRs benötigt ja aber wirklich nur ein paar 
Register Werte.

Gerade bei Anfängern ist das delay zwar schnell gelernt, aber meist nur 
schwer wegzubekommen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

N. M. schrieb:
> Die Frage habe ich gestellt da man einem Anfänger den bereits laufenden
> Timer Ausreden möchte.
Darum geht es doch überhaupt nicht.

Ich sag es einfach mal andersrum: auch wenn er in seinen Code nochmal 10 
Timer und 20 Interrupts einfügt, wird er damit das eigentliche Problem 
nicht lösen. Das ist also eine völlig unnötige Kompensationshandlung.

: Bearbeitet durch Moderator
von Teo D. (teoderix)


Lesenswert?

N. M. schrieb:
> Ich schon. Aber ich bin auch nicht der TO :-)

Ubs.... :D


N. M. schrieb:
> Ich finde den Timer gut, deshalb die Frage wie er
> es ohne Timer machen soll.

Eine etwas elegantere Methode were, das Program weiterlaufen zu lassen 
und jedes mal, beim eintritt in die ADC Routine, das Flag zu prüfen und 
den "alten" Wert der vorherigen Messung auszuwerten. Dann die neue 
Messung starten....

von STK500-Besitzer (Gast)


Lesenswert?

Lothar M. schrieb:
> STK500-Besitzer schrieb:
>> dass das momentan noch nicht optimal ist.
> Wir sind hier noch weit weg vom "Optimieren". Zum "Optimieren" müsste
> das Programm ja erst mal überhaupt das tun, was es soll.

ja, genau. Was anderes meinte ich auch nicht.

von Wolfgang (Gast)


Lesenswert?

Lothar M. schrieb:
> Für solche Programme auf Bastelinbetriebnahmeniveau tue ich mir eben
> genau den Schuh nicht an, erst mal das komplette Framework mit
> Interrupts und Timer zum laufen zu bekommen und dann an die Lösung der
> eigentlichen Aufgabe zu gehen.

Wenn du damit quasi als Template starten würdest, könntest du dir 
grundsätzlich das "zum Laufen bekommen" sparen. Es würde einfach 
funktionieren. Du hast für die eigentliche Aufgabe gleich ein solides 
Gerüst und nicht irgendeine Bastelei. Spätestens wenn du sinnvoll 
filtern willst, um z.B. für die Anzeige stabile Mittelwerte zu erzeugen, 
ist eine äquidistante Abtastung (unabhängig vor irgendwelchen 
sporadischen Verzögerungen durch die Displayroutinen) sinnvoll.

von STK500-Besitzer (Gast)


Lesenswert?

Wolfgang schrieb:
> Wenn du damit quasi als Template starten würdest, könntest du dir
> grundsätzlich das "zum Laufen bekommen" sparen. Es würde einfach
> funktionieren. Du hast für die eigentliche Aufgabe gleich ein solides
> Gerüst und nicht irgendeine Bastelei. Spätestens wenn du sinnvoll
> filtern willst, um z.B. für die Anzeige stabile Mittelwerte zu erzeugen,
> ist eine äquidistante Abtastung (unabhängig vor irgendwelchen
> sporadischen Verzögerungen durch die Displayroutinen) sinnvoll.

Und jeder Anfänger hat auch schon die Übersicht, wie man sowas aufbaut - 
ganz mein Humor.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Wolfgang schrieb:
> Du hast für die eigentliche Aufgabe gleich ein solides Gerüst
Ja, genau richtig erfasst. Ich habe tatsächlich einige Erfahrung mit 
etlichen µC und verwende so ein "Standardframework" mit (am 
allerwichtigsten) einem 1ms-Tick. Der Witz dabei: ich kenne dieses 
Framework in- und auswendig. Der TO Denis hat diese Voraussetzungen 
nicht.

Wie oft hast du als Anfänger wegen unerklärlicher Effekte an 
irgendwelchen Interrupts (je nach µC am besten noch priorisiert, 
verschachtelt und verreigelt) herumgesucht? Genau das wird auch dem TO 
passieren.

Und wenn es klemmt, dann bin ich trotz Framework blitzschnell beim 
"Dreizeiler", wo nichts läuft ausser das, womit ich grade Probleme habe.

Teo D. schrieb:
> N. M. schrieb:
>> Ich finde den Timer gut, deshalb die Frage wie er
>> es ohne Timer machen soll.
> Eine etwas elegantere Methode were, das Program weiterlaufen zu lassen
> und jedes mal, beim eintritt in die ADC Routine, das Flag zu prüfen
Ich kenne da solche Spezialisten, die verlassen sich auf den Timer, 
rechnen sich (korrekterweise) aus, dass der ADC mit den gewählten 
Einstellungen nach 1ms sicher fertig ist, lesen den in der Timer-ISR aus 
ohne(!) auf das Flag zu schauen (war ja berechnet, dass der ADC sicher 
fertig sein wird) und starten den ADC nach dem Auslesen gleich wieder 
neu.

Funktioniert tadellos, bis einer nach geraumer Zeit mal was am Timer 
oder der ADC-Konfiguration ändert...

Denis B. schrieb:
> ich habe ein Programm
Noch ein Tipp dazu: schreib alle paar Sekunden auch mal den statischen 
"Festtext" nochmal raus:
1
lcd_putstr("Luxmeter");      // Ausgabe Festtext: 8 Zeichen
Denn wenn irgendwelche Störimpulse (ESD, Handy, ...) auf die Leitungen 
zum display kommen, dann könnte es sein, dass in diesem Text ein 
Müllzeichen auftaucht. Und das bleibt dort, weil es erst beim nächsten 
einschalten wieder geschrieben wird.

: Bearbeitet durch Moderator
von Teo D. (teoderix)


Lesenswert?

Lothar M. schrieb:
>> Eine etwas elegantere Methode were, das Program weiterlaufen zu lassen
>> und jedes mal, beim eintritt in die ADC Routine, das Flag zu prüfen
> Ich kenne da solche Spezialisten, die verlassen sich auf den Timer,
> rechnen sich (korrekterweise) aus, dass der ADC mit den gewählten
> Einstellungen nach 1ms sicher fertig ist

Da wäre ich alleine schon, viel zu faul, um das 
auszurechnen/abzuschätzen....  :D

von Manfred (Gast)


Lesenswert?

Lothar M. schrieb:
> N. M. schrieb:
>> Und dann mit 20kHz das Display aktualisieren?
> Für solche Programme auf Bastelinbetriebnahmeniveau verplempere ich dann
> einfach wissentlich Rechenzeit und nehme ein delay().

Für eine Fehlersuche ja. Später macht es Sinn, sich den Anzeigewert zu 
merken und das Display nur zu beschreiben, wenn der neue Wert eine 
relevante Änderung ergibt.

Zum Beispiel bei meiner Lötstation, da ist der Meßintervall dynamisch. 
Die Zeit, das komplette Display zu beschreiben, war bei einigen 10ms und 
damit störend. Ich schreibe nur eine Zeile neu, wenn sich die Temperatur 
um 2° geändert hat und gewinne damit Zeit für die Hauptaufgabe, die 
Regelung.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Manfred schrieb:
> Später macht es Sinn
Bezweifelt ja keiner. Zu allerletzt ich. Aber wir sind eben im Jetzt, wo 
der ADC nicht läuft. Und der kommt auch nicht ans Laufen, wenn man 
weiterhin am Framework rumfrickelt. Dass man sich dur diese 
Interrupt-Geschichte auch noch die für Anfänger verwirrende 
Volatile-Geschichte einhandelt, das macht die Sache nicht 
nachvollziehbarer.

Manfred schrieb:
> Die Zeit, das komplette Display zu beschreiben, war bei einigen 10ms und
> damit störend.
Aber nicht für den User, sondern nur für deinen Programmablauf.
> Ich schreibe nur eine Zeile neu, wenn sich die Temperatur
> um 2° geändert hat und gewinne damit Zeit
Ich schreibe den gesamten Text in einen Buffer im RAM und in der 
1ms-Timer-ISR wird jeweils 1 Zeichen ausgegeben. Weil dafür keine 
Wartezeit nötig ist, ist da in der ISR kaum Overhead und ein 4x20 
Display wird 12x pro Sekunde komplett neu beschrieben.

Aber das alles ist ewig weit weg vom hiesigen Problem "ADC wird nicht 
eingelesen".

: Bearbeitet durch Moderator
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.