Hallo! Wie kann ich in AVR Assembler 2 Analogeingänge (PINC 0 und PINC 1) "gleichzeitig" einlesen und daraufhin in Register kopieren? Hat jemand einen Code in Assembler den er mir freundlicherweise übermitteln kann, damit ich es auch lernen kann? Viiiiiiiiiieln Dank!! Johann
Die AVRs können die Analogeingänge nur einzeln wandeln. Sind mehrere Eingänge zu wandeln, so muss dieses sequenziell geschehen. Gleichzeitig is nich. Gruß, Magnetus
Hi >Wie kann ich in AVR Assembler 2 Analogeingänge (PINC 0 und PINC 1) >"gleichzeitig" einlesen und daraufhin in Register ... Das geht noch nicht mal in Assembler. Der AVR hat nur einen ADC (mit mehreren Eingängen über Multiplexer). Also du kannst also immer nur Einen Eingang bedienen. Ansonsten einfach: Messung machen, ADMUX umschalten, nächste Messung. MfG Spess
"gleichzeitig" geht, gleichzeitig geht nicht. "gleichzeitig" bedeutet, ersten Kanal starten, ADC-Ende abwarten, Ergebnis lesen, auf zweiten Kanal umschalten und ADC starten, ADC-Ende abwarten, Ergebnis lesen, zurückschalten auf ersten Kanal, usw. Eine Wandlung dauert 13 ADC-Zyklen (wenn es nicht die allererste nach Aktivierung des ADC ist) , wobei je nach Takteinstellung der ADC-Takt 100kHz bis 200kHz beträgt. Wenn das nicht "gleichzeitig" genug ist, ist der AVR der falsche Prozessor, oder du bauchst einen externen 2-Kanal-ADC. Code gibts im Tutorial oben links. Oliver
Das hatten wir schon mal: Gleichzeitg geht nicht. Beitrag "2 ADC-Kanäle "gleichzeitig" abtasten - AVR Atmega32"
Das mit dem "gleichzeitig" Abtasten war mir bereits bekannt, nur meinte ich das gleichzeitige nutzen von 2 Analogeingängen am µC. Das mit dem ADMUX umstellen hab ich gemacht nur ohne Erfolg, da die Werte völlig unbrauchbar waren. Hat jemand einen Code den er mir evtl. zeigen kann, wie dies funktioniert? Bin sehr dankbar!!!!! Johann.
> Das mit dem > ADMUX umstellen hab ich gemacht nur ohne Erfolg, da die Werte völlig > unbrauchbar waren. Unter bestimmten Bedingungen ist die erste Messung nach dem Umschalten von ADMUX fehlerhaft. Wirf sie weg und miss erneut, die zweite Messung (und jede weitere) ist dann ok. ...
Hallo! So sieht mein Erstentwurf aus:
1 | ;+------------------------------------------------------------------------------ |
2 | ;| Title : ADC mit 2 Eingängen |
3 | ;+------------------------------------------------------------------------------ |
4 | ;| Funktion : |
5 | ;| Schaltung : |
6 | ;+------------------------------------------------------------------------------ |
7 | ;| Prozessor : ATmega8-16PU |
8 | ;| Takt : 3686400 Hz |
9 | ;| Sprache : Assembler |
10 | ;| Datum : |
11 | ;| Version : 001 |
12 | ;| Autor : Wiethaler Johann |
13 | ;+------------------------------------------------------------------------------ |
14 | .include "m8def.inc" |
15 | |
16 | ;------------------------------------------------------------------------------- |
17 | ; Reset and Interrupt vector ;VNr. Beschreibung |
18 | ;------------------------------------------------------------------------------- |
19 | .org 0x000 |
20 | rjmp main |
21 | .org INT0addr ; External Interrupt0 Vector Address |
22 | reti |
23 | .org INT1addr ; External Interrupt1 Vector Address |
24 | reti |
25 | .org OC2addr ; Output Compare2 Interrupt Vector Address |
26 | reti |
27 | .org OVF2addr ; Overflow2 Interrupt Vector Address |
28 | reti |
29 | .org ICP1addr ; Input Capture1 Interrupt Vector Address |
30 | reti |
31 | .org OC1Aaddr ; Output Compare1A Interrupt Vector Address |
32 | reti |
33 | .org OC1Baddr ; Output Compare1B Interrupt Vector Address |
34 | reti |
35 | .org OVF1addr ; Overflow1 Interrupt Vector Address |
36 | reti |
37 | .org OVF0addr ; Overflow0 Interrupt Vector Address |
38 | reti |
39 | .org SPIaddr ; SPI Interrupt Vector Address |
40 | reti |
41 | .org URXCaddr ; USART Receive Complete Interrupt Vector Address |
42 | reti |
43 | .org UDREaddr ; USART Data Register Empty Interrupt Vector Address |
44 | reti |
45 | .org UTXCaddr ; USART Transmit Complete Interrupt Vector Address |
46 | reti |
47 | .org ADCCaddr ; ADC Interrupt Vector Address |
48 | reti |
49 | .org ERDYaddr ; EEPROM Interrupt Vector Address |
50 | reti |
51 | .org ACIaddr ; Analog Comparator Interrupt Vector Address |
52 | reti |
53 | .org TWIaddr ; Irq. vector address for Two-Wire Interface |
54 | reti |
55 | |
56 | |
57 | .org INT_VECTORS_SIZE |
58 | |
59 | .def status1 = r16 |
60 | .def status2 = r17 |
61 | .def temp1 = r18 |
62 | .def temp2 = r19 |
63 | .def temp3 = r20 |
64 | .def temp4 = r21 |
65 | .def temp5 = r22 |
66 | .def temp6 = r23 |
67 | |
68 | |
69 | main: |
70 | ldi temp1, LOW(RAMEND) ; Stackpointer initialisieren |
71 | out SPL, temp1 |
72 | ldi temp1, HIGH(RAMEND) |
73 | out SPH, temp1 ; |
74 | ldi temp1,0b00111111 |
75 | out DDRB,temp1 |
76 | ldi temp1,0b11111100 |
77 | out DDRD,temp1 |
78 | |
79 | mainloop: |
80 | rcall ADC1 |
81 | rcall ADC2 |
82 | ret |
83 | |
84 | ADC1: ldi temp1,0b01000000 |
85 | out ADMUX,temp1 |
86 | ldi temp1,0b10111101 |
87 | out ADCSRA,temp1 |
88 | in temp2,ADCL |
89 | out PORTB,temp2 |
90 | ret |
91 | |
92 | ADC2: ldi temp1,0b01000001 |
93 | out ADMUX,temp1 |
94 | ldi temp1,0b10111101 |
95 | out ADCSRA,temp1 |
96 | in temp2,ADCL |
97 | out PORTD,temp2 |
98 | ret |
Johann wrote:
1 | > mainloop: |
2 | > rcall ADC1 |
3 | > rcall ADC2 |
4 | > ret |
Was hat denn das ret da verloren? Das gibt nen sauberen Stack-Underflow. Da die mainloop nicht mit call aufgerufen wird, darf da kein ret hin! Schließlich gibt es nichts, wo man von da aus hin zurückspringen kann. Wenn überhaupt, dann kommt da ein rjmp mainloop hin! So, wie es da steht, geht das Programm nach dem ersten Durchlauf der mainloop ins Nirvana und es gibt einen Reset.
du musst waren, bis die Wandlung fertig ist und nicht gleich das ADC Register einlesen
Martin wrote: > du musst waren, bis die Wandlung fertig ist und nicht gleich das ADC > Register einlesen Das kommt noch dazu. Ein weiteres Zeichen dafür, dass Johann das AVR-Tutorial nicht gelesen hat, was dringend zu empfehlen wäre (es ist ja weiter oben schon mal angesprochen worden...) Abgesehen davon liest Du nur ADCL ein, was (abgesehen davon, dass es unsinnig ist, nur das Low-Byte zu lesen) aufgrund der Registersynchronisation dazu führt, dass nach dem ersten Einlesen ADCL und ADCH für jegliche weitere Zugriffe seitens des ADC blockiert sind und von da an immer derselbe Wert ausgelesen wird. Nach einem Lesezugriff auf ADCL muss grundsätzlich auch ADCH gelesen werden! Wenn nur 8 Bit Auflösung benötigt werden, dann ADLAR setzen und nur ADCH lesen. Das geht.
So, ich habe mal einen separaten, allgemeinen Artikel zum Thema [[AVR 16-Bit-Register]] erstellt. Die Infos standen in der Form bisher nur im AVR-GCC-Tutorial...
Ich hab´s hinbekommen:
1 | .include "m8def.inc" |
2 | |
3 | .def temp = r16 |
4 | |
5 | main: |
6 | ldi temp, LOW(RAMEND) ; Stackpointer initialisieren |
7 | out SPL, temp |
8 | ldi temp, HIGH(RAMEND) |
9 | out SPH, temp |
10 | ldi temp,0b00111111 |
11 | out DDRB,temp |
12 | ldi temp,0b11111100 |
13 | out DDRD,temp |
14 | ldi r16,0b11011101 ;ADC Enable, Vorteiler = 32 |
15 | out ADCSRA,r16 ;Interrupt Enable, single Conv. |
16 | |
17 | |
18 | |
19 | |
20 | ;------------------------------------------------------------------------ |
21 | mainloop: |
22 | |
23 | ldi r16,0 ;Wert ins r16 laden |
24 | out ADMUX,r16 ;r16 in AD Wandler laden |
25 | in r26,ADCL ;Low Teil des AD-Wandler ausl. |
26 | in r27,ADCH ;High Teil des AD-Wandler ausl. |
27 | sbi ADCSRA,6 ;Starte nächste Konvertierung |
28 | asr r27 ;Schiebe Bit 0 ins C-Flag |
29 | ror r26 ;Schiebe alle Bit´s nach rechts |
30 | asr r27 ;Schiebe nächstes Bit ins C-Flag |
31 | ror r26 ;Schiebe alle Bit´s nach rechts |
32 | out PORTB,r26 |
33 | rcall wait |
34 | ldi r16,1 ;Wert ins r16 laden |
35 | out ADMUX,r16 ;r16 in AD Wandler laden |
36 | in r26,ADCL ;Low Teil des AD-Wandler ausl. |
37 | in r27,ADCH ;High Teil des AD-Wandler ausl. |
38 | sbi ADCSRA,6 ;Starte nächste Konvertierung |
39 | asr r27 ;Schiebe Bit 0 ins C-Flag |
40 | ror r26 ;Schiebe alle Bit´s nach rechts |
41 | asr r27 ;Schiebe nächstes Bit ins C-Flag |
42 | ror r26 ;Schiebe alle Bit´s nach rechts |
43 | out PORTD,r26 |
44 | rcall wait |
45 | rjmp mainloop |
46 | |
47 | |
48 | wait: inc r17 |
49 | brne wait |
50 | ret |
nur verstehen tu ich´s mit dem wait nicht ganz, wenn ich doch eh einen Vorteiler von 32 habe? Mit dem 16Bit Registern hab ich jetzt auch verstanden. Daaaanke! Johann
Johann wrote: > Ich hab´s hinbekommen: Nein, hast Du nicht! > sbi ADCSRA,6 ;Starte nächste Konvertierung > [...] > rcall wait > [...] > > wait: inc r17 > brne wait > ret Das ist völliger Mumpitz! Du musst warten, bis der ADC sich meldet, dass er fertig ist. Da gibt es zwei Methoden, das zu tun (bzw. zwei Statusbits, die man zu diesem Zweck abfragen kann). Was Du hier machst, funktioniert nur dann mit Glück, wenn die Wartezeit wirklich länger ist, als der ADC für eine Wandlung benötigt! > Mit dem 16Bit Registern hab ich jetzt auch > verstanden. Daaaanke! Na, wenigstens etwas...
Siehe dem Auszug aus dem GCC-Tutorial: >while ( ADCSRA & (1<<ADSC) ) { > ; // auf Abschluss der Konvertierung warten > }
Bitte tu dir selbst und uns einen Gefallen, und LIES das AVR-Tutorial durch, zumindest den ADC-Abschnitt:
1 | wait_adc: |
2 | sbic ADCSRA, ADSC ; wenn der ADC fertig ist, wird dieses Bit gelöscht |
3 | rjmp wait_adc |
Gast wrote: > Siehe dem Auszug aus dem GCC-Tutorial: Nützt ihm bei Assembler nicht viel. Aber auf das AVR-Tutorial ist er ja auch erst dreimal hingewiesen worden...
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.