Forum: Mikrocontroller und Digitale Elektronik Atmega8 7 Analogwerte - ADC


von Matthias (Gast)


Lesenswert?

Hallo Leute,

ich komme wieder nicht weiter.

Meine ersten versuche:
Ich Starte den ADC mittels Timer alle ca. 1/15s und springt per 
Interrupt in ADC_Start (Z und Y Pointer sind vorerst nirgens im Programm 
verwendet).
Danach soll er alle 7 Messwerte (nur die höherwertigen 8 bit) im SRAM 
ablegen.


Zum testen der Analogwerte habe ich folgedes Programm mit einer LED.
Mein Problem ist, dass die LED wenn sie aus sein sollte willkürlich 
flackert.
Wenn ich den Wert für ADMUX fix festlege (also mit ldi ....) oder wenn 
ich zwischen den einzelnen Messungen mehr als ca. 1-10 ms pause lasse 
funktioniert es richtig:

Bitte um Hilfe.

Test schleifen:
1
  ldi   XL, LOW(DSRAM_Analogwerte)             ; Adresse des Strings in den
2
    ldi   XH, HIGH(DSRAM_Analogwerte)            ; Z-Pointer laden
3
4
loop:
5
6
7
    ld temp4, X
8
9
    cpi temp4, 0x7F
10
    BRSH ADC_Test_H
11
12
    cpi temp4, 0x7D  
13
    BRLO ADC_Test_L  
14
15
  rjmp loop
16
17
18
ADC_Test_L:
19
20
    cbi PORTB, 0
21
22
    rjmp loop
23
24
ADC_Test_H:
25
26
    sbi PORTB, 0
27
28
    rjmp loop

ADC Routine
1
; ADC Routine
2
3
ADC_Start:
4
5
6
   
7
    ldi     ZL, LOW(DFlash_ADC_ADMUX*2)             ; Adresse des Strings in den
8
      ldi     ZH, HIGH(DFlash_ADC_ADMUX*2)            ; Z-Pointer laden
9
  
10
    ldi     YL, LOW(DSRAM_Analogwerte)             ; Adresse des Strings in den
11
      ldi     YH, HIGH(DSRAM_Analogwerte)            ; Z-Pointer laden
12
13
  
14
ADC_Messung_akt:  
15
    
16
      
17
    lpm temp1, Z
18
    cpi temp1, 0b00000000
19
    BREQ ADC_Messung_ende
20
                                                                                                   ;  ldi temp1, 0b11100000
21
    lpm temp1, Z+
22
    out ADMUX, temp1
23
24
    ldi temp1, 1<<ADEN | 1<<ADSC | 1<<ADIE | 1<<ADPS2 
25
26
    out ADCSRA, temp1
27
    
28
    ret
29
30
ADC_Messung_ende:
31
32
    ret
33
    
34
ADC_Messung_fertig:
35
  
36
  
37
    in temp1, ADCH
38
    st Y+, temp1
39
40
  
41
42
    rcall ADC_Messung_akt
43
44
45
    reti
46
47
48
; Datenbereich Flash
49
50
51
DFlash_ADC_ADMUX:         ;ADMUX Register ADC | REFS1 | REFS0 | ADLAR |     |  MUX3 | MUX2 | MUX1 | MUX0 | 
52
53
    .DB 0b11100000, 0b11100001, 0b11100010, 0b11100011, 0b11100100, 0b11100101, 0b11100110, 0b00000000
54
  
55
  
56
    ;  0b11100000,    ;0  ADC0 PC0 - Leuchtdauer Poti 
57
    ;  0b11100001    ;1  ADC1 PC1 - Helligkeit Poti
58
    ;  0b11100010,    ;2  ADC2 PC2 - Empfindlichkeit PIR Poti
59
    ;  0b11100011,    ;3  ADC3 PC3 - Heligkeit LDR
60
    ;  0b11100100,    ;4  ADC4 PC4 - Temperaur außen
61
    ;  0b11100101,    ;5  ADC5 PC5 - Batterie Spannung  
62
    ;  0b11100110,    ;6  ADC6 19 - PIR 
63
    ;  0b00000001,    ;7  Messungen fertig
64
    ;  0b11100111,    ;8  ADC7 22 - Res 
65
    
66
67
; Datenbereich SRAM
68
.DSEG
69
70
DSRAM_Analogwerte:
71
72
    .Byte 1        ;0  ADC0 PC0 - Leuchtdauer Poti 
73
    .Byte 1        ;1  ADC1 PC1 - Helligkeit Poti
74
    .Byte 1        ;2  ADC2 PC2 - Empfindlichkeit PIR Poti
75
    .Byte 1        ;3  ADC3 PC3 - Heligkeit LDR
76
    .Byte 1        ;4  ADC4 PC4 - Temperaur außen
77
    .Byte 1        ;5  ADC5 PC5 - Batterie Spannung
78
    .Byte 1        ;6  ADC6 19 - PIR 
