; ;************************************************************************ ; 1227747 ECU 160 Baud ALDL display / Juha Niinikoski ; Test code put together 11.9.2000 ; First working code 12.9.2000 v0.01 ; BLM Cell resolver & temperature conversion 13.9.2000 v0.02 ; O2 mV, MAP Kpa & TPs % conversion added 14.9.2000 ; PA3 display, knock warning & some bit indicators added 15.9.2000 ; VFD / LCD routine clean up & display format 26.9.2000 v1.00 ; Page & normal/diag switches. Diag display. 27.9.2000 v1.01 ; Display shows Wait until ALDL data is present. 29.3.2001 v1.02 ; Tested with 808 ECU. 808 needs more delay after clear screen. Additional ; delay makes display flicker. New display consept without clear ; screen commands. Assembly switch for knock warning 1.4.2001 v 1.10 ; Conversion for 1227165 ECM started 12.05.2002 ; Initial try. BPW not implemented yet. 16.05,2002 ; Temperature display corrections & Prom ID 17.05.2002 ; Sync bug found & corrected 20.05.2002 ; tuukka equ 1 ; Tuukka special ; ;************************************************************************ ; LIST P = 16F84, R = HEX ; INCLUDE "p16f84.inc" ; org 0x2007 ; set configuration bits dw _xt_osc & _wdt_off & _cp_off & _pwrte_on ; ;************************************************************************ ; LCD I/O parameters ; lcddata equ porta ; Port A0:3 = LCD data lcdctr equ portb ; Port B6:7 = LCD control ; LCDRS EQU 6 ; Lcd register select output LCDEN EQU 7 ; Lcd enable output ; LCD commands LCDCLER EQU b'00000001' ; Clears display, resets curcor LCDCM EQU b'10000000' ; Sets cursor using bits 0 - 6 line1 equ .0 ; Line 1 range - 0 to 0x13 line2 equ 0x40 ; Line 2 range - 0x40 to 0x53 line3 equ 0x14 ; Line 3 range - 0x14 to 0x27 line4 equ 0x54 ; line 4 range - 0x54 to 0x67 ; diag equ 1 ; diagnostic I/O 1 = on, 0 = off #define diag_io portb, 3 ; diagnostic I/O for RX timing check ; kw_on equ 1 ; knock warning detection 1 = on, 0 = off ; ;************************ Data RAM Assignments ********************** ; ORG 0CH ; Dummy Origin for RAM ; ; LCD I/O variables GP1 res 1 ; General purpose register chcnt ; map variables to save memory STRNUM res 1 CHPT res 1 ; Character string pointer in string. LCDCH res 1 ; Saves byte to be sent to lcd while ; it is processed DLYCNT res 1 COUNT res 1 TEMP res 1 TABOFF res 1 ; Table ofset pointer in lcd string lookup apu res 1 ; anotger gp register ; biglcd equ 0 ; size of lcd panel zsup equ 1 ; leading zero supress in 4 digit displays disp5d equ 0 ; # of digits displayed ; ;mulcnd res 1 ; 8 bit multiplicand ;mulplr res 1 ; 8 bit multiplier H_byte res 1 ; 16-bit register L_byte res 1 ; ; ; B2_BCD Bin to BCD conversion variables ; count res 1 ; ! already defined nflag res 1 ; negative number flag ; mulcnd ; map variables to save memory R0 res 1 ; hi order mulplr R1 res 1 ; 5 digit BCD output R2 res 1 ; A4 res 1 ; hi orde value A3 res 1 ; 5 byte ASCII output A2 res 1 A1 res 1 A0 res 1 ; lo order value ; ; Interrupt routine variables ; w_temp res 1 ; W save during interrupt status_temp res 1 ; status save during interrupt fsr_temp res 1 ; FSR save during interrupt ; ; ALDL variables ; koldpa3 res 1 ; incremental knock counter ; ; 160 Baud receiver variables ; filter equ 1 ; switch for input filtering 1 = on fcount equ .3 ; filter delay ; rx_buff res 1 ; ALDL input shift register bit_count res 1 ; ALDL input bit counter rx_byte res 1 ; received ALDL data byte int_temp res 1 ; temp storage for int routines ; sync equ 7 ; sync pattern received byte_rdy equ 6 ; byte ready in rx_byte flags res 1 ; ALDL receiver state flags ; rx_count res 1 ; characters received after last sync msg_num res 1 ; modulo 256 counter for aldl messages buff_ptr res 1 ; aldl buffer write pointer ; ; 1227165 ALDL data steream ; WORD BIT DESCRIPTION ; ---- --- --------------- aldl_buff ; define input buffer structure MW2 res 1 ; 1 MODE WORD 2 ; 0 OVERDRIVE ON ; 1 MALF 14 OR 15 THIS STARTUP ; 2 REFERENCE PULSE OCCURRED ; 3 DIAGNOSTIC SWITCH IN FACTORY TEST POSITION (3.9K) ; 4 DIAGNOSTIC SWITCH IN DIAGNOSTIC POSITION (0 OHMS) ; 5 DIAGNOSTIC SWITCH IN ALDL POSITION (10k) ; 6 HIGH BATTERY VOLTAGE ; 7 SHIFT LIGHT ; PROMIDH res 1 ; 2 PROMID (MSB) PROMIDL res 1 ; 3 PROMID (LSB) PROMID = (MSB)*256 + (LSB) IAC res 1 ; 4 IAC PRESENT POSITION N = COUNTS CTEMP res 1 ; 5 COOLANT TEMPERATURE SEE TABLE 1 VSPEED res 1 ; 6 VEHICLE SPEED MPH = N EGR res 1 ; 7 EGR DUTY CYCLE RPM res 1 ; 8 ENGINE RPM RPM = N * 25 TPS res 1 ; 9 THROTTLE POSITION SENSOR VOLTS = N * .0196 INT res 1 ; 10 CLOSED LOOP INTEGRATOR NONE O2 res 1 ; 11 OXYGEN SENSOR MILLIVOLTS = N * 4.34 ; MALFFLG1 res 1 ; 12 MALFFLG1 ; 0 MALF CODE 23 MAT LOW ; 1 MALF CODE 22 THROTTLE POSITION SENSOR LOW ; 2 MALF CODE 21 THROTTLE POSITION SENSOR HIGH ; 3 MALF CODE 16 NOT USED ; 4 MALF CODE 15 COOLANT SENSOR LOW ; 5 MALF CODE 14 COOLANT SENSOR HIGH ; 6 MALF CODE 13 OXYGEN SENSOR ; 7 MALF CODE 12 NO REFERENCE PULSES ; MALFFLG2 res 1 ; 13 MALFFLG2 ; 0 MALF CODE 35 NOT USED ; 1 MALF CODE 34 MAF LOW ; 2 MALF CODE 33 MAF HIGH ; 3 MALF CODE 32 EXHAUST GAS RECIRCULATION FAILURE ; 4 MALF CODE 31 NOT USED ; 5 MALF CODE 26 NOT USED ; 6 MALF CODE 25 MAT HIGH ; 7 MALF CODE 24 VSS ; MALFFLG3 res 1 ; 14 MALFFLG3 ; 0 MALF CODE 51 PROM ERROR ; 1 MALF CODE 46 NOT USED ; 2 MALF CODE 45 VATS FAILED ; 3 MALF CODE 44 OXYGEN SENSOR RICH ; 4 MALF CODE 41 OXYGEN SENSOR LEAN ; 5 MALF CODE 42 ESC FAILURE ; 6 MALF CODE 41 CYLINDER SELECT ERROR ; 7 MALF CODE 36 BURNOFF DIAGNOSTICS ; MALFFLG4 res 1 ; 15 MALFFLG4 ; 0 MALF CODE 51 CAL PACK MISSING ; 1 MALF CODE 52 OVER VOLTAGE ; 2 MALF CODE 53 FUEL PUMP VOLTAGE ; 3 MALF CODE 54 ADU ERROR ; 4 MALF CODE 56 NOT USED ; 5 MALF CODE 61 NOT USED ; 6 MALF CODE 62 NOT USED ; 7 MALF CODE 63 NOT USED ; ; MWAF1 res 1 ; 16 MWAF1 ; 0 NOT USED ; 1 BLM ENABLE FLAG ; 2 NOT USED ; 3 NOT USED ; 4 VSS FAILURE ; 5 EECC SLOW O2 RICH/LEAN FLAG ; 6 RICH FLAG ; 7 CLOSED LOOP FLAG ; MAT res 1 ; 17 MANIFOLD TEMPERATURE MCUIO res 1 ; 18 MCUIO ; 0 PARK NEUTRAL ; 1 NO HIGH GEAR ; 2 OVERDRIVE REQUEST ; 3 NOT USED ; 4 EGR DIAG SWITCH CLOSED ; 5 TCC LOCKED ; 6 FAN REQUEST ; 7 NO AC REQUEST ; OLDPA3 res 1 ; 19 OLDPA3 N = COUNTS BLM res 1 ; 20 BASE PULSE COURSE CORRECTION(BLM) O2CNT res 1 ; 21 O2 CROSS COUNTS N = COUNTS MAFH res 1 ; 22 MAFL res 1 ; 23 BPWH res 1 ; 24 BPWL res 1 ; 25 ; aldl_buffe res 1 aldl equ aldl_buff - 1 ; for data stream offsets (starts from 1, buffer from 0) ; ;*********************************************************************** ; ORG 0 ; Restart vector goto main0 ; ORG 4 ; INT vector goto irqserv ; serve interrupts ;*********************************************************************** ; Out 2 hex caharacters from W ; This routine must stay in page 0 ! ; out2hexs movwf temp movlw ' ' call putlcd goto o2h1 ; ; Out 2 hex withou space out2hex movwf temp ; o2h1 swapf temp, w andlw 0x0f call hextable nop call putlcd ; movf temp, w andlw 0x0f call hextable nop call putlcd ; return ; HexTable clrf pclath ; ! this routine must reside in page 0 addwf pcl retlw '0' ;0 retlw '1' ;1 retlw '2' ;2 retlw '3' ;3 retlw '4' ;4 retlw '5' ;5 retlw '6' ;6 retlw '7' ;7 retlw '8' ;8 retlw '9' ;9 retlw 'A' ;A retlw 'B' ;b retlw 'C' ;C retlw 'D' ;D retlw 'E' ;E retlw 'F' ;F ; ;*********************************************************************** ; main0 ;*********************************************************************** ; 16F84 cpu RAM cleaning ; zeroes ram 0x0c - 0x4f (0x7f) ; movlw 0x0c ; start of 16F84 ram movwf fsr ramc1 clrf indf ; clear indirect location incf fsr, f ; next location btfss fsr, 7 ; cleans up to 0x7f goto ramc1 ; ;*********************************************************************** ; Set up lcd port & IRQ system. ; ; Outputs ; RA0 - 3 lcd data ; RB6 lcd register select ; RA7 lcd enable clrf lcddata clrf lcdctr bsf status, rp0 ; select bank 1 movlw b'11110000' ; Set port A data directions, A0:3=outputs movwf trisa movlw b'00110111' ; Set port B data directions movwf trisb ; RB0 = int input bcf status, rp0 ; select bank 0 ; call initlcd ; init LCD routines ; bsf status, rp0 ; select bank 1 bcf option_reg, intedg ; RB0 interrupt with falling edge bcf option_reg, not_rbpu ; B-port pull ups on bcf option_reg, t0cs ; Internal clock for TMR0 bcf option_reg, psa ; Enable prescaler bcf option_reg, ps2 bcf option_reg, ps0 bsf option_reg, ps1 ; prescaler = 8 bcf status, rp0 ; back to bank 0 ; ; ;********************************************************************** ; ; Display banner messages ; movlw line2 call lcdcur ; Position text on line 2 movlw .1 ; Hello message call string movlw line3 call lcdcur ; Position text on line 3 movlw .2 ; Version message call string ; movlw .30 ; wait about 3s call wait100 ; movlw line4 call lcdcur ; line 4 movlw .19 ; Wait message call string ; ;************************************************************** ; ; Init ALDL application variables ; ; clrf rx_buff ; clrf bit_count ; clrf rx_byte ; clrf flags ; movlw aldl_buff ; init aldl buffer pointer movwf buff_ptr ; ; Enable interrupts = Let's go ; bsf intcon, gie ; enable interrupts bsf intcon, inte ; enable RB0 ALDL input interrupts ; wfs btfss flags, sync goto wfs ; wait for first sync ; ;************************************************************** ; ; Main loop is executed every time when sync pattern have occured at aldl bus. ; RB1 selects displayed page. Open = 1 = page 0 ; RB2 selects normal/diag mode. Open = 1 = normal ; main1 btfss flags, sync goto main1 ; wait for sync bcf flags, sync incf msg_num, f ; increment message counter ;__________________________ btfss portb, 2 ; normal / diag display select goto disp_diag ;__________________________ disp_normal btfss portb, 1 ; select display page goto disp_page2 ;__________________________ disp_page1 movlw line1 call lcdcur ; line 1 ; call disp_rpm call disp_space call disp_iac call disp_space call disp_d call disp_space ; if kw_on call knock ; this overrides line 1 if knock endif ;__________________________ movlw line2 call lcdcur ; line 2 ; call disp_tps call disp_space call disp_o2 call disp_space call disp_r call disp_space ;__________________________ movlw line3 call lcdcur ; line 3 ; call disp_maf call disp_space call disp_int call disp_space call disp_c call disp_space ;__________________________ movlw line4 call lcdcur ; line 4 ; call disp_bpw call disp_space call disp_blm call disp_space call disp_l call disp_space ; goto main1 ; ;______________________________________________ ; ; second display page ; ; disp_page2 ; movlw line1 call lcdcur ; line 1 ; call disp_mat call disp_space call disp_tmp movlw .3 call disp_wspaces ;__________________________ movlw line2 call lcdcur ; line 2 ; call disp_spd call disp_space call disp_pa3 movlw .3 call disp_wspaces ;__________________________ movlw line3 call lcdcur ; line 3 ; call disp_occ call disp_space call disp_o2 movlw .3 call disp_wspaces ;__________________________ movlw line4 call lcdcur ; line 4 ; call disp_msg_num call disp_space call disp_rx_count movlw .3 call disp_wspaces ; goto main1 ; ;______________________________________________ ; ; diagnostics display = show raw aldl data ; page switch selects dec or hex display. RB1=open=1=hex display ; disp_diag btfss portb, 1 ; select display page goto disp_diag2 ; movlw aldl_buff ; set buffer pointer movwf chpt ; movlw line1 call lcdcur ; line 1 call disp_line movlw .1 ; fill rest of the line with spaces call disp_wspaces ; if hex display selected movlw line2 call lcdcur ; line 2 call disp_line movlw .1 call disp_wspaces movlw line3 call lcdcur ; line 3 call disp_line movlw .1 call disp_wspaces movlw line4 call lcdcur ; line 4 call disp_line movlw .1 call disp_wspaces goto main1 ; disp_line movlw .6 ; For 165 we need 25 bytes. movwf chcnt ; World is not perfect 6*4 = 24 ; disp_line1 movf chpt, w incf chpt, f ; uppdate character pointer movwf fsr ; set indirect pointer movf indf, w ; get data ; call out2hex ; display in hex format call disp_space decfsz chcnt, f goto disp_line1 ; continue this line return ; ;______________________________________________ ; ; second diag page ; disp_diag2 ; call lcdclr ; clear display movf BPWL, w ; lasta character from rx buffer call out2hex ; now world is perfect ; movlw line3 call lcdcur ; line 3 movlw 'I' ; skow Prom ID call putlcd movlw 'D' call putlcd movlw ' ' call putlcd movf PROMIDH, w call out2hex movf PROMIDL, w call out2hex goto main1 ; ;*************************************************************** ; ALDL parameter display routines ; Independent routines for each displayed paremeter ; disp_iac ; unit = count, range 0 - 255 movlw .3 ; display IAC call string movf IAC, w ; get IAC count goto disp_end ; ; ; do coarse ad value to temperature conversion ; tst10 macro ad1 movlw ad1 subwf temp, w ; test if equal or less skpc call add10 ; 10 degrees increment endm ; tst5 macro ad2 movlw ad2 subwf temp, w ; test if equal or less skpc call add5 ; 5 degrees increment endm ; add5 movlw .5 ; increnent temperature 5 deg addwf l_byte, f return add10 movlw .10 ; 10 deg addwf l_byte, f return ; disp_tmp ; temp is ad_value * 0.75 - 40 movlw .4 ; display Coolant Temp call string movf CTEMP, W ; get temp AD count movwf mulcnd movlw .3 ; multiply by 3 movwf mulplr call mpy ; 0.74 == 3/4 call div4 ; then divide by 4 movlw .40 call subhl ; subtract offset btfss h_byte, 7 ; test if negative goto disp_end2 ; clrf h_byte ; no negative display clrf l_byte ; at least not yet goto disp_end2 ; disp_mat movlw .13 ; display MAT Temp call string movf MAT, W movwf temp clrf h_byte clrf l_byte ; show 0 if .lt. 10 degrees ; ; do raw test and skip conversion ; this is truncated MAT conversion table. 0 - 125 deg. ; with coarse step ; tst10 .218 ; 10 tst10 .199 ; 20 tst10 .177 ; 30 tst10 .152 ; 40 tst10 .126 ; 50 tst10 .102 ; 60 tst5 .92 ; 65 tst5 .81 ; 70 tst5 .72 ; 75 tst5 .64 ; 80 tst5 .56 ; 85 tst5 .50 ; 90 tst5 .44 ; 95 tst5 .39 ; 100 tst5 .34 ; 105 tst10 .26 ; 115 tst10 .21 ; 125 stop testin now it is boiling anyway ; goto disp_end2 ; show conversion result from l_byte ; disp_spd ; unit = MPH or KPH, range = 0 - 255 movlw .5 ; display Vechicle Speed call string movf VSPEED, w ; get speed goto disp_end ; disp_maf ; show maf high byte only movlw .6 ; display MAF call string movf MAFH, w ; get MAF high value goto disp_end ; disp_rpm ; unit = RPM, range = 0 - 6375 movlw .7 ; display RPM call string movf RPM, w ; get rpm data movwf mulcnd movlw .25 movwf mulplr ; multiply it by 25 call mpy goto disp_end2 ; disp_tps ; unit = %, range = 0- 100 movlw .8 ; display TPS call string movf TPS, w ; get TPS AD count movwf mulcnd movlw .100 ; multiply by 100 movwf mulplr call mpy call div256 ; then divide by 256 goto disp_end2 ; disp_int ; unit = unit, range = 0 - 255 movlw .9 ; display Integrator call string movf INT, w ; get Integrator goto disp_end ; disp_o2 ; unit = mV, range = 0 - 1115 movlw .10 ; display O2 volts call string movf O2, w ; get o2 raw value movwf mulcnd ; do conversion mV = ad*70/16 movlw .70 movwf mulplr ; multiply it by 70 call mpy call div16 ; divide by 16 goto disp_end2 ; show result ; disp_blm ; unit = unit, range = 0 - 255 movlw .11 ; display BLM call string movf BLM, w ; get BLM value goto disp_end ; disp_occ ; unit = unit, range = 0 - 255 movlw .12 ; display O2 cross counts call string movf O2CNT, w ; get o2 cross count goto disp_end ; disp_pa3 ; unit = unit, range = 0 - 255 movlw .15 ; display OLDPA3 parameter call string movf OLDPA3, w ; get OLDPA3 value goto disp_end ; knock ; display if knock detected movf OLDPA3, w ; get OLDPA3 value xorwf koldpa3,w ; check is same as before skpnz return ; yes = no action movf OLDPA3, w ; get OLDPA3 value movwf koldpa3 ; store as old value call lcdclr ; write over what ever we have on the display movlw .16 ; display knock warning message call string movlw .8 ; fill rest of the line with spaces goto disp_wspaces ; disp_rx_count movlw .18 call string movf rx_count, w ; show how many bytes received since clrf rx_count ; reset character counter goto disp_end ; disp_msg_num movlw .17 call string movf msg_num, w ; show aldl message number goto disp_end ; disp_bpw ; display BPW raw data movlw .14 ; display bpw call string movf BPWH, w movwf h_byte movf BPWL, w movwf l_byte goto disp_end2 ; disp_end movwf l_byte ; this is common part for almost disp_end1 clrf h_byte ; all parameter display routines disp_end2 call b2_bcd ; convert to decimal call disp5 ; show result movlw ' ' call putlcd return ; ; Display various flags ; disp_c ; display cloced loop flag movlw ' ' ; assume not set btfsc mwaf1, 7 ; test closed loop flag movlw 'C' ; closed loop indicator call putlcd return ; disp_l ; display enable learn flag movlw ' ' ; assume not set btfsc mwaf1, 1 ; test enable learn flag movlw 'L' ; closed loop indicator call putlcd return ; disp_d ; display diag flag movlw ' ' ; assume not set btfsc mw2, 4 ; test diag flag movlw 'D' ; closed loop indicator call putlcd return ; disp_r ; display rich flag movlw ' ' ; assume not set btfsc mwaf1, 6 ; test rich flag movlw 'R' ; closed loop indicator call putlcd return ; disp_space movlw ' ' ; display one space goto putlcd ; disp_Wspaces movwf A0 ; display W number of spaces dws movlw ' ' ; display one space call putlcd decfsz A0, f goto dws return ; ;*************************************************************** ; ; Interrupt services. ; 160 Baud ALDL receiver ; flags.sync = 1 when sync pattern found. Bit must be cleared by application. ; flags.byte_rdy = 1 when character received. Bit must be cleared by application. ; rx_byte = received character. Must be read before next byte_rdy. ; Data is also stored in aldl_buff starting from sync. buff_ptr = buffer pointer. ; Rx_count shows # of characters received after last sync pattern (for diagnostics) ; ; irqserv ; movwf w_temp ; save W & status swapf status, w movwf status_temp movf fsr, w ; save fsr movwf fsr_temp ; ; test which interrupt bcf status, rp0 ; be shure we are in bank 0 btfss intcon, intf ; check if rb0 irq goto tmr0int ; was not rb0 irq, must be tmr0 ; ; ALDL data input RB0 interrupt at falling edge ; rb0int ; Data is sampled about 2 mS after start bit falling edge ; XTAL = 4.9152 MHz => clock = 1.2288 MHz, cycle = 813,8 nS ; prescaler = 8 => tmr input = 6.5 yS => tmr preset = 230 ; this gives 2 mS delay. Total delay is this + timer set up latency. ; bcf intcon, intf ; reset irq flag movlw .256-.230 ; arm TMR0 for data sampling movwf tmr0 bcf intcon, t0if ; clear irq flag bsf intcon, t0ie ; enable tmr0 irq goto irqret ; ; TMR0 interrupt do data sampling & receive bit ; tmr0int bcf intcon, t0if ; clear irq flag bcf intcon, t0ie ; disable tmr0 interrupts ; if filter ; ; Do simple filtering for aldl (RB0) input line. ! very noicy input ; may lock this filter up ! ; test movlw fcount ; # of tests to determine B0 input state movwf int_temp btfss portb, 0 ; remember logical 1 = bit 0 ! goto test1 ; filter logical 1 test0 nop btfss portb, 0 ; check if still 0 goto test ; no restsrt filtering decfsz int_temp goto test0 clrc ; set 0 bit goto test9 test1 nop btfsc portb, 0 ; check if still 1 goto test ; no restart filtering decfsz int_temp goto test1 setc test9 ; it is 1 ; else ; ; simple aldl input line sampling without filtering ; clrc ; quess for 0 btfss portb, 0 ; check it setc ; is 1 endif ; if diag bsf diag_io ; signal data sampling point endif ; rlf rx_buff, f ; shift bit in ; ; test if sync pattern received ; skpc goto rx_char incfsz rx_buff, w ; test if buffer was all ones goto rx_char ; ; sync received movlw .9 ; 160 baud character bit count movwf bit_count bsf flags, sync ; set sync received flag ; movlw aldl_buff ; reset aldl buffer pointer movwf buff_ptr ; goto irqret ; rx_char decfsz bit_count, f ; test if all bits received goto irqret ; movlw .9 ; reset bit counter movwf bit_count movf buff_ptr, w ; set FSR movwf fsr movf rx_buff, w ; transfer ready character movwf rx_byte bsf flags, byte_rdy ; set byte ready flag ; incf rx_count, f ; increment character counter movwf indf ; store also to aldl buffer @ fsr ; movlw aldl_buffe xorwf buff_ptr, w ; do boundary check skpz ; already at end, something wrong incf buff_ptr, f ; increment buffer pointer clrf rx_buff ; destroy rxbuff and prevent false sync (last bit of last byte == 1) ; irqret if diag bcf diag_io ; reset timing measurement output endif ; movf fsr_temp, w ; restore fsr movwf fsr swapf status_temp, w ; restore status & W movwf status swapf w_temp, f swapf w_temp, w ; retfie ; ;*************************************************************** ; ; LCD I/O routines ; ;****** ; CLKLCD clocks data/command to the lcd by making the EN line ; high then low. CLKLCD MACRO BSF lcdctr,LCDEN ; Lcd enable high BCF lcdctr,LCDEN ; Lcd enable low ENDM ;****** ; TABSET sets up the lcd table offset pointer before string output ; starts TABSET MACRO MOVLW b'11111111' ; Offset is incremented on each call to ; table - first call must generate zero value ; offset. MOVWF TABOFF ENDM ;****** ; POINT increments the string pointer offset and adds it to the ; PLC ready for string lookup POINT MACRO INCF TABOFF MOVFW TABOFF ADDWF PCL ENDM ;****** ; POINT3 increments the string pointer offset and adds it to the ; PLC ready for string lookup. Sets PCLATH to 3 POINT3 MACRO MOVLW .3 ; Page 3xx MOVWF PCLATH INCF TABOFF MOVFW TABOFF ADDWF PCL ENDM ;****** ; POINT4 increments the string pointer offset and adds it to the ; PLC ready for string lookup. Sets PCLATH to 4 ( for 16F877 etc) POINT4 MACRO MOVLW .3 MOVWF PCLATH INCF TABOFF MOVFW TABOFF ADDWF PCL ENDM ;-------------------------------------------------------------------------- ;****** ; STRING sends the string with number in W register - to the lcd STRING MOVWF STRNUM TABSET ; Xero the offset CALL DOSTR ; Character from string RETURN ;****** ; BCDLCD sends the bcd character in W to lcd BCDLCD IORLW b'00110000' ; Convert to ascii ;****** ; PUTLCD sends the ASCII character in W to lcd PUTLCD MOVWF LCDCH CALL CHALCD ; Character to lcd RETURN ; ;****** ; WAITGP waits for the number of ms in GP1 WAITGP MOVLW .74 ; 1ms DELAY CALL DL1 MOVLW .255 CALL DL1 DECF GP1 ; TOTAL DELAY N * 1 ms BNZ WAITGP ; Loop until delay is complete RETURN ; Exit from WAITGP ; wait100 movwf apu ; wait n * 100 ms W = delay wa101 movlw .100 movwf gp1 call waitgp ; wait 100 ms decfsz apu goto wa101 return ;-------------------------------------------------------------------------- ; LCD Setup ;-------------------------------------------------------------------------- ; INITLCD ;****** ; Reset the lcd INITA MOVLW .20 ; Delay for 20 ms to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd MOVLW b'00000011' ; Reset MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW .6 ; Delay to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd MOVLW b'00000011' ; Reset MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW .5 ; Delay for 5 ms to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd MOVLW b'00000011' ; Reset MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW .5 ; Delay for 5 ms to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd MOVLW b'00000010' ; 4 bit interface MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW .5 ; Delay for 5 ms to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd MOVLW b'00000010' ; 4 bit interface MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW b'00001000' ; 2 LINES, 5*7 MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW .5 ; Delay for 5 ms to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd MOVLW b'00000000' ; Display OFF MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW b'00001000' ; MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW .5 ; Delay for 5 ms to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd MOVLW b'00000000' ; Display clear MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW b'00000001' ; MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW .5 ; Delay for 5 ms to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd MOVLW b'00000000' ; Entry mode set MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW b'00000110' ; MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW .5 ; Delay for 5 ms to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd MOVLW b'00000000' ; Display on MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW b'00001100' ; MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW .5 ; Delay for 5 ms to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd RETURN ; ;******************************************************************** ; Binary To BCD Conversion Routine ; The 16 bit binary number is input in locations H_byte and ; L_byte with the high byte in H_byte. ; The 5 digit BCD number is returned in R0, R1 and R2 with R0 ; containing the MSD in its right most nibble. ; B2_BCD bcf STATUS,0 ; clear the carry bit movlw .16 movwf count clrf R0 clrf R1 clrf R2 loop16 rlf L_byte, F rlf H_byte, F rlf R2, F rlf R1, F rlf R0, F ; decfsz count, F goto adjDEC goto bcdasc ; continue with ascii conv RETLW 0 ; adjDEC movlw R2 movwf FSR call adjBCD ; movlw R1 movwf FSR call adjBCD ; movlw R0 movwf FSR call adjBCD ; goto loop16 ; adjBCD movlw 3 addwf 0,W movwf temp btfsc temp,3 ; test if result > 7 movwf 0 movlw 0x30 addwf 0,W movwf temp btfsc temp,7 ; test if result > 7 movwf 0 ; save as MSD RETLW 0 ; ; continue with ASCII conversion bcdasc movf r2, w ; convert low order byte r0 movwf A1 andlw 0x0f addlw 0x30 ; low order nible = ASCII number movwf A0 swapf A1, w andlw 0x0f addlw 0x30 ; hi order nible = ASCII movwf A1 ; movf r1, w ; convert low order byte r1 movwf A3 andlw 0x0f addlw 0x30 ; low order nible = ASCII number movwf A2 swapf A3, w andlw 0x0f ; sets also Z-flag ; if zsup bz lzsup addlw 0x30 ; if non zero show number goto lz1 lzsup movlw 0x20 ; if zero replace with space lz1 movwf A3 else addlw 0x30 ; hi order nible = ASCII movwf A3 endif ; movf r0, w ; convert low order byte r2 andlw 0x0f addlw 0x30 ; hi order nible = ASCII movwf A4 ; save but dont care later ; retlw 0 ; ;************************************************************** ; display ascii result of bcd conversion ; disp5 if disp5d movf A4, w call putlcd endif movf A3, w ; display 4 digits call putlcd movf A2, w call putlcd movf A1, w call putlcd movf A0, w call putlcd retlw 0 ; ;************************************************************** ; ; Simplified math routines ; ; Subtract W from l_byte & h_byte result saved to l_byte &h_byte ; subhl subwf l_byte, f skpc decf h_byte, f return ; ; Divide H_byte & L_byte by 256, 16, 8 or 4 ; div16 movlw .4 ; 4 * shift right = div by 16 goto div80 ; div8 movlw .3 ; 3 * shift right = div by 8 goto div80 ; div4 movlw .2 ; 2 * shift right = div by 4 goto div80 ; div80 movwf temp div81 clrc rrf h_byte, f rrf l_byte, f decfsz temp, f goto div81 retlw 0 ; div256 movf h_byte, w ; divide by 256 movwf l_byte clrf h_byte return ; ; 8 * 8 multiply. The 16 bit result is stored in 2 bytes ; Before calling the subroutine "mpy", the multiplier should ; be loaded in location "mulplr", and the multiplicand in ; "mulcnd". The 16 bit result is stored in locations ; H_byte & L_byte. mpy clrf H_byte clrf L_byte movlw 8 movwf count movf mulcnd, W bcf STATUS, C ; Clear the carry bit in the status Reg. loop rrf mulplr, F btfsc STATUS, C addwf H_byte, F rrf H_byte, F rrf L_byte, F decfsz count, F goto loop retlw 0 ; ;************************************ ; ; Part of LCD routine moved out from 0x300 page to get ; more room for messages ; ; LCD64/2 gives a delay of 64us or 1.6ms while the lcd accepts the ; data or command. LCD64 MOVLW .22 ; Gives 65 us delay GOTO DL1 ; LCD2 MOVLW .65 ; Gives 1.6ms delay CALL DL1 MOVLW .255 CALL DL1 MOVLW .255 GOTO DL1 ; DL1 MOVWF DLYCNT DL11 DECF DLYCNT, F BTFSS STATUS, Z GOTO DL11 RETLW .0 ; Exit from CHA/COMLCD routines ; ;-------------------------------------------------------------------------- ; 0x300 page of ROM ;-------------------------------------------------------------------------- ; Text strings and control subroutines must be stored on the correct ; page or this pcogram WILL NOT FUNCTION CORRECTLY. ; Only move code around if you are absoluteley clear as to what you ; are doing! ORG 0x300 ; Last page for messages LAST EQU b'10000000' ; Value to add to last character in a string ;****** ; DOSTR uses CALLSTR table to direct flow to the correct lookup table ; for lcd strings. Gets string characters and outputs to lcd DOSTR MOVLW .3 ; 3xx Page MOVWF PCLATH ; Keep the pageing ok MOVFW STRNUM ; Get the string number CALL CALLSTR MOVWF LCDCH CALL CHALCD ; Character to lcd BTFSS LCDCH,7 ; Test if end of string flagged - bit 7 set GOTO DOSTR ; Loop until all sent RETURN ;****** ; CALLSTR is the dispatch table for lcd string lookup ; CALLSTR ADDWF PCL NOP GOTO MSG1 ; 'Banner display' GOTO MSG2 ; 'version info' GOTO MSG3 ; 'IAC' GOTO MSG4 ; 'TMP' GOTO MSG5 ; 'SPD' GOTO MSG6 ; 'MAF' GOTO MSG7 ; 'RPM' GOTO MSG8 ; 'TPS' GOTO MSG9 ; 'Int' GOTO MSG10 ; 'O2 ' GOTO MSG11 ; 'BLM' GOTO MSG12 ; 'Occ' GOTO MSG13 ; 'MAT' GOTO MSG14 ; 'BPW' GOTO MSG15 ; 'PA3' GOTO MSG16 ; 'Knock' GOTO MSG17 ; 'Msg' ALDL message # GOTO MSG18 ; 'Rxc' ALDL message character count GOTO MSG19 ; 'Wait data' ; ; THE TEXT STRINGS! MSG1 POINT3 ; Use macro POINT3 when the string is in 0x300 ; address area if tuukka RETLW 'T' ; Tuukka special RETLW 'u' RETLW 'u' RETLW 'k' RETLW 'k' RETLW 'a' RETLW ' ' RETLW 'v' RETLW 'o' RETLW 'i' RETLW 't' RETLW 't' RETLW 'a' RETLW 'a' RETLW ' ' RETLW ' ' RETLW 'H' RETLW 'I' RETLW 'P' RETLW 'O'+LAST else RETLW '1' RETLW '6' RETLW '0' RETLW 'B' RETLW 'a' RETLW 'u' RETLW 'd' RETLW ' ' RETLW '1' RETLW '2' RETLW '2' RETLW '7' RETLW '1' RETLW '6' RETLW '5' RETLW ' ' RETLW 'D' RETLW 'i' RETLW 's' RETLW 'p'+LAST endif ; MSG2 POINT3 RETLW 'v' RETLW ' ' RETLW '1' RETLW '.' RETLW '0' RETLW '1' RETLW ' ' RETLW 'J' RETLW 'N' RETLW 'i'+LAST ; MSG3 POINT3 RETLW 'I' RETLW 'A' RETLW 'C'+LAST ; MSG4 POINT3 RETLW 'T' RETLW 'M' RETLW 'P'+LAST ; MSG5 POINT3 RETLW 'S' RETLW 'P' RETLW 'D'+LAST ; MSG6 POINT3 RETLW 'M' RETLW 'A' RETLW 'F'+LAST ; MSG7 POINT3 RETLW 'R' RETLW 'p' RETLW 'm'+LAST ; MSG8 POINT3 RETLW 'T' RETLW 'P' RETLW 'S'+LAST ; MSG9 POINT3 RETLW 'I' RETLW 'n' RETLW 't'+LAST ; MSG10 POINT3 RETLW 'O' RETLW '2' RETLW ' '+LAST ; MSG11 POINT3 RETLW 'B' RETLW 'L' RETLW 'M'+LAST ; MSG12 POINT3 RETLW 'O' RETLW 'c' RETLW 'c'+LAST ; MSG13 POINT3 RETLW 'M' RETLW 'A' RETLW 'T'+LAST ; MSG14 POINT3 RETLW 'B' RETLW 'P' RETLW 'W'+LAST MSG15 POINT3 RETLW 'P' RETLW 'A' RETLW '3'+LAST MSG16 POINT3 RETLW ' ' RETLW ' ' RETLW ' ' RETLW '!' RETLW ' ' RETLW 'K' RETLW 'n' RETLW 'o' RETLW 'c' RETLW 'k' RETLW ' ' RETLW '!'+LAST ; MSG17 POINT3 RETLW 'M' RETLW 's' RETLW 'g' + LAST ; MSG18 POINT3 RETLW 'R' RETLW 'x' RETLW 'c' + LAST ; MSG19 POINT3 RETLW 'W' RETLW 'a' RETLW 'i' RETLW 't' RETLW ' ' RETLW 'd' RETLW 'a' RETLW 't' RETLW 'a' + LAST ; ;-------------------------------------------------------------------------- ; Subroutines to handle the lcd ;-------------------------------------------------------------------------- ; CHALCD writes the character in W register to the lcd. ; On entry, the display character is in LCDCH. CHALCD ; Get the upper nibble and load to the lcd port SWAPF LCDCH,W ; Get the ms nibble to ls position ANDLW 07H ; Strip to ms nibble in ls position, ; and mask top bit in case this is the lset ; character in a string MOVWF lcddata ; Data to lcd port BSF lcdctr,LCDRS ; Select lcd data ; Clock the ms nibble to the lcd CLKLCD ; Get the lower nibble and load to the lcd port MOVFW LCDCH ; Get back the character ANDLW 0FH ; Strip to ms nibble in ls position MOVWF lcddata ; Data to lcd port BSF lcdctr,LCDRS ; Select lcd data ; Clock the ls nibble to the lcd. CLKLCD BCF lcdctr,LCDRS GOTO LCD64 ; Delay then exit from CHALCD ;***** ; COMLCD writes the command in W register to the lcd ; On entry, the command character is in LCDCH. COMLCD ; Get the upper nibble and load to the lcd port SWAPF LCDCH,W ; Get the ms nibble to ls position ANDLW 0FH ; Strip to ms nibble in ls position MOVWF lcddata ; Command to lcd port ; Clock the ms nibble to the lcd CLKLCD ; Get the lower nibble and load to the lcd port MOVFW LCDCH ; Get back the character ANDLW 0FH ; Strip to ms nibble in ls position MOVWF lcddata ; Command to lcd port ; Clock the ls nibble to the lcd. CLKLCD GOTO LCD2 ; Delay then exit from COMLCD ;****** ; LCDCL1R clears the display and resets the cursor LCDCLR MOVLW LCDCLER ; LCD clear command MOVWF LCDCH GOTO COMLCD ;****** ; LCDCUR sets cursor to position on using value in W register ; line1 - 4 are defined for 4 * 20 display ; LCDCUR IORLW LCDCM MOVWF LCDCH GOTO COMLCD ; END