Forum: Mikrocontroller und Digitale Elektronik Probleme beim ADC-Wert auf LCD ausgeben


von Stefan M. (celmascant)


Lesenswert?

Hallo ihr MC-Gurus!

Ich habe mich gerade frisch hier angemeldet, das ist also mein erstes 
Posting.
Ganz kurz zu mir: Ich bin 24, Elektriker und Hobbyelektroniker.
Vor ca. 8 Jahren hab ich das erste mal mit MC's gebastelt, bis vor 
kurzem noch mit dem AT89C2051. Jetzt "arbeite" ich seit ca. einem Monat 
mit der atMega-Serie (mega32)
Programmiert habe ich bisher immer mit Assembler, da seh ich wenigstens 
durch^^ Bascom geht eigendlich auch, aber das wollt ich net kaufen, und 
die 4k waren sooo schnell voll^^
Bei C verstehe ich nur Banhof und komme garnicht mit klar.

Also, meine Testumgebung besteht aus dem Pollin Evaluation-board V2.0.1, 
dem Pollin Addon-Board V1.0 und einer Lochrasterkarte wo alles 
draufkommt was ich bei den anderen beiden Platinen vermisse.
Die beiden Polin-Karten habe ich schon leicht modifiziert, sodas ich 
zumindest die ADC-Grundbeschaltung dran habe, der MAX232 funktioniert 
und die Taster gegen Masse schalten.

Ich habe bereits das Tutorial "abgearbeitet".
Das LCD funktioniert wunderbar, nachdem ich mir die Tutorial-Routine auf 
8-Bit umgeschrieben habe.

*Nun zu meinem Problem:*

Ich habe das Tutorial-Programm zum ADC-Wert ausgeben 8Das einfache, ohne 
Umrechnung in Spannung) leicht geändet.(Taktfrequenz, MCU-Typ, 
LCD-Routinen)
Am PC empfange ich die Werte einwandfrei, ich kann mittels Poti schön 
die Spannung am Eingang einstellen und bekomme dementsprechend die 
Messwerte via Uart geleiftert.
Nun wollte ich den Wert auf das LCD schreiben und habe zum Umrechnen der 
16-Bit Zahl
1. einfach den ASCII-Code aus dem Register "Zeichen" nach "temp1" 
kopiert und an das LCD als Daten gesendet und
2. die 16-Bit-Umwandlung aus dem Tutorial genommen.
Beides funktioniert auf den ersten Blick auch.
Am PC kommt immer das richtig an, jedoch beim LCD nicht.
Von 00000-ca.00273 geht alles so wie es soll. Wenn ich dann am Poti 
weiterdrehe kommt jedoch nur noch auf dem PC der richtige Messwert an.
Auf dem LCD "zittern" die letzen 3 Stellen, gehen evtl sogar wieder 
etwas zurück (also Wert auf 00247 zB.) und springen dann plötzlich auf 
ca.11393
Am PC wird jedoch der richtige Wert angezeigt: 0000393
Wenn ich noch weiter drehe, zB. am PC auf 00411, steht auf dem LCD 
11511.
Bei 00543 am PC zeigt mir das LCD 11553 an.
Bei 00605 auf dem PC zeigt das LCD 11715.

Also irgendwas kommt offensichtlich durcheinander, wenn es wirkleich ein 
Wert wird, der nich mehr in 8bit gespeichert werden kann.

Das ADC-Test-Programm:

