Forum: Mikrocontroller und Digitale Elektronik Voltemeter mit PIC16F887


von Marcus W. (Gast)


Lesenswert?

Hallo ihr,

nochmal danke für die Hilfe beim letzten mal ;)

Ich hoffe ihr könnt mir nochmal helfen. Mein letztes Übungsprojekt 
sollte ein Voltmeter mit dem PIC über eine LCD-Anzeige werden.

Leider funktioniert das nicht so wirklich. Habe die grundsätliche 
Anleitung von Sprut und habe versucht sie erstmal auf meinen PIC um zu 
schreiben.

Leider zeigt er mir nichts an. Habe schon versucht den Fehler selber zu 
finden aber leider ohne wirklichen Erfolg.

Konnte aber feststellen das die LCD Routinen funktionieren. Muss also an 
irgendwas anderem liegen



Schon einmal danke im vorraus ^^

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

von M. J. (manfred-64)


Lesenswert?

Probier's mal ohne Bussyflag abfrage.
warte statt dessen 1mSec.+
Hab hier auch so'n teil das daß Bussyflag nicht korrekt das ausgeben 
will.

von Maik W. (werner01)


Lesenswert?

hallo,


mit ANSELH konfigurierst Du deine PORTS!

Für analog muß da eine 1 stehen?


Grüße

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.