Hallo zusammen, möchte mit einem ATMEGA 8 eine einfache Temperaturmessung realisieren, dazu habe ich über einen Messverstärker einen PT100 an den ADC angeschlossen. Dieser liefert mir nun Werte zwischen 0x004 => -20,0°C und 0x3E9 => 70,0°C diese hex-Werte möchte ich über eine Tabelle den Temperaturen, die an einem LCD angezeigt werden sollen zuordnen. Dazu habe ich folgenden Code geschrieben: ADC_into_celsius: rcall lcd_clear rcall lcd_home ldi zl,low(celsius_werte*2) ; Z Pointer laden ldi zh,high(celsius_werte*2) ;es wird die erste adresse der Tabelle celsius_werte markiert add zl, temp2 ;auszugebende temperatur in Tabelle markieren brcc weiter ;carry bit gesetzt wegen überlauf? inc zh weiter: add zh, temp5 push temp3 ldi temp3, 6 ;ab markierter stelle 6 zeichen lesen ADC_into_celsius_sub: dec temp3 tst temp3 ;ist temp3 = 0 ? =>wenn ja wurde 6 mal gelesen breq ADC_into_celsius_end ;wenn temp3 null ist anzeige beenden lpm temp1, Z+ ;durch z pointer markierte daten lesen in temp1 ;schreiben und z pointer um 1 erhöhen rcall lcd_data rjmp ADC_into_celsius_sub ADC_into_celsius_end: pop temp3 celsius_werte: .db "-20,00" .... .db "+70,00" In temp2 wird das low-byte der analog digital Wandlung in temp5 das high-byte der analog digital Wandlung übergeben temp1 ist das register in dem die Daten dem LCD übergeben werden Nun mein Problem: An der Anzeige wird mir -12,0 angezeigt. Rechne ich jedoch den hex wert manuell um müßten 25°C angezeigt werden. Ich vermute daß an der Stelle der beiden add Befehle was schief geht. Wo liegt der Fehler? Gruß Moschder
Schau Dir bitte mal in der Befehlssatz-Dokumentation den Befehl adc (add with carry) an, v.a. das Codebeispiel. Was sollen übrigens die riesigen Leerzeilen-Blöcke in dem Code? Meinst Du, das lässt sich so besser lesen? Das Gegenteil ist der Fall! Außerdem solltest Du Dir die Hinweise zur Formatierung unter den Forenregeln mal ansehen. Da steht eine Möglichkeit, wie man AVR-Assembler-Code schön formatieren kann...
Da Du an jeder "Stelle" in der Tabelle 6 Zeichen stehen hast, musst Du den Adress-Offset (also den Hex-Wert für die Temperatur) aber auch noch mit 6 multiplizieren, damit Du auf den Anfang des richtigen Strings kommst...
Zur Verdeutlichung mal mit Beispielwerten:
1 | celsius_werte*2 -20,00 |
2 | celsius_werte*2+6 -19,90 |
3 | celsius_werte*2+12 -19,80 |
4 | celsius_werte*2+18 -19,70 |
5 | celsius_werte*2+24 -19,60 |
6 | ...usw... |
7 | celsius_werte*2+5976 +69,50 |
8 | celsius_werte*2+5982 +69,60 |
9 | celsius_werte*2+5988 +69,70 |
10 | celsius_werte*2+5994 +69,80 |
11 | celsius_werte*2+6000 +69,90 |
12 | celsius_werte*2+6006 +70,00 |
Der Offset ist also immer sechs mal der Hex-Wert vom ADC.
vielen Dank für Deine Antworten, die Multiplikation mit 6 ist wohl der Schlüssel. Leider werden die Zahlen dann sehr groß und ich müßte mehrere Register verwenden, was bestimmt zu Problemen führt. Weiß nicht wie ich da ansetzen kann. Bevor ich mit der Tabelle angefangen habe, habe ich mal versucht die Celsius Werte zu berechnen dies hat aber nicht geklappt (kommazahl, 10 bit, division multipikation)
Routinen für Multiplikation und Division findet man als Atmel Application Note.
@ Moschder (Gast) >die Multiplikation mit 6 ist wohl der Schlüssel. >Leider werden die Zahlen dann sehr groß und ich müßte mehrere Register >verwenden, was bestimmt zu Problemen führt. Nicht wirklich. >Weiß nicht wie ich da ansetzen kann. Festkommaarithmetik AVR-Tutorial: ADC MfG Falk
Hi! ADC_into_celsius_sub: push ZL push ZH ;nur wenn Z noch woanders benutzt ldi zl,low(celsius_werte*2) ; Z Pointer laden ldi zh,high(celsius_werte*2) add zl,temp2 adc zh,temp5 lsl zl rol zh ;*2 mov temp2,zl mov temp5,zh ;*2 merken lsl zl rol zh ;*4 add zl,temp2 adc zh,temp5 ;zu *4 (*2) addieren =*6 ldi temp2, 6 ;ab markierter stelle 6 zeichen lesen Ausgeben: lpm temp1, Z+ ;durch z pointer markierte daten lesen in temp1 rcall lcd_data ; ist bestimmt die Ausgabe dec temp2 brne Ausgabe ; nicht 0? -> Ausgabe pop ZH pop ZL ;nur wenn Z woanders noch benutzt ret Hoffe ich habe mich nicht vertan. Viel Erfolg, Uwe
Hi! Und ging's? Vermutlich eher nicht. Und warum?.. weil ganze Adresse *6, also nochmal: ADC_into_celsius_sub: push ZL push ZH ;nur wenn Z noch woanders benutzt lsl temp2 rol temp5 ;*2 mov zl,temp2 mov zh,temp5, ;*2 merken lsl temp2 rol temp5 ;*4 add zl,temp2 adc zh,temp5 ;zu *4 (*2) addieren =*6 ldi temp2,low(celsius_werte*2) ; Z Pointer laden ldi temp5,high(celsius_werte*2) add zl,temp2 ;und zu Temp.wert dazu adc zh,temp5 ldi temp2, 6 ;ab markierter stelle 6 zeichen lesen Ausgeben: lpm temp1, Z+ ;durch z pointer markierte daten lesen in temp1 rcall lcd_data ; ist bestimmt die Ausgabe dec temp2 brne Ausgabe ; nicht 0? -> Ausgabe pop ZH pop ZL ;nur wenn Z woanders noch benutzt ret Hoffe das stimmt jetzt.(ungetestet) Übrigens: "0x004 => -20,0°C" und "celsius_werte*2 -20,00" passt so nicht, da bist du schon bei "celsius_werte*2+24 -19,60" Viel Erfolg, Uwe
Uwe und allen anderen besten Dank, nun funktioniert das Ganze wie gewünscht! Am A/D Wandler angeschlossen ist ein 4 Draht Messverstärker mit PT100 dieser ist ohne Potis aufgebaut daher kann ich nicht den vollen Bereich von 0 bis 1023 verwenden, da der Verstärker nicht exakt abgleichbar ist. Daher der Wert 0x004. Die Werte bis 0x004 verwende ich als PT100 Kurzschluß Erkennung, sie sind mit einem Fehlercode versehen. Gruß Moschder
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.