(Ja, ich weiss das z.B. XTAL und F_CPU das gleiche ist, aber ich bin ja 
noch am probieren. Ich habe beim Label Transmit die auskommentierten 
Zeilen gelassen. Damit wird einfach das über den UART gesendete Zeichen 
am LCD ausgegeben, inclusive CR und LF^^ nach dem Label no_round ist die 
aktuelle LCD-Ausgabe, welche die Umwandlung aus dem LCD-Tutorial 
benutzt)
1
.NOLIST
2
.INCLUDE "m32def.inc"
3
.LIST
4
5
.ifndef XTAL
6
.equ XTAL = 16000000
7
.endif
8
9
rjmp start
10
11
.def temp1     = r16         ; allgemeines temp Register, zur kurzfristigen Verwendung
12
.def temp2     = r17         ; Register für 24 Bit Addition, Lowest Byte
13
.def temp3     = r18         ; Register für 24 Bit Addition, Middle Byte
14
.def temp4     = r19         ; Register für 24 Bit Addition, Highest Byte
15
.def adlow     = r20         ; Ergebnis vom ADC / Mittelwert der 256 Messungen
16
.def adhigh    = r21         ; Ergebnis vom ADC / Mittelwert der 256 Messungen
17
.def messungen = r22         ; Schleifenzähler für die Messungen
18
.def ztausend  = r23         ; Zehntausenderstelle des ADC Wertes
19
.def tausend   = r24         ; Tausenderstelle des ADC Wertes
20
.def hundert   = r25         ; Hunderterstelle des ADC Wertes
21
.def zehner    = r26         ; Zehnerstelle des ADC Wertes
22
.def zeichen   = r27         ; Zeichen zur Ausgabe auf den UART
23
 
24
.equ F_CPU = 16000000                            ; Systemtakt in Hz
25
.equ BAUD  = 9600                               ; Baudrate
26
 
27
; Berechnungen
28
.equ UBRR_VAL   = ((F_CPU+BAUD*8)/(BAUD*16)-1)  ; clever runden
29
.equ BAUD_REAL  = (F_CPU/(16*(UBRR_VAL+1)))     ; Reale Baudrate
30
.equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000)  ; Fehler in Promille
31
 
32
.if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))       ; max. +/-10 Promille Fehler
33
  .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit zu hoch!"
34
.endif
35
36
.include "LCD_Routinen_8bit.asm"
37
38
; hier geht das Programm los
39
start:
40
    ldi     temp1, LOW(RAMEND)                  ; Stackpointer initialisieren
41
    out     SPL, temp1
42
    ldi     temp1, HIGH(RAMEND)
43
    out     SPH, temp1
44
 
45
;UART Initalisierung
46
 
47
    ldi     temp1, LOW(UBRR_VAL)                    ; Baudrate einstellen
48
    out     UBRRL, temp1
49
    ldi     temp1, HIGH(UBRR_VAL)
50
    out     UBRRH, temp1
51
 
52
    sbi     UCSRB, TXEN                         ; TX einschalten
53
 
54
; LCD Initialisieren
55
  rcall LCD_Init
56
  rcall LCD_Clear
57
  rcall LCD_Home
58
59
; ADC initialisieren: Single Conversion, Vorteiler 128
60
 
61
    ldi     temp1, (1<<REFS0)                   ; Kanal 0, interne Referenzspannung 5V
62
    out     ADMUX, temp1
63
    ldi     temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)
64
    out     ADCSRA, temp1
65
66
    ldi     zeichen, 82
67
    rcall   transmit
68
    ldi     zeichen, 101
69
    rcall   transmit
70
    ldi     zeichen, 115
71
    rcall   transmit
72
    ldi     zeichen, 101
73
    rcall   transmit
74
    ldi     zeichen, 116
75
    rcall   transmit
76
    ldi     zeichen, 13         ; CR, Carrige Return (Wagenrücklauf)
77
    rcall   transmit
78
    ldi     zeichen, 10         ; LF, Line Feed (Neue Zeile)
79
    rcall   transmit
80
81
82
83
Main:
84
    clr     temp1
85
    clr     temp2
86
    clr     temp3
87
    clr     temp4
88
 
89
    ldi     messungen, 0        ; 256 Schleifendurchläufe
90
 
91
; neuen ADC-Wert lesen  (Schleife - 256 mal)
92
 
93
sample_adc:
94
    sbi     ADCSRA, ADSC        ; den ADC starten
95
 
96
wait_adc:
97
    sbic    ADCSRA, ADSC        ; wenn der ADC fertig ist, wird dieses Bit gelöscht
98
    rjmp    wait_adc
