This is an old revision of the document!
;###############################################################################
;# 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