; Keyboard and DOGM display driver By EBE 26.02.2007 ; Version 1.0 ; Keyboard and LCD(s) are used on the same Port to save pins. ; PCB-ID: PIC_motherboard_LCD_V1.1 by EBe ; PIC-Pinout ; PORTA: All Outputs, for testing ; PORTB: 0 LCD Display E ChipSelect ; 1 Keyboard 1 4 7 * ; 2 LCD Display RS Keyboard 2 5 8 0 ; 3 Keyboard 3 6 9 # ; 4 ---------I I I I ; 5 -----------+ I I ; 6 LCD SPI clock -------------+ I ; 7 LCD SPI Data ---------------+ LIST P=16F628 ;tell assembler what chip we are using include "P16F628.inc" ;include the defaults for the chip __config 0x3F22 ;sets the configuration settings (osc=HS; WDT=OFF; PWRUPT=ON; BROWN=DIS.; MCLR=ENABLED; LVP=DIS; EEprotect=DIS, CodeP=OFF) ; Oscillator = 8MHz ERRORLEVEL -302 ;SUPPRESS BANK SELECTION MESSAGES ; Definitions ; Variable declaration CBLOCK 0x20 ; start of ram in 16F628 ;add variables w_temp ; Stores W-register during Interrupt status_temp ; Stores Status-register during Interrupt loops ; WAIT-Delay in ms loops2 ; internally used in WAIT-loop Initflags ; Holds Flags for several initalisation routines TXSPI ; Holds Byte to be transmitted via SPI Bit_counter ; Counts bits of serial-communication BYTE Baud_counter ; Create correct delay for sending/receiving serial data ENDC ;Add Constants/Equates here ;Example LCDPORT Equ PORTB ;set constant LCDPORT = 'PORTB' Ini_opt Equ B'00001000' ; pull-up resistors #define LcdE PORTB,0 ; enable Lcd (ChipSelect) #define LcdRs PORTB,2 ; Daten Lcd (nicht control) #define LcdSI PORTB,7 ; SPI Data #define LcdSCL PORTB,6 ; SPI clock signal #define LcdPort PORTB ; Datenbus des LCD ; Define Bits of "initflags" #define LcdInitFlag Initflags,0 ; used in OutLcdControl SUB ; LCD control commands. SPI-interface CONSTANT FSSPI1 = B'00111000' ; 0x38, Function Set: 8-bit, Double Line, no Double Height, Instr.Set= 00 CONSTANT FSSPI2 = B'00111001' ; 0x39, Function Set: 8-bit, Double Line, no Double Height, Instr.Set= 01 CONSTANT BIASSPI = B'00010100' ; 0x14, BIAS: 1/5, FX=0 CONSTANT CONTRASTSPI = B'01111000' ; 0x78, Contrast: C3=1, C2=0,C1=0, C0=0 CONSTANT POWERSPI = B'01010101' ; 0x55, POWER/ICON/Contrast: ICON=Off, Booster=On, C5=0, C4=1 CONSTANT FOLLOWERSPI = B'01101101' ; 0x6D, Follower: Fon=On, Rab2=1, Rab1=0, Rab0=1 ;LCD Commands controlling Cursor, etc CONSTANT LCDCLR = B'00000001' ;Clear Display and Cursor -> Home (OK) CONSTANT LCDCH = B'00000010' ;Cursor ->Home (OK) CONSTANT LCDCL = B'00000100' ;Entry Mode Set: Cursor -> to right, Display shift: OFF (OK) CONSTANT LCDCR = B'00000110' ;Entry Mode Set: Cursor -> to left, Display shift: OFF (OK) CONSTANT LCDSL = B'00011000' ;Display Content move -> to left (OK) CONSTANT LCDSR = B'00011100' ;Display Content move -> to right (OK) CONSTANT LCDL1 = B'10000000' ;Display: select Line1; Set DDRAM Address to 00F = line1,character1 CONSTANT LCDL2 = B'11000000' ;Display: select Line2; Set DDRAM Address to 40F = line2,character1 CONSTANT LCDOFF = B'00001000' ;Display: OFF CONSTANT LCDON1 = B'00001111' ;Diplay: ON, Cursor ON, Blinking ON CONSTANT LCDON2 = B'00001100' ;Diplay: ON, Cursor OFF, Blinking OFF ;end of defines org 0x0000 ;org sets the origin, 0x0000 for the 16F62x, goto start ;********************************************************************************************************** ;--- Interrupt service routine starts here ;********************************************************************************************************** org 0x004 ; Interrupt vector, int handler code comes next. ;---Mandatory start of Interrupt service routine, do NOT change unless necessary!!!------------------- int_handler bcf INTCON, GIE ; disable Interrupt movwf w_temp swapf STATUS,w bcf STATUS,RP0 ; status_temp in Bank 0 movwf status_temp ;---------------------------------------------------------------------------------- ;Interupt Service Routine ; Add your own code ;---Mandatory end of Interrupt service routine, do NOT change!!!------------------- int_exit swapf status_temp,w movwf STATUS swapf w_temp,f swapf w_temp,w bcf INTCON, T0IF ; reset the tmr0 interrupt flag bsf INTCON, GIE ; enable General Interrupt retfie ;--- Interrupt service routine stops here ------------------- ;********************************************************************************************************** ;***Initialization of important PIC- and external hardware ;********************************************************************************************************** start movlw 0x07 movwf CMCON ;turn PORTA comparators off (make it almost! like a 16F84) ;--- Set up OPTION register movlw b'00001000' ; ; x------- ; 7, 0=enable, 1=disable, portb pullups ; -x------ ; 6, 1=/, int edge select bit ; --x----- ; 5, timer0 source, 0=internal clock, 1=ext pin. ; ---x---- ; 4, timer0 ext edge, 1=\ ; ----x--- ; 3, prescaler assign, 1=wdt, 0=timer0 ; -----x-- ; 2,1,0, timer0 prescaler rate select ; ------x- ; 000=2, 001=4, 010=8, 011=16, etc. ; -------x ; bsf STATUS,RP0 ; select Bank1 bcf STATUS,RP1 movwf OPTION_REG ; load data into OPTION_REG ;--- TRISA/PORTA initialization banksel TRISA movlw B'00000000' ; PortB all Outputs movwf TRISA bcf STATUS, RP0 ; select Bank 0 clrf PORTA ; Reset PORTA outputs to ZERO ;--- TRISB/PORTB initialization banksel TRISB movlw B'00000000' ; PortB all Outputs movwf TRISB bcf STATUS, RP0 ; select Bank 0 clrf PORTB ; Reset PORTB outputs to ZERO ;---Enable/Disable Interrupts bsf STATUS,RP0 bsf INTCON, T0IE ; Timer0 interrupt enabled bsf INTCON, GIE ; General Interrupt enabled bcf STATUS,RP0 ; select bank0 ;---Display initialization bsf LcdSCL ; Set clockline HIGH call InitLcd ;********************************************************************************************************** ;---Main program starts here, keep it as short as possible and use subroutines,macros, etc ;********************************************************************************************************** main movlw LCDCLR ; Clear LCD call OutLcdControl ; Write command to LCD movlw LCDL1 ; Select LCD-Line1 call OutLcdControl ; Write command to LCD movlw 'A' ; ASCII letter "A" call OutLcdDaten ; Write letter to LCD goto main ;********************************************************************************************************** ;*** Add Subroutines below here to keep the main programm flow clear ;********************************************************************************************************** ;***************************************************** ;+++LCD-Routinen - LCD-Routines - LCD-Routiinit ****** ;***************************************************** ;Electronic Assembly DOG-M xxx LCD's ;LCD initialisieren in 9 Schritten ;LCD initialization takes 9 steps ; Pausen sind auskommentiert, da die OutLcdControl -Routine eine generelle 2ms Pause nach jedem Byte einhält. ; Daher braucht man die im Datenblatt angegebenen minimalen Pausen nicht verwenden. InitLcd movlw D'200' ; 200 ms Pause movwf loops call WAIT ; bsf LcdInitFlag ; Do not use 2ms delay in OutLcdControl movlw FSSPI1 ; 1.) Function set: 0011 1000 call OutLcdControl ; movlw D'50' ; 30us Pause ; movwf loops ; call WAITus movlw FSSPI2 ; 2.) Function set: 0011 1001 call OutLcdControl ; movlw D'50' ; 30us Pause ; movwf loops ; call WAITus movlw BIASSPI ; 3.) BIAS SPI call OutLcdControl ; movlw D'50' ; 30us Pause ; movwf loops ; call WAITus movlw POWERSPI ; 5.) POWER SPI call OutLcdControl ; movlw D'50' ; 30us Pause ; movwf loops ; call WAITus movlw FOLLOWERSPI ; 6.) FOLLOWER SPI call OutLcdControl movlw D'200' ; 200 ms Pause movwf loops call WAIT movlw CONTRASTSPI ; 4.) CONTRAST SPI call OutLcdControl ; movlw D'50' ; 30us Pause ; movwf loops ; call WAITus movlw LCDON2 ; 7.) LCD ON, no cursor, no blink call OutLcdControl ; movlw D'50' ; 30 us Pause ; movwf loops ; call WAITus movlw LCDCLR ; 8.) Clear Display call OutLcdControl movlw D'2' ; 2 ms Pause movwf loops call WAIT movlw LCDCR ; 9.) Entry mode Set, Cursor Auto Increment call OutLcdControl ; movlw D'50' ; 30 us Pause ; movwf loops ; call WAITus bcf LcdInitFlag ; Use 2ms regular delay in OutLcdControl return ;***************************************************** ; Transfer a Byte from W to the LCD containing control data ; SPI-MODE ;***************************************************** OutLcdControl movwf TXSPI movlw 8 ; load Bit counter to send 8 Bits movwf Bit_counter bcf LcdE ; Enable Chip Select bcf LcdRs ; Write Instruction (ensure its really "0") call Wait_s Send_1 rlf TXSPI, f ; move current Bit to Carry Flag, MSB first, rotate left btfsc STATUS, C bsf LcdSI ; High if Bit = 1 btfss STATUS, C bcf LcdSI ; Low if Bit = 0 bcf LcdSCL ; Set clockline LOW = 0 call Wait_s bsf LcdSCL ; Set clockline to HIGH = 1 and write Bit (rising edge) call Wait_s decfsz Bit_counter, f ; all 8 Bits sent? goto Send_1 ; No, continue call Wait_s bsf LcdE ; deactivate LCD's chipselect bsf LcdRs ; set LCD's RS line HIGH btfsc LcdInitFlag ; Do not use 2ms delay in OutLcdControl if Flag = 1 return movlw d'2' ; Wait 2ms, so that longest command is executed. According to datasheet max 1.5ms. movwf loops call WAIT ; wait return ;***************************************************** ; Transfer a Byte from W to the LCD containing "ASCII" data ; SPI-MODE ;***************************************************** OutLcdDaten movwf TXSPI movlw 8 ; load Bit counter to send 8 Bits movwf Bit_counter bcf LcdE ; LCD3 Chip Select bsf LcdRs ; Write Data (ensure its really "1") call Wait_s Send_2 rlf TXSPI, f ; move current Bit to Carry Flag, MSB first, rotate left btfsc STATUS, C bsf LcdSI ; High if Bit = 1 btfss STATUS, C bcf LcdSI ; Low if Bit = 0 bcf LcdSCL ; Set clockline LOW = 0 call Wait_s bsf LcdSCL ; Set clockline to HIGH = 1 and write Bit call Wait_s decfsz Bit_counter, f ; all 8 Bits sent? ; goto Send_2 ; No, continue call Wait_s bsf LcdE ; deactivate LCD3's hipselect bsf LcdRs ; set clockline HIGH btfsc LcdInitFlag ; Do not use 2ms delay in OutLcdControl if Flag = 1 return movlw d'2' ; Wait 2ms, so that longest command is executed. movwf loops call WAIT ; wait return ;********************************************************** ; SPI Clock Delay for LOW/HIGH state ; SPI Clock Pause fuer LOW/HIGH Zustand ; Delay at 8MHz = 32us ; Pause bei 8Mhz ca. 32us Wait_s movlw D'8' ; movwf Baud_counter Wait_1 ; 6 cycles/Zyklen nop nop nop nop decfsz Baud_counter, 1 goto Wait_1 return ;***************************************************************** ;***********Delay "loops" * 1 ms ********************************* ;***************************************************************** ; Universal 1ms Delay loop, used for LCD initialization, button debounce, etc. ; Parameter: loops - variable delay from 1-255ms ; ; 8 MHz external clockspeed equals 2 MHz internal speed ; 1ms requires 2000 commands ; 200 loops á 10 commands equal 2000 = 1ms (1.03ms measured) ; Adjust this delay-loop if you use different clock-speeds WAIT top movlw .200 ; timing adjustment variable (1ms) movwf loops2 top2 nop ; do nothing... nop nop nop nop nop ; nop decfsz loops2, F ; is inner loop ready? goto top2 ; No, repeat. ; decfsz loops, F ; is outer loop ready? goto top ; No, repeat. retlw 0 ; Ready, return with parameter "0" ;***************************************************************** ;***********Delay "loops" * 2 us ********************************* ;***************************************************************** ; Universal 2us Delay loop, used for LCD initialization, button debounce, etc. ; Parameter: loops - variable delay from 2us-560us ; ; 8 MHz external clockspeed equals 2 MHz internal speed ; 10us requires 20commands ; Adjust this delay-loop if you use different clock-speeds WAITus top3 nop decfsz loops, F ; is outer loop ready? goto top3 ; No, repeat. retlw 0 ; Ready, return with parameter "0" ;--- End of Program end