99
 
100
; ADC einlesen:
101
 
102
    in      adlow, ADCL         ; immer zuerst LOW Byte lesen
103
    in      adhigh, ADCH        ; danach das mittlerweile gesperrte High Byte
104
 
105
; alle 256 ADC-Werte addieren
106
; dazu wird mit den Registern temp4, temp3 und temp2 ein
107
; 24-Bit breites Akkumulationsregister gebildet, in dem
108
; die 10 Bit Werte aus adhigh, adlow aufsummiert werden
109
 
110
    add     temp2, adlow        ; addieren
111
    adc     temp3, adhigh       ; addieren über Carry
112
    adc     temp4, temp1        ; addieren über Carry, temp1 enthält 0
113
    dec     messungen           ; Schleifenzähler MINUS 1
114
    brne    sample_adc          ; wenn noch keine 256 ADC Werte -> nächsten Wert einlesen
115
 
116
; Aus den 256 Werten den Mittelwert berechnen
117
; Mathematisch eine Division durch 256
118
; Da aber 2^8 = 256 ist ist da einfach durch das weglassen des niederwertigsten Bytes
119
; erreicht werden
120
;
121
; allerdings wird der Wert noch gerundet
122
 
123
    cpi     temp2,128           ; "Kommastelle" kleiner als 128 ?
124
    brlo    no_round            ; ist kleiner ==> Sprung
125
 
126
; Aufrunden
127
    subi    temp3, low(-1)      ; addieren von 1
128
    sbci    temp4, high(-1)     ; addieren des Carry
129
 
130
no_round:
131
 
132
;   Ergebnis nach adlow und adhigh kopieren
133
;   damit die temp Register frei werden
134
 
135
    mov     adlow, temp3
136
    mov     adhigh, temp4
137
138
;provisorishe LCD-Ansteuerung
139
140
  push temp2
141
  push temp3
142
143
  mov temp2, adlow
144
  mov temp3, adhigh
145
  rcall lcd_number16
146
  pop temp3
147
  pop temp2
148
149
;in ASCII umwandeln
150
; Division durch mehrfache Subtraktion
151
 
152
    ldi     ztausend, '0'-1     ; Ziffernzähler direkt als ASCII Code
153
Z_ztausend:
154
    inc     ztausend
155
    subi    adlow, low(10000)   ; -10,000
156
    sbci    adhigh, high(10000) ; 16 Bit
157
    brcc    Z_ztausend
158
                                    
159
    subi    adlow, low(-10000)  ; nach Unterlauf wieder einmal addieren
160
    sbci    adhigh, high(-10000); +10,000
161
 
162
    ldi     tausend, '0'-1      ; Ziffernzähler direkt als ASCII Code
163
Z_tausend:
164
    inc     tausend
165
    subi    adlow, low(1000)    ; -1,000
166
    sbci    adhigh, high(1000)  ; 16 Bit
167
    brcc    Z_tausend
168
                                    
169
    subi    adlow, low(-1000)   ; nach Unterlauf wieder einmal addieren
170
    sbci    adhigh, high(-1000) ; +1,000
171
 
172
    ldi     hundert, '0'-1      ; Ziffernzähler direkt als ASCII Code
173
Z_hundert:
174
    inc     hundert
175
    subi    adlow, low(100)     ; -100
176
    sbci    adhigh, high(100)   ; 16 Bit
177
    brcc    Z_hundert
178
                                    
179
    subi    adlow, low(-100)    ; nach Unterlauf wieder einmal addieren
180
    sbci    adhigh, high(-100)  ; +100
181
 
182
    ldi     zehner, '0'-1       ; Ziffernzähler direkt als ASCII Code
183
Z_zehner:
184
    inc     zehner
185
    subi    adlow, low(10)      ; -10
186
    sbci    adhigh, high(10)    ; 16 Bit
187
    brcc    Z_zehner
188
                                    
189
    subi    adlow, low(-10)     ; nach Unterlauf wieder einmal addieren
190
    sbci    adhigh, high(-10)   ; +10
