Code:
; list p=16f876a ; list directive to define processor
#include P16F876A.INC ; processor specific variable definitions
__CONFIG _LVP_OFF & _BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC
; STATUS bit definitions
#define _C STATUS,0 ; fuer die Kurzschreibung
#define _Z STATUS,2 ; von Bitpruefungen "BTFSS _Z"
; Hardware-Signale
; PORT A
; Pins RA0/1/3 analog beschaltet
; Pin RA2 Ausgang ENL fuer LCD
; Pin RA4 Eingang
; Pin RA5 Ausgang ENR fuer Register
; PORT B
; LCD-Modul Und Latch: nur Ausgaenge
; Datenpuffer: cio_lcd, dat_reg
; Flag-Bits
#define LCD_TXF flaxa,0 ; =1: Sendeauftrag fuer ISR ans LCD
#define LCD_RS flaxa,1 ; =1: Datenregister, =0: Befehlsregister
#define LZBLANK flaxa,2 ; =1: unterdruecke fuehrende Nullen
#define REG_TXF flaxa,3 ; =1: Sendeauftrag fuer Registerwerte
#define SCRFLAG flaxa,6 ; =1: temporaeres Flag
; #define NEWDATA flaxa,7 ; =1:
; gültig für f_OSZ = 12MHz (HS_OSC)
T1PREH EQU 0xF4 ; preload = 2^16 - d'3000' = 0xF448 für 1000,0 Hz @ 12MHz /4, 1:1
T1PREL EQU 0x48 ; d.h. 3000x 1µs bis zum Overflow
;***** KONSTANTEN *****
ADR_BMA020 EQU 0x70 ; I2C-Basisadresse des g-Sensors
; Pin-Nummern fuer LCD und Out-Register
BIT_ENL EQU d'2' ; Port A: LCD-Enable-Signal
BIT_ENR EQU d'5' ; Port A: Out-Register-EN an
BIT_RW EQU d'2' ; Port B: Read- /Write-Signal LCD
BIT_RS EQU d'1' ; Port B: RegisterSelect-Signal, Funktion: Data bzw. /Instruction
;***** BANK(0)-EXKLUSIVE REGISTER 0x20..0x6F
CBLOCK 0x20
cio_lcd ; Datenpuffer LCD
dat_reg ; Datenpuffer OpenColl, Register
cio_dac ; Datenpuffer Digital-Analog-Wandler (D7..D0 --> D0..7, seitenverkehrt)
mscr ; Scratch Byte fuer das Hauptprogramm (alles ausser ISR)
iscr ; Scratch Byte fuer die Interrruptausfuehrung (ISR)
buf_ra ; EN-Ausgaenge LCD und Register
sta_ra ; dig. Eingang
buf_rc ; falls mal Ausgaenge sein werden
sta_rc ; Tasteneingaenge
flaxa ; div. Flags
dat_lcd ; Netto-/Nutz-Daten zum LCD; NICHT die Bitleiste inkl. Steuersignale am Bus: das ist cio_lcd
cur_zsp ; Text-Position Zeile,Spalte
cur_cmd ; DisplayDataRAM-Adresse fuer LCD-Modul
txt_fst ; "first char"-Index des gewaehlten Fixtexts
txt_idx ; Laufvariable
i2c_adr ; Device-Adresse
i2c_reg ; Registeradresse im Device
i2c_dat ; Dateninhalt des Registers
loopcount ; frei verfuegbarer Durchlaufzaehler
gxraw ; Rohwert-MSB g-Sensor x-Achse
gyraw ; Rohwert-MSB g-Sensor y-Achse
gzraw ; Rohwert-MSB g-Sensor z-Achse
ENDC ;
;***** GLOBALE VARIABLEN 0x70..0x7F
dlycnt EQU 0x7A ; allg. Delay-Restzyklen zu je 1ms
ticker EQU 0x7B ; allg. Laufvariable u.a. fuer das Lebenszeichen
tickerh EQU 0x7C ; Folgestufe zur Zaehlung der ticker-Ueberlaeufe
temp_w EQU 0x7D ; variable used for context saving
temp_status EQU 0x7E ; variable used for context saving
temp_pclath EQU 0x7F ; variable used for context saving
;**********************************************************************
; ; Begin of 2k-Code Page #0 (1/4)
ORG 0x0000 ; processor reset vector
;**********************************************************************
nop ; nop required for icd
goto MAIN ; go to beginning of program
nop
nop
;**********************************************************************
ORG 0x004 ; interrupt vector location
;**********************************************************************
;********** Kontext sichern **********
movwf temp_w ; save off current W register contents
movf STATUS,w ; move status register into W register
movwf temp_status ; save off contents of STATUS register
movf PCLATH,w ; move pclath register into w register
movwf temp_pclath ; save off contents of PCLATH register
; Lead-In
bcf STATUS,RP0 ;
bcf STATUS,RP1 ; Bank 0 als default
bcf PCLATH,4 ;
bcf PCLATH,3 ; Code Page #0
;;************** ANFANG DER TMR1-ISR *******************
ISR_TMR1
bcf PIR1,TMR1IF ; auslösendes Flag löschen
movlw T1PREH ; Preload-Werte laden
movwf TMR1H ;
movlw T1PREL ;
movwf TMR1L ;
ISR_DIGIN
; Momentaufnahmen der dig. Eingaenge
movf PORTA,w ;
movwf sta_ra ;
movf PORTC,w ;
movwf sta_rc ;
ISR_DIGIN_E
ISR_LCD
; LCD bedienen
btfss LCD_TXF ; ToDo-Flag da? Sendeauftrag?
goto ISR_LCD_E ; =0: nix zu tun
bcf LCD_TXF ; Arbeit da; Flag loeschen
movf cio_lcd,w ;
movwf PORTB ;
bsf buf_ra,BIT_ENL ; das Bit fuer EN am LCD
movf buf_ra,w ;
movwf PORTA ; LCD enable aktiv
nop ; Wartezeit, ...
nop ;
nop ;
nop ;
nop ;
nop ; 6* 0,33us = 2us
bcf buf_ra,BIT_ENL ;
movf buf_ra,w ;
movwf PORTA ; LCD enable wieder passiv
nop ; Wartezeit, ...
nop ;
nop ;
nop ;
nop ;
nop ; 6* 0,33us = 2us
ISR_LCD_E
ISR_REG
; Register bedienen
btfss REG_TXF ; neue Daten ?
goto ISR_REG_E ; DAC ohne Auftrag nicht stoeren (DAC haengt DIREKT am PORTB)
bcf REG_TXF ; Arbeit da; Flag loeschen
movf dat_reg,w ;
movwf PORTB ;
bsf buf_ra,BIT_ENR ; das Bit fuer EN am Register
movf buf_ra,w ;
movwf PORTA ; Register-enable aktiv
nop ; Wartezeit, ...
nop ;
nop ;
nop ;
nop ;
nop ; 6* 0,33us = 2us
bcf buf_ra,BIT_ENR ;
movf buf_ra,w ;
movwf PORTA ; Register-enable wieder passiv
nop ; Wartezeit, ...
nop ;
nop ;
nop ;
nop ;
nop ; 6* 0,33us = 2us
ISR_REG_E
; Millisekunden-Eieruhr
movf dlycnt,f ; Z-Flag generieren
btfss STATUS,Z ;
decf dlycnt,f ; dekr., wenn nicht null (Z=0)
; Hier laeuft die 'Unruh' des Controllers bzw. seiner Firmware
incf ticker,f ; universell und immer in Bewegung
movf ticker,w ;
btfsc _Z ;
incf tickerh,f ;
; abschliessende Arbeiten vor Ende der ISR:
ISR_TAIL
; ... derzeit nichts
;************** ENDE DER TMR1-ISR *******************
ISR_RESTORE
; Kontext wiederherstellen
movf temp_pclath,w ; retrieve copy of PCLATH register
movwf PCLATH ; restore pre-isr PCLATH register contents
movf temp_status,w ; retrieve copy of STATUS register
movwf STATUS ; restore pre-isr STATUS register contents
swapf temp_w,f ; Kniff: W laden, ohne den Status zu veraendern !
swapf temp_w,w ; restore pre-isr W register contents
retfie ; return from interrupt (bewirkt auch ein "bsf INTCON,GIE")
;***
MAIN ; Das Hauptprogramm
; RAM (partiell) initialisieren
movlw 0x20 ; erste Speicherzelle
movwf FSR ; Zeiger setzen
RAMCLR
clrf INDF ; Zugriff !
incf FSR,f ; naechste Zelle
btfss FSR,7 ; fertig ? Zeiger >= 0x80 ?
goto RAMCLR ; NEIN
RAMCLR_E
; Portregister fuer digitale Ausgaenge initialisieren
movlw b'00010000' ; 5: EN des Registers, 4: OC, 2: EN des LCD
movwf buf_ra ;
movwf PORTA ; (Umbau-bedingte Abweichung von meinem Anschlussprinzip)
movlw b'00000000' ;
movwf cio_lcd ;
movwf PORTB ;
movlw b'00000000' ; PORTC[4;3] unbedingt auf "L" setzen,
movwf buf_rc ;
movwf PORTC ; damit der I2C-Bus-Reset durchfuehrbar ist
; I/O-Leitungen konfigurieren
banksel TRISA
movlw b'11001011' ; 5: EN Register, 4: OC, 3, 1, 0: ANx, 2: EN LCD
movwf TRISA ;
movlw b'00000000' ; alles Ausgaenge fuer LCD-Modul, Register, DAC
movwf TRISB ;
movlw b'11111000' ; 7..5: Tasten; 4,3: I2C; 2,1: PWM, 0: I/O
movwf TRISC ;
banksel PORTA ; Bank 0
; ADC konfigurieren
bsf STATUS,RP0 ; Bank 1
movlw b'01000100' ; Fosc/64 left just.
movwf ADCON1 ;
bcf STATUS,RP0 ; Bank 0
movlw b'10011000' ; Start mit Poti-Kanal
movwf ADCON0 ;
; Timer1 Prescaler konfig. & Preload
; gültig für f_OSZ = 4MHz (HFINTOSC-default prescaler 2:1)
movlw b'00000000' ;
movwf T1CON ;
movlw T1PREH ; preload = 2^16 - d'3000' für 1000,0 Hz @ 12MHz /4, 1:1
movwf TMR1H ; d.h. 3000x 0,333µs bis zum Overflow
movlw T1PREL ;
movwf TMR1L ;
; Interrupts enablen, Timer in Gang setzen
bsf INTCON,PEIE ; Gruppe der Peripherals
bsf INTCON,GIE ; globales Enable
bsf STATUS,RP0 ; Bank 1
bsf PIE1,TMR1IE ; Timer 1: 1= IRQ enable
bcf STATUS,RP0 ; Bank 0
bsf T1CON,TMR1ON ; Timer 1: 1= starten
; I2C Bus Recovery, falls erforderlich
I2CCLR_A
btfss PORTC,3 ; SCL-Signal
goto I2CCLR ;
btfss PORTC,4 ; SDA-Signal
goto I2CCLR ;
goto I2CCLR_E ; keines von beiden ist low, Bus ist frei
I2CCLR
bsf STATUS,RP0 ; Bank 1
; bcf TRISC,3 ; SCL aktiv = low, fallende Taktflanke
movf TRISC,w
andlw b'11110111'
movwf TRISC
bcf STATUS,RP0 ; Bank 0
movlw d'5' ;
call P0_IDLE ; ... und warten
;
bsf STATUS,RP0 ; Bank 1
; bsf TRISC,3 ; SCL passiv = high, steigende Taktflanke
movf TRISC,w
iorlw b'00001000'
movwf TRISC
bcf STATUS,RP0 ; Bank 0
movlw d'5' ;
call P0_IDLE ; ... und warten
goto I2CCLR_A ; Bus frei? Testen!
I2CCLR_E
bsf buf_rc,3 ;
bsf buf_rc,4 ; eventuell loest dies hier das Nichtfunktionieren der I2C-Verbindung
movf buf_rc,w ;
movwf PORTC ;
; LCD-Modul initialisieren
pagesel LCD_INIT ;
call LCD_INIT ; Basisinitialisierung
; pagesel LCD_CGRAM ;
; call LCD_CGRAM ; laden der frei definierbaren Zeichen
pagesel MAIN ;
; I2C initialisieren
pagesel I2C_INIT100 ;
call I2C_INIT100 ; I2C mit 100kHz starten
pagesel MAIN ;
movlw d'5'
call P0_IDLE
;**********************************************************************
; Anfang der Hauptschleife
;**********************************************************************
SCHLEIFE
; incf loopcount,f
pagesel ACC_GETGXYZ
call ACC_GETGXYZ
pagesel SCHLEIFE
; Unterfunktion zum Test des g-Sensormoduls BMA020
; X-Komponente anzeigen
movlw 0x11 ; Cursor positionieren
movwf cur_zsp ;
pagesel LCD_SETCURSOR ;
call LCD_SETCURSOR ;
; gekürzt
; Y-Komponente anzeigen
movlw 0x21 ; Cursor positionieren
movwf cur_zsp ;
pagesel LCD_SETCURSOR ;
call LCD_SETCURSOR ;
; gekürzt
; Z-Komponente anzeigen
movlw 0x28 ; Cursor positionieren
movwf cur_zsp ;
pagesel LCD_SETCURSOR ;
call LCD_SETCURSOR ;
; gekürzt
; Kontrolle fuer zyklischen Schleifendurchlauf
movlw 0x18 ; Cursor positionieren
movwf cur_zsp ;
pagesel LCD_SETCURSOR ;
call LCD_SETCURSOR ;
; gekürzt
pagesel SCHLEIFE
goto SCHLEIFE
;**********************************************************************
; Ende der Hauptschleife
;**********************************************************************
P0_IDLE
; Prinzip: "Jeder Code Page ihre eigene Bummelfunktion"
; wartet stur, bis die ISR den Zaehler dlycnt bis Null heruntergezaehlt hat
; benutzt dabei den selben Zaehler wie LCD_IDLE
movwf dlycnt ; Delayzeit wird im W-Register geliefert
P0_IDLE_1
movf dlycnt,f ; zero flag generieren
btfss STATUS,Z ; bei Z=1 ausbrechen
goto P0_IDLE_1 ;
return ;
;**********************************************************************
;**********************************************************************
ORG 0x0800 ; Begin of 2k-Code Page #1 (2/4)
;**********************************************************************
;**********************************************************************
;;**********************************************************************
;; Initialisierung des I2C-Moduls
;I2C_INIT100
; movlw b'00001000' ; I2C Master Mode mit SSPADD
; movwf SSPCON ;
; bsf SSPCON,SSPEN ; und aktivieren
; ;
; bsf STATUS, RP0 ; Bank 1
; movlw 0x27 ; Achtung: Tabelle im Datenblatt des PIC16F87xA ist falsch; siehe MSSP-Errata
;; movlw 0xFF ; Test, minimale Frequenz
; movwf SSPADD ; Reload-Wert fuer Clock-Takt
; bcf STATUS, RP0 ; Bank 0
;
; banksel SSPSTAT
; bsf SSPSTAT,SMP ; =1: _disable_ slew rate control
; bcf SSPSTAT,CKE ; disable SMP-specific inputs
; banksel PORTA
; ;
; return ;
;**********************************************************************
; Initialisierung des I2C-Moduls
I2C_INIT100
bsf STATUS, RP0 ; Bank 1
movlw 0x27 ; etwa 100kHz bei 12MHz-Oszillator
movwf SSPADD ; Reload-Wert für Clock-Takt
bcf STATUS, RP0 ; Bank 0
;
movlw b'00001000' ; I2C Master Mode mit SSPADD
movwf SSPCON ;
bsf SSPCON,SSPEN ; und aktivieren
;
return ;
;**********************************************************************
; Beschleunigungsmesswerte aus dem BMA020 abholen: b.a.w. nur 3 MSBytes;
; Die hier implementierte I2C-Protokoll-Makrostruktur ist Chip-spezifisch.
ACC_GETGXYZ
; *********************** Ordnung und Ruhe am I2C-Bus ***************
; call I2C_SETTLE ; MSSP-Modul neu starten
; ******
; call I2C_W_STOP ; weitere Bus-Aktivitaeten unterbinden
; *************************************************************
; *** Protokollzyklus: Accelerometer auslesen ***
; *************************************************************
; *********************** Kommunikation starten ***************
call I2C_W_START ; (erstmalig) Start-Bedingung senden
; *********************** Adresspointer setzen ***************
movlw ADR_BMA020 ; Device schreibend (R/W = 0) adressieren
movwf SSPBUF ; ... und senden
call I2C_R_ACK ; /ACK vom Slave abwarten
; ******
movlw 0x02 ; Adresspointer
movwf SSPBUF ; ... senden
call I2C_R_ACK ; /ACK vom Slave abwarten
; *********************** Device auslesen ***************
call I2C_W_START ; (erneut) Start-Bedingung senden
; ******
movlw ADR_BMA020 ; Device lesend (R/W = 1) adressieren
iorlw 0x01 ; R/W = 1
movwf SSPBUF ; senden
call I2C_R_ACK ; /ACK vom Slave abwarten
; ******
call I2C_R_BYTE ; Byte anfordern (02h) und verwerfen
movf SSPBUF,w ; dummy read
call I2C_W_ACK ; /ACK senden
; ******
call I2C_R_BYTE ; Byte anfordern (03h)
movf SSPBUF,w ; Datum
movwf gxraw ; ... uebernehmen
call I2C_W_ACK ; /ACK senden
; ******
call I2C_R_BYTE ; Byte anfordern (04h) und verwerfen
movf SSPBUF,w ; dummy read
call I2C_W_ACK ; /ACK senden
; ******
call I2C_R_BYTE ; Byte anfordern (05h)
movf SSPBUF,w ; Datum
movwf gyraw ; ... uebernehmen
call I2C_W_ACK ; /ACK senden
; ******
call I2C_R_BYTE ; Byte anfordern (06h) und verwerfen
movf SSPBUF,w ; dummy read
call I2C_W_ACK ; /ACK senden
; ******
call I2C_R_BYTE ; LETZTES Byte (07h) anfordern
movf SSPBUF,w ; Datum
movwf gzraw ; ... uebernehmen
call I2C_W_NACK ; NACK senden
incf loopcount,f ; zu Testzwecken
; *********************** Kommunikation beenden ***************
call I2C_W_STOP ; Stop-Bedingung senden
; *************************************************************
; *** Ende Protokollzyklus ***
; *************************************************************
return ;
;**********************************************************************
; nachfolgend die granularen I2C-Protokollelemente
;**********************************************************************
;**********************************************************************
; universeller Pseudo-Befehl "I2C-Bus zur Ruhe bringen" (Master)
I2C_SETTLE
; bcf I2C_TO ; Stoermeldung optimistisch loeschen
bcf PIR1,SSPIF ; I2C-Int.Request
bcf SSPCON,SSPEN ; MSSP deaktivieren
nop ;
nop ;
nop ;
bsf SSPCON,SSPEN ; und neu starten
nop ;
nop ;
nop ;
return ;
;**********************************************************************
; universeller I2C-Befehl "Start senden" (Master)
; Blockierungspotential: Fehldiagnose "Bus-Kollision" durch EMI oder Kupferwurm
I2C_W_START
bcf PIR1,SSPIF ; I2C-Int.Request
bsf STATUS, RP0 ; Bank 1
bsf SSPCON2,SEN ; Start-Kondition einleiten
bcf STATUS, RP0 ; Bank 0
btfsc SSPCON,WCOL
goto I2C_W_START
I2CWSTART
; btfsc I2C_TO ; wenn I2C-Stoerung,
; return ; dann nicht warten !
btfss PIR1,SSPIF ; /ACK schon empfangen ?
goto I2CWSTART ;
bcf PIR1,SSPIF ; JA, fertig !
return ;
;**********************************************************************
; universeller I2C-Befehl "Repeated Start senden" (Master)
; Blockierungspotential: Fehldiagnose "Bus-Kollision" durch EMI oder Kupferwurm
I2C_W_RSTART
bcf PIR1,SSPIF ; I2C-Int.Request
bsf STATUS, RP0 ; Bank 1
bsf SSPCON2,RSEN ; Repeated-Start-Kondition einleiten
bcf STATUS, RP0 ; Bank 0
; btfsc SSPCON,WCOL
; goto I2C_W_RSTART
I2CWRSTART
; btfsc I2C_TO ; wenn I2C-Stoerung,
; return ; dann nicht warten !
btfss PIR1,SSPIF ; /ACK schon empfangen ?
goto I2CWRSTART ;
bcf PIR1,SSPIF ; JA, fertig !
return ;
;**********************************************************************
; universeller I2C-Befehl "Acknowledge /ACK vom Slave abwarten" (Master)
; Blockierungspotential: /ACK nicht detektiert
I2C_R_ACK
I2CRACK
; btfsc I2C_TO ; wenn I2C-Stoerung,
; return ; dann nicht warten !
btfss PIR1,SSPIF ; /ACK schon empfangen ?
goto I2CRACK ;
bcf PIR1,SSPIF ; JA, fertig !
return ;
;**********************************************************************
; universeller I2C-Befehl "Byte vom Slave holen" (Master)
; Blockierungspotential:
I2C_R_BYTE
bcf PIR1,SSPIF ; I2C-Int.Request
bsf STATUS, RP0 ; Bank 1
bsf SSPCON2,RCEN ; Empfangsbereitschaft herstellen
bcf STATUS, RP0 ; Bank 0
I2CRBYTE
; btfsc I2C_TO ; wenn I2C-Stoerung,
; return ; dann nicht warten !
; Dateneingang abwarten
btfss PIR1,SSPIF ; Empfangsdaten im Buffer ?
goto I2CRBYTE ;
bcf PIR1,SSPIF ; JA, fertig !
return ;
;**********************************************************************
; universeller I2C-Befehl "Acknowledge /ACK senden" (Master)
; (das ist ein Acknowledge mit aufforderndem Beigeschmack)
I2C_W_ACK
bcf PIR1,SSPIF ; I2C-Int.Request
bsf STATUS, RP0 ; Bank 1
bcf SSPCON2,ACKDT ; Ackn.-Pegel =0 setzen: --> /ACK (=0)
bsf SSPCON2,ACKEN ; /ACK-Sequenz starten
bcf STATUS, RP0 ; Bank 0
I2CWACK
; btfsc I2C_TO ; wenn I2C-Stoerung,
; return ; dann nicht warten !
; warten auf Ende der Acknowledge-Sequenz
btfss PIR1,SSPIF ; Sequenz schon beendet ?
goto I2CWACK ;
bcf PIR1,SSPIF ; JA, fertig !
return ;
;**********************************************************************
; universeller I2C-Befehl "Not-Acknowledge NACK senden" (Master)
; (das ist ein Acknowledge mit abweisendem Beigeschmack)
I2C_W_NACK
bcf PIR1,SSPIF ; I2C-Int.Request
bsf STATUS, RP0 ; Bank 1
bsf SSPCON2,ACKDT ; Ackn.-Pegel =1 setzen --> NACK : "OK, aber keine weiteren Daten erwuenscht"
bsf SSPCON2,ACKEN ; NACK-Sequenz starten
bcf STATUS, RP0 ; Bank 0
I2CWNACK
; btfsc I2C_TO ; wenn I2C-Stoerung,
; return ; dann nicht warten !
btfss PIR1,SSPIF ; Sequenz schon beendet ?
goto I2CWNACK ;
bcf PIR1,SSPIF ; JA, fertig !
return ;
;**********************************************************************
; universeller I2C-Befehl "Stop senden" (Master)
I2C_W_STOP
bcf PIR1,SSPIF ; I2C-Int.Request
bsf STATUS, RP0 ; Bank 1
bsf SSPCON2,PEN ; Stop-Sequenz starten
bcf STATUS, RP0 ; Bank 0
I2CWSTOP
; btfsc I2C_TO ; wenn I2C-Stoerung,
; return ; dann nicht warten !
btfss PIR1,SSPIF ; Sequenz schon beendet ?
goto I2CWSTOP ;
bcf PIR1,SSPIF ; JA, fertig !
return ;
;**********************************************************************
;**********************************************************************
ORG 0x1000 ; Begin of 2k-Code Page #2 (3/4)
;**********************************************************************
;**********************************************************************
;**********************************************************************
;**********************************************************************
ORG 0x1800 ; Begin of 2k-Code Page #3 (4/4)
;**********************************************************************
;**********************************************************************
;**********************************************************************
LCD_IDLE
; wartet stur, bis die ISR den Zaehler dlycnt bis Null heruntergezaehlt hat
movwf dlycnt ; Delayzeit wird im W-Register geliefert
LCD_IDLE_1
movf dlycnt,f ; zero flag generieren
btfss STATUS,Z ; bei Z=1 ausbrechen
goto LCD_IDLE_1 ;
return ;
;**********************************************************************
LCD_PUSH ; nur jeweils EIN 4-bit-Uebertragungsvorgang, weil in der fruehen Initialisierungsphase
; variable Wartezeiten, daher kein delay eingebaut
movf dat_lcd,w ; Nettodaten holen
andlw 0xF0 ; D7..D4 isolieren; RS (D/I) und RW sind damit passend "L" eingestellt
movwf cio_lcd ; Uebergabewert speichern
bsf LCD_TXF ; Uebergabe-Flag fuer ISR setzen
LCD_PUSH_1
btfsc LCD_TXF ; Flag=0 --> ISR hat uebernommen! ?
goto LCD_PUSH_1 ;
return ;
;**********************************************************************
LCD_INIT
pagesel LCD_IDLE
movlw d'30' ;
call LCD_IDLE ; >= 15ms nach PowerOn warten
movlw 0x30 ; 0x30: Reset
movwf dat_lcd ;
call LCD_PUSH ;
movlw d'10' ;
call LCD_IDLE ; >= 4.1ms warten
movlw 0x30 ; 0x30: Reset
movwf dat_lcd ;
call LCD_PUSH ;
movlw d'3' ;
call LCD_IDLE ; >= 100us warten; 1ms kann auch 0us sein!
movlw 0x30 ; 0x30: Reset
movwf dat_lcd ;
call LCD_PUSH ;
movlw d'3' ;
call LCD_IDLE ; Verarbeitungszeit weiterhin jeweils 1ms + X ?????
movlw 0x20 ; 0x20: 4-bit-Datenbus
movwf dat_lcd ;
call LCD_PUSH ;
movlw d'3' ;
call LCD_IDLE ; >= 1ms interne Verarbeitungszeit ?????
; ab hier wird explizit 4-bit-weise auf D[7:4] kommuniziert,
; zuerst oberes Nibble, dann unteres Nibble
movlw 0x28 ; 0x28: System Set: 4-Bit / 2-zeilig
movwf dat_lcd ;
call LCD_CMD ;
movlw d'3' ;
call LCD_IDLE ;
movlw 0x06 ; 0x06: Entry Mode: v.l.n.r. ohne shift
movwf dat_lcd ;
call LCD_CMD ;
movlw d'3' ;
call LCD_IDLE ;
movlw 0x01 ; 0x01: Clear Display
movwf dat_lcd ;
call LCD_CMD ;
movlw d'10' ;
call LCD_IDLE ;
movlw 0x0C ; 0x0C: Display On, kein Cursor
movwf dat_lcd ;
call LCD_CMD ;
movlw d'10' ;
call LCD_IDLE ;
return ;
END ; directive 'end of program'
Lesezeichen