79
    .Byte 1        ;7  ADC7 22 - Res

von spess53 (Gast)


Lesenswert?

Hi

Poste bitte (als Anhang) dein komplettes Programm.

Aber als erster Tip: In Interruptroutinen generell SREG sichern.

MfG Spess

von Matthias (Gast)


Lesenswert?

1
.include "m8def.inc"
2
3
4
5
.def temp1 = r16
6
.def temp2 = r17
7
.def temp3 = r18
8
.def temp4 = r19
9
.def temp5 = r20
10
11
12
13
.equ XTAL = 419500
14
15
16
.org 0x000          ; Reset Handler
17
         rjmp init            
18
19
.org 0x005          ; Timer 1 Overflow
20
    rjmp Timer_reset
21
22
    reti
23
24
 
25
.org 0x008           ; Capture Event 
26
    rjmp PWM_1
27
28
.org 0x009          ; Timer 0 Overflow
29
        
30
  rcall ADC_Start
31
  
32
33
  
34
  reti
35
36
.org 0x00E          ; ADC Conversion Complete
37
  rjmp ADC_Messung_fertig
38
    
39
    reti
40
41
init: 
42
43
    ldi      temp1, HIGH(RAMEND)     ; Stackpointer initialisieren
44
    out      SPH, temp1
45
    ldi      temp1, LOW(RAMEND)
46
    out      SPL, temp1
47
  
48
49
50
; TIMER 0 für Takt
51
52
  ldi temp1, 1<<CS02  | 1<<CS00    ; Vorteiler Timer 0 aus 1024
53
  out TCCR0, temp1
54
  
55
  ldi temp1, 1<<TOIE0          ; Overflow Timer 0 Enable
56
  out TIMSK, temp1
57
  
58
59
; ADC init
60
61
  ldi temp1, 1<<ADEN | 1<<ADIE | 1<<ADPS2  
62
  out ADCSRA, temp1
63
64
65
66
    
67
 
68
  ldi   XL, LOW(DSRAM_Analogwerte)             ; Adresse des Strings in den
69
    ldi   XH, HIGH(DSRAM_Analogwerte)            ; Z-Pointer laden
70
71
72
73
  sei
74
75
76
77
loop:
78
79
80
    ld temp4, X
81
82
    cpi temp4, 0x7F
83
    BRSH ADC_Test_H
84
85
    cpi temp4, 0x7D  
86
    BRLO ADC_Test_L  
87
88
  rjmp loop
89
90
91
ADC_Test_L:
92
93
    cbi PORTB, 0
94
95
    rjmp loop
96
97
ADC_Test_H:
98
99
    sbi PORTB, 0
100
101
    rjmp loop
102
103
104
105
; ADC Routine
106
107
ADC_Start:
108
109
110
   
111
    ldi     ZL, LOW(DFlash_ADC_ADMUX*2)             ; Adresse des Strings in den
112
      ldi     ZH, HIGH(DFlash_ADC_ADMUX*2)            ; Z-Pointer laden
113
  
114
    ldi     YL, LOW(DSRAM_Analogwerte)             ; Adresse des Strings in den
115
      ldi     YH, HIGH(DSRAM_Analogwerte)            ; Z-Pointer laden
116
117
  
118
ADC_Messung_akt:  
119
    
120
      
121
    lpm temp1, Z
122
    cpi temp1, 0b00000000
123
    BREQ ADC_Messung_ende
124
                                                                                                   ;  ldi temp1, 0b11100000
125
    lpm temp1, Z+
126
    out ADMUX, temp1
127
128
    ldi temp1, 1<<ADEN | 1<<ADSC | 1<<ADIE | 1<<ADPS2 
129
130
    out ADCSRA, temp1
131
    
132
    ret
133
134
ADC_Messung_ende:
135
136
    ret
137
    
138
ADC_Messung_fertig:
139
  
140
  
141
    in temp1, ADCH
142
    st Y+, temp1
143
144
  ;
145
146
    rcall ADC_Messung_akt
147
148
149
    reti
150
151
152
; Datenbereich Flash
153
154
155
156
DFlash_ADC_ADMUX:         ;ADMUX Register ADC | REFS1 | REFS0 | ADLAR |     |  MUX3 | MUX2 | MUX1 | MUX0 | 
157
158
    .DB 0b11100000, 0b11100001, 0b11100010, 0b11100011, 0b11100100, 0b11100101, 0b11100110, 0b00000000
159
  
160
  
161
    ;  0b11100000,    ;0  ADC0 PC0 - Leuchtdauer Poti 
162
    ;  0b11100001    ;1  ADC1 PC1 - Helligkeit Poti
163
    ;  0b11100010,    ;2  ADC2 PC2 - Empfindlichkeit PIR Poti
164
    ;  0b11100011,    ;3  ADC3 PC3 - Heligkeit LDR
165
    ;  0b11100100,    ;4  ADC4 PC4 - Temperaur außen