191
 
192
    subi    adlow, -'0'         ; adlow enthält die Einer, Umwandlung in ASCII
193
 
194
;an UART Senden
195
    rcall lcd_home
196
    mov     zeichen, ztausend   ; Zehntausender Stelle
197
    rcall   transmit
198
    mov     zeichen, tausend    ; Tausender Stelle ausgeben
199
    rcall   transmit    
200
    mov     zeichen, hundert    ; Hunderter Stelle ausgeben
201
    rcall   transmit
202
    mov     zeichen, zehner     ; Zehner Stelle ausgeben
203
    rcall   transmit
204
    mov     zeichen, adlow      ; Einer Stelle ausgeben
205
    rcall   transmit
206
    ldi     zeichen, 13         ; CR, Carrige Return (Wagenrücklauf)
207
    rcall   transmit
208
    ldi     zeichen, 10         ; LF, Line Feed (Neue Zeile)
209
    rcall   transmit
210
211
 
212
    rjmp    Main
213
 
214
transmit:
215
    sbis    UCSRA,UDRE          ; Warten, bis UDR bereit ist ...
216
    rjmp    transmit
217
    out     UDR, zeichen        ; und Zeichen ausgeben
218
;    push temp1
219
;    mov temp1, zeichen
220
;    rcall LCD_Data
221
;    pop temp1
222
    ret

Und hier noch meine 8bit-LCD-Routinen:

(um die Macros locate und printflash erweitert, ausserdem testweise die 
16bit-Addition auch bei 100er und 10er-Stellen hinzugefügt)
1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                 LCD-Routinen                 ;;
3
;;                 ============                 ;;
4
;;               by Stefan Muster               ;;
5
;;nach Vorbild des Microcontroller.net-Tutorials;;
6
;;                                              ;;
7
;; 8bit-Interface                               ;;
8
;; DB0-DB7:       PortB                         ;;
9
;; RW:        PD3 - noch in Arbeit          ;;
10
;; RS:            PD4                           ;;
11
;; E:             PD5                           ;;
12
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13
14
.equ LCD_PORT = PORTA  ;Datenport
15
.equ LCD_DDR  = DDRA
16
.equ LCD_Strg_PORT = PORTB
17
.equ PIN_RS   = 2    ;
18
.equ PIN_E    = 0
19
.equ Pin_RW    = 1
20
.equ LCD_Strg_DDR = DDRB
21
22
 ;sendet ein Datenbyte an das LCD
23
lcd_data:
24
           push  temp2
25
           push  temp3
26
          
27
           in    temp3, LCD_Strg_PORT     
28
           sbr   temp3, (1<<Pin_RS)     ; RS auf 1 setzen
29
           out   LCD_Strg_PORT, temp3
30
           out   LCD_PORT, temp1         ; ausgeben
31
           rcall lcd_enable              
32
           rcall delay50us               ; Delay-Routine aufrufen
33
34
           pop   temp3
35
           pop   temp2
36
           ret                           ; zurück zum Hauptprogramm
37
 
38
 ; sendet einen Befehl an das LCD
39
lcd_command:                            ; wie lcd_data, nur ohne RS zu setzen
40
           push  temp2
41
           push  temp3
42
43
           in    temp3, LCD_Strg_PORT  ; schreibt den Zustand von LCD_Strg_PORT nach temp3
44
           ;cbr   temp3, Pin_RS      ; Setzt RS auf 0 (0=Befehl)
45
           andi  temp3, 0b11111011
46
           out   LCD_Strg_PORT, temp3  ; Gibt temp3 an LCD_Strg_PORT aus (jetzt mit RS=0)
47
           out   LCD_PORT, temp1    ; Gibt den Befehl an LCD_PORT aus
48
           rcall lcd_enable
49
           rcall delay50us
50
 
51
           pop   temp3
52
           pop   temp2
53
           ret
54
 
55
 ; erzeugt den Enable-Puls
56
lcd_enable:
57
           sbi LCD_Strg_PORT, PIN_E          ; Enable high
