ADC.asm


1
.include "m8def.inc"       ;Definitionsdatei einbinden
2
3
; single ADC
4
.def  temp  =R18      ;temporary storage register 
5
.def  Txbyte  =R19      ;Data to be transmitted 
6
.def  Rxbyte  =R20      ;Received data 
7
.DEF rmp = R21 ; als Vielzweckregister verwendet für Umwandlung
8
.def temp1 = r25
9
.def temp2 = r26
10
.def temp3 = r22
11
.def temp4 = r23
12
.def rxbyte = r24
13
14
                           
15
.org 0x0000
16
17
  rjmp reset
18
 
19
reset:
20
  ldi r16, low(RAMEND)
21
  out SPL, r16
22
  ldi r16, high(RAMEND)
23
  out SPH, r16
24
 
25
;  sbi UCR,RXEN                   ;RX aktivieren
26
  sbi UCSRB,TXEN                   ;TX aktivieren
27
  ldi temp,12; 4800 1000000/(9600*16)-1  ;4000000/(9600*16)-1   ;Baudrate 9600 einstellen
28
  out UBRRL,temp
29
  ldi r16, (1<<URSEL)|(1<<USBS)|(3<<UCSZ0)
30
  out UCSRC,r16
31
32
33
  ldi r16, 0b11000111  ; 110.. = Internal Ref 2.56V  letzen 3 stellen für analog eingang
34
  out ADMUX, r16    ; 010.. = AVCC , ca 5.07V
35
  ldi r16, 0b10001101
36
  out ADCSR, r16
37
38
    ldi temp1, 0xFF    ;Port D = Ausgang
39
    out DDRB, temp1
40
41
    rcall lcd_init     ;Display initialisieren
42
    rcall lcd_clear    ;Display löschen
43
44
 
45
46
loop:
47
  rcall delay
48
  rcall delay
49
  rcall delay
50
  rcall delay
51
        
52
    sbi ADCSR,ADSC
53
    rcall delay
54
  rcall delay
55
  rcall delay
56
  rcall delay
57
        
58
         
59
loop2:  
60
  sbis ADCSR,ADIF
61
  rjmp loop2
62
 
63
  in r16, ADCL
64
  in r17, ADCH
65
66
  ;com r16      ;für Convertierung Invert aus 5V->0V 0V->5V
67
  ;mov txbyte, r16
68
  ;rcall  putchar
69
  ;mov temp1, r16
70
  ;rcall  lcd_data
71
72
73
  ;com r17
74
  ;mov temp1, r17
75
  ;rcall  lcd_data
76
77
  ;mov txbyte, r17
78
  ;rcall  putchar
79
  
80
  andi r17,$03
81
  mov rmp,r17 ; Wandle um ADC-Wert um
82
  mov R2,rmp
83
  mov rmp,r16
84
  mov R1,rmp
85
  rcall fpconv10 ; Rufe die Umwandlungsroutine
86
87
  mov temp1, r5  ; ASCII-Ergebnis steht in R5-R10
88
  rcall  lcd_data
89
  mov temp1, r6
90
  rcall  lcd_data
91
  mov temp1, r7
92
  rcall  lcd_data
93
  mov temp1, r8
94
  rcall  lcd_data
95
  mov temp1, r9
96
  rcall  lcd_data
97
  mov temp1, r10
98
  rcall  lcd_data
99
  
100
  rcall lcd_Cursor_home
101
  rjmp loop
102
103
104
delay:
105
  push r16
106
  push r17
107
  in r16,SREG
108
  push r16
109
  ldi  r16, $FF;$84    ; 132 - 1,604,1,1=607  =  +1=80125Takte
110
dloop0:  ldi  r17, $FF;$C9    ; 201 - 1,1,1 = 603+1=604
111
dloop1: dec  r17
112
        brne dloop1    ; 0.02003 sec , ca 20 msec
113
        dec  r16
114
        brne dloop0
115
        pop r16
116
        out SREG,r16
117
        pop r17
118
        pop r16
119
  ret
120
121
;***** Receive byte from UART to Rxbyte
122
123
;getchar:    
124
  ;sbis USR, RXC                   ; warten bis ein Byte angekommen ist
125
  ;rjmp getchar
126
    ;in Rxbyte, UDR                      ; empfangenes Byte nach Rxbyte kopieren
127
;ret                 ; zurück zum Hauptprogramm
128
129
;***** Transmit byte in Txbyte to UART
130
131
132
putchar:    
133
  sbis UCSRA,UDRE  ;Warten, bis UDR für das nächste Byte bereit ist  
134
  rjmp putchar
135
  out UDR, Txbyte
136
ret               
137
138
139
140
;UMWANDLUNGSROUTINE
141
142
fpconv10:
143
  rcall fpconv10c ; Prüfe die Eingabezahl in R2:R1
144
  brcs fpconv10e ; Wenn Carry, dann Ergebnis="E.EEE"
145
        rcall fpconv10m ; Multipliziere mit 320.313
146
  rcall fpconv10r ; Runden und Division mit 65536
147
  rcall fpconv10a ; Umwandlung in ASCII-String
148
  rjmp fpconv10f ; Setze Dezimalpunkt und Nullabschluss
149
fpconv10e:
150
  ldi rmp,'E' ; Fehlermeldung in Ergebnistext
151
  mov R5,rmp
152
  mov R7,rmp
153
  mov R8,rmp
154
  mov R9, rmp
155
fpconv10f:
156
  ldi rmp,'.' ; Setze Dezimalpunkt
157
  mov R6,rmp
158
  ldi rmp, 86 ;V
159
  ;clr rmp ; Null-Abschluss setzen
160
  mov R10,rmp
161
  ret ; Alles fertig
162
;
163
; Unterprogramm Eingabeprüfung
164
;
165
fpconv10c:
166
  ldi rmp,$03 ; Vergleiche MSB mit 03
167
  cp rmp,R2 ; wenn R2>$03, setze carry bei Rückkehr
168
  ret
169
;
170
; Unterprogramm Multiplikation mit 320.313
171
;
172
; Startbedingung:
173
; +---+---+
174
; | R2+ R1|  Eingabezahl
175
; +---+---+
176
; +---+---+---+---+
177
; | R6| R5| R4| R3| Multiplikant 320.313 = $00 04 E3 38 (00 02 80 A0) bei 2,56V
178
; | 00| 04| E3| 38| 328.000 (05 01 40) bei 5.12V
179
; +---+---+---+---+
180
; +---+---+---+---+
181
; |R10| R9| R8| R7| Resultat
182
; | 00| 00| 00| 00|
183
; +---+---+---+---+
184
;
185
fpconv10m:
186
  clr R6 ; Setze den Multiplikant auf 320.313
187
  ldi rmp,$04
188
  mov R5,rmp
189
  ldi rmp,$E3
190
  mov R4,rmp
191
  ldi rmp,$38
192
  mov R3,rmp
193
  clr R10 ; leere Ergebnisregister
194
  clr R9
195
  clr R8
196
  clr R7
197
fpconv10m1:
198
  mov rmp,R1 ; Prüfe ob noch Bits zu multiplizieren
199
  or rmp,R2 ; Irgendein Bit Eins?
200
  brne fpconv10m2 ; Noch Einsen, mach weiter
201
  ret ; fertig, kehre zurück
202
fpconv10m2:
203
  lsr R2 ; Schiebe MSB nach rechts (teilen durch 2)
204
  ror R1 ; Rotiere LSB rechts und setze Bit 7
205
  brcc fpconv10m3 ; Wenn das niedrigste Bit eine 0 war,
206
;    dann überspringe den Additionsschritt
207
    add R7,R3 ; Addiere die Zahl in R6:R5:R4:R3 zum Ergebnis
208
  adc R8,R4
209
  adc R9,R5
210
  adc R10,R6
211
fpconv10m3:
212
  lsl R3 ; Multipliziere R6:R5:R4:R3 mit 2
213
  rol R4
214
  rol R5
215
  rol R6
216
  rjmp fpconv10m1 ; Wiederhole für das nächste Bit
217
;
218
; Runde die Zahl in R10:R9 mit dem Wert von Bit 7 von R8
219
;
220
fpconv10r:
221
  clr rmp ; Null nach rmp
222
  lsl R8 ; Rotiere Bit 7 ins Carry
223
  adc R9,rmp ; Addiere LSB mit Übertrag
224
  adc R10,rmp ; Addiere MSB mit Übertrag
225
  mov R2,R10 ; Kopiere den Wert nach R2:R1 (durch 65536 teilen)
226
  mov R1,R9
227
  ret
228
;
229
; Wandle das Wort in R2:R1 in einen ASCII-Text in R5:R6:R7:R8:R9:R10
230
;
231
; +---+---+
232
; + R2| R1| Eingangswert 0..5.000
233
; +---+---+
234
; +---+---+
235
; | R4| R3| Dezimalteiler
236
; +---+---+
237
; +---+---+---+---+---+---+
238
; | R5| R6| R7| R8| R9|R10| Ergebnistext (für Einmgangswert 5,000)
239
; |'5'|'.'|'0'|'0'|'0'|$00| mit Null-Abschluss
240
; +---+---+---+---+---+---+
241
;
242
fpconv10a:
243
  ldi rmp,HIGH(1000) ; Setze Dezimalteiler auf 1.000
244
  mov R4,rmp
245
  ldi rmp,LOW(1000)
246
  mov R3,rmp
247
  rcall fpconv10d ; Hole ASCII-Ziffer durch wiederholtes Abziehen
248
  mov R5,rmp ; Setze Tausender Zeichen
249
  clr R4 ; Setze Dezimalteiler auf 100
250
  ldi rmp,100
251
  mov R3,rmp
252
  rcall fpconv10d ; Hole die nächste Ziffer
253
  mov R7,rmp ; Setze Hunderter Zeichen
254
  ldi rmp,10 ; Setze Dezimalteiler auf 10
255
  mov R3,rmp
256
  rcall fpconv10d ; Hole die nächste Ziffer
257
  mov R8,rmp ; Setze Zehner Zeichen
258
  ldi rmp,'0' ; Wandle Rest in ASCII-Ziffer um
259
  add rmp,R1
260
  mov R9,rmp ; Setze Einer Zeichen
261
  ret
262
;
263
; Wandle Binärwort in R2:R1 in eine Dezimalziffer durch fortgesetztes
264
; Abziehen des Dezimalteilers in R4:R3 (1000, 100, 10)
265
;
266
fpconv10d:
267
  ldi rmp,'0' ; Beginne mit ASCII-0
268
fpconv10d1:
269
  cp R1,R3 ; Vergleiche Wort mit Teiler
270
  cpc R2,R4
271
  brcc fpconv10d2 ; Carry nicht gesetzt, subtrahiere Teiler
272
  ret ; fertig
273
fpconv10d2:
274
  sub R1,R3 ; Subtrahiere Teilerwert
275
  sbc R2,R4
276
  inc rmp ; Ziffer um eins erhöhen
277
  rjmp fpconv10d1 ; und noch einmal von vorne
278
;
279
; Ende der Fließkomma-Umwandlungsroutinen
280
;
281
;
282
; Ende des Umwandlungstestprogramms
283
;
284
;.include "lcd-routines.asm"            ;LCD-Routinen werden hier eingefügt
285
286
287
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
288
;;                 LCD-Routinen                ;;
289
;;                 ============                ;;
290
;;                                     ;;
291
;;                                             ;;
292
;; 4bit-Interface                              ;;
293
;; DB4-DB7:       PB0-PB3                      ;;
294
;; RS:            PB4                          ;;
295
;; E:             PB5                          ;;
296
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
297
298
 