166
    ;  0b11100101,    ;5  ADC5 PC5 - Batterie Spannung  
167
    ;  0b11100110,    ;6  ADC6 19 - PIR 
168
    ;  0b00000001,    ;7  Messungen fertig
169
    ;  0b11100111,    ;8  ADC7 22 - Res 
170
    
171
172
; Datenbereich SRAM
173
.DSEG
174
175
DSRAM_Analogwerte:
176
177
    .Byte 1        ;0  ADC0 PC0 - Leuchtdauer Poti 
178
    .Byte 1        ;1  ADC1 PC1 - Helligkeit Poti
179
    .Byte 1        ;2  ADC2 PC2 - Empfindlichkeit PIR Poti
180
    .Byte 1        ;3  ADC3 PC3 - Heligkeit LDR
181
    .Byte 1        ;4  ADC4 PC4 - Temperaur außen
182
    .Byte 1        ;5  ADC5 PC5 - Batterie Spannung
183
    .Byte 1        ;6  ADC6 19 - PIR 
184
    .Byte 1        ;7  ADC7 22 - Res

von Matthias (Gast)


Lesenswert?

Ja, könnte mit cpi und BREQ was zu tun haben, da cpi flags im SREG 
stetzt.

Nur bin ich noch nicht dahintergekommen.

mfg
Matthias

von Karl H. (kbuchegg)


Lesenswert?

SREG sichern ist auf jeden Fall wichtig.

Das andere:
Es könnte sein, dass die Umschaltung zwischen den ADC Kanälen zu schnell 
erfolgt und sich daher die Sample&Hold Stufe am Eingang nicht schnell 
genug auf den nächsten Eingang einstellen kann. Meistens macht man es 
so, dass man die erste Messung nach dem Umschalten des Kanals verwirft 
und erst die 2.te nimmt. Zumindest sieht man das so in vielen 
Programmen. Was wirklich dahinter steckt und ob es notwendig ist, kann 
ich dir jetzt so auch nicht sagen.

von spess53 (Gast)


Lesenswert?

Hi

> Meistens macht man es
>so, dass man die erste Messung nach dem Umschalten des Kanals verwirft
>und erst die 2.te nimmt. Zumindest sieht man das so in vielen
>Programmen. Was wirklich dahinter steckt und ob es notwendig ist, kann
>ich dir jetzt so auch nicht sagen.

Das wird eigentlich nur nach Umschaltung der Referenzspannungsquelle 
empfohlen. Bei Messungen alle 66ms sehe ich da nicht das Problem.

@Matthias (Gast)

Ich empfehle dir folgendes:

Den ADC einmal mit den relevanten Einstellungen außer ADSC und MUX3..0 
zu initialisieren

Eine Speicherstelle für den Kanal festlegen (ich bevorzuge RAM). Dient 
gleichzeitig als Offset zum Speichern

Im Timer0-Overflow-Interrupt den ADC starten (->Adsc)

Im ADC Complete Interrupt den ADC auslesen, speichern und auf den 
nächsten Kanal umschalten

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

spess53 schrieb:
> Hi
>
>> Meistens macht man es
>>so, dass man die erste Messung nach dem Umschalten des Kanals verwirft
>>und erst die 2.te nimmt. Zumindest sieht man das so in vielen
>>Programmen. Was wirklich dahinter steckt und ob es notwendig ist, kann
>>ich dir jetzt so auch nicht sagen.
>
> Das wird eigentlich nur nach Umschaltung der Referenzspannungsquelle
> empfohlen. Bei Messungen alle 66ms sehe ich da nicht das Problem.

Oh. Die idee in seinem Code ist aber nicht alle 66ms zu messen.

Mit dem Timer startet er eine Kette von Ereignissen. Der ADC läuft auf 
Interrupt. Mit jedem Interrupt holt er das Ergebnis, stellt den Kanal um 
und startet die nächste Wandlung, bis am Ende dann der ADC nicht mehr 
gestartet wird und alles zum Erliegen kommt, bis dann der Timer erneut 
alles triggert.
Ich bin mir auch noch nicht sicher, ob ich das so machen würde bzw. was 
ich davon halten soll.


> Ich empfehle dir folgendes:
>
> Den ADC einmal mit den relevanten Einstellungen außer ADSC und MUX3..0
> zu initialisieren
>
> Eine Speicherstelle für den Kanal festlegen (ich bevorzuge RAM). Dient
> gleichzeitig als Offset zum Speichern
>
> Im Timer0-Overflow-Interrupt den ADC starten (->Adsc)
>
> Im ADC Complete Interrupt den ADC auslesen, speichern und auf den
> nächsten Kanal umschalten

Hmm.
Genau das macht er doch.
Jetzt bin ich verwirrt.

von spess53 (Gast)


Lesenswert?

Hi

>Genau das macht er doch.
>Jetzt bin ich verwirrt.

Nach genauerer Durchsicht wohl zurecht.

MfG Spess

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.