58
           nop                          ; 9 Taktzyklen warten
59
           nop
60
           nop
61
           nop
62
           nop
63
           nop
64
           nop
65
           nop
66
           nop
67
           cbi LCD_Strg_PORT, PIN_E          ; Enable wieder low
68
           ret                          ; Und wieder zurück                     
69
 
70
 ; Pause nach jeder Übertragung
71
delay50us: ;ret                            ; 50us Pause
72
           push temp1
73
           ldi  temp1, ( XTAL * 50 / 4 ) / 1000000
74
delay50us_:
75
           nop
76
           dec  temp1
77
           brne delay50us_
78
           pop temp1
79
           ret                          ; wieder zurück
80
81
 ; Längere Pause für manche Befehle
82
delay5ms:  ;ret                             ; 5ms Pause
83
           push temp1
84
           push temp2
85
           ldi  temp1, ( XTAL * 5 / 607 ) / 1000
86
WGLOOP0:   ldi  temp2, $C9
87
WGLOOP1:   dec  temp2
88
           brne WGLOOP1
89
           dec  temp1
90
           brne WGLOOP0
91
           pop temp2
92
           pop temp1
93
           ret                          ; wieder zurück
94
 
95
 ; Initialisierung: muss ganz am Anfang des Programms aufgerufen werden
96
lcd_init:
97
           push  temp1
98
           push temp3
99
           in    temp1, LCD_Strg_DDR
100
           ori   temp1, (1<<PIN_E) | (1<<PIN_RS) ;| (1<<PIN_RW)
101
           out   LCD_Strg_DDR, temp1
102
           ldi temp1, 0xff
103
           out LCD_DDR, temp1
104
105
106
           ldi   temp3,6
107
powerupwait:
108
           rcall delay5ms
109
           dec   temp3
110
           brne  powerupwait
111
           ldi   temp1,    0b00000011   ; muss 3mal hintereinander gesendet
112
           out   LCD_PORT, temp1        ; werden zur Initialisierung
113
           rcall lcd_enable             ; 1
114
           rcall delay5ms
115
           rcall lcd_enable             ; 2
116
           rcall delay5ms
117
           rcall lcd_enable             ; und 3!
118
           rcall delay5ms
119
           ldi   temp1,    0b00110000   ; 8bit
120
           out   LCD_PORT, temp1
121
           rcall lcd_enable
122
           rcall delay5ms
123
           ldi   temp1,     0b00111000  ;System set
124
           rcall lcd_command
125
           ldi   temp1,    0b00001100   ; Display ein / Cursor aus / kein Blinken
126
           rcall lcd_command
127
           ldi   temp1,    0b00000100   ; inkrement / kein Scrollen
128
           rcall lcd_command
129
           pop   temp3
130
           pop temp1
131
           ret
132
 
133
134
135
 ; Sendet den Befehl zur Löschung des Displays
136
lcd_clear:
137
           push  temp1
138
           ldi   temp1,    0b00000001   ; Display löschen
139
           rcall lcd_command
140
           rcall delay5ms
141
           pop   temp1
142
           ret
143
144
 ; Cursor Home
145
lcd_home:
146
           push  temp1
147
           ldi   temp1,    0b00000010   ; Cursor Home
148
           rcall lcd_command
149
           rcall delay5ms
150
           pop   temp1
151
           ret
152
153
.macro locate ;Zeile (0,1), Spalte (0...39) ;Positionierung der Ausgabeposition
154
           push temp1                    ;Register sichern
155
           ldi temp1,128+((@0 & 1)<<6)+(@1 & 63) ;Zeile in Bit 6, Spalte in den Rest
156
           rcall lcd_command          ;an LCD als Befehl ausgeben
157
           pop temp1                     ;Register wiederherstellen
158
.endmacro
159
160
161
162
 ; Einen konstanten Text aus dem Flash Speicher
163
 ; ausgeben. Der Text wird mit einer 0 beendet
164
.macro printflash ;Startadresse des Strings im Flash (als Label angegeben)
165
    ;Gibt einen String aus dem Flash an LCD aus
