; Author: Steven Lovegrove, http://www.doc.ic.ac.uk/~sl203/ ; Title : Multi Input / Output Bluetooth Robot ; Description: ; For controlling my bluetooth robot. Interupt based design relatively ammenable to ; modification. ; ; Supports ADC, Bluetooth communication with BlueStamp BR-SC11A, Program Flashing over ; bluetooth, IR Send Receive (in progress) and Motor Control on PortD. ; ; Targetted for PIC16F877 ; Allowed Use: ; You may do what you like with this code, but I would appreciate an acknoledgement and ; link in the source code from anything derived from it. Thanks. ; ------------------------------------------------------------------------------ ; PIC16F877 program Configuration ;---------------------------------------------- title "ADC" LIST R=DEC INCLUDE "P16F877.inc" INCLUDE "usart_flash.inc" PAGE __CONFIG _CP_OFF & _HS_OSC & _PWRTE_ON & _WDT_OFF & _DEBUG_OFF & _LVP_OFF & _BODEN_OFF & _WRT_ENABLE_ON & _CPD_OFF ; General purpose registers, bank 1 ;---------------------------------------------- cblock 0x20 char, char1, char2, temp, tmr0_counter, timeouts endc ; General purpose registers, all banks ;---------------------------------------------- cblock 0x70 user_flags, cmd_flags ByteCount, LineChecksum, AddrH, AddrL, RecType HexDataL, HexDataH, Temp, Temp1, TempG W_TEMP, STATUS_TEMP endc ; User flags ;---------------------------------------------- UF_CONNECTED equ 7 UF_DATA_MODE equ 6 UF_CONNECTING equ 5 UF_AT equ 4 UF_IGNORE_NEXT equ 3 UF_POST_COMMA equ 2 UF_IR equ 1 UF_STARTED equ 0 ; Command flags ;---------------------------------------------- CMD_OUTPUT_LDR equ 7 CMD_COUNT equ 6 CMD_PORTD_DATA equ 5 ; Commands in ;---------------------------------------------- CMD0_REQUEST_ACK equ 0x01 CMD0_START_FLASH equ 0x02 CMD0_TOGGLE_LEDS equ 0x03 CMD0_TOGGLE_LDR_OUTPUT equ 0x04 CMD0_HANGUP_SLEEP equ 0x05 CMD0_TOGGLE_BEEP equ 0x06 CMD0_TOGGLE_COUNT equ 0x07 CMD1_PORTD_DATA equ 0x08 ; Commands out ;---------------------------------------------- CMDI0_ACK equ 'K' CMDI0_CONNECTED equ '*' CMDI0_FLASH_SUCCESS equ '^' CMDI0_FLASH_CHECKSUM_ERR equ '$' CMDI0_FLASH_WRITE_ERR equ '!' CMDI0_SHUTDOWN equ 0x01 CMDI2_LDR equ 0x02 CMDI0_BUTTON_DOWN equ 0x03 CMDI2_IR equ 0x04 CMDI0_IR_start equ 0x05 CMDI0_IR_end equ 0x06 org 0x00 ; Entry point ;---------------------------------------------- goto start ; pass over interupt vector org 0x04 ; interupt vector ;---------------------------------------------- ; Context save movwf W_TEMP ; W_TEMP = w movf STATUS, w ; STATUS_TEMP = STATUS movwf STATUS_TEMP clrf STATUS ; Bank 0 btfsc PIR1, RCIF call RXInteruptHandler btfsc PIR1, CCP1IF call Capture1Handler btfsc INTCON, T0IF call Timer0Handler btfsc PIR1, TMR1IF call Timer1Handler btfsc INTCON, RBIF call PortBChangedHandler clrf PIR1 ; Context restore movf STATUS_TEMP, w movwf STATUS swapf W_TEMP, f swapf W_TEMP, w retfie start ; Program Start ;---------------------------------------------- clrf STATUS ; Bank 0 clrf user_flags ; Reset Connection status clrf cmd_flags ; Reset Command state call initUART ; Setup UART for comms with BT chip call initAD ; Setup ADC for Light Sensor call initTimer0 ; Start Timer0 call initPorts ; Setup port input and outputs call initCapture1 ; Setup Compare1 bsf INTCON, PEIE ; Enable peripheral interupts bsf INTCON, GIE ; Enable interupts, start to receive stuff MainLoop btfss user_flags, UF_CONNECTED goto MainLoop ; Loop whilst not connected goto MainLoop data_mode ; Start Data Mode ;---------------------------------------------- movlw str_data_mode & 0xff call putString bsf user_flags, UF_DATA_MODE return command_mode ; Start Command Mode ;---------------------------------------------- movlw str_data_escape & 0xff call putString bcf user_flags, UF_DATA_MODE return startLDR_AD ; Perform ADC conversion and return in w ;---------------------------------------------- bsf ADCON0, 2 ; Start converion (set go/done¬ bit - ADCON0) btfsc ADCON0, 2 ; 5 - Wait for conversion goto $ - 1 return putChar ; Send byte in w over USART, busy-wait ;---------------------------------------------- bsf STATUS, RP0; ; Bank 1 btfss TXSTA, TRMT ; Loop until ready to send goto $ - 1 bcf STATUS, RP0 ; Bank 0 movwf TXREG ; Push charactor over USART from w return getChar ; Receive byte into w from USART, busy-wait ;---------------------------------------------- bsf STATUS, RP0; ; Bank 1 btfss TXSTA, TRMT ; Loop until ready to send goto $ - 1 bcf STATUS, RP0 ; Bank 0 movf RCREG, w ; Load recieved char into w return initUART ; Setup UART for send\recieve 9600 8-N-1 ;---------------------------------------------- bsf STATUS, RP0 ; Bank 1 bcf TXSTA, SYNC ; Asynchronous coms bcf TXSTA, BRGH ; Low Speed clock movlw 32 ; SPBRG = (ClockSpeed) / ( Baud*16*( 4**(1-BRGH) ) ) -1 movwf SPBRG ; Baud = 9600, ClockSpeed = 20x10^6, BRGH = 0 bcf STATUS, RP0 ; Bank 0 bsf RCSTA, SPEN ; Enable serial transmition bsf RCSTA, CREN ; Enable serial reception bsf STATUS, RP0 ; Bank 1 bcf TXSTA, TX9 ; 8 bits to send bcf TXSTA, RX9 ; 8 bits to recieve bsf TXSTA, TXEN ; Enable data transmit bsf PIE1, RCIE ; Enable interupt on receive bcf STATUS, RP0 ; Bank 0 return initAD ; Turn on and configure the AD module, input pin RE2 (10) ;---------------------------------------------- movlw 249 movwf ADCON0 ;set the result to be left-aligned (ie with msb in high byte) bsf STATUS, RP0 ; Bank 1 bcf ADCON1, 7 bcf STATUS, RP0 ; Bank 0 return initTimer0 ; Start timer0 for low precision timer event generation ;---------------------------------------------- bsf STATUS, RP0 ; Bank 1 movlw 11010111b andwf OPTION_REG, f ; internal clock, prescaler for tmr0 movlw 00000111b iorwf OPTION_REG, f ; prescaler = 111 (1:256) bcf STATUS, RP0 ; Bank 0 clrf TMR0 ; clear timer0 bcf INTCON, T0IF ; Clear pending interupts on tmr0 bsf INTCON, T0IE ; Enable TMR0 interupts return initCapture1 ; Initialise and start capture CCP1 and Start timer ;---------------------------------------------- ; ccp1 movlw 00000100b ; Capture falling edge movwf CCP1CON bsf STATUS, RP0 ; Bank 1 bsf PIE1, CCP1IE ; Enable Capture interrupts bsf TRISC, 2 ; Make CCP1 input pin bcf STATUS, RP0 ; Bank 0 ; timer 1 movlw 0 movwf TMR1L movwf TMR1H bcf T1CON, T1CKPS1 ; 1:1 prescaler bcf T1CON, T1CKPS0 bsf STATUS, RP0 ; Bank 1 bsf PIE1, TMR1IE ; Enable TIMER1 interupts bcf STATUS, RP0 ; Bank 0 bsf T1CON, TMR1ON ; Start Timer return initPorts ; Setup the ports we want to use ;---------------------------------------------- movlw 0 movwf PORTD ; Clear PORTD (no LED's or noise) bsf STATUS, RP0 ; Bank 1 movwf TRISD ; make PORTD output for LED's movlw 0xFF ; make PORTB input movwf TRISB bcf OPTION_REG, NOT_RBPU ; enable PORTB Pull-Ups bcf INTCON, RBIF ; Clear PORTB interupts flag bsf INTCON, RBIE ; enable PORTB change interupts bcf STATUS, RP0 return ;putByteHex ;; output byte in w in hex ;;---------------------------------------------- ; movwf temp ; swapf temp, w ; call convert ; call putChar ; movf temp, w ; call convert ; call putChar ; movlw ' ' ; call putChar ; return ; ;convert ;; Take low nibble of w and convert to ascii ;;---------------------------------------------- ; andlw 0x0F ; clear high nibble of w ; movwf temp1 ; movlw 10 ; subwf temp1, w ; w = in - 10 ; btfsc STATUS, C ; addlw 'A'-('0'+10) ; 0 <= w : w = in - 10 + 'A' ; addlw '0'+10 ; w < 0 : w = in + '0' ; return ; LookupTables (same 256 block as putString) ;---------------------------------------------- ;str_setupBT ; dt "ATSN,Rusty",0x0d,"ATSW24,1,0,0,0",0x0d,"ATSW25,2,2,0,0",0x0d,0x00 str_connect_debian dt "ATDM,0010DCAF6648,1101",0x0d, 0x00 str_data_mode dt 0x0d, "ATMD", 0x0d, 0x00 str_data_escape dt "+++", 0x0d, 0x00 str_cancel_connect dt "ATUCL", 0x0d, 0x00 str_hangup dt "ATDH", 0x0d, 0x00 str_bt_cpu_reset dt "ATURST", 0x0d, 0x00 putString ; Output string at program addr w over USART ;---------------------------------------------- movwf temp putStringLoop call fetchChar andlw 0xff ; test Z btfsc STATUS, Z return call putChar incf temp, f movf temp, w goto putStringLoop fetchChar ; Returns retlw data at Program Address w ;---------------------------------------------- movwf PCL ; jump to w RXInteruptHandler ; Handle USART recieve interupts ;---------------------------------------------- movf RCREG, w ; Load recieved char into w movwf char ; char = w ; Test if ignore input btfsc user_flags, UF_IGNORE_NEXT goto RXInteruptHandler_IGNORE_NEXT ; Test if we're started, and want to ignore all data btfss user_flags, UF_STARTED return ; Test if expecting PORTD Data btfsc cmd_flags, CMD_PORTD_DATA goto cmd_portd_data ; Test if AT state change sublw 0x0d ; Test CR btfsc STATUS, Z goto RXInteruptHandler_CR ; Test if AT internal btfsc user_flags, UF_AT goto RXInteruptHandler_AT ; User Command goto RXInteruptHandler_User return RXInteruptHandler_IGNORE_NEXT bcf user_flags, UF_IGNORE_NEXT return RXInteruptHandler_CR btfsc user_flags, UF_AT goto RXInteruptHandler_CR_END ;CR_START bsf user_flags, UF_AT bsf user_flags, UF_IGNORE_NEXT return RXInteruptHandler_CR_END bcf user_flags, UF_AT bsf user_flags, UF_IGNORE_NEXT return RXInteruptHandler_AT ; Handle non-AT input ;---------------------------------------------- movf char, w sublw ',' ; Test Comma btfsc STATUS, Z goto RXInteruptHandler_comma movf char2, w ; 2 Char buffer movwf char1 movf char, w movwf char2 return RXInteruptHandler_comma bsf user_flags, UF_POST_COMMA return ; movlw '0' ; Convert code to single byte ; subwf char1, f ; representation for compare ; subwf char2, f ; swapf char1, w ; addwf char2, w ; movwf char ; sublw 0x01 ; Test for Connection Event ; btfsc STATUS, Z ; goto event_connected ; movf char, w ; Test for Disconnection Event ; sublw 0x23 ; btfsc STATUS, Z ; goto event_disconnected ; ;more tests ; return ; RXInteruptHandler_User ; Handle non-AT input ;---------------------------------------------- movf char, w sublw CMD0_REQUEST_ACK btfsc STATUS, Z ; Request Ack goto cmd_ack_response movf char, w sublw CMD0_START_FLASH btfsc STATUS, Z ; Flash Firmware goto cmd_flash_firmware movf char, w sublw CMD0_TOGGLE_LEDS btfsc STATUS, Z ; Toggle LED's goto cmd_toggle_leds movf char, w sublw CMD0_TOGGLE_LDR_OUTPUT btfsc STATUS, Z ; Toggle LDR Output goto cmd_toggle_ldr movf char, w sublw CMD0_HANGUP_SLEEP btfsc STATUS, Z ; Close BT connection & sleep goto cmd_bluetooth_disconnect_stop movf char, w sublw CMD0_TOGGLE_BEEP btfsc STATUS, Z ; Toggle Annoying buzzer goto cmd_toggle_beep movf char, w sublw CMD0_TOGGLE_COUNT btfsc STATUS, Z ; Toggle Count sequence goto cmd_toggle_count movf char, w sublw CMD1_PORTD_DATA btfsc STATUS, Z ; Expect PORTD Data bsf cmd_flags, CMD_PORTD_DATA return cmd_ack_response ; Respond to request for Acknowledgement ;---------------------------------------------- movlw CMDI0_ACK call putChar return cmd_flash_firmware ; Flash Firmware command ;---------------------------------------------- banksel INTCON ; Disable interupts clrf INTCON pagesel FlashEEPROM goto FlashEEPROM cmd_toggle_leds ; Toggle LED's command ;---------------------------------------------- movlw 00001111b xorwf PORTD, f return cmd_toggle_ldr ; Toggle LDR output command ;---------------------------------------------- movlw 1 << CMD_OUTPUT_LDR xorwf cmd_flags, f return cmd_toggle_beep ; Toggle Annoying loud beep ;---------------------------------------------- movlw 00010000b xorwf PORTD, f return cmd_toggle_count ; Toggle Counting sequence ;---------------------------------------------- movlw 1 << CMD_COUNT xorwf cmd_flags, f return cmd_portd_data ; Load Data to push to PORTD ;---------------------------------------------- bcf cmd_flags, CMD_PORTD_DATA movf char, w movwf PORTD return cmd_bluetooth_disconnect_stop ; Disconnect BT, disable interupts 'n sleep ;---------------------------------------------- banksel INTCON ; Disable interupts clrf INTCON clrf STATUS call command_mode movlw str_hangup & 0xff call putString goto $ Timer0Handler ; Handle Timer overflow interupts ;---------------------------------------------- bcf INTCON, T0IF ; Clear IF, and re-enable bsf INTCON, T0IE decf tmr0_counter, f ;1:8 movf tmr0_counter, w andlw 00000111b btfss STATUS, Z return btfsc cmd_flags, CMD_COUNT call Timer0Handler_count ;1:128 movf tmr0_counter, w andlw 01111111b btfss STATUS, Z return btfsc cmd_flags, CMD_OUTPUT_LDR call Timer0Handler_output_ldr ;1:256 movf tmr0_counter, w btfss STATUS, Z return btfss user_flags, UF_STARTED goto Timer0Handler_start movf user_flags, w andlw (1<