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


von Peter X. (vielfrass)


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?
1
;****************************************************************************
2
; AT TINY15
3
; ADC-Wert über RS232 mit 19200 Baud ausgeben
4
;****************************************************************************
5
.include "E:\C\programme\atmel\avr studio\appnotes\TN15def.inc"
6
;****************************************************************************
7
.equ  RS232_Port  0
8
;****************************************************************************
9
.def    ACC             = R16
10
.def    Loopcounter1    = R17
11
.def    Loopcounter2    = R18
12
.def  Loopcounter3  = R19
13
14
.def    Zahl_h          = R20
15
.def    Zahl_l          = R21
16
.def    buff_h          = R22
17
.def    buff_l          = R23
18
.def  Counter    = R24
19
;****************************************************************************
20
Start:
21
  ldi  ACC,86    ;Nur bei diesem Chip!!!
22
        out  OSCCAL,ACC
23
        
24
        sbi     DDRB,RS232_Port
25
        sbi     PORTB,RS232_Port
26
        
27
        ldi  ACC,0b11111110
28
        out  PORTB,ACC
29
30
  ldi  ACC,0b00000010
31
  out  ADMUX,ACC
32
  ldi  ACC,0b11100011
33
  out  ADCSR,ACC
34
35
  ldi  Counter,'A'  
36
Big_loop:
37
        ldi     ZH,high(2*Botschaft)
38
        ldi     ZL,low(2*Botschaft)
39
        ldi     Loopcounter3,(Ende_Botschaft - Botschaft) * 2
40
  rcall  Text_ausgeben
41
42
        in  Zahl_h,ADCH
43
        in  Zahl_l,ADCL
44
  rcall  Zahl_ausgeben
45
46
        ldi     ACC,' '
47
        rcall   RS232_putchar
48
        
49
        mov     ACC,Counter
50
        rcall   RS232_putchar
51
        inc  Counter
52
        cpi  Counter,'Z' + 1
53
        brne  nicht_10
54
        ldi  Counter,'A'
55
nicht_10:        
56
        ldi     ACC,13
57
        rcall   RS232_putchar
58
        ldi     ACC,10
59
        rcall   RS232_putchar
60
  
61
  ldi  ACC,10
62
  rcall  Delay
63
  rjmp  Big_loop
64
;****************************************************************************
65
Text_ausgeben:
66
        lpm
67
        subi    ZL,low(-1)
68
        sbci    ZH,high(-1)
69
        mov     ACC,r0
70
        rcall   RS232_putchar
71
        dec     Loopcounter3
72
        brne    Text_ausgeben
73
  ret
74
;****************************************************************************
75
Zahl_ausgeben:
76
        ldi     ZH,high(2*Dezimalzahlen)
77
        ldi     ZL,low(2*Dezimalzahlen)
78
        ldi     Loopcounter3,5  ;Die Zahl hat 5 Dezimalziffern
79
Ausgabe_loop2:
80
        lpm
81
        mov     buff_l,r0
82
        subi    ZL,low(-1)
83
        sbci    ZH,high(-1)
84
        lpm
85
        mov     buff_h,r0
86
        subi    ZL,low(-1)
87
        sbci    ZH,high(-1)
88
        ldi     ACC,-1
89
Subtrahier_loop:
90
        inc     ACC
91
        sub     Zahl_l,buff_l
92
        sbc     Zahl_h,buff_h
93
        brsh    Subtrahier_loop
94
        add     Zahl_l,buff_l
95
        adc     Zahl_h,buff_h
96
        subi    ACC,(-48)
97
        rcall   RS232_putchar
98
        dec     Loopcounter3
99
        brne    Ausgabe_loop2
100
  ret
101
;****************************************************************************
102
RS232_putchar:  
103
  clc        ;Startbit
104
  ldi  Loopcounter2,10  ;Startbit + 8 bit + Stopbit
105
Send_loop:
106
  brcs  nicht_null    ;1/2
107
        cbi     PORTB,RS232_Port  ;2
108
nicht_null:
109
  brcc  nicht_eins    ;1/2
110
        sbi     PORTB,RS232_Port  ;2
111
nicht_eins:        
112
  nop
113
  ldi  Loopcounter1,24    ;1
114
wait_loop:
115
  dec  Loopcounter1    ;1
116
  brne  wait_loop    ;1/2
117
  sec        ;1
118
  ror  ACC      ;1
119
  dec  Loopcounter2    ;1
120
  brne  Send_loop    ;2
121
  ret
122
;****************************************************************************
123
Delay:
124
  dec  Loopcounter2
125
  brne  Delay
126
  dec  Loopcounter1
127
  brne  Delay
128
  dec  ACC
129
  brne  Delay
130
  ret
131
;****************************************************************************
132
Dezimalzahlen:
133
.DW     10000
134
.DW     1000
135
.DW     100
136
.DW     10
137
.DW     1
138
Botschaft:
139
.DB  "ADC => "
140
Ende_Botschaft:
141
;****************************************************************************

von Jörg X. (Gast)


Lesenswert?

1
ADCL must be read first, then ADCH.
und noch
1
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

von Peter X. (vielfrass)


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:
1
        in  Zahl_l,ADCL
2
        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.

von Sven P. (Gast)


Lesenswert?

ADCH ist ein temporäres Register.

von Johannes M. (johnny-m)


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.

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.