Hi, für eine Anwendung soll der µC drei Spannungen umwandeln und verarbeiten können. Als Test sollten diese nurmal auf ein LCD Display ausgegeben werden. Ich hab den Code aus dem AVR-Tutorial dieser Seite dafür umgeschrieben, allerdings funktioniert die Anwendung nicht, da die angezeigten Werte nicht stimmen, bzw. sich gegenseitig beeiflussen. Hier der Code: .include "m8def.inc" ; .def definiert ein Synonym (Namen) für ein µC Register .def temp1 = r16 ; allgemeines temp Register, zur kurzfristigen Verwendung .def temp2 = r17 .def adlow = r20 ; Ergebnis des ADC' .def adhigh = r21 ; Ergebnis des ADC' .def ztausend = r23 ; Zehntausenderstelle des ADC Wertes .def tausend = r24 ; Tausenderstelle des ADC Wertes .def hundert = r25 ; Hunderterstelle des ADC Wertes .def zehner = r26 ; Zehnerstelle des ADC Wertes .def temp5 = r28 ; LCD-Routines .def temp6 = r29 ; LCD-Routines .def temp7 = r30 ; LCD-Routines ldi temp1, LOW(RAMEND) ; LOW-Byte der obersten RAM-Adresse out SPL, temp1 ldi temp1, HIGH(RAMEND) ; HIGH-Byte der obersten RAM-Adresse out SPH, temp1 ldi temp1, 0xFF ; Port D = Ausgang out DDRD, temp1 rcall lcd_init ; Display initialisieren rcall lcd_clear ; Display löschen ; ADC initialisieren: ADC0, Vcc als Referenz, Single Conversion, Vorteiler 128 ldi temp1, (1<<REFS0) ; Kanal 0, interne Referenzspannung 5V out ADMUX, temp1 ldi temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0) out ADCSRA, temp1 Main: rcall lcd_clear rcall ADI_1 rcall ADW rcall ADI_2 rcall ADW rcall ADI_3 rcall ADW rjmp Main ADW: clr temp1 clr temp5 clr ztausend clr tausend clr hundert clr zehner clr adlow clr adhigh rcall sample_adc rcall wait_adc ; ADC einlesen: in adlow, ADCL ; immer zuerst LOW Byte lesen in adhigh, ADCH ; danach das mittlerweile gesperrte High Byte ldi ztausend, '0'-1 ; Ziffernzähler direkt als ASCII Code ; bzgl. '0'-1 siehe Beitrag "Hilfe zu AVR-Tutorial ADC" rcall Z_ztausend rcall Z_tausend rcall Z_hundert rcall Z_zehner rcall Print ret delay: ; 5ms Pause (bei 4 MHz) ldi temp1, $21 WGLOOP0_: ldi temp2, $C9 WGLOOP1_: dec temp2 brne WGLOOP1_ dec temp1 brne WGLOOP0_ ret ; wieder zurück ADI_1: ldi temp1, (1<<REFS0) ; Kanal 0, interne Referenzspannung 5V out ADMUX, temp1 ldi temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0) out ADCSRA, temp1 ret ADI_2: ldi temp1, (1<<REFS0) ; Kanal 0, interne Referenzspannung 5V ldi temp1,2 out ADMUX, temp1 ldi temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0) out ADCSRA, temp1 ret ADI_3: ldi temp1, (1<<REFS0) ; Kanal 0, interne Referenzspannung 5V ldi temp1,3 out ADMUX, temp1 ldi temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0) out ADCSRA, temp1 ret sample_adc: sbi ADCSRA, ADSC ; den ADC starten ret wait_adc: sbic ADCSRA, ADSC ; wenn der ADC fertig ist, wird dieses Bit gelöscht rjmp wait_adc ret Z_ztausend: inc ztausend subi adlow, low(10000) ; -10,000 sbci adhigh, high(10000) ; 16 Bit brcc Z_ztausend subi adlow, low(-10000) ; nach Unterlauf wieder einmal addieren sbci adhigh, high(-10000); +10,000 ldi tausend, '0'-1 ; Ziffernzähler direkt als ASCII Code ret Z_tausend: inc tausend subi adlow, low(1000) ; -1,000 sbci adhigh, high(1000) ; 16 Bit brcc Z_tausend subi adlow, low(-1000) ; nach Unterlauf wieder einmal addieren sbci adhigh, high(-1000) ; +1,000 ldi hundert, '0'-1 ; Ziffernzähler direkt als ASCII Code ret Z_hundert: inc hundert subi adlow, low(100) ; -100 sbci adhigh, high(100) ; 16 Bit brcc Z_hundert subi adlow, low(-100) ; nach Unterlauf wieder einmal addieren sbci adhigh, high(-100) ; +100 ldi zehner, '0'-1 ; Ziffernzähler direkt als ASCII Code ret Z_zehner: inc zehner subi adlow, low(10) ; -10 sbci adhigh, high(10) ; 16 Bit brcc Z_zehner subi adlow, low(-10) ; nach Unterlauf wieder einmal addieren sbci adhigh, high(-10) ; +10 subi adlow, -'0' ; adlow enthält die Einer, Umwandlung in ASCII ret Print: mov temp5, ztausend ; Zeichen anzeigen rcall lcd_data mov temp5, tausend ; Zeichen anzeigen rcall lcd_data mov temp5, hundert ; Zeichen anzeigen rcall lcd_data mov temp5, zehner ; Zeichen anzeigen rcall lcd_data mov temp5, adlow ; Zeichen anzeigen rcall lcd_data ldi temp5, $0A rcall lcd_data rcall delay ret .include "lcd-routines.asm" ; LCD-Routinen werden hier eingefügt Lässt man bei Main, den Tail für die dritte und zweite Wandlung weg, klappt es. Wo liegt denn der Fehler, oder kann man mit dem Atmeg8 einfach keine drei ADC-Pins in einer Anwendung benutzen? Mfg Vaio
ich bin zwar nicht so firm in sachen ASM, aber ich hatte vor kurzem noch das gleiche problem in C. ich konnte einen AD-wert bekommen, wollte ich mehrere haben, wurden die gegenseitig beeinflusst. die lösung des problems war der taktvorteiler des ADC. du musst eben nen ziemlich geringen takt einstellen, für den adc.. näheres weiß ich grad nicht auswendig, datenblatt wird helfen mfg
ps: im tutorial stehts ja auch, 50 bis 200khz solltest du aus dem vorteiler herausbekommen. http://www.mikrocontroller.net/articles/AVR-Tutorial:_ADC
Hi Wo kommen die zu messenden Spannungen her? Wenn die Impedanz der Quellen zu hoch ist, können sich die Kanäle beeinflussen. MfG Spess
Ich hab mal alle Vorteiler durchprobiert, hat aber leider nix gebracht.?? Trotzdem schon mal danke für den Tipp;) Vaio
@spess53 Zum Testen waren sind die Spannungen erstmal "inter" gewesen, sprich einfach an GND, bzw. VCC geklemmt.
Hi Dein Programm ist auch noch fehlerhaft: ADI_2: ldi temp1, (1<<REFS0) ; Kanal 0, interne Referenzspannung 5V ldi temp1,2 out ADMUX, temp1 Du lädst erst '1<<REFS0' nach temp1 und überschreibst das dann mit 2. Dadurch ist deine Referenzspannungeinstellung weg. Außerdem ist es unnötig für jeden Kanal (welche benutzt du eigentlich) ein eigenes Unterprogramm mit einer Initialisierung zu benutzen. Besser du schreibst ein Unterprogramm, dem die Kanalnummer per Register übergeben. MfG Spess
Vaio schrieb: > ADI_3: > ldi temp1, (1<<REFS0) ; Kanal 0, interne > Referenzspannung 5V > ldi temp1,3 > out ADMUX, temp1 mit " ldi temp1, (1<<REFS0)" schaltest Du die Referenzspannung ein und mit " ldi temp1,3" wieder aus ?????? Gruß Anja
Ich hab den Code jetzt so umgwandelt und jetzt geht es mehr oder weniger: ADI_1: ldi temp1,64 ; Kanal 0, interne Referenzspannung 5V out ADMUX, temp1 ldi temp1,135 out ADCSRA, temp1 ret ADI_2: ldi temp1,65 ; Kanal 1, interne Referenzspannung 5V out ADMUX, temp1 ldi temp1,135 out ADCSRA, temp1 ret ADI_3: ; Kanal 2, interne Referenzspannung 5V ldi temp1,66 out ADMUX, temp1 ldi temp1,135 out ADCSRA, temp1 ret Ich benutze die Pins 23-25, sprich PC0-PC2
Zwischen dem Setzen von ADMUX und dem Start der Wandlung könnte man noch mal probieren, dem Analogteil noch ein bisschen Zeit zu gönnen, damit sich der Eingangspegel vom S&H genau genug einstellen kann. MfG
HI >Ich hab den Code jetzt so umgwandelt und jetzt geht es mehr oder >weniger: Eher mehr oder eher weniger? > ldi temp1,135 > out ADCSRA, temp1 Diese Schreibweise ist total unverständlich. Bleibe bitte bei dieser:
1 | ldi temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0) |
Das mit dem ein Unterprogramm ist dir wohl zu kompliziert? Hier mal ein Beispiel wie das aussehen kann:
1 | ; Kanal in r16 |
2 | messung: push r17 |
3 | in r17, ADMUX |
4 | andi r17,0b11110000 ; MUX-Bits ausblende |
5 | or r17,r16 ; mit Kanal verbinden |
6 | out ADMUX,r17 ; Kanal setzen |
7 | |
8 | sbi ADCSRA,ADSC ; Wandlung starten |
9 | messung10: sbic ADCSRA,ADSC ; Ende abwarten |
10 | rjmp messung10 |
11 | pop r17 |
12 | ret ; Ergebnis in ADC |
Übrigens sind Unterprogramme, die nur ein, zwei Befehle enthalten nicht sehr sinnvoll. Spart keinen oder kaum Flash und kostet Rechenzeit. MfG Spess
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.