166
    ;Der Parameter beschreibt die Startadresse, 
167
    ;das Ende ist $00
168
           push zh                    ;verwendete Register
169
           push zl                    ;sichern
170
           ldi zh,high(2*@0)          ;Pointer
171
           ldi zl,low(2*@0)           ;setzen
172
           rcall lcd_printf           ;Aufruf...
173
           pop zl                     ;verwendete Register
174
           pop zh                     ;wiederherstellen
175
.endmacro
176
177
lcd_printf:   ;Wird vom Makro aufgerufen. Gibt Flash-String an LCD aus.
178
           push temp1                    ;Variable beschaffen
179
           lpm temp1,z+                  ;Zeichen holen
180
           tst temp1                     ;Ende-Kennung? 
181
           breq pc+3                  ;ja...
182
           rcall lcd_data             ;nein, ausgeben
183
           rjmp pc-4                  ;nochmal
184
           pop temp1                     ;Variable entsorgen
185
           ret                        ;fertig, zurück...
186
187
188
 ; Eine Zahl aus dem Register temp1 dezimal ausgeben
189
lcd_number:
190
           push  temp1
191
           push  temp2
192
           push  temp3
193
194
           mov   temp2, temp1
195
                                  ; abzählen wieviele Hunderter
196
                                          ; in der Zahl enthalten sind
197
           ldi   temp1, '0'
198
lcd_number_1:
199
           subi  temp2, 100
200
           brcs  lcd_number_2
201
           inc   temp1
202
           rjmp  lcd_number_1
203
                                          ;
204
                                          ; die Hunderterstelle ausgeben
205
lcd_number_2:
206
           rcall lcd_data
207
           subi  temp2, -100              ; 100 wieder dazuzählen, da die
208
                                          ; vorherhgehende Schleife 100 zuviel
209
                                          ; abgezogen hat
210
211
                                          ; abzählen wieviele Zehner in
212
                                          ; der Zahl enthalten sind
213
           ldi   temp1, '0'
214
lcd_number_3:
215
           subi  temp2, 10
216
           brcs  lcd_number_4
217
           inc   temp1
218
           rjmp  lcd_number_3
219
220
                                          ; die Zehnerstelle ausgeben
221
lcd_number_4:
222
           rcall lcd_data
223
           subi  temp2, -10               ; 10 wieder dazuzählen, da die
224
                                          ; vorhergehende Schleife 10 zuviel
225
                                          ; abgezogen hat
226
227
                                          ; die übrig gebliebenen Einer
228
                                          ; noch ausgeben
229
           ldi   temp1, '0'
230
           add   temp1, temp2
231
           rcall lcd_data
232
233
           pop   temp3
234
           pop   temp2
235
           pop   temp1
236
           ret
237
238
;**********************************************************************
239
;
240
; Eine 16 Bit Zahl ohne Vorzeichen ausgeben
241
;
242
; Übergabe:            Zahl im Register temp2 (low Byte) / temp3 (high Byte)
243
; veränderte Register: keine
244
;
245
lcd_number16:
246
           push  temp1
247
           push  temp2
248
           push  temp3
249
 
250
; ** Zehntausender **
251
           ldi   temp1, '0'-1
252
lcd_number1:
253
           inc   temp1
254
           subi  temp2, low(10000)
255
           sbci  temp3, high(10000)
256
           brcc  lcd_number1
257
           subi  temp2, low(-10000)
258
           sbci  temp3, high(-10000)
259
           rcall lcd_data
260
 
261
; ** Tausender **
262
           ldi   temp1, '0'-1
263
lcd_number2:
264
           inc   temp1
265
           subi  temp2, low(1000)
266
           sbci  temp3, high(1000)
267
           brcc  lcd_number2
268
           subi  temp2, low(-1000)
269
           sbci  temp3, high(-1000)
270
           rcall lcd_data
271
 
272
; ** Hunderter **
273
           ldi   temp1, '0'-1
274
lcd_number3:
275
           inc   temp1
