Forum: Mikrocontroller und Digitale Elektronik ATMega16 ADC Kanal wechseln?


von ralf (Gast)


Lesenswert?

Hi.

Hab schon gesucht ob es Beiträge gibt die mein Problem lösen, aber ich 
habe nichts gefunden auch wenn viele dasselbe Problem hatten.

Ich will im Betrieb den ADC Kanal wechseln und hab im Datenblatt 
gelesen, man soll das ADEN Bit löschen, dann den Kanal wechseln und dann 
ADEN wieder setzen.
1
  ldi     temp, (0<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0)
2
    out     ADCSRA, temp
3
    ldi     temp, (1<<REFS0) | (0<<REFS1) | (0<<ADLAR) | (0<<MUX0) | (1<<MUX1) | (1<<MUX2) | (0<<MUX3) | (0<<MUX4)
4
    out     ADMUX, temp
5
    ldi     temp, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0)
6
    out     ADCSRA, temp

Ich habe zwei Routinen, also quasi "Kanal1_auslesen" und 
"Kanal2_auslesen". Am Anfang jeder Routine steht der obige Codeblock und 
bei dem einen setze ich (1<<MUX0) und beim anderen lösche ich es mit 
(0<<MUX0).

Die Routinen werden abwechseln aufgerufen. Beim ersten Aufruf von 
Routine1 wird der erste Kanal ausgelesen. Dann wird die zweite Routine 
aufgerufen und Kanal2 wird ausgelesen, dann wieder Routine1 und ab hier 
wird nur noch Kanal2 ausgelesen, statt auch Kanal1. Wo könnte da der 
Fehler liegen?

ADC wird anschließend an den Block oben ganz schlicht über:
1
  sbi ADCSRA, ADSC
2
wait_adc2:
3
    sbic    ADCSRA, ADSC
4
    rjmp    wait_adc2
5
6
  in r23, ADCH
7
  in r22, ADCL

ausgelesen.

von Thomas F. (igel)


Lesenswert?

Das Geht auch ohne aus- und einschalten.

Siehe Codebeispiel. Dieser Läuft produktiv auf einem Atmega8:

;    ADCs einlesen:
      cbi ADMUX, 1      ;Kanal 0
      cbi ADMUX, 0
      rcall adc_read
      mov adc0, temp1

      sbi ADMUX, 0      ;Kanal 1
      rcall adc_read
      mov temp_innen, temp1

      cbi ADMUX, 0
      sbi ADMUX, 1      ;Kanal 2
      rcall adc_read
      mov temp_aussen, temp1

      rjmp main
;------------------------------------------------------
adc_read:
      ldi temp1, 0b11010101  ;ADC-Single shot starten
      out ADCSR, temp1
      nop

adc_wait:  sbis ADCSR, ADIF    ;ADC-Conversion abwarten
      rjmp adc_wait

      in temp1, ADCH      ; 8-Bit Auflösung
      ret

von ralf (Gast)


Lesenswert?

Nein klappt nicht. Habs grad ausprobiert. Immer noch das Problem, das 
die erste Konversion Kanal1 ausliest und ab da nur noch Kanal2.

von ralf (Gast)


Lesenswert?

Fehler gefunden. Wusste nicht dass man anscheinend beim ADC das Low Byte 
vor dem High Byte auslesen muss!

von Herr M. (herrmueller)


Lesenswert?

Nicht nur beim ADC, bei allen 16bit Registern, auch Timer usw. . Beim 
Lesen des  Lowbyte wird gleichzeitig das Highbyte zwischengespeichert, 
damit sich der Wert nicht zwischen Low- und Highbyte lesen nochmal 
ändert, und so falsche Ergebnisse kommen. Beim Schreiben muss man erst 
High schreiben.

Aus dem Datenblatt:
When the low byte of a 16-bit register is read by the CPU, the high byte 
of the 16-bit register is copied into the temporary register in the same 
clock cycle as the low byte is read.

To do a 16-bit write, the high byte must be written before the low byte. 
For a 16-bit read, the low byte must be read before the high byte.

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.