ATMega16 ADC Kanal wechseln?

Gast #2382089
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.
#2382095
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
#2382302
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren