1 | ;*************************************************************************
|
2 | ; Projekt: Projekt 1
|
3 | ; Projektdatei: PR01.mcp
|
4 | ; Quelldatei: PR01.asm
|
5 | ; Von: Knorr
|
6 | ; Date: 27.01.2010
|
7 | ; Software: MPASM
|
8 | ; Hardware: PIC16F8xx Programmer Module
|
9 | ; Controller PIC16F887
|
10 | ; 7-Segmentanzeige an PORT
|
11 | ; Latcheingang D0 an RC0 (Ausgang)
|
12 | ; Schalter an RC3
|
13 | ; Taster an RC4
|
14 | ; Schrittmotor CLOCK an RC6 (Ausgang)
|
15 | ; Schrittmotor CCW, /CCW an RC7 (Ausgang)
|
16 | ; Texteditor-Code-Page: 1250 (ANSI - Central Europe)
|
17 | ;*************************************************************************
|
18 |
|
19 | ; ------------------------------------------------------------------------
|
20 | ; includes
|
21 | ; ------------------------------------------------------------------------
|
22 | include <p16f887.inc> ; Definitionen fuer Zielcontroller
|
23 |
|
24 | ;-------------------------------------------------------------------------
|
25 | ; PIC Konfiguration
|
26 | ; ------------------------------------------------------------------------
|
27 | list p=16f887 ; list directive to define processor
|
28 |
|
29 | ; Konfigurationsworte 1 und 2 definieren
|
30 | ; '__CONFIG' Direktive wird benutzt, um die Konfigurationdaten in den Quellcode einzubetten.
|
31 | ; Die Labels der einzelnen Bits müssen der p16f887.inc Datei entsprechen.
|
32 | ; Konfigurationswort 1 definieren an Adresse 2007h:
|
33 | ; INT RC oscillator ohne Taktausgabe an RA6 und RA7
|
34 | ; wdt off
|
35 | ; power up timer off
|
36 | ; external Reset on
|
37 | ; code protection off
|
38 | ; data code protection off
|
39 | ; Brown-out Reset off
|
40 | ; Internal External Switchover off
|
41 | ; Fail-Safe Clock Monitor off
|
42 | ; Low Voltage Programming off
|
43 | ; ICD off
|
44 | __CONFIG _CONFIG1, _HS_OSC & _WDT_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOR_OFF & _IESO_OFF & _FCMEN_OFF & _LVP_OFF & _DEBUG_OFF
|
45 |
|
46 | ; osc options: _INTRC_OSC_CLKOUT &_HS_OSC & _XT_OSC
|
47 |
|
48 | ; Konfigurationswort 2 definieren an Adresse 2008h:
|
49 | ; Brown-out Reset Selection = 2,1V
|
50 | ; Write protection off (Flash Program Memory Self Write)
|
51 | __CONFIG _CONFIG2, _BOR21V & _WRT_OFF
|
52 |
|
53 | ;********************************************************
|
54 | ; Variablen festlegen
|
55 |
|
56 | ;16 Bit Rechenregister
|
57 | xw0 equ 0x22 ;
|
58 | xw1 equ 0x23 ;
|
59 | f0 equ 0x24 ;
|
60 | f1 equ 0x25 ;
|
61 | counter equ 0x26 ;
|
62 | Fehler equ 0x27 ;
|
63 | ST equ 0x28 ;
|
64 | SZ equ 0x29 ;
|
65 | SH equ 0x2A ;
|
66 | SE equ 0x2B ;
|
67 | loops equ 0x2C ; timer für wait
|
68 | loops2 equ 0x2D ; timer für wait
|
69 | LcdStatus equ 0x2E ;
|
70 | LcdDaten equ 0x2F ;
|
71 |
|
72 |
|
73 | Ini_con Equ B'00000000' ; TMR0 -> Interupt disable
|
74 | Ini_opt Equ B'00000010' ; pull-up
|
75 |
|
76 | ; für LCD-Pins
|
77 | #define LcdE PORTB,0 ; enable Lcd
|
78 | #define LcdRw PORTB,3 ; read Lcd
|
79 | #define LcdRs PORTB,2 ; Daten Lcd (nicht control)
|
80 | #define LcdPort PORTB ; Datenbus des LCD (obere 4 Bit)
|
81 |
|
82 | ;********************************************************
|
83 | ; Das Programm beginnt mit der Initialisierung
|
84 |
|
85 | Init
|
86 | BANKSEL ANSELH
|
87 | movlw b'00000000'
|
88 | movwf ANSELH
|
89 | BANKSEL TRISB ; Bank 1
|
90 | movlw Ini_opt ; pull-up on
|
91 | movwf OPTION_REG
|
92 | movlw B'00000000' ; PortB alle outputs
|
93 | movwf TRISB
|
94 | BANKSEL PORTB ; Bank 0
|
95 | clrf PORTB
|
96 | movlw Ini_con ; Interupt disable
|
97 | movwf INTCON
|
98 |
|
99 | ; ADC initialisieren
|
100 | ; ADC einschalten
|
101 | BSF ADCON0, 0 ; ADON=1
|
102 | ; ADC-Eingang AN0 auswählen
|
103 | BCF ADCON0, 5 ; ADCHS2=0
|
104 | BCF ADCON0, 4 ; ADCHS1=0
|
105 | BCF ADCON0, 3 ; ADCHS0=0
|
106 | ; ADC speed für 5 ... 20 MHz einstellen
|
107 | BSF ADCON0, 7 ; ADCS1=1
|
108 | BCF ADCON0, 6 ; ADCS0=0
|
109 | ; Daten rechtsbündig
|
110 | BSF STATUS,RP0 ; Bank1
|
111 | clrf ADCON1
|
112 | BSF ADCON1, 7 ; ADFM=1
|
113 | BCF STATUS,RP0 ; Bank0
|
114 |
|
115 |
|
116 | ;Display initialisieren
|
117 | call InitLcd
|
118 |
|
119 |
|
120 | Mainloop
|
121 | call ADC ; Spannung messen nach f1,f0
|
122 | call mV ; Wandlung in Millivolt nach f1,f0
|
123 | call B2D ; Wandlung in dezimal nach ST,SH,SH,SE
|
124 | call Ausgabe ; anzeigen am LCD
|
125 | goto Mainloop
|
126 |
|
127 |
|
128 | ;*****************************************************
|
129 | ; Spannung mit ADC messen
|
130 | ; Ergebnis nach F1,f0
|
131 | ADC
|
132 | BSF ADCON0, 2 ; ADC starten
|
133 | ADCloop
|
134 | BTFSC ADCON0, 2 ; ist der ADC fertig?
|
135 | GOTO ADCloop ; nein, weiter warten
|
136 | movfw ADRESH ; obere 2 Bit auslesen
|
137 | movwf f1 ; obere 2-Bit nach U1H
|
138 | bsf STATUS,RP0 ; Bank1
|
139 | movfw ADRESL ; untere 8 Bit auslesen
|
140 | bcf STATUS,RP0 ; Bank0
|
141 | movwf f0 ; untere 8-Bit nach U1L
|
142 | return
|
143 |
|
144 |
|
145 | ;*********************************************************************
|
146 | ;16 bit Adition, C-Flag bei Überlauf gesetzt
|
147 | Add16 ; 16-bit add: f := f + xw
|
148 | movf xw0,W ; xw0 nach W
|
149 | addwf f0,F ; f0 := f0 + xw0
|
150 |
|
151 | movf xw1,W ; xw1 nach W
|
152 | btfsc STATUS,C ; fall ein Überlauf auftrat:
|
153 | incfsz xw1,W ; xw1+1 nach W
|
154 | addwf f1,F ; f1 := f1 + xw1
|
155 |
|
156 | return ; fertig
|
157 |
|
158 |
|
159 | ;*****************************************************
|
160 | ; 16 Bit Subtraktion, bei Überlauf (neg. Ergebnis) ist C gesetzt
|
161 | Sub16 ; 16 bit f:=f-xw
|
162 | clrf Fehler ; extraflags löschen
|
163 |
|
164 | movf xw0, w ; f0:=f0-xw0
|
165 | subwf f0, f
|
166 |
|
167 | btfsc STATUS,C
|
168 | goto Sub16a
|
169 | movlw 0x01 ; borgen von f1
|
170 | subwf f1, f
|
171 |
|
172 | btfss STATUS,C
|
173 | bsf Fehler, C ; Unterlauf
|
174 |
|
175 | Sub16a
|
176 | movf xw1,w ; f1:=f1-xw1
|
177 | subwf f1 ,f
|
178 |
|
179 | btfss STATUS,C
|
180 | bsf Fehler, C ; Unterlauf
|
181 |
|
182 | bcf STATUS, C ; C-Flag invertieren
|
183 | btfsc Fehler, C
|
184 | bsf STATUS, C
|
185 | return
|
186 |
|
187 |
|
188 | ;*****************************************************
|
189 | ; Division durch 2 wird w-mal ausgeführt
|
190 | ; die zu dividierende Zahl steht in xw
|
191 | Div2
|
192 | movwf counter ; Anzahl der Divisionen speichern
|
193 | Div2a ; 16 bit xw:=xw/2
|
194 | bcf STATUS, C ; carry löschen
|
195 | rrf xw1, f
|
196 | rrf xw0, f
|
197 |
|
198 | decfsz counter, f ; fertig?
|
199 | goto Div2a ; nein: noch mal
|
200 | return
|
201 |
|
202 | ;*****************************************************
|
203 | ; Wandlung des ADC-Wert in Millivolt (binär)
|
204 | ; Der ADC-Wert steht in f1,f0
|
205 | ; Ergebnis steht in f1,f0
|
206 | mV
|
207 | ; zunächst die Multiplikation mal 5
|
208 | movfw f0
|
209 | movwf xw0
|
210 | movfw f1
|
211 | movwf xw1
|
212 | call Add16 ; f := 2xADC
|
213 | call Add16 ; f := 3xADC
|
214 | call Add16 ; f := 4xADC
|
215 | call Add16 ; f := 5xADC
|
216 |
|
217 | ; ADC * 5 nach xw kopieren
|
218 | movfw f0
|
219 | movwf xw0
|
220 | movfw f1
|
221 | movwf xw1 ; xw := 5xADC
|
222 |
|
223 | ; xw durch 64 dividieren (6 mal durch 2)
|
224 | ; dann ist xw = 5xADC/64
|
225 | movlw 6
|
226 | call Div2
|
227 | call Sub16 ; f := 5xADC - 5xADC/64
|
228 |
|
229 | ; xw auf 5xADC/128 verringern
|
230 | movlw 1
|
231 | call Div2
|
232 | call Sub16 ; f := 5xADC - 5xADC/64 - 5xADC/128
|
233 | return ; fertig
|
234 |
|
235 |
|
236 | ;*****************************************************
|
237 | ; Wandlung einer Binärzahl (< 10000) in eine Dezimalzahl
|
238 | ; Die Binärzahl steht in f1,f0
|
239 | ; die Dezimalstellen werden in ST (tausender), SH (hunderter),
|
240 | ; SZ (zehner) und SE (einer) gespeichert im BCD-Code
|
241 | B2D
|
242 | ; Test auf tausender 1000d = 0x03E8
|
243 | movlw 0x03
|
244 | movwf xw1
|
245 | movlw 0xE8
|
246 | movwf xw0
|
247 | call B2Da
|
248 | movwf ST
|
249 | ; Test auf hunderter 100d = 0x0064
|
250 | clrf xw1
|
251 | movlw 0x64
|
252 | movwf xw0
|
253 | call B2Da
|
254 | movwf SH
|
255 | ; Test auf zehner 10d = 0x000A
|
256 | clrf xw1
|
257 | movlw 0x0A
|
258 | movwf xw0
|
259 | call B2Da
|
260 | movwf SZ
|
261 | movfw f0
|
262 | movwf SE
|
263 | return
|
264 |
|
265 | B2Da
|
266 | clrf counter
|
267 | B2Sb incf counter, f ; wie oft abgezogen?
|
268 | call Sub16 ; f:=f-xw
|
269 | btfss STATUS, C ; zu oft abgezogen?
|
270 | goto B2Sb ; nein: noch einmal
|
271 | call Add16 ; f:=f+xw
|
272 | decf counter, w ; weil immer 1 zuviel gezählt wird
|
273 | return
|
274 |
|
275 |
|
276 | ;*****************************************************
|
277 | ;Anzeige der dezimalzahl am LCD mit 'mV'
|
278 | ; input: ST, SH, SZ, SE dezimalstellen im BCD-Code
|
279 | Ausgabe
|
280 | movlw B'10000000' ; 1. Zeile
|
281 | call OutLcdControl
|
282 | movlw '0' ; 30h = '0011 0000'
|
283 | iorwf ST, w ; BCD -> ASCII
|
284 | call OutLcdDaten ; zum LCD
|
285 | movlw '0'
|
286 | iorwf SH, w
|
287 | call OutLcdDaten
|
288 | movlw '0'
|
289 | iorwf SZ, w
|
290 | call OutLcdDaten
|
291 | movlw '0'
|
292 | iorwf SE, w
|
293 | call OutLcdDaten
|
294 | movlw 'm' ; 'mA' anhängen
|
295 | call OutLcdDaten
|
296 | movlw 'V'
|
297 | call OutLcdDaten
|
298 | return
|
299 |
|
300 |
|
301 | ;*****************************************************
|
302 | ;+++LCD-Routinen**************************************
|
303 | ;*****************************************************
|
304 | ;LCD initialisieren, Begrüßung ausgeben
|
305 |
|
306 | InitLcd
|
307 | movlw D'255' ; 250 ms Pause nach dem Einschalten
|
308 | movwf loops
|
309 | call WAIT
|
310 |
|
311 | movlw B'00110000' ; 1
|
312 | movwf LcdPort
|
313 | bsf LcdE
|
314 | nop
|
315 | bcf LcdE
|
316 |
|
317 | movlw D'50' ; 50 ms Pause
|
318 | movwf loops
|
319 | call WAIT
|
320 |
|
321 | movlw B'00110000' ; 2
|
322 | call Control8Bit
|
323 | movlw B'00110000' ; 3
|
324 | call Control8Bit
|
325 | movlw B'00100000' ; 4
|
326 | call Control8Bit
|
327 |
|
328 | movlw B'00000001' ; löschen und cusor home
|
329 | call OutLcdControl
|
330 | movlw B'00101000' ; 5 function set, 4-bit 2-zeilig, 5x7
|
331 | call OutLcdControl
|
332 | movlw B'00001000' ; 6 display off
|
333 | call OutLcdControl
|
334 | movlw B'00000110' ; 7 entry mode, increment, disable display-shift
|
335 | call OutLcdControl
|
336 | movlw B'00000011' ; 8 cursor home, cursor home
|
337 | call OutLcdControl
|
338 | movlw B'00001100' ; 9 display on, Kursor aus , Blinken aus
|
339 | call OutLcdControl
|
340 | return
|
341 |
|
342 | ;*****************************************************
|
343 | ; ein Steuerbyte 8-bittig übertragen
|
344 | Control8Bit
|
345 | movwf LcdPort
|
346 | bsf LcdE
|
347 | nop
|
348 | bcf LcdE
|
349 | movlw D'10'
|
350 | movwf loops
|
351 | call WAIT
|
352 | return
|
353 |
|
354 | ;*****************************************************
|
355 | ; darauf warten, daß das Display bereit zur Datenannahme ist
|
356 | LcdBusy
|
357 | bsf STATUS, RP0 ; make Port B4..7 input
|
358 | movlw B'11110000'
|
359 | iorwf TRISB, f
|
360 | bcf STATUS, RP0
|
361 | BusyLoop
|
362 | bcf LcdRs
|
363 | bsf LcdRw ; Lesen
|
364 | bsf LcdE
|
365 | nop
|
366 | movf LcdPort, w
|
367 | movwf LcdStatus
|
368 | bcf LcdE
|
369 | nop
|
370 | bsf LcdE ; Enable
|
371 | nop
|
372 | bcf LcdE
|
373 | btfsc LcdStatus, 7 ; teste bit 7
|
374 | goto BusyLoop
|
375 | bcf LcdRw
|
376 | bsf STATUS, RP0 ; make Port B4..7 output
|
377 | movlw B'00001111'
|
378 | andwf TRISB, f
|
379 | bcf STATUS, RP0
|
380 | return
|
381 |
|
382 | ;*****************************************************
|
383 | ; aus W ein Byte mit Steuerdaten zum Display übertragen
|
384 | OutLcdControl
|
385 | movwf LcdDaten
|
386 | call LcdBusy
|
387 | movf LcdDaten, w
|
388 | andlw H'F0'
|
389 | movwf LcdPort ; Hi-teil Daten schreiben
|
390 | bsf LcdE
|
391 | nop
|
392 | bcf LcdE ; Disable LcdBus
|
393 | swapf LcdDaten, w
|
394 | andlw H'F0'
|
395 | movwf LcdPort ; Lo-teil Daten schreiben
|
396 | bsf LcdE
|
397 | nop
|
398 | bcf LcdE ; Disable LcdBus
|
399 | return
|
400 |
|
401 | ;*****************************************************
|
402 | ; aus W ein Datenbyte zum Display übertragen
|
403 | OutLcdDaten
|
404 | movwf LcdDaten
|
405 | call LcdBusy
|
406 | movf LcdDaten, w
|
407 | andlw H'F0'
|
408 | movwf LcdPort ; Hi-teil Daten schreiben
|
409 | bsf LcdRs ; Daten
|
410 | bsf LcdE ; Enable LcdBus
|
411 | nop
|
412 | bcf LcdE ; Disable LcdBus
|
413 | swapf LcdDaten, w
|
414 | andlw H'F0'
|
415 | movwf LcdPort ; Lo-teil Daten schreiben
|
416 | bsf LcdRs ; Daten
|
417 | bsf LcdE
|
418 | nop
|
419 | bcf LcdE ; Disable LcdBus
|
420 | bcf LcdRs ;
|
421 | return
|
422 |
|
423 |
|
424 | ;*****************************************************
|
425 | ;Zeitverzögerung um loops * 1 ms
|
426 | ; 10 MHz externer Takt bedeutet 2,5 MHz interner Takt
|
427 | ; also dauert 1 ms genau 2500 Befehle
|
428 | ; 250 Schleifen a 10 Befehle sind 2500 Befehle = 1 ms
|
429 |
|
430 | WAIT
|
431 | top movlw .250 ; timing adjustment variable (1ms)
|
432 | movwf loops2
|
433 | top2 nop ; sit and wait
|
434 | nop
|
435 | nop
|
436 | nop
|
437 | nop
|
438 | nop
|
439 | nop
|
440 | decfsz loops2, F ; inner loops complete?
|
441 | goto top2 ; no, go again
|
442 | ;
|
443 | decfsz loops, F ; outer loops complete?
|
444 | goto top ; no, go again
|
445 | retlw 0 ; yes, return from subWAIT
|
446 |
|
447 |
|
448 | end
|