299
 
300
 ;sendet ein Datenbyte an das LCD
301
lcd_data:
302
           mov temp2, temp1             ;"Sicherungskopie" für
303
                                        ;die Übertragung des 2.Nibbles
304
           swap temp1                   ;Vertauschen
305
           andi temp1, 0b00001111       ;oberes Nibble auf Null setzen
306
           sbr temp1, 1<<4              ;entspricht 0b00010000
307
       out PORTB, temp1             ;ausgeben
308
           rcall lcd_enable             ;Enable-Routine aufrufen
309
                                        ;2. Nibble, kein swap da es schon
310
                                        ;an der richtigen stelle ist
311
           andi temp2, 0b00001111       ;obere Hälfte auf Null setzen 
312
           sbr temp2, 1<<4              ;entspricht 0b00010000
313
           out PORTB, temp2             ;ausgeben
314
           rcall lcd_enable             ;Enable-Routine aufrufen
315
           rcall delay50us              ;Delay-Routine aufrufen
316
           ret                          ;zurück zum Hauptprogramm
317
318
 ;sendet einen Befehl an das LCD
319
lcd_command:                            ;wie lcd_data, nur ohne RS zu setzen
320
           mov temp2, temp1
321
           swap temp1
322
           andi temp1, 0b00001111
323
           out PORTB, temp1
324
           rcall lcd_enable
325
           andi temp2, 0b00001111
326
           out PORTB, temp2
327
           rcall lcd_enable
328
           rcall delay50us
329
           ret
330
331
 ;erzeugt den Enable-Puls
332
lcd_enable:
333
           sbi PORTB, 0                 ;Enable high
334
           nop                          ;3 Taktzyklen warten
335
           nop
336
           nop
337
           cbi PORTB, 0                 ;Enable wieder low
338
           ret                          ;Und wieder zurück                     
339
340
 ;Pause nach jeder Übertragung
341
delay50us:                              ;50us Pause
342
           ldi  temp1, $42
343
delay50us_:dec  temp1
344
           brne delay50us_
345
           ret                          ;wieder zurück
346
347
 ;Längere Pause für manche Befehle
348
delay5ms:                               ;5ms Pause
349
           ldi  temp1, $21
350
WGLOOP0:   ldi  temp2, $C9
351
WGLOOP1:   dec  temp2
352
           brne WGLOOP1
353
           dec  temp1
354
           brne WGLOOP0
355
           ret                          ;wieder zurück
356
357
 ;Initialisierung: muss ganz am Anfang des Programms aufgerufen werden
358
lcd_init:
359
           ldi  temp3,50
360
powerupwait:
361
           rcall  delay5ms
362
           dec  temp3
363
           brne  powerupwait
364
           ldi temp1, 0b00000011        ;muss 3mal hintereinander gesendet
365
           out PORTB, temp1             ;werden zur Initialisierung
366
           rcall lcd_enable             ;1
367
           rcall delay5ms
368
           rcall lcd_enable             ;2
369
           rcall delay5ms
370
           rcall lcd_enable             ;und 3!
371
           rcall delay5ms
372
           ldi temp1, 0b00000010        ;4bit-Modus einstellen
373
           out PORTB, temp1
374
           rcall lcd_enable
375
           rcall delay5ms
376
           ldi temp1, 0b00101000        ;noch was einstellen...
377
           rcall lcd_command
378
           ldi temp1, 0b00001100        ;...nochwas...
379
           rcall lcd_command
380
           ldi temp1, 0b00000100        ;endlich fertig
381
           rcall lcd_command
382
           ret
383
384
 ;Sendet den Befehl zur Löschung des Displays
385
lcd_clear:
386
           ldi temp1, 0b00000001   ;Display löschen
387
           rcall lcd_command
388
           rcall delay5ms
389
           ret
390
391
392
lcd_Cursor_home:
393
           ldi temp1, 0b00000010   ;Cursor Home           
394
           rjmp lcd_command
395
           ret