Code:
;==========================================================================
;
; Configuration Bits
;
;==========================================================================
_CP_OFF EQU H'3FFF'
_DEBUG_OFF EQU H'3FFF'
_LVP_OFF EQU H'3F7F'
_WRT_OFF EQU H'3FFF'
_PWRTE_ON EQU H'3FF7'
_WDT_OFF EQU H'3FFB'
_BODEN_OFF EQU H'3FBF'
_HS_OSC EQU H'3FFE'
LIST
;==========================================================================
;
; Configuration
;
;==========================================================================
__CONFIG _CP_OFF & _DEBUG_OFF & _LVP_OFF & _WRT_OFF & _PWRTE_ON & _WDT_OFF & _BODEN_OFF & _HS_OSC
;**************************************************************
;* Pinbelegung
;* ----------------------------------
;* PORTA: 0 < Spannung U
;* 1 -
;* 2 -
;* 3 -
;* 4 -
;* 5 -
;* 6 -
;* 7 -
;*
;* PORTB: 0 LCD Display E
;* 1 -
;* 2 LCD Display RS
;* 3 LCD Display R/W
;* 4 LCD Display D4
;* 5 LCD Display D5
;* 6 LCD Display D6
;* 7 LCD Display D7
;*
;* PORTC: 0 -
;* 1 -
;* 2 -
;* 3 -
;* 4 -
;* 5 -
;* 6 -
;* 7 -
;*
;**************************************************************
;
;sprut (zero) Bredendiek 01/2003
;
; Lehrbeispiel: ADC mit LCD
;
; Prozessor 16F876
;
; Prozessor-Takt 10 MHz
;
; LCD am PortB
;**********************************************************
ERRORLEVEL -302 ;SUPPRESS BANK SELECTION MESSAGES
; Configuration festlegen:
; Power on Timer, kein Watchdog, HS-Oscillator, kein Brown out, kein LV-programming
__CONFIG _PWRTE_ON & _WDT_OFF & _HS_OSC & _BODEN_OFF & _LVP_OFF
;********************************************************
; Variablen festlegen
;16 Bit Rechenregister
xw0 equ 0x22 ;
xw1 equ 0x23 ;
f0 equ 0x24 ;
f1 equ 0x25 ;
counter equ 0x26 ;
Fehler equ 0x27 ;
ST equ 0x28 ;
SZ equ 0x29 ;
SH equ 0x2A ;
SE equ 0x2B ;
loops equ 0x2C ; timer für wait
loops2 equ 0x2D ; timer für wait
LcdStatus equ 0x2E ;
LcdDaten equ 0x2F ;
Ini_con Equ B'00000000' ; TMR0 -> Interupt disable
Ini_opt Equ B'00000010' ; pull-up
; für LCD-Pins
#define LcdE PORTB,0 ; enable Lcd
#define LcdRw PORTB,3 ; read Lcd
#define LcdRs PORTB,2 ; Daten Lcd (nicht control)
#define LcdPort PORTB ; Datenbus des LCD (obere 4 Bit)
;********************************************************
; Das Programm beginnt mit der Initialisierung
Init bsf STATUS, RP0 ; Bank 1
movlw Ini_opt ; pull-up on
movwf OPTION_REG
movlw B'00000000' ; PortB alle outputs
movwf TRISB
bcf STATUS, RP0 ; Bank 0
clrf PORTB
movlw Ini_con ; Interupt disable
movwf INTCON
; ADC initialisieren
; ADC einschalten
BSF ADCON0, 0 ; ADON=1
; ADC-Eingang AN0 auswählen
BCF ADCON0, 5 ; ADCHS2=0
BCF ADCON0, 4 ; ADCHS1=0
BCF ADCON0, 3 ; ADCHS0=0
; ADC speed für 5 ... 20 MHz einstellen
BSF ADCON0, 7 ; ADCS1=1
BCF ADCON0, 6 ; ADCS0=0
; Daten rechtsbündig
BSF STATUS,RP0 ; Bank1
clrf ADCON1
BSF ADCON1, 7 ; ADFM=1
BCF STATUS,RP0 ; Bank0
;Display initialisieren
call InitLcd
Mainloop
call ADC ; Spannung messen nach f1,f0
call mV ; Wandlung in Millivolt nach f1,f0
call B2D ; Wandlung in dezimal nach ST,SH,SH,SE
call Ausgabe ; anzeigen am LCD
goto Mainloop
;*****************************************************
; Spannung mit ADC messen
; Ergebnis nach F1,f0
ADC
BSF ADCON0, 2 ; ADC starten
ADCloop
BTFSC ADCON0, 2 ; ist der ADC fertig?
GOTO ADCloop ; nein, weiter warten
movfw ADRESH ; obere 2 Bit auslesen
movwf f1 ; obere 2-Bit nach U1H
bsf STATUS,RP0 ; Bank1
movfw ADRESL ; untere 8 Bit auslesen
bcf STATUS,RP0 ; Bank0
movwf f0 ; untere 8-Bit nach U1L
return
;*********************************************************************
;16 bit Adition, C-Flag bei Überlauf gesetzt
Add16 ; 16-bit add: f := f + xw
movf xw0,W ; xw0 nach W
addwf f0,F ; f0 := f0 + xw0
movf xw1,W ; xw1 nach W
btfsc STATUS,C ; fall ein Überlauf auftrat:
incfsz xw1,W ; xw1+1 nach W
addwf f1,F ; f1 := f1 + xw1
return ; fertig
;*****************************************************
; 16 Bit Subtraktion, bei Überlauf (neg. Ergebnis) ist C gesetzt
Sub16 ; 16 bit f:=f-xw
clrf Fehler ; extraflags löschen
movf xw0, w ; f0:=f0-xw0
subwf f0, f
btfsc STATUS,C
goto Sub16a
movlw 0x01 ; borgen von f1
subwf f1, f
btfss STATUS,C
bsf Fehler, C ; Unterlauf
Sub16a
movf xw1,w ; f1:=f1-xw1
subwf f1 ,f
btfss STATUS,C
bsf Fehler, C ; Unterlauf
bcf STATUS, C ; C-Flag invertieren
btfsc Fehler, C
bsf STATUS, C
return
;*****************************************************
; Division durch 2 wird w-mal ausgeführt
; die zu dividierende Zahl steht in xw
Div2
movwf counter ; Anzahl der Divisionen speichern
Div2a ; 16 bit xw:=xw/2
bcf STATUS, C ; carry löschen
rrf xw1, f
rrf xw0, f
decfsz counter, f ; fertig?
goto Div2a ; nein: noch mal
return
;*****************************************************
; Wandlung des ADC-Wert in Millivolt (binär)
; Der ADC-Wert steht in f1,f0
; Ergebnis steht in f1,f0
mV
; zunächst die Multiplikation mal 5
movfw f0
movwf xw0
movfw f1
movwf xw1
call Add16 ; f := 2xADC
call Add16 ; f := 3xADC
call Add16 ; f := 4xADC
call Add16 ; f := 5xADC
; ADC * 5 nach xw kopieren
movfw f0
movwf xw0
movfw f1
movwf xw1 ; xw := 5xADC
; xw durch 64 dividieren (6 mal durch 2)
; dann ist xw = 5xADC/64
movlw 6
call Div2
call Sub16 ; f := 5xADC - 5xADC/64
; xw auf 5xADC/128 verringern
movlw 1
call Div2
call Sub16 ; f := 5xADC - 5xADC/64 - 5xADC/128
return ; fertig
;*****************************************************
; Wandlung einer Binärzahl (< 10000) in eine Dezimalzahl
; Die Binärzahl steht in f1,f0
; die Dezimalstellen werden in ST (tausender), SH (hunderter),
; SZ (zehner) und SE (einer) gespeichert im BCD-Code
B2D
; Test auf tausender 1000d = 0x03E8
movlw 0x03
movwf xw1
movlw 0xE8
movwf xw0
call B2Da
movwf ST
; Test auf hunderter 100d = 0x0064
clrf xw1
movlw 0x64
movwf xw0
call B2Da
movwf SH
; Test auf zehner 10d = 0x000A
clrf xw1
movlw 0x0A
movwf xw0
call B2Da
movwf SZ
movfw f0
movwf SE
return
B2Da
clrf counter
B2Sb incf counter, f ; wie oft abgezogen?
call Sub16 ; f:=f-xw
btfss STATUS, C ; zu oft abgezogen?
goto B2Sb ; nein: noch einmal
call Add16 ; f:=f+xw
decf counter, w ; weil immer 1 zuviel gezählt wird
return
;*****************************************************
;Anzeige der dezimalzahl am LCD mit 'mV'
; input: ST, SH, SZ, SE dezimalstellen im BCD-Code
Ausgabe
movlw B'10000000' ; 1. Zeile
call OutLcdControl
movlw '0' ; 30h = '0011 0000'
iorwf ST, w ; BCD -> ASCII
call OutLcdDaten ; zum LCD
movlw '0'
iorwf SH, w
call OutLcdDaten
movlw '0'
iorwf SZ, w
call OutLcdDaten
movlw '0'
iorwf SE, w
call OutLcdDaten
movlw 'm' ; 'mA' anhängen
call OutLcdDaten
movlw 'V'
call OutLcdDaten
return
;*****************************************************
;+++LCD-Routinen**************************************
;*****************************************************
;LCD initialisieren, Begrüßung ausgeben
InitLcd
movlw D'255' ; 250 ms Pause nach dem Einschalten
movwf loops
call WAIT
movlw B'00110000' ; 1
movwf LcdPort
bsf LcdE
nop
bcf LcdE
movlw D'50' ; 50 ms Pause
movwf loops
call WAIT
movlw B'00110000' ; 2
call Control8Bit
movlw B'00110000' ; 3
call Control8Bit
movlw B'00100000' ; 4
call Control8Bit
movlw B'00000001' ; löschen und cusor home
call OutLcdControl
movlw B'00101000' ; 5 function set, 4-bit 2-zeilig, 5x7
call OutLcdControl
movlw B'00001000' ; 6 display off
call OutLcdControl
movlw B'00000110' ; 7 entry mode, increment, disable display-shift
call OutLcdControl
movlw B'00000011' ; 8 cursor home, cursor home
call OutLcdControl
movlw B'00001100' ; 9 display on, Kursor aus , Blinken aus
call OutLcdControl
return
;*****************************************************
; ein Steuerbyte 8-bittig übertragen
Control8Bit
movwf LcdPort
bsf LcdE
nop
bcf LcdE
movlw D'10'
movwf loops
call WAIT
return
;*****************************************************
; darauf warten, daß das Display bereit zur Datenannahme ist
LcdBusy
bsf STATUS, RP0 ; make Port B4..7 input
movlw B'11110000'
iorwf TRISB, f
bcf STATUS, RP0
BusyLoop
bcf LcdRs
bsf LcdRw ; Lesen
bsf LcdE
nop
movf LcdPort, w
movwf LcdStatus
bcf LcdE
nop
bsf LcdE ; Enable
nop
bcf LcdE
btfsc LcdStatus, 7 ; teste bit 7
goto BusyLoop
bcf LcdRw
bsf STATUS, RP0 ; make Port B4..7 output
movlw B'00001111'
andwf TRISB, f
bcf STATUS, RP0
return
;*****************************************************
; aus W ein Byte mit Steuerdaten zum Display übertragen
OutLcdControl
movwf LcdDaten
call LcdBusy
movf LcdDaten, w
andlw H'F0'
movwf LcdPort ; Hi-teil Daten schreiben
bsf LcdE
nop
bcf LcdE ; Disable LcdBus
swapf LcdDaten, w
andlw H'F0'
movwf LcdPort ; Lo-teil Daten schreiben
bsf LcdE
nop
bcf LcdE ; Disable LcdBus
return
;*****************************************************
; aus W ein Datenbyte zum Display übertragen
OutLcdDaten
movwf LcdDaten
call LcdBusy
movf LcdDaten, w
andlw H'F0'
movwf LcdPort ; Hi-teil Daten schreiben
bsf LcdRs ; Daten
bsf LcdE ; Enable LcdBus
nop
bcf LcdE ; Disable LcdBus
swapf LcdDaten, w
andlw H'F0'
movwf LcdPort ; Lo-teil Daten schreiben
bsf LcdRs ; Daten
bsf LcdE
nop
bcf LcdE ; Disable LcdBus
bcf LcdRs ;
return
;*****************************************************
;Zeitverzögerung um loops * 1 ms
; 10 MHz externer Takt bedeutet 2,5 MHz interner Takt
; also dauert 1 ms genau 2500 Befehle
; 250 Schleifen a 10 Befehle sind 2500 Befehle = 1 ms
WAIT
top movlw .250 ; timing adjustment variable (1ms)
movwf loops2
top2 nop ; sit and wait
nop
nop
nop
nop
nop
nop
decfsz loops2, F ; inner loops complete?
goto top2 ; no, go again
;
decfsz loops, F ; outer loops complete?
goto top ; no, go again
retlw 0 ; yes, return from subWAIT
end
Prozessor:
Lesezeichen