Hallo,
ich habe einen Fototransistor über den PA0 (ADC0) an meinem Atmega 32
angeschlossen.
Die Werte werden ausgelesen und an das Display von Pollin TC1602A-09
ausgegeben.
Das Display funktioniert einwandfrei nur meine Werte "spinnen" etwas,
meistens kann ich nur die ersten beiden Ziffern des 10bit Wertes
erkennen, die restlichen werden meiner Meinung nach zu schnell hin und
her gewechselt so dass man es nicht vom Display ablesen kann. Auch ein
Kondensator am AREF Pin gegen VCC brachte keinen Unterschied.
Testweise habe ich ein Poti(1MOhm) angeschlossen und ein Delay von
1000ms eingefügt bis zum nächsten anzeigen eines neuen Wertes.
Die Werte gingen von 0 bis ca. 800 dann über in einen negativen Wert von
300 und mehr.
Was mache ich falsch ?
Danke
hier mein Code:
Wozu der ganze Hackmack mit Interrupts? Gerade bei einem ADC ist das
meistens nicht wirklich sinnvoll.
Als Faustregel kannst du dir merken: IN dem Moment, in dem du eine
Ausgabe in einer ISR auf LCD oder UART hast, hast du falsch designed. So
etwas macht man niemals.
> uint8_t LowADC = ADCL;> uint16_t theTenBitResults = ADCH<<8 | LowADC;
Auf einem AVR mit gcc brauchst du dich nicht darum kümmern, dass du 2
Register auslesen musst um ein 16 Bit Ergebnis zu erhalten. Das ist ein
Detail um das sich der COmpiler kümmert
uint16_t Result = ADC;
fertig.
Und den eigentlich spannenden Teil, nämlich die Funktion
Send_An_IntegerToLCD, den hast du natürlich unterschlagen.
Nciht lesbare Warte am LCD haben 2 Ursachen
* zum einen ist die Update Frequenz viel zu hoch. Du kannst als Mensch
nicht mehr als 3 oder 4 Werte pro Sekunde ablesen. Es ist daher völlig
sinnlos, wenn du 100-tausend Updates pro Sekunde am LCD machst
* aber selbst wenn deine UPdate-Frequenz angepasst ist, dann ist es für
uns Menschen sehr hilfreich, wenn zb die Einerstelle einer Zahl immer an
derselben Position am LCD aufscheint, so dass die Zahl nicht ständig
links rechts wandert. D.h. es ist sinnvoll eine formatierte Ausgabe in
ein Feld mit konstanter Größe zu machen.
Ob du das tust und wie du das tust, kann man nicht sagen, denn die
Funktion selbst zeigst du ja nicht her. Dass aber mit der was nicht
stimmt, folgt schon daraus, dass ein uint16_t als unsigned WErt per
Definition schon kein Vorzeichen und damit immer positiv ist, was aber
deine Ausgabefunktion anscheinend nicht so beeindruckt. Ok, bei
maximalen Werten von 0 bis 1023 sollte das keinen Unterschied machen ob
signed oder unsigned. In diesem Wertebereeich gibt es kein BItmuster,
welches als signed interpretiert jemals als negative Zahl aufgefasst
werden könnte.
> Auch ein Kondensator am AREF Pin gegen VCC brachte keinen Unterschied.
Was heißt da AUCH?
Der Kondensator gehört da mindestens hin.
Genauso wie ein 100nF Kondensator an VCC/GND bzw. AVcc/GND.
Ohne diese 3 Kondensatoren brauchen wir erst mal gar nicht weiter
diskutieren
solltest du nochmal nachdenken. Die ist ziemlicher Quatsch.
Vor allen Dingen erreichst du nicht das was du willst: eine
rechtsbündige Ausgabe in einem Feld gewisser Größe. Diese Ausgabe ist
wieder linksbündig und damit tanzen die Zahlen vor dem Benutzer je nach
Größenordnung hin und her.
Wenn du es dir leisten kannst, dann nimm halt sprintf um dir das Leben
erst mal leichter zu machen.
Ok habe ich so verändert, sowie die stdio.h eingefügt.
Jetzt habe ich den Unterstrich in der 2 Zeile ganz links am Display aber
keine Zahlen ?
Irgendwo kann noch etwas nicht stimmen in meinem Code :-(
cube4 schrieb:> Ok habe ich so verändert, sowie die stdio.h eingefügt.>> Jetzt habe ich den Unterstrich in der 2 Zeile ganz links am Display aber> keine Zahlen ?
Welchen UNterstrich?
Da wird nirgends ein UNterstrich ausgegeben.
OK.
Bin mir nicht sicher, ob die avr-libc den * in der Formatangabe kennt.
Ist zwar eine C-Standardsache, aber auf dem AVR wurde da einiges
abgespeckt.
Mach da erst mal eine Konstante rein
Also die ersten 3 Ziffern kann ich Einwandfrei ablesen die letzte
"wackelt" schon noch etwas, außer das Poti das ich gerade angeschlossen
habe ist auf 0 oder 1023 dann sind alle stabil.
Ich überlege noch einen Mittelwert über ein Array zu realisieren ?
cube4 schrieb:> Also die ersten 3 Ziffern kann ich Einwandfrei ablesen die letzte> "wackelt" schon noch etwas
Das ist ziemlich normal.
So um die +-2 ADC_Werte wackeln wirst du haben. Man müsste sonst
wesentlich mehr Aufwand treiben um die Referenzspannung stabil zu halten
bzw. die 'Sensorschaltung' wird etwas Rauschen einbringen. Kurz und gut:
rechne damit, dass die letzte Stelle nicht wie festgenagelt stabil steht
und du machst dir selber das Leben leichter.
>, außer das Poti das ich gerade angeschlossen> habe ist auf 0 oder 1023 dann sind alle stabil.>> Ich überlege noch einen Mittelwert über ein Array zu realisieren ?
Wozu Array?
Brauchst du doch nicht.
Steck den ADC-Ausleseteil in eine Funktion, damit du ihn leicht
handhabbar hast
1
uint16_tReadADC()
2
{
3
ADCSRA=(1<<ADSC);
4
while(ADCSRA&(1<<ADSC)){}// auf Abschluss der Konvertierung warten
5
6
returnADC;
7
}
und mach dir daraus aufbauend eine Funktion, die zb 8 Messungen macht
und daraus den Mittelwert errechnet
1
uint16_tReadADCAverage()
2
{
3
uint16_tResult=0;
4
uint8_ti;
5
6
for(i=0;i<8;i++)
7
Result+=ReadADC();
8
9
returnResult/8;
10
}
und ruf die in deiner Hauptschleife auf
1
...
2
while(1)
3
{
4
Ergebnis=ReadADCAverage();
5
Send_An_IntegerToMrLCD(1,2,Ergebnis,4);
6
}
7
}
Und schon siehst du auf deinem LCD jeweils den Mittelwert aus 8
Messungen. Und das ganze in leicht handhabbaren Funktionen aufgeteilt.
Also irgendwo ist der Hund begraben.
Wenn ich de Funktionen einfüge bekomme ich nur 0000 angezeigt.
Bin nochmal mein C++-Buch durchgegangen aber finde den Fehler nicht.