; ULTRASONIC RANGE FINDER - PIC Code ; ; Version info: ; 0.3 - Current version ; Fixed 'no echo' hang discovered at design fair ; 0.2 - Added true 'h' function ; transposed 'f' and 'b' commands to move motor ; correct way ; ; 0.1 - First working code ; prog rangtest list p=16f877 __config H'3D31' #include "p16f877.inc" ;variable defines #define MOT_DELAY 0x20 #define mot_pos 0x21 #define cap_high 0x22 #define cap_low 0x23 #define charBuf 0x70 #define printf_temp 0x71 #define ISR_w 0x72 #define ISR_status 0x73 #define curMode 0x74 #define ISR_charBuf 0x75 #define temp 0x76 #define hex_temp 0x77 #define hex_temp2 0x78 #define DELAY_NUM 0x79 #define DELAY_CTR 0x7a ;misc defines #define char_rx 0 #define cap_done 1 ;constants #define DELAY_TIME 0x04 ;signal defines #define TESTOUT PORTC, 0 #define INIT PORTC, 1 #define ECHO PORTC, 2 #define BLNK PORTE, 0 #define BINH PORTE, 1 #define MOT_CON PORTD #define HOME PORTA, 0 ; macro BANK0 - switches to bank0 BANK0 macro bcf STATUS, RP0 bcf STATUS, RP1 endm ; macro BANK1 - switches to bank1 BANK1 macro bsf STATUS, RP0 bcf STATUS, RP1 endm ; macro BANK2 - switches to bank2 BANK2 macro bcf STATUS, RP0 bsf STATUS, RP1 endm ; macro BANK3 - switches to bank3 BANK3 macro bsf STATUS, RP0 bsf STATUS, RP1 endm org 0 goto start org 4 goto ISR ; null terminated strings for use with printf function START_TITLE retlw 0x0d retlw 0x0a retlw 'R' retlw 'a' retlw 'n' retlw 'g' retlw 'e' retlw 'r' retlw ' ' retlw 'V' retlw 'e' retlw 'r' retlw '.' retlw ' ' retlw '0' retlw '.' retlw '3' retlw 0x0d retlw 0x0a retlw 0x00 start call init_IO ;call init IOs call init_getChar ;call init_getChar call init_ints ;enable interrupts movlw 0x0a ;delay PIC for 10ms in order to ensure call delay_w_ms ;ranger module has time to start up BANK0 movlw DELAY_TIME ;init MOT_DELAY global movwf MOT_DELAY clrf mot_pos ;init mot_pos variable movlw START_TITLE call printf bcf T1CON, TMR1CS ; set Timer1 into Timer mode - internal clock bsf T1CON, TMR1ON ; enable Timer1 movlw b'00000101' ; set intialize capture mode setting movwf CCP1CON ; set capture mode clrf curMode ; clear current mode register command_wait movlw 0x0d ;send carridge return call sendChar movlw 0x0a call sendChar movlw ':' ;print prompt call sendChar clrf TMR1H ;clear timer1 clrf TMR1L command_loop btfss curMode, char_rx ;has a char been received? goto command_loop ;nope, loop bcf curMode, char_rx ;yup, clear flag movfw ISR_charBuf sublw 'd' ;is it a 'd'? btfsc STATUS, Z goto set_delay ;yup, goto dummy routine movfw ISR_charBuf sublw 'f' ;is it a 'f'? btfsc STATUS, Z goto step_fwd ;yup, goto step_fwd routine movfw ISR_charBuf sublw 'b' ;is it a 'b'? btfsc STATUS, Z goto step_bkwd ;yup, goto step_bkwd routine movfw ISR_charBuf sublw 'g' ;is it a 'g'? btfsc STATUS, Z goto get_range ;yup, goto get_range routine movfw ISR_charBuf sublw 'h' ;is it an 'h'? btfsc STATUS, Z goto go_home ;yup, goto go_home routine goto command_loop ;no command received, go back ;---------------------------------------------------------------------------- ;set_delay - sets the delay variable set_delay BANK0 sd_loop btfss curMode, char_rx ;has a char been received? goto sd_loop ;nope, loop bcf curMode, char_rx ;yup, clear flag movfw ISR_charBuf sublw 0x1b ;is the character 'ESC'? btfsc STATUS, Z goto command_wait ;yup go back to command_wait movlw '0' subwf ISR_charBuf, W ;convert from ASCII movwf temp ;save result sublw 9 btfss STATUS, C ;is the number more than 9? goto command_wait ;yup, abort movlw DELAY_TIME ;initialize MOT_DELAY with movwf MOT_DELAY ;smallest delay incf temp, F ;we will add DELAY_TIME to sd_lp2 decfsz temp, F ;MOT_DELAY 'temp' times goto sd_again ;we increment movfw MOT_DELAY call print_hex ;print out new delay goto command_wait ;all done, go back sd_again movlw DELAY_TIME ;add another DELAY_TIME to addwf MOT_DELAY, F ;MOT_DELAY goto sd_lp2 ;loop ;---------------------------------------------------------------------------- ;go_home - moves the motor backward until "home" signal is received go_home BANK0 btfsc HOME goto command_wait call go_bkwd goto go_home ;---------------------------------------------------------------------------- ; step_bkwd - moves the motor 1 step backward go_bkwd BANK0 call sb_mot_prev ;get next output for motor control movwf MOT_CON ;output the result to MOT_CON port movfw MOT_DELAY ;the move is done, delay to let hw call delay_w_ms ;settle return ;all done, go back ;---------------------------------------------------------------------------- ;get_range - instructs the ranger module to get a range (by pulling INIT high) ;once the range is captured by the ccp it is printed out, routine returns ;and aborts if ESC is pressed get_range BANK0 clrf TMR1H ;clear timer1 registers clrf TMR1L bsf INIT ;raise INIT, we are now waiting for BANK1 bsf PIE1, TMR1IE ;enable timer1 overflow interrupt BANK0 bsf TESTOUT ;the ccp to capture the pulse gr_loop btfsc curMode, cap_done ;have we captured? goto gr_print_range ;yup, capture it btfss curMode, char_rx ;has a char been received? goto gr_loop ;nope, loop bcf curMode, char_rx ;yup, clear flag movfw ISR_charBuf sublw 0x1b ;is it an ESC? btfss STATUS, Z goto gr_loop ;nope, loop bcf INIT ;we received ESC, abort, return INIT bcf TESTOUT ;to low BANK1 bcf PIE1, TMR1IE ;disable TMR1 overflow interrupt BANK0 goto command_wait ;and go back gr_print_range bcf curMode, cap_done ;clear the cap_done flag movfw cap_high ;print out the result of the cap call print_hex movfw cap_low call print_hex bcf INIT ;all done, bring INIT low again bcf TESTOUT goto command_wait ;and return ;---------------------------------------------------------------------------- ; step_bkwd - moves the motor 1 step backward step_bkwd BANK0 call sb_mot_prev ;get next output for motor control movwf MOT_CON ;output the result to MOT_CON port movfw MOT_DELAY ;the move is done, delay to let hw call delay_w_ms ;settle ; call sb_mot_prev ;get next output for motor control ; movwf MOT_CON ;output the result to MOT_CON port ; movfw MOT_DELAY ;the move is done, delay to let hw ; call delay_w_ms ;settle goto command_wait ;all done, go back sb_mot_prev BANK0 decf mot_pos, F ;decrement current position movlw b'00000111' ;if it's less than 0 mask off andwf mot_pos, F ;upper 5 bits to keep in 0->7 movfw mot_pos ;range addwf PCL, F ;retrieve the prev motor pos retlw b'00001000' retlw b'00000100' retlw b'00000010' retlw b'00000001' retlw b'00001000' retlw b'00000100' retlw b'00000010' retlw b'00000001' ;---------------------------------------------------------------------------- ; step_fwd - moves the motor 1 step forward step_fwd BANK0 call sf_mot_next ;get next output for motor control movwf MOT_CON ;output the result to MOT_CON port ; movfw MOT_DELAY ;the move is done, delay to let hw ; call delay_w_ms ;settle ; call sf_mot_next ;get next output for motor control ; movwf MOT_CON ;output the result to MOT_CON port ; movfw MOT_DELAY ;the move is done, delay to let hw ; call delay_w_ms ;settle goto command_wait ;all done, go back sf_mot_next BANK0 incf mot_pos, F ;increment current position movlw b'00000111' ;if it's more than 7 mask off andwf mot_pos, F ;upper 5 bits to keep in 0->7 movfw mot_pos ;range addwf PCL, F ;retrieve the next motor pos retlw b'00001000' retlw b'00000100' retlw b'00000010' retlw b'00000001' retlw b'00001000' retlw b'00000100' retlw b'00000010' retlw b'00000001' ;---------------------------------------------------------------------------- ;print_hex routine - outputs the byte in W in ASCII print_hex BANK0 movwf hex_temp ;save character to be printed andlw B'11110000' ;mask off lower nibble movwf hex_temp2 bcf STATUS, C ;shift upper nibble to lower nibble rrf hex_temp2, F bcf STATUS, C rrf hex_temp2, F bcf STATUS, C rrf hex_temp2, F bcf STATUS, C rrf hex_temp2, F movlw 0x0a ;is it bigger than 0x0a? subwf hex_temp2, W movlw 0x30 ;set to add 0x30 btfsc STATUS, C movlw 0x37 ;yup, set to add 0x37 addwf hex_temp2, W call sendChar ;send upper nibble in ASCII form movlw B'00001111' andwf hex_temp, W ;mask off upper nibble movwf hex_temp2 movlw 0x0a ;is it bigger than 0x0a? subwf hex_temp2, W movlw 0x30 ;set to add 0x30 btfsc STATUS, C movlw 0x37 ;yup, set to add 0x37 addwf hex_temp2, W call sendChar ;send lower nibble in ASCII form return ;return ;--------------------------------------------------------------------------------- ;init_IO routine - sets up the chip with the correct port directions and port settings init_IO BANK0 bcf INIT ;ensure INIT is low bcf BLNK ;ensure BLNK is low bcf BINH ;ensure BINH is low BANK1 movlw B'00001011' ;setting port directions movwf TRISA ;port A movlw B'00000111' ;turn off A/D convertor movwf ADCON1 ;all A/D pins are digital I/O movlw B'11111111' movwf TRISB ;port B movlw B'11100100' ;set RC1 to output and RC2 to input movwf TRISC ;port C movlw B'11110000' ;set lower 4 bits to output to control movwf TRISD ;motor movlw B'00000100' ;set RE0 and RE1 to output (to drive movwf TRISE ;BLNK and BINH signals) BANK0 bcf INIT ;ensure INIT is low bcf TESTOUT ;set TESTOUT to low bcf BLNK ;ensure BLNK is low bcf BINH ;ensure BINH is low clrf MOT_CON ;clear MOT_CON port, all windings off return ;------------------------------------------------------------------------------ ; interrupt service routine ISR movwf ISR_w ; save w swapf STATUS, w ; save current status clrf STATUS ; set ram page 1 movwf ISR_status ; save current status btfss PIR1, RCIF ;is RCIF set (byte received)? goto INT_CCP_CHK ;nope, skip serial receive call ISR_getChar ; get the character received movwf ISR_charBuf ; save it bcf PIR1, RCIF ; clear interrupt flag bsf curMode, char_rx call sendChar ; send character received call init_getChar ; init to receive another character INT_CCP_CHK btfss PIR1, CCP1IF ; has the CCP caused an interrupt? goto INT_TMR ;nope, check if overflow bcf INIT ;reset INIT line bcf TESTOUT movfw CCPR1H ;save cap time movwf cap_high movfw CCPR1L movwf cap_low bsf curMode, cap_done ;set capture flag bcf PIR1, CCP1IF ;clear interrupt flag clrf TMR1H clrf TMR1L INT_TMR btfss PIR1, TMR1IF ;did TMR1 overflow? goto INT_END ;nope, get out of ISR bcf INIT ;reset INIT line bcf TESTOUT bcf PIR1, TMR1IF ;clear TMR1 interrupt flag BANK1 bcf PIE1, TMR1IE ;clear TMR1 interrupt enable flag BANK0 movlw 0xFF ;move fake high value into movwf cap_high ;cap registers movlw 0xFF movwf cap_low bsf curMode, cap_done ;set the cap_done flag clrf TMR1H clrf TMR1L INT_END swapf ISR_status, W ; restore status register movwf STATUS swapf ISR_w, F swapf ISR_w, W ; restore W register retfie ; return from interrupt ;--------------------------------------------------------------------------------- ;subroutine init_ints - enables interrupts init_ints BANK1 ;bsf PIE1, RCIE ; enable receive interrupts bsf PIE1, CCP1IE ; enable capture interrupt bsf INTCON, PEIE ; enable peripheral interrupts bsf INTCON, GIE ; enable interrupts BANK0 return ;--------------------------------------------------------------------------------- ; subroutine sendChar - sends the character in W to the serial port sendChar BANK1 sendChar_loop btfss TXSTA, TRMT ;is TSR empty goto sendChar_loop movwf charBuf ;save char to be sent movlw 0x0c ;set baud rate generator for 19200bps movwf SPBRG ;with 4MHz crystal bsf TXSTA, BRGH ;set high speed mode bcf TXSTA, SYNC ;clear SYNC bit BANK0 bsf RCSTA, SPEN ;set SPEN bit BANK1 bsf TXSTA, TXEN ;enable transmission movfw charBuf ;get char to be sent BANK0 movwf TXREG ;move char to be sent into tx reg return ;--------------------------------------------------------------------------------- ; subroutine printf - outputs the null terminated string at address ; in W to the serial port printf movwf printf_temp ; load character counter printf_loop call table_lookup ; get a character from the table movwf charBuf ; necessary to effect Z movfw charBuf ; necessary to effect Z btfss STATUS, Z ; is character a null? goto printf_go_on ; nope, go on return ; yup, hit a null, return printf_go_on call sendChar ; we have a non zero number, send it incf printf_temp, F ; increment counter goto printf_loop ; start loop again table_lookup movfw printf_temp ; move address of chr to get into w movwf PCL ; set PCL to that address ;-------------------------------------------------------------------------- ;delay_w_ms - delays operation for number of ms contained in w ;WARNING: NOT INTERRUPT AWARE delay_w_ms BANK0 movwf DELAY_NUM call delay_1ms decfsz DELAY_NUM, F goto $-2 BANK0 return ;-------------------------------------------------------------------------- ;delay_1ms - delays operation for 1ms for a PIC running at 4MHz ;WARNING: NOT INTERRUPT AWARE delay_1ms BANK0 ; movlw d'248' movlw d'229' movwf DELAY_CTR nop decfsz DELAY_CTR, F goto $-2 BANK0 return ;--------------------------------------------------------------------------------- ;inits the USART for character reception for getChar routine init_getChar BANK1 movlw 0x0c ;set baud rate generator for 19200bps movwf SPBRG ;with 4MHz crystal bsf TXSTA, BRGH ;set high speed mode bcf TXSTA, SYNC ;clear SYNC bit BANK0 bsf RCSTA, SPEN ;set SPEN bit bsf RCSTA, CREN ;enable reception BANK1 bsf PIE1, RCIE ; enable receive interrupts BANK0 return ;now ready to receive, return ;--------------------------------------------------------------------------------- ;getChar ISR ISR_getChar movfw RCREG ;move the result into W bcf RCSTA, CREN ;clear this bit in case an error occured return ;we're done, return from call ;-------------------------------------------------------------------------- END