title "RC Pulse Count V1" ;******************************************************************************** ; By: Ted Callahan 1-Mar-04 e-mail: ted@foxflier.com * ; LCD code adapted from original code by Andrew Kieran * ; Binary to ascii code from PICLIST by A. Borowski * ; e-mail: a.borowski@student.qut.edu.au * ; e-mail: akieran@ureach.com * ;******************************************************************************** ; Purpose: Measure pulsewidth output (PPM) from an RC receiver in * ; milliseconds and display on a bit-shifted, serial LCD display. * ; Pulse widths from 0 to 2.5ms can be measured to an accuracy of * ; .01ms. * ;******************************************************************************** ; Note: Target is PIC 16F628. Delay routines assume a 4Mhz clock. * ; LCD is PicVue PC064PYL, 2 line X 8 Character LCD on Port A. * ; Logical connection: 8 bits + RS & E. RW - grounded (write only) * ; Physical connection: 9 bits (data+RS) shifted + clock + Enable * ; Data + RS: RA0 Clock: RA1 Enable: RA2 * ; Pulse input on RB0 * ;******************************************************************************** list p=16f628 ; list directive to define processor #include ; processor specific variable definitions __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC & _BODEN_OFF ; ***** VARIABLE DEFINITIONS w_temp EQU 0x20 ; variable used for context saving status_temp EQU 0x21 ; variable used for context saving ChrCnt EQU 0x22 ; pointer to character being output to LCD LCDTemp EQU 0x23 ; character being output to the LCD BitCnt EQU 0x24 ; bit counter for shifting d1 EQU 0x25 ; delay counter 1 d2 EQU 0x26 ; delay counter 2 d3 EQU 0x27 ; delay counter 3 BIN EQU 0x28 ; input byte for bin2ascii conversion huns EQU 0x29 ; ascii hundreds output from bin2ascii tens EQU 0x2A ; ascii tens output ones EQU 0x2B ; ascii ones output count EQU 0x2C ; counter for bin2ascii hi_cnt EQU 0x2D ; hi byte of counter for zero message display lo_cnt EQU 0x2E ; lo byte of counter for zero message display #DEFINE PortLCD PORTA #DEFINE LCDData 0 ; b0 - LCD data bit #DEFINE LCDClk 1 ; b1 - LCD clock #DEFINE LCDE 2 ; b2 - Enable strobe ;********************************************************************** ORG 0x000 ; processor reset vector goto main ; go to beginning of program ORG 0x004 ; interrupt vector location movwf w_temp ; save current W register contents movf STATUS,w ; move status register into W register movwf status_temp ; save contents of STATUS register ; interupt handler goes here movf status_temp,w ; retrieve copy of STATUS register movwf STATUS ; restore pre-isr STATUS register contents swapf w_temp,f swapf w_temp,w ; restore pre-isr W register contents retfie ; return from interrupt GetLCDChr ; this table jump routine must be in the first 256 byte page movlw HIGH SndMsg ; load PCLATH with page info for text strings movwf PCLATH movf ChrCnt, W ; ChrCnt is the number of bytes into the page for each character addlw LOW SndMsg btfsc STATUS, C incf PCLATH, F movwf PCL ; no return statement required because we're changing the PCL directly main call InitPorts ; clear ports and setup TRIS registers call LCDSetup ; initialize the LCD and clear the screen call Greeting ; display greeting message call Pulsis ; display 'Pulse is' on LCD line 1 call ZeroPulse ; display '0.00ms' on line 2 cout clrf BIN ; set BIN to zero INCF lo_cnt, 1 ; increment the low count BTFSC STATUS, Z ; lo_cnt overflow? INCF hi_cnt, 1 ; yes, increment hi_cnt BTFSC STATUS, Z ; hi_cnt overflow? call ZeroPulse ; yes, so no pulse in .6 seconds so display 0.00ms BTFSS PORTB, 0 ; test RB0 GOTO cout ; wait while input pin is low countup ; RB0 is now hi INCF BIN, 1 ; increment BIN BTFSC STATUS, Z ; check for overflow in BIN GOTO cout ; restart if BIN overflows - pulse greater than 255 NOP ; NOP padding to get a 10us count loop NOP NOP NOP BTFSC PORTB, 0 ; see if RB0 is still hi GOTO countup ; if so continue to count pulse call bin2ascii ; convert BIN to ascii, result comes back in huns, tens, ones call Pulsis movlw 0x80 + 0x41 ; set cursor to 2nd row, col 2 call SndLCDCmd movf huns,0 call SndLCDChr ; output the count to the display movlw '.' call SndLCDChr movf tens,0 call SndLCDChr movf ones,0 call SndLCDChr movlw 'm' call SndLCDChr movlw 's' call SndLCDChr goto cout ; =========== ; SUBROUTINES ; =========== Pulsis movlw 0x80 + 0x00 ; 1st row col 1 call SndLCDCmd movlw LOW (M1Start - M1Start) ; set pointer to start of string call SndLCDStr movlw LOW (M3Start - M1Start) ; set pointer to start of string call SndLCDStr return ZeroPulse ; Output 0.00ms to LCD movlw 0x80 + 0x41 call SndLCDCmd movlw LOW (M5Start - M1Start) ; set pointer to start of string call SndLCDStr return InitPorts BCF INTCON, INTE ; Disable the RB0 interrupt clrf PortLCD ; clear LCD port MOVLW 0x07 MOVWF CMCON ; make sure the comparator module is off BSF STATUS, RP0 BCF STATUS, RP1 MOVLW B'11111000' ; set Port A pins 0,1,2 as outputs MOVWF TRISA MOVLW B'00000001' ; set RB0 as input MOVWF TRISB bcf STATUS, RP0 ; switch to Bank0 return LCDSetup call d20ms ; wait 20ms while LCD initializes movlw 0x30 ; LCD command (8-bit (logical) interface call SndLCDCmd movlw 0x38 ; LCD command (8-bit, 2 line display, 5X7 matrix) call SndLCDCmd movlw 0x0e ; LCD command (display on, cursor underline, call SndLCDCmd ; and no blinking cursor) call LCDCls ; Clear the screen movlw LOW (M9Start - M1Start) ; set pointer to start of string call SndLCDStr return LCDCls movlw 0x01 ; LCD command 01 (clear display - takes 1.64ms) call SndLCDCmd call d20ms ; overkill time delay return SndLCDChr bsf STATUS, C ; set RS high (character) when carry bit gets output goto SndIt SndLCDCmd bcf STATUS, C ; set RS low (command) when carry bit gets output SndIt bsf PortLCD, LCDE ; take E high before shifting data movwf LCDTemp ; save character to output movlw 09 ; loop through 8 bits + carry (RS) movwf BitCnt OutData bsf PortLCD, LCDData ; output the state of the carry flag on LCDData line btfss STATUS, C bcf PortLCD, LCDData bcf PortLCD, LCDClk ; clock out each bit nop bsf PortLCD, LCDClk ; Data shifts on low-high transition rrf LCDTemp, F decfsz BitCnt, F ; loop if all bits not sent goto OutData bcf PortLCD, LCDE ; lower E to latch data in LCD return SndLCDStr ; w must contain the offset of the string to output movwf ChrCnt SndLoop call GetLCDChr ; return with character to output in w xorlw 0x00 ; test if it's zero btfsc STATUS, Z return ; return if character is 0x00 call SndLCDChr ; output character incf ChrCnt, F ; pointer for next character goto SndLoop Greeting movlw 0x80 + 0x00 ; set cursor to 1st row, col 1 call SndLCDCmd ; Send string text to LCD movlw LOW (M6Start - M1Start) ; set pointer to start of string call SndLCDStr movlw LOW (M1Start - M1Start) ; set pointer to start of string call SndLCDStr movlw 0x80 + 0x40 ; set cursor to 2nd row, col 1 call SndLCDCmd movlw LOW (M2Start - M1Start) ; set pointer to start of string call SndLCDStr call d250ms ; pause while startup message displays call d250ms call d250ms call d250ms call d250ms call d250ms call LCDCls ; Clear the screen return ; Delay = 2o milliseconds ; Clock frequency = 4 MHz ; Actual delay = 20ms seconds = 0.02 seconds = 20000 cycles ; Delay code by Nikolai Golovchenko's delay code generator, ; found at: http://www.piclist.org/techref/piclist/codegen/index.htm ; d20ms ;19998 cycles movlw 0x9F movwf d1 movlw 0x10 movwf d2 Delay_0 decfsz d1, f goto $+2 decfsz d2, f goto Delay_0 ;2 cycles goto $+1 return ; Delay = 250 milliseconds ; Clock frequency = 4 MHz ; Actual delay = 0.25 seconds = 250000 cycles ; d250ms ;249998 cycles movlw 0x4F movwf d1 movlw 0xC4 movwf d2 Delay_1 decfsz d1, f goto $+2 decfsz d2, f goto Delay_1 ;2 cycles goto $+1 return ; This routine converts the binary value in BIN to 3 digit ASCII suitable for ; display on the LCD. Input in the variable BIN. Output is in variables ; huns, tens, and ones. The routine uses ADD-3 algorithm bin2ascii movlw 8 movwf count clrf huns clrf tens clrf ones BCDADD3 movlw 5 subwf huns, 0 btfsc STATUS, C CALL ADD3HUNS movlw 5 subwf tens, 0 btfsc STATUS, C CALL ADD3TENS movlw 5 subwf ones, 0 btfsc STATUS, C CALL ADD3ONES decf count, 1 bcf STATUS, C rlf BIN, 1 rlf ones, 1 btfsc ones,4 ; CALL CARRYONES rlf tens, 1 btfsc tens,4 ; CALL CARRYTENS rlf huns,1 bcf STATUS, C movf count, 0 btfss STATUS, Z GOTO BCDADD3 movf huns, 0 ; add ASCII Offset addlw h'30' movwf huns movf tens, 0 ; add ASCII Offset addlw h'30' movwf tens movf ones, 0 ; add ASCII Offset addlw h'30' movwf ones RETURN ADD3HUNS movlw 3 addwf huns,1 RETURN ADD3TENS movlw 3 addwf tens,1 RETURN ADD3ONES movlw 3 addwf ones,1 RETURN CARRYONES bcf ones, 4 bsf STATUS, C RETURN CARRYTENS bcf tens, 4 bsf STATUS, C RETURN ;**************end of bin2ascii****************** ORG 0x0700 ; keep LCD output strings at the start of a 256 byte block SndMsg M1Start retlw 'P' ; return the next letter in w retlw 'U' retlw 'L' retlw 'S' retlw 'E' retlw 0x00 ; '0' marks the end of an output string M2Start retlw 'C' retlw 'O' retlw 'U' retlw 'N' retlw 'T' retlw " " retlw 'V' retlw '1' retlw 0x00 M3Start retlw " " retlw 'i' retlw 's' retlw 0x00 M4Start retlw 'm' retlw 's' retlw 0x00 M5Start retlw '0' retlw '.' retlw '0' retlw '0' retlw 'm' retlw 's' retlw 0x00 M6Start retlw 'R' retlw 'C' retlw " " retlw 0x00 M7Start retlw " " retlw 0x00 M8Start retlw " " retlw 0x00 M9Start retlw 0x00 END ; directive 'end of program'