This is an old revision of the document!
Tire Pressure Sensor Code
Return to Tire Pressure Sensor Project.
;############################################################################### ;# TITLE "Pressure Sense" ;# ;# Program : Pressure sensor using an MPX5700DP sensor and LCD display ;# Version :1.0 ;# Revision Date : ;# Author : Jeff Brown ;# ;# ;# ;############################################################################### ; radix hex #define RA0_PICDEM ; If Defined, Pot on RA0, otherwise, RA8 ; #define LCD_PICDEM ; If Defined, Pot on RA0, otherwise, RA8 ; #define I2C_7SEG ; If Defined, use I2C to control display #DEFINE ADRC0 b'' #DEFINE ADRC1 b'' ; #define DEBUG ;list p=18F452 list p=18F2220 ;include "P18F452.INC" include "P18F2220.INC" #ifdef LCD_PICDEM include "XLCD.inc" ;This include all required files and variables. #endif ; ******************************* ; * Variables * ; ******************************* UDATA_ACS reg res 1 W_Temp res 1 STATUS_Temp res 1 BSR_Temp res 1 Temp res 1 Mult0 res 1 Mult1 res 1 Mult2 res 1 Mtemp0 res 1 Mtemp1 res 1 Mtemp2 res 1 TenK res 1 Thou res 1 Hund res 1 Tens res 1 Ones res 1 _Error res 1 Checksum res 1 Brightness res 1 SAA_Control res 1 global Temp global Mult0 global Mult1 global Mult2 global Mtemp0 global Mtemp1 global Mtemp2 global TenK global Thou global Hund global Tens global Ones global _Error global Checksum global Brightness global SAA_Control ; SAA1064 Constants SAA1064ADDRESS EQU B'01110000' ; Address SAA1064CONTROL EQU B'00000111' ; Control SAA1064SEGDASH EQU B'01000000' ; - SAA1064SEGDP EQU B'10000000' ; . SAA1064SEGJ EQU B'00011110' ; J ; ******************************* ; * Macros * ; ******************************* Bin_Out macro Floc ; Output a Binary Value variable i i = 0 while i < 8 if (i==4) movlw ' ' #ifdef LCD_PICDEM call XLCDPut #endif endif movlw '0' btfsc Floc,(7-i),A i+=1 movlw '1' #ifdef LCD_PICDEM call XLCDPut #endif endw endm I2C_AckWait macro nop btfsc SSPCON2,ACKSTAT Goto $-2 endm I2C_SendStart macro BSF SSPCON2,SEN ; Send Start call I2C_BusyWait endm I2C_SendStop macro BSF SSPCON2,PEN ; Send Stop call I2C_BusyWait endm #ifdef LCD_PICDEM ;The user can declare different definitions and make necessary commands XLCDCursorOnBlinkOn equ B'00001111' ;Display on Cursor on and Blink on XLCDCursorOnBlinKOff equ B'00001110' ;Display on Cursor on and Blink off XLCDDisplayOnCursorOff equ B'00001100' ;Display on Cursor off XLCDDisplayOff equ B'00001000' ;Display off XLCDAddrIncrOnShiftOn equ B'00000111' ;increment DDRAM address and Display shift during read and wite XLCDAddrIncrOnShiftOff equ B'00000110' ;increment DDRAM address no Display shift during read and wite XLCDAddrIncrOffShiftOff equ B'00000100' ;Do not increment DDRAM address and shift during read and wite XLCDDisplayMoveRight equ B'00011100' ;Display moves right,DDRAM Content remain unchanged XLCDDisplayMoveLeft equ B'00011000' ;Display moves left,DDRAM Content remain unchanged XLCDCursorMoveRight equ B'00010100' ;Cursor moves right,DDRAM Content remain unchanged XLCDCursorMoveLeft equ B'00010000' ;Cursor moves left,DDRAM Content remain unchanged #endif ;****************************************************************************** ; VECTORS org 0x000000 ; Processor reset vector (power-up here) nop nop ; First two instructions are nop's (no operation) to allow ; usage of break-points when using the debugger. goto Start ; Go to the beginning of the Main Program org 0x000008 ; High Priority ISR (Interrupt Service Routine) vector ; Start of High Priority ISR ; Write your custom High Priority ISR code here or place goto HiPriority_ISR ; a "goto HiPriority_ISR" here if you cannot fit the ; required code in before the low priority ISR at 0x0018. ; Remember, each instruction eats two lines of program ; memory and instructions always start at even numbers. ; i.e. The first instruction begins at memory location 0x000, ; the next at 0x002, then 0x004, and so on. retfie FAST ; Return from High Priority ISR and re-enable Global Interrupts. ; The "FAST" parameter tells the MCU to reload W, STATUS, and ; BSR registers from the shadow registers which context saves ; these registers the instant an interrupt occurs. ; We don't use the "FAST" option for the Low Priority ISR ; because if the High Priority interrupt is enabled and should ; ever occur while the program is still servicing the Low ; Priority ISR, then it will over-write the previous values ; saved in the shadow registers. ; Therefore, if only one ISR is required, use the High Priority ; with the FAST option for easy context saving. ; NOTE: When a High Priority interrupt occurs, the GIE/GIEH bit is hardware disabled until ; execution of the "retfie". This prevents subsequent High Priority interrupts from ; interferring with the ISR in progress. This could mean however missing some important ; interrupt if competing interrupts occur too quickly. The High Priority interrupt can ; interrupt however a Low Priority interrupt which has its own enable/disable bit PEIE/GIEL. ; If a Low Priority ISR is in progess, it prevents another low priority from occuring until ; complete but it cannot prevent a high priority interrupt from preempting it. The High ; Priority bit GIE/GIEH acts as the overall enable/disable bit for ALL priority interrupts. ; The reason for context saving W, STATUS, and BSR is that the values in these registers ; can affect moment by moment the result of subsequent instructions. If an interrupt ; routine alters their value(s) then when the program resumes at the point where it was ; interrupted, the results may become unpredicatable unless we first restore the values of ; W, STATUS, and BSR to their "as found" values the instant we leave the ISR (Interrupt ; Service Routine). org 0x000018 ; Low Priority ISR (Interrupt Service Routine) vector nop ; movff STATUS,STATUS_Temp ; Save the Status register contents ; movwf W_Temp,A ; Save the W register contents ; movff BSR, BSR_Temp ; Save the Bank Select Register contents ; ; ; Write your custom Low Priority ISR code here. ; ; ; End of Low Priority ISR, restore the W, Status, and BSR registers. ; movff BSR_Temp,BSR ; Restore the Bank Select Register ; movf W_Temp,W,A ; Restore the Working Register ; movff STATUS_Temp, STATUS ; Restore the Status register ; ; retfie ; Return from Low Priority ISR and re-enable ; ; any Low Priority Interrupts. PGM CODE ;Message db "LCD:", 0 ;display of string ;Lookup Table for 7-seg ;TODO Add test to make sure number is 0x0F or below ;DP is Bit 7 SEG_LOOKUP MOVWF Temp,A MOVLW 0x10 SUBWF Temp,A BTFSC STATUS,C RETLW B'11000000' ; Return 0xC0 if over 0x0F - Light up DP and G segments BCF STATUS,C RLCF Temp,w ADDWF PCL,F RETLW B'00111111' ; 0 RETLW B'00000110' ; 1 RETLW B'01011011' ; 2 RETLW B'01001111' ; 3 RETLW B'01100110' ; 4 RETLW B'01101101' ; 5 RETLW B'01111101' ; 6 RETLW B'00000111' ; 7 RETLW B'01111111' ; 8 RETLW B'01100111' ; 9 RETLW B'01110111' ; A RETLW B'01111100' ; B RETLW B'01011000' ; C RETLW B'01011110' ; D RETLW B'01111001' ; E RETLW B'01110001' ; F ;End of Lookup Start ; PORTA ;make PORTA digital(control signals are on PORTA) CLRF LATA CLRF TRISA ; #ifdef RA0_PICDEM ; BSF TRISA,RA0 ; #else BSF TRISA,RA5 ; #endif BSF TRISA,RA4 ; PORTB CLRF LATB CLRF TRISB ; PORTC CLRF TRISC,A BSF TRISC,SCL ; SDO as Input BSF TRISC,SDA ; SCK as Input ; PORTD ; CLRF LATD ; ; movlw 0x06 ; movwf ADCON1 #ifdef LCD_PICDEM call XLCDInit ;initialize LCD module(machine cycle talken for this call goto StartDisplay #if XLCDBLOCKING ==0 ;this part is assembled and called only in non blocking mode PollBF: ;XLCDIsBusy is called, if LCD module is busy w return with 1 else 0 call XLCDIsBusy ;in actual practice the user can continue with his code rather that ;polling like this and he can check by calling XLCDIsBusy to see if movwf reg ;the module is free before sending his next command to LCD. btfsc reg,0 ;(here in the example XLCDIsBusy is in a loop and stays there untill goto PollBF ;the busy flag is clreared) return #endif #endif StartDisplay ;movlw b'10000111' ; Prescaler 1:256 Enable Timer0, 16-bit, internal clock, rising edge ; movlw b'10000010' ; Prescaler 1:8 Enable Timer0, 16-bit, internal clock, rising edge ;movlw b'10000100' ; Prescaler 1:32 Enable Timer0, 16-bit, internal clock, rising edge ;movlw b'11000100' ; Prescaler 1:32 Enable Timer0, 8-bit, internal clock, rising edge ;movlw b'11000010' ; Prescaler 1:8 Enable Timer0, 8-bit, internal clock, rising edge ;movlw b'11000000' ; Prescaler 1:2 Enable Timer0, 8-bit, internal clock, rising edge ; movwf T0CON,A ; Initialize Timer BSF TRISA,RA0 movlw b'00000001' movwf ADCON0,A ; Initialize A/D Converter movlw b'00001110' ; AN0 movwf ADCON1,A ; Initialize A/D Converter movlw b'10011011' movwf ADCON2,A ; Initialize I2C Comm movlw 0x09 ; For 4MHz Clock movwf SSPADD BSF SSPSTAT,SMP ; Disable Slew Rate Control BCF SSPSTAT,CKE ; Disable SMBus specific inputs movlw b'00001000' ; MSSP as I2C Master movwf SSPCON1 BSF SSPCON1,SSPEN ; Enable SSP Module #ifdef LCD_PICDEM call XLCDClear ; Clear LCD #endif movlw 0xff movwf Checksum clrf Brightness incf Brightness,F loop call Read_AD ; Read A/D Converter movf ADRESL,W,A ; Move ADRESL movwf Mult0,A ; to Mult0 movf ADRESH,W,A ; Move ADRESL movwf Mult1,A ; to Mult1 clrf Mult2,A ; Clear Mult2 clrf _Error,A ; Clear _Error call _41_Sub call _141_Multiply call _Divide_by_128 call bin16_bcd movlw 0 ; Skip updating if no change xorwf Thou,W,A ; xorwf Hund,W,A ; xorwf Tens,W,A ; xorwf Ones,W,A ; movwf Mtemp0,A ; subwf Checksum,W,A; btfsc STATUS,Z ; goto No_Change ; movf Mtemp0,W,A ; movwf Checksum,A ; I2C_SendStart movlw SAA1064ADDRESS ; Address, Write Mode movwf SSPBUF call I2C_BusyWait I2C_AckWait movlw 0x00 ; Send Instruction Byte movwf SSPBUF call I2C_BusyWait I2C_AckWait call Brightfunc movwf SSPBUF call I2C_BusyWait I2C_AckWait movf _Error,F,A ; If _Error is set, change output to --- btfsc STATUS,Z goto noerr MOVLW SAA1064SEGDASH call SEG_SEND call SEG_SEND call SEG_SEND call SEG_SEND I2C_SendStop goto LCDpart noerr movf Ones,W call SEG_LOOKUP call SEG_SEND movf Tens,W call SEG_LOOKUP movwf Mult0,A ; Add Decimal Point BSF Mult0,7 ; to the right of movf Mult0,W ; the second digit call SEG_SEND movf Thou,W addwf Hund,W btfsc STATUS,Z ; Blank character if 0 goto blnkchr MOVF Hund,W call SEG_LOOKUP blnkchr call SEG_SEND movf Thou,W btfss STATUS,Z ; Blank character if 0 call SEG_LOOKUP call SEG_SEND I2C_SendStop ; Send STOP over I2C ; call ; goto loop ; Convert Thou:Hund:Tens:Ones to ASCII LCDpart movlw '0' addwf Thou,F,A addwf Hund,F,A addwf Tens,F,A addwf Ones,F,A ; Suppress Leading 0 for Thousands movlw '0' subwf Thou,W,A movlw ' ' btfss STATUS,Z ; If Thou was '0' goto Skip_Blank movwf Thou,A ; Change to ' ' ; Suppress Leading 0 for hundreds movlw '0' subwf Hund,W,A movlw ' ' btfsc STATUS,Z ; If Hund was '0' movwf Hund,A ; Change to ' ' Skip_Blank movf _Error,F,A ; If _Error is set, change output to --- btfsc STATUS,Z goto No_Error movlw '-' movwf Thou,A movwf Hund,A movwf Tens,A movwf Ones,A No_Error #ifdef LCD_PICDEM call XLCDClear ; Clear LCD movf Thou,W,A call XLCDPut movf Hund,W,A call XLCDPut movf Tens,W,A call XLCDPut movlw '.' call XLCDPut movf Ones,W,A call XLCDPut movlw ' ' call XLCDPut movlw 'P' call XLCDPut movlw 's' call XLCDPut movlw 'i' call XLCDPut movlw ' ' call XLCDPut movlw ' ' call XLCDPut movlw '0' addwf Brightness,W call XLCDPut movlw '/' call XLCDPut movlw '7' call XLCDPut #endif No_Change call Delay goto loop ; ; Subroutines ; Read_AD bsf ADCON0,GO_DONE,A ; Take AD measurement Check_AD btfsc ADCON0,GO_DONE,A ; Wait until done goto Check_AD ; Loop until Done return RA4_Button btfsc PORTA,RA4 return clrf Mult0 nop nop decfsz Mult0,f goto $-6 btfsc PORTA,RA4 return btfss PORTA,RA4 goto $-2 ; btg PORTB,RB0 incf Brightness,f btfsc Brightness,3 clrf Brightness return Brightfunc ; movf Brightness,f ; btfsc STATUS,Z ; incf Brightness,f movlw b'00000111' andwf Brightness,w movwf Temp bcf STATUS,C rlncf Temp,f rlncf Temp,f rlncf Temp,f rlncf Temp,f movlw SAA1064CONTROL IORWF Temp,w movwf SAA_Control return I2C_BusyWait ; Wait until I2C is free bsf LATB,RB3 BW_loop btfsc SSPSTAT,NOT_W goto BW_loop BW_loop2 movf SSPCON2,W andlw b'0001111' ; Check ACKEN, RCEN, PEN, RSEN, SEN btfss STATUS,Z goto BW_loop2 BCF LATB,RB3 ; btfss SSPSTAT,BF return SEG_SEND MOVWF Mult1 MOVWF SSPBUF CALL I2C_BusyWait I2C_AckWait MOVF Mult1,W return Delay movlw b'00000010' ; Prescaler 1:8 Disable Timer0, 16-bit, internal clock, rising edge ;movwf T0CON,A ; Initialize Timer ;bcf INTCON,T0IF,A ; Clear Timer0 movwf T0CON,A ; Initialize Timer bcf INTCON,TMR0IF,A ; Clear Timer0 movlw 0xFF ; Delay movwf TMR0H movlw b'10000000' ; Delay movwf TMR0L bsf T0CON,TMR0ON ; Enable Timer0 Delay_wt ;call RA4_Button ; Check RA4 Button btfss INTCON,TMR0IF,A goto Delay_wt ; Wait until delay bcf T0CON,TMR0ON return TX_Pressure ; Display "Pressure" #ifdef LCD_PICDEM movlw 'P' call XLCDPut movlw 'r' call XLCDPut movlw 'e' call XLCDPut movlw 's' call XLCDPut movlw 's' call XLCDPut movlw 'u' call XLCDPut movlw 'r' call XLCDPut movlw 'e' call XLCDPut movlw ':' call XLCDPut movlw ' ' call XLCDPut movlw '_' call XLCDPut movlw '_' call XLCDPut movlw '.' call XLCDPut movlw '_' call XLCDPut #endif return _Divide_by_128 ; Divide by 2^7 rlcf Mult0,F,A ; Rotate left 1 (Multiply by 2) rlcf Mult1,F,A ; rlcf Mult2,F,A ; movf Mult1,W,A ; Rotate right 8 (Divide by 256) movwf Mult0,A ; movf Mult2,W,A ; movwf Mult1,A ; movlw 0 ; movwf Mult2,A ; return _41_Sub ; Subtract 41 movlw .41 subwfb Mult0,F,A ; Subtract 41 btfsc STATUS,C ; If no Carry, goto _41end ; goto end movf Mult1,W,A btfsc STATUS,Z ; Make sure ADH is not zero goto _41Error ; Otherwise ERROR decf Mult1,F,A ; Decrement ADH for carry goto _41end _41Error movlw 0xFF movwf _Error,A movlw 0 movwf Mult1,A movwf Mult0,A _41end retlw 0 _141_Multiply ; Generated by www.piclist.com/cgi-bin/constdivmul.exe (1-May-2002 version) ; Sat Dec 29 07:01:17 2007 GMT ; Mult = Mult * 141 ; Temp = Mtemp ; Mult size = 10 bits ; Error = 0.5 % ; Bytes order = little endian ; Round = no ; ALGORITHM: ; Clear accumulator ; Add input * 128 to accumulator ; Add input * 8 to accumulator ; Add input * 4 to accumulator ; Add input * 1 to accumulator ; Move accumulator to result ; ; Approximated constant: 141, Error: 0 % ; Input: Mult0 .. Mult1, 10 bits ; Output: Mult0 .. Mult2, 18 bits ; Code size: 45 instructions ;copy accumulator to temporary movf Mult1,w,A movwf Mtemp1,A movf Mult0,w,A movwf Mtemp0,A ;shift temporary left 2 times bcf STATUS,C rlcf Mtemp0,f,A rlcf Mtemp1,f,A rlcf Mtemp0,f,A rlcf Mtemp1,f,A ;add temporary to accumulator movf Mtemp0,w,A addwf Mult0,f,A movf Mtemp1,w,A BTFSC STATUS,C incfsz Mtemp1,w,A addwf Mult1,f,A ;shift temporary left 1 times bcf STATUS,C rlcf Mtemp0,f,A rlcf Mtemp1,f,A ;add temporary to accumulator movf Mtemp0,w,A addwf Mult0,f,A movf Mtemp1,w,A BTFSC STATUS,C incfsz Mtemp1,w,A addwf Mult1,f,A ;shift temporary left 4 times swapf Mtemp1,f,A movf Mtemp1,w,A andlw 0x0F xorwf Mtemp1,f,A movwf Mtemp2,A swapf Mtemp0,f,A movf Mtemp0,w,A andlw 0x0F xorwf Mtemp0,f,A iorwf Mtemp1,f,A ;add temporary to accumulator clrf Mult2 movf Mtemp0, w addwf Mult0, f movf Mtemp1, w BTFSC STATUS,C incfsz Mtemp1, w addwf Mult1, f movf Mtemp2, w BTFSC STATUS,C incfsz Mtemp2, w addwf Mult2, f retlw 0 ;---------------- Binary (16-bit) to BCD ----------------------- ; Microchip Code ; xxx = highest possible result bin16_bcd ; Takes number in Mult1:Mult0 ; Returns decimal in ; TenK:Thou:Hund:Tens:Ones swapf Mult1,W andlw 0x0F addlw 0xF0 movwf Thou addwf Thou,F addlw 0xE2 movwf Hund addlw 0x32 movwf Ones movf Mult1,W andlw 0x0F addwf Hund,F addwf Hund,F addwf Ones,F addlw 0xE9 movwf Tens addwf Tens,F addwf Tens,F swapf Mult0,W andlw 0x0F addwf Tens,F addwf Ones,F rlcf Tens,F rlcf Ones,F comf Ones,F rlcf Ones,F movf Mult0,W andlw 0x0F addwf Ones,F rlcf Thou,F movlw 0x07 movwf TenK movlw 0x0A ; Ten Lb1: decf Tens,F addwf Ones,F btfss STATUS,C bra Lb1 Lb2: decf Hund,F addwf Tens,F btfss STATUS,C bra Lb2 Lb3: decf Thou,F addwf Hund,F btfss STATUS,C bra Lb3 Lb4: decf TenK,F addwf Thou,F btfss STATUS,C bra Lb4 retlw 0 HiPriority_ISR nop return end