276
           subi  temp2, low(100)
277
           sbci  temp3, high(100)
278
           brcc  lcd_number3
279
           subi  temp2, low(-100)
280
           sbci  temp3, high(-100)
281
           rcall lcd_data
282
 
283
; ** Zehner **
284
           ldi   temp1, '0'-1
285
lcd_number4:
286
           inc   temp1
287
           subi  temp2, (10)
288
           brcc  lcd_number4
289
           subi  temp2, low(-10)
290
           sbci  temp3, high(-10)
291
           rcall lcd_data
292
 
293
; ** Einer **
294
           ldi   temp1, '0'
295
           add   temp1, temp2
296
           rcall lcd_data
297
 
298
; ** Stack aufräumen **
299
           pop   temp3
300
           pop   temp2
301
           pop   temp1
302
 
303
           ret

Ich hoffe ihr könnt mir helfen und mir sagen wo der Fehler versteckt 
ist.
Hab heut schon den halben Tag gesucht und komme nicht weiter.

Also, Danke schonmal im Vorraus für eure Hilfe!

Gruss Stefan

von Z8 (Gast)


Lesenswert?

dampf mal Deine Main ein:
______________________________________________________________________ 
___
Main:
    clr     temp1
    clr     temp2
    clr     temp3
    clr     temp4

    ldi     messungen, 0        ; 256 Schleifendurchläufe

; neuen ADC-Wert lesen  (Schleife - 256 mal)

sample_adc:
    sbi     ADCSRA, ADSC        ; den ADC starten

wait_adc:
    sbic    ADCSRA, ADSC        ; wenn der ADC fertig ist, wird dieses 
Bit gelöscht
    rjmp    wait_adc

; ADC einlesen:

    in      adlow, ADCL         ; immer zuerst LOW Byte lesen
    in      adhigh, ADCH        ; danach das mittlerweile gesperrte High 
Byte

; alle 256 ADC-Werte addieren
; dazu wird mit den Registern temp4, temp3 und temp2 ein
; 24-Bit breites Akkumulationsregister gebildet, in dem
; die 10 Bit Werte aus adhigh, adlow aufsummiert werden

    add     temp2, adlow        ; addieren
    adc     temp3, adhigh       ; addieren über Carry
    adc     temp4, temp1        ; addieren über Carry, temp1 enthält 0
    dec     messungen           ; Schleifenzähler MINUS 1
    brne    sample_adc          ; wenn noch keine 256 ADC Werte -> 
nächsten Wert einlesen

; Aus den 256 Werten den Mittelwert berechnen
; Mathematisch eine Division durch 256
; Da aber 2^8 = 256 ist ist da einfach durch das weglassen des 
niederwertigsten Bytes
; erreicht werden
;
; allerdings wird der Wert noch gerundet

    cpi     temp2,128           ; "Kommastelle" kleiner als 128 ?
    brlo    no_round            ; ist kleiner ==> Sprung

; Aufrunden
    subi    temp3, low(-1)      ; addieren von 1
    sbci    temp4, high(-1)     ; addieren des Carry

no_round:

  rcall lcd_number16

    rjmp    Main
______________________________________________________________________ 
______



Was passier dann?  Z8

von Z8 (Gast)


Lesenswert?

jetzt sehe ichs:

>; Übergabe:     Zahl im Register temp2 (low Byte) / temp3 (high Byte)

no_round:

  mov temp2, temp3    ;!!!
  mov temp3, temp4    ;!!!
  rcall lcd_number16

  rjmp    Main

von Stefan M. (celmascant)


Lesenswert?

Für die Übergabe habe ich doch bei der provisorischen LCD-Ansteuerung 
folgende Zeilen:

;provisorishe LCD-Ansteuerung

  push temp2
  push temp3

  mov temp2, adlow
  mov temp3, adhigh
  rcall lcd_number16
  pop temp3
  pop temp2

Wenn ich jetzt bei no_round adlow und adhig direkt durch die Register 
ersetze, funktioniert die UART-Ausgabe ja nicht mehr. Dann müsste ich 
die umschreiben (was eigendlich kein Problem ist).

