www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ADC liefert immer den selben Wert


Autor: Peter X. (vielfrass)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
habe einen ATtiny 15.
Habe ihm RS232 (nur TX, RX kommt auch noch)beigebracht. (Ein MAX232 an 
PB0)
Habe dann versucht den ADC in Betrieb zu nehmen. Leider bekomme ich 
stets den gleichen Wert, egal ob ich PB3 offen lasse oder an Masse oder 
VCC lege.
Der Wert ist z.B. 216 oder 390, manchmal 1023. (ADLAR = 0 => 
rechtsbündig)
Habe freilaufende und single Conversion probiert.
Wo habe ich einen Gedankenfehler?
;****************************************************************************
; AT TINY15
; ADC-Wert über RS232 mit 19200 Baud ausgeben
;****************************************************************************
.include "E:\C\programme\atmel\avr studio\appnotes\TN15def.inc"
;****************************************************************************
.equ  RS232_Port  0
;****************************************************************************
.def    ACC             = R16
.def    Loopcounter1    = R17
.def    Loopcounter2    = R18
.def  Loopcounter3  = R19

.def    Zahl_h          = R20
.def    Zahl_l          = R21
.def    buff_h          = R22
.def    buff_l          = R23
.def  Counter    = R24
;****************************************************************************
Start:
  ldi  ACC,86    ;Nur bei diesem Chip!!!
        out  OSCCAL,ACC
        
        sbi     DDRB,RS232_Port
        sbi     PORTB,RS232_Port
        
        ldi  ACC,0b11111110
        out  PORTB,ACC

  ldi  ACC,0b00000010
  out  ADMUX,ACC
  ldi  ACC,0b11100011
  out  ADCSR,ACC

  ldi  Counter,'A'  
Big_loop:
        ldi     ZH,high(2*Botschaft)
        ldi     ZL,low(2*Botschaft)
        ldi     Loopcounter3,(Ende_Botschaft - Botschaft) * 2
  rcall  Text_ausgeben

        in  Zahl_h,ADCH
        in  Zahl_l,ADCL
  rcall  Zahl_ausgeben

        ldi     ACC,' '
        rcall   RS232_putchar
        
        mov     ACC,Counter
        rcall   RS232_putchar
        inc  Counter
        cpi  Counter,'Z' + 1
        brne  nicht_10
        ldi  Counter,'A'
nicht_10:        
        ldi     ACC,13
        rcall   RS232_putchar
        ldi     ACC,10
        rcall   RS232_putchar
  
  ldi  ACC,10
  rcall  Delay
  rjmp  Big_loop
;****************************************************************************
Text_ausgeben:
        lpm
        subi    ZL,low(-1)
        sbci    ZH,high(-1)
        mov     ACC,r0
        rcall   RS232_putchar
        dec     Loopcounter3
        brne    Text_ausgeben
  ret
;****************************************************************************
Zahl_ausgeben:
        ldi     ZH,high(2*Dezimalzahlen)
        ldi     ZL,low(2*Dezimalzahlen)
        ldi     Loopcounter3,5  ;Die Zahl hat 5 Dezimalziffern
Ausgabe_loop2:
        lpm
        mov     buff_l,r0
        subi    ZL,low(-1)
        sbci    ZH,high(-1)
        lpm
        mov     buff_h,r0
        subi    ZL,low(-1)
        sbci    ZH,high(-1)
        ldi     ACC,-1
Subtrahier_loop:
        inc     ACC
        sub     Zahl_l,buff_l
        sbc     Zahl_h,buff_h
        brsh    Subtrahier_loop
        add     Zahl_l,buff_l
        adc     Zahl_h,buff_h
        subi    ACC,(-48)
        rcall   RS232_putchar
        dec     Loopcounter3
        brne    Ausgabe_loop2
  ret
;****************************************************************************
RS232_putchar:  
  clc        ;Startbit
  ldi  Loopcounter2,10  ;Startbit + 8 bit + Stopbit
Send_loop:
  brcs  nicht_null    ;1/2
        cbi     PORTB,RS232_Port  ;2
nicht_null:
  brcc  nicht_eins    ;1/2
        sbi     PORTB,RS232_Port  ;2
nicht_eins:        
  nop
  ldi  Loopcounter1,24    ;1
wait_loop:
  dec  Loopcounter1    ;1
  brne  wait_loop    ;1/2
  sec        ;1
  ror  ACC      ;1
  dec  Loopcounter2    ;1
  brne  Send_loop    ;2
  ret
;****************************************************************************
Delay:
  dec  Loopcounter2
  brne  Delay
  dec  Loopcounter1
  brne  Delay
  dec  ACC
  brne  Delay
  ret
;****************************************************************************
Dezimalzahlen:
.DW     10000
.DW     1000
.DW     100
.DW     10
.DW     1
Botschaft:
.DB  "ADC => "
Ende_Botschaft:
;****************************************************************************

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ADCL must be read first, then ADCH.
und noch
When ADCL is read, the ADC Data Register is not updated until ADCH is read.
Aus dem Datenblatt... (gilt auch für die 16-Bit Timer-register, falls 
vorhanden)

rtfm, Jörg

Autor: Peter X. (vielfrass)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat jetzt funktioniert, besten Dank für den prima Tip. Muss ich doch 
irgendwie im Datenbaltt überlesen haben :-(

Habe jetzt nur diese beiden Zeilen vertauscht:
        in  Zahl_l,ADCL
        in  Zahl_h,ADCH
und schon geht's!
Aber warum?
Der ADC ist doch im Freilaufenden Mode, und ich frage doch in einer 
Endlosschleife ab.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ADCH ist ein temporäres Register.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sven Pauli wrote:
> ADCH ist ein temporäres Register.
Nö, ist es nicht.

Die Reihenfolge ergibt sich schlicht aus der Tatsache, dass beim Lesen 
von ADCL das High-Byte ADCH gegen Schreibzugriffe seitens der Hardware 
gesichert wird, bis es ebenfalls gelesen wurde. Das verhindert, dass 
zwischen den Lesezugriffen auf Low- und High-Byte ein neues 
Wandlungsergebnis im Register abgelegt werden kann. So kann 
gewährleistet werden, dass Low- und High-Byte aus der selben Wandlung 
stammen. Steht aber alles im Datenblatt...

Und bevor jetzt die Frage kommt "Warum nicht andersrum?": Es gibt die 
Möglichkeit, mit Hilfe des Steuerbits ADLAR das Ergebnis in den beiden 
Registern linksbündig auszurichten, damit man bei geringerer geforderter 
(oder durch "Übertaktung" gegebener) Auflösung nur die 8 höchstwertigen 
Bits auslesen kann. Damit man dann aber auch wirklich nur 8 Bit einlesen 
muss, reicht es dann, nur das ADCH zu lesen und man erspart sich so 
unnötige Lesevorgänge.

Man kann sich einfach merken: Wenn ADCL gelesen wurde, dann muss 
(sinnvollerweise möglichst bald danach) ADCH gelesen werden, damit die 
Register wieder freigegeben werden und der ADC ein neues Ergebnis 
hineinschreiben kann.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.