#include ;#include "banks.inc" ; This header file defines configurations, registers, and other useful ; bits of information for the PIC18F4550 microcontroller. These names ; are taken to match the data sheets as closely as possible. CONFIG WDT = OFF; Disable watchdog timer CONFIG MCLRE = ON; MCLEAR Pin on CONFIG DEBUG = OFF; disable Debug Mode CONFIG LVP = OFF; Low-Voltage programming disabled CONFIG FOSC = HSPLL_HS; HS oscillator, PLL enabled, HS used by USB CONFIG PBADEN = OFF; PORTB<4:0> pins are configured as digital I/O on Reset CONFIG VREGEN = ON ; USB voltage regulator enabled CONFIG PLLDIV = 5 ; PLL prescaler Divide by 5 (20 MHz oscillator input) CONFIG USBDIV = 2 ; USB clock source comes from the 96 MHz PLL divided by 2 CONFIG CP0 = ON ; Code Protect CONFIG CP1 = ON CONFIG CP2 = ON CONFIG CPB = ON ; Boot Sect Code Protect CONFIG CPD = OFF ; EEPROM Data Protect CONFIG WRT0 = OFF ; Table Write Protect CONFIG WRT1 = OFF CONFIG WRT2 = OFF CONFIG WRTB = ON ; Boot Table Write Protest ;--------------------IR_test.ASM------------------------ ; Test IR and other sensors of our robot ;for the pic18f4550 20Mhz -> 4Mhz -> 100Mhz processor ;------------------------------------------------------ ; Edwin Armstrong AKA (efa) ;------------------------------------------------------ ; 03/10/09 Modified code to work with pic 18F4550 procesor (efa) ; 01/24/10 Added test code for LCD (efa) ; 03/25/10 added IR test code for LCD (efa) ;------------------------------------------------------ list p=18f4550 ;------------------------------------------------------- ; setup equates for ram memory -- Pic16f648: 0x20 to 0x7F (in bank 0), 0xA0 to 0xEF (in bank 1), ; 0x120 to 0x16F (in bank 2). 256 total ram count equ 0x20 ocount equ 0x21 ncount equ 0x22 ncount1 equ 0x23 ncount2 equ 0x24 ncount3 equ 0x25 seconds equ 0x26 tenths equ 0x27 sens equ 0x28 ;sensor status flag rt_sens, etc. LCD_tmp1 equ 0x29 nops equ 0x2a ;---------------------------- LCD defines -------------------------------- ; see post includes for LCD control, at bottom of program... ; LCD and port defines #DEFINE LCD_D4 PORTA, 0 #DEFINE LCD_D5 PORTA, 1 #DEFINE LCD_D6 PORTA, 2 #DEFINE LCD_D7 PORTA, 3 #DEFINE LCD_RS PORTA, 4 ; Register Select, 0 = Command, 1 = Data #DEFINE LCD_E PORTA, 5 ; enable, strobe from 1 to 0 to send data ;--------------------- special registers and flags ------------------ porta equ PORTA portb equ PORTB portc equ PORTC portd equ PORTD porte equ PORTE w equ 0 f equ 1 FSR equ 04h ;-------------------------------------------------------------------- EStrobe MACRO ; Strobe the "E" Bit BSF LCD_E call wait_ms ; wait 1 ms BCF LCD_E call wait_ms ; wait 1 ms ENDM ;-------------------------------------------------------------------- clearLCD MACRO ; home and clear the LCD MOVLW 0x01 CALL LCD_wrtCMD ENDM ;-------------------------------------------------------------------- leftIR_LCD MACRO ; Left IR detect MOVLW 'L' CALL LCD_wrtData MOVLW 'e' CALL LCD_wrtData MOVLW 'f' CALL LCD_wrtData MOVLW 't' CALL LCD_wrtData MOVLW ' ' CALL LCD_wrtData MOVLW 'I' CALL LCD_wrtData MOVLW 'R' CALL LCD_wrtData MOVLW ' ' CALL LCD_wrtData MOVLW 'D' CALL LCD_wrtData MOVLW 'e' CALL LCD_wrtData MOVLW 't' CALL LCD_wrtData MOVLW 'e' CALL LCD_wrtData MOVLW 'c' CALL LCD_wrtData MOVLW 't' CALL LCD_wrtData ENDM ;-------------------------------------------------------------------- rightIR_LCD MACRO ; Right IR detect MOVLW 'R' CALL LCD_wrtData MOVLW 'i' CALL LCD_wrtData MOVLW 'g' CALL LCD_wrtData MOVLW 'h' CALL LCD_wrtData MOVLW 't' CALL LCD_wrtData MOVLW ' ' CALL LCD_wrtData MOVLW 'I' CALL LCD_wrtData MOVLW 'R' CALL LCD_wrtData MOVLW ' ' CALL LCD_wrtData MOVLW 'D' CALL LCD_wrtData MOVLW 'e' CALL LCD_wrtData MOVLW 't' CALL LCD_wrtData MOVLW 'e' CALL LCD_wrtData MOVLW 'c' CALL LCD_wrtData MOVLW 't' CALL LCD_wrtData ENDM ;-------------------------------------------------------------------- bumper_LCD MACRO ; Bumber detect MOVLW 'B' CALL LCD_wrtData MOVLW 'u' CALL LCD_wrtData MOVLW 'm' CALL LCD_wrtData MOVLW 'p' CALL LCD_wrtData MOVLW 'e' CALL LCD_wrtData MOVLW 'r' CALL LCD_wrtData MOVLW ' ' CALL LCD_wrtData MOVLW 'D' CALL LCD_wrtData MOVLW 'e' CALL LCD_wrtData MOVLW 't' CALL LCD_wrtData MOVLW 'e' CALL LCD_wrtData MOVLW 'c' CALL LCD_wrtData MOVLW 't' CALL LCD_wrtData ENDM ;-------------------------------------------------------------------- fire_LCD MACRO ; Fire detect MOVLW 'F' CALL LCD_wrtData MOVLW 'i' CALL LCD_wrtData MOVLW 'r' CALL LCD_wrtData MOVLW 'e' CALL LCD_wrtData MOVLW ' ' CALL LCD_wrtData MOVLW 'D' CALL LCD_wrtData MOVLW 'e' CALL LCD_wrtData MOVLW 't' CALL LCD_wrtData MOVLW 'e' CALL LCD_wrtData MOVLW 'c' CALL LCD_wrtData MOVLW 't' CALL LCD_wrtData ENDM ;-------------------------------------------------------------------- org 0x800; program starts at 0x800, the bootloader lives in the code space 0x0 to 0x7ff. goto begin begin ; Initialize and setup processor to do work ; movlw 0x0F ; turn (A to D) off for port A, all pin are digital movwf ADCON1 movlw 0x00 ; load w with 0000 0000 - all outputs MOVWF TRISA movlw 0x00 ; load w with 0000 0000 - all outputs MOVWF TRISB movlw 0x00 ; load w with 0000 0000 - C0 (lft-IR), C6 (rt-IR) MOVWF TRISC movlw 0x30 ; load w with 0011 0000 - D4 (frt-bump), D5(fire) MOVWF TRISD movlw 0x04 ; load w with 0000 0100 - (IR detect) MOVWF TRISE bcf INTCON, GIE ;disable interrupts MOVLW 0x07 ; turn comparators off and MOVWF CMCON ; enable pins for I/O functions ;**************** Clear Ports ********************* clrf porta clrf portb clrf portc clrf portd ;-------------------------------- Wait for a second ------------------------- movlw 0x01 ; load 1 seconds to wait in w movwf seconds ; load w value to seconds call wait ; wait for alotted 1 seconds ;---------------------------------------------------------------------------- call LCD_init ; Init the LCD loop1 clrf sens ; clear sensors status flags call chk_sens ;check sensors (1=lt_ir, 2=rt_ir, 3=bumper, 6-fire) ;================ Check Left IR ======================== btfss sens,1 ; if(lt_ir == TRUE) goto left_endif goto left_if left_if leftIR_LCD ;Display Left detection message goto clear ; skip to clear to avoid multiple detects left_endif ;================ Check Right IR ======================= btfss sens,2 ; if(rt_ir == TRUE) goto right_endif goto right_if right_if rightIR_LCD ;Display Right detection message goto clear ; skip to clear to avoid multiple detects right_endif ;================ Check Bumper IR ====================== btfss sens,3 ; if(bumper == TRUE) goto bump_endif goto bump_if bump_if bumper_LCD ;Display Bumper detection message goto clear ; skip to clear to avoid multiple detects bump_endif ;=============== Check Fire sensor ==================== btfss sens,6 ; if(fire == TRUE) goto fire_endif goto fire_if fire_if fire_LCD ;Display Fire detection message goto clear ; skip to clear to avoid multiple detects fire_endif ;======================================================= incf sens ; ++sens decfsz sens ; --sens goto clear goto loop1 ; skip clearLCD when no sensor activity clear movlw 0x01 ; load 1 second wait in w movwf seconds ; load w value to seconds call wait ; wait for alotted seconds clearLCD ;Home and clear the LCD GOTO loop1 ;======================================================= ;======================================================= ; Check sensor status ; last updated 5/07/09 (efa) ;------------------------------------------------------- chk_sens call chk_fire ; check for fire call chk_bump ; check front bumper call chk_right ; check right sensor for an object call chk_left ; check left sensor for an object return ;------------------------------------------------------- ; chk_left:: look left using left IR sensor ; 2/25/10 (efa) ;------------------------------------------------------- chk_left call lt_led_on ;Turn left IR led on call wait100th ; allow time for the LED to ramp up call wait100th btfss porte,2 ;if(chk_left == TRUE) porte bit2 is grounded goto chk_left_if goto chk_left_else chk_left_if bsf sens,1 ; set chk_left, IR detected, to TRUE goto chk_left_endif chk_left_else bcf sens,1 ; clear chk_left, IR detected, to FALSE chk_left_endif call leds_off ; Turn off all IR LEDs return ;------------------------------------------------------- ; chk_right:: look right using right IR sensor ; 2/25/10 (efa) ;------------------------------------------------------- chk_right call rt_led_on ;Turn right IR led on call wait100th ; allow time for the LED to ramp up call wait100th btfss porte,2 ;if(chk_right == TRUE) porte bit2 is grounded goto chk_right_if goto chk_right_else chk_right_if bsf sens,2 ; set chk_right, IR detected, to TRUE goto chk_right_endif chk_right_else bcf sens,2 ; clear chk_right, IR detected, to FALSE chk_right_endif call leds_off ; Turn off all IR LEDs return ;------------------------------------------------------- ; f_bump:: subroutine to Check front bumper ; 3/12/09 (efa) ;------------------------------------------------------- chk_bump btfss portd,4 ; skip if bit4 is +5volts goto chk_bump_if1 goto chk_bump_else1 chk_bump_if1 ; bsf sens,3 ; front bumper was bumped goto chk_bump_endif1 chk_bump_else1 bcf sens,3 ; front bumper not bumped chk_bump_endif1 return ;------------------------------------------------------- ; chk_fire:: look at pin (c1) -- heat sensor ; 4/20/09 (efa) ;------------------------------------------------------- chk_fire btfss portd,5 ;if(chk_fire == TRUE) bit5 is not +5volts goto chk_fire_if goto chk_fire_else chk_fire_if bsf sens,6 ; set fire, to TRUE goto chk_fire_endif chk_fire_else bcf sens,6 ; clear fire, to FALSE chk_fire_endif return ;------------------------------------------------------- ; rt_led_on:: subroutine to turn the right IR led on (inverted logic) ; 3/30/09(efa) ;------------------------------------------------------- rt_led_on bcf portc,6 ;rt_led (off!)(conducts more through ground)bit6 (c6) return ;------------------------------------------------------- ; lt_led_on:: subroutine to turn the left IR led on (inverted logic) ; 4/20/09(efa) ;------------------------------------------------------- lt_led_on bcf portc,0 ;lt_led (off!)(conducts more through ground)bit0 (c0) return ;------------------------------------------------------- ; leds_off:: subroutine to turn all IR leds off (inverted logic) ; 4/20/09(efa) ;------------------------------------------------------- leds_off bsf portc,0 ;lt_led (on!) bit0 (c0) bsf portc,6 ;rt_led (on!) bit6 (c6) return ;------------------------------------------------------- ; LCD_init:: Initialize LCD, set it to 4bit mode ; 02/06/10 (efa) ;------------------------------------------------------- LCD_init: bcf LCD_RS ; Enter command mode, Register Select, 0 = Command, 1 = Data movlw 0x30 ; force to 8 bit mode, send upper nibble call LCD_wrtCMD_nibble call wait_ms; movlw 0x30 ; force to 8 bit mode, send upper nibble call LCD_wrtCMD_nibble call wait_ms; movlw 0x30 ; force to 8 bit mode, send upper nibble call LCD_wrtCMD_nibble call wait_ms; movlw 0x20 ; force to 4 bit mode, send upper nibble call LCD_wrtCMD_nibble call wait100th; ; wait 10 ms ; **** Now that we are in 4bit mode, send data a nibble at a time **** MOVLW 0x28 ; set to 4 bit, 2 line, 5x7 display call LCD_wrtCMD MOVLW 0x08 ; Don't shift display, hide cursor CALL LCD_wrtCMD MOVLW 0x01 ; clear and home cursor CALL LCD_wrtCMD MOVLW 0x06 ; set sursor movement to the right CALL LCD_wrtCMD ; MOVLW 0x80 ; move cursor to line 1, home on left ; CALL LCD_wrtCMD MOVLW 0x0F ; turn on display w/ blinking cursor CALL LCD_wrtCMD RETURN ;;============================================================ ; Send an instruction byte (command) to the LCD ;;============================================================ LCD_wrtCMD: BCF LCD_RS ; RS low = Command mode CALL LCDsendByte ; Send the instruction byte RETURN ;;============================================================ ; Send a character to the LCD ;;============================================================ LCD_wrtData: BSF LCD_RS ; RS high = character data CALL LCDsendByte ; Send the character RETURN ;;============================================================ ; Send an instruction byte (command) to the LCD ;;============================================================ LCD_wrtCMD_nibble: BCF LCD_RS ; RS low = Command mode movwf LCD_tmp1 ;;***************** do the upper nibble ****************** BCF LCD_D7 ; Clear data bits BCF LCD_D6 BCF LCD_D5 BCF LCD_D4 BTFSC LCD_tmp1, 7 ; Load high nibble BSF LCD_D7 BTFSC LCD_tmp1, 6 BSF LCD_D6 BTFSC LCD_tmp1, 5 BSF LCD_D5 BTFSC LCD_tmp1, 4 BSF LCD_D4 EStrobe ; strobe the E bit to send data call wait_ms ; Short delay for instruction to settle RETURN ;;============================================================ ; LCDsendByte:: Send a byte to the LCD, assumes RS already set ;;============================================================ LCDsendByte: MOVWF LCD_tmp1 ; Store byte in LCD_tmp1 ;;***************** do the upper nibble ****************** BCF LCD_D7 ; Clear data bits BCF LCD_D6 BCF LCD_D5 BCF LCD_D4 BTFSC LCD_tmp1, 7 ; Load high nibble BSF LCD_D7 BTFSC LCD_tmp1, 6 BSF LCD_D6 BTFSC LCD_tmp1, 5 BSF LCD_D5 BTFSC LCD_tmp1, 4 BSF LCD_D4 EStrobe ; strobe the E bit to send data ;;***************** do the lower nibble ****************** BCF LCD_D7 ; Clear data bits BCF LCD_D6 BCF LCD_D5 BCF LCD_D4 BTFSC LCD_tmp1, 3 ; Load low nibble BSF LCD_D7 BTFSC LCD_tmp1, 2 BSF LCD_D6 BTFSC LCD_tmp1, 1 BSF LCD_D5 BTFSC LCD_tmp1, 0 BSF LCD_D4 EStrobe ; strobe the E bit to send data RETURN ;;=========================================================== ;------------------------------------------------------- ; wait:: subroutine to "wait" for up to 255 seconds. ; Wait routine uses "pause" and variable "seconds" ; 01/31/10 (efa) - calibrated (+/- .1%) ;------------------------------------------------------- wait movwf seconds ; wait for 1-255 seconds incf seconds,f ; start 1 second back... s_loop movlw 0x0a ;max value inner counter movwf ncount1 ;load value inner counter decfsz seconds,f ; --ncount goto start ; pause for a time return ; subroutine return start movlw 0x01 ; load 1/10 seconds to wait in w movwf tenths ; load w value to seconds call wait10th ; pause for .1 seconds decfsz ncount1,f ; --ncount1 goto start ; inner1 loop goto s_loop ; go back to s_loop ;------------------------------------------------------- ; wait10th:: subroutine to "wait" for up to 255 (1/10) seconds. ; Wait routine uses "pause" and variable "seconds" ; 02/04/10 (efa) - calibrated ;------------------------------------------------------- wait10th movwf tenths ; wait for 1-255 (1/10) seconds incf tenths,f ; start 1 second back... s_loop1 movlw 0x0a ;max value inner counter movwf ncount2 ;load value inner counter decfsz tenths,f ; --ncount goto start1 ; pause for a time return ; subroutine return start1 call wait100th ; pause for .01 seconds decfsz ncount2,f ; --ncount1 goto start1 ; inner1 loop goto s_loop1 ; go back to s_loop ;------------------------------------------------------- ; wait100th:: subroutine to pause for 1/100 second ; To decrease pause decrease max value in outer loop ; 02/04/10 (efa) - calibrated ;------------------------------------------------------- wait100th movlw 0x0a ;max value outer counter (10) movwf ncount3 ;load value outer counter outer1 call wait_ms ; no operation, just a delay decfsz ncount3,f ; --ocount goto outer1 ; outer loop return ; subroutine return ;------------------------------------------------------- ; wait_ms:: subroutine to wait for 1/1000 second ; To decrease pause decrease max value in outer loop ; 1/30/10 (efa) calibrated ;------------------------------------------------------- wait_ms movlw 0x18 ;max value outer counter () movwf ocount ;load value outer counter outer movlw 0x7b ;max value inner counter movwf ncount ;load value inner counter inner nop ; no operation, just a delay decfsz ncount,f ; --ncount goto inner ; inner loop decfsz ocount,f ; --ocount goto outer ; outer loop return ; subroutine return ;------------------------------------------------------- ;; Final post-code includes ;; INCLUDE "lcd_4bit.inc" end