Wenn ich mein Main einkürze, so wie du es vorschlägst hätte ich ja keine 
Ausgabe der Daten mehr, oder seh ich das falsch?
Aber danke für die Antworten.

Was ich noch vergessen hatte: Ich programmiere mit dem AVR-Studio V4.16 
und die Programme werden per Ponyprog2000 V2.06f Beta übertragen.

Gruss Stefan

von Stefan M. (celmascant)


Lesenswert?

So, hab jetzt ein wenig weiter experimentiert.
Ich habe die komplette UART-Ansteuerung mal rausgenommen (so wie Z8 
vorgeschlagen hat, inclusive der Übergebe in den richtigen Registern^^)
Das Problem besteht weiterhin.
Dann habe ich mein 4x16 LCD angschlossen -> das gleiche.
So, jetzt hab ich in der ersten LCD-Zeile konstant "01" ausgegeben, 2 
Leerzeichen, dann die über UART gesendeten ASCII-Zeichen.
In der 2. Zeile stehen die von LCD_number16 ausgegebenen Zeichen, in der 
3. und 4. Zeile wird adlow und adhigh als binärzahl ausgegeben.
Über die serielle Schnittstelle funktioniert nach wie vor alles super, 
jedoch beim LCD nicht.
Wenn ich z.B. den ADC-Wert 270 einstelle, "Zittern" einige Nullstellen, 
also springen kurz auf 1, selbst die 0 vom 01 in der ersten Zeile!!!
Ausserdem habe ich bei den Variablen in Zeile 1 und 2 ein Zeichen zu 
viel.
Kann es sein das ich ein Timingproblem beim LCD habe? Wenn ja, verstehe 
ich nur nicht, warum dann z.B. ein konstanter Text richtig ausgegeben 
wird.

Also, ist es möglich das solch komischen Werte durch ein falsches Timing 
entstehen?

Gruss Stefan

EDIT: Hab gerade festgestellt, das alle Variablen, also auch die binären 
nach kurzer Zeit eine Stelle mehr haben (die sich allerdings nie 
verändert).

von Stefan M. (celmascant)


Lesenswert?

Ok, hab den Fehler gefunden, denk ich.
Das LCD lief noch über PortA mit DB0-DB7.
Der benutzte ADC-Eingang ist PA.0 ...
Wenn ich da jetzt ne analoge Spannung anlege, erkennt das LCD das 
irgendwann als High (1) und dann gibts halt keine 0 mehr, sondern 
nurmehr Einsen.
Hab jetzt die LCD-Routine angepasst, das die Datenleitungen an Port C 
sind, aber irgendwie funktioniert da was nicht. initialisiert wird 
irgendwie, aber Zeichen kommen keine raus... auch nicht mit meinem 
Tstprogramm was bisher immer funktioniert hat.

Gruss Stefan

von spess53 (Gast)


Lesenswert?

Hi

JTAG-Fuse

MfG Spess

von Stefan M. (celmascant)


Lesenswert?

Danke für die Antwort, hat aber leider nix gebracht.
Egal ob Jtag an oder aus, es will nicht funktionieren.
Hab es jetzt an PortD angeschlossen, wo es allerdings auch niht auf 
anhieb klappte. Erst nachdem ich das Programm nochmals assembliert und 
neu geladen hatte (ohne auch nur ein Zeichen zu ändern) geht es jetzt.

Kann es sein, das das AVR-Studio ab und zu beim Assemblieren die 
änderungen nicht mitassembliert?

EDIT:
So, weitergebastelt, also Uart auskommentiert, und siehe da: Der 
Analogwert wird korrekt als Dezimalzahl und die Register adlow und 
adhigh werden korrekt als Binärzahl dargestellt. Auch der "statische" 
Text wird ohne Fehler angezeigt!

JUPPIIIIIIIII! Es geht!!!!
Jetzt muss ich nur noch rausfinden, warum es an PortC nicht geht^^

Gruss Stefan

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.