;******************************************************************* ; PIC_LANC.ASM ; Read & Control Sony Lanc with a PIC ;******************************************************************* ; ; This routine is the beginning of a routine to read and control a ; sony camera by LANC. LANC is a 9600 baud protocol, so the first ; job is to read the LANC at 9600 baud using a 4mhz clock! ; ; for this we will connect the LANC line directly to portA bit 4 ; with a 10K pullup resistor to +5V. ; ; A 4 x 4 multiplexed keypad is connected to port B, with 100 K ; pullups on B 0-3, and 10K in series with each line B4-7. ; ; This is very rough and unpolished. Many mistakes. ; ; -David Meed 96/10/07 ; ; Please feel free to use, modify and distribute to others as ; long as you include a note indicating your sources. I'd love ; to hear about any progress you make. ;******************************************************************* ; Some of the code has been lifted from Microchip's Embedded Control ; Handbook, Application Note AN510: "Implementation of an ; Asynchronous Serial I/O Using PIC 16C5x Microcontrollers" ;******************************************************************* ; Comments to David Meed (dmeed@nbnet.nb.ca) or on CCBBS ; 1994/09/09 ;******************************************************************* ;Edited by Pasi Lassila. Now it works with latest MPLAB and configured ;for PIC16F84A. Start up now works with new pcb and parts. ;pasi.lassila@gmail.com ;******************************************************************* ;******************************************************************* ; Begin code ;******************************************************************* ; Set processor we will be using ; LIST P=16F84A ;original was 16C84 ;****************** PIC16F84A Register Equates ************************ ; ; Standard list of equates for all 16F84A projects ; ;*********************************************************************** ; PIC84 equ 0H ; Define Reset Vectors ; IND0 equ 00h RTCC equ 1h PC equ 2h STATUS equ 3h ; F3 Reg is STATUS Reg. FSR equ 4h ; PORT_A equ 5h PORTA equ 05h porta equ 05h PORT_B equ 6h ; I/O Port Assignments PORTB equ 06h ; I/O register RB portb equ 06h ; ; EEDATA equ 8h ; EEADR equ 9h ; PCLATH equ 0AH ; INTCON equ 0BH ; ; OPTN equ 80H ; ; TRISA equ 85h ; TRISB equ 86h ; TRISC equ 87h EECON1 equ 88h ; EECON2 equ 89h ; ; ; ;*********************************************************************** ; ; ; STATUS REG. Bits CARRY equ 0h ; Carry Bit is Bit.0 of F3 C equ 0h DCARRY equ 1h DC equ 1h Z_bit equ 2h ; Bit 2 of F3 is Zero Bit Z equ 2h P_DOWN equ 3h PD equ 3h T_OUT equ 4h TO equ 4h RP0 equ 5h ; RP1 equ 6h ; IRP equ 7h ; ; GIE equ 7h ;16F84A INTCON register bits ADIE equ 6h ;16F84A INTCON register bits RTIE equ 5h ;16F84A INTCON register bits INTE equ 4h ;16F84A INTCON register bits RBIE equ 3h ;16F84A INTCON register bits RTIF equ 2h ;16F84A INTCON register bits INTF equ 1h ;16F84A INTCON register bits RBIF equ 0 ;16F84A INTCON register bits ; _RBPU_ equ 7h ;16F84A OPTION register bits INTEDG equ 6h ;16F84A OPTION register bits RTS equ 5h ;16F84A OPTION register bits RTE equ 4h ;16F84A OPTION register bits PSA equ 3h ;16F84A OPTION register bits PS2 equ 2h ;16F84A OPTION register bits PS1 equ 1h ;16F84A OPTION register bits PS0 equ 0 ;16F84A OPTION register bits ; EEIF equ 4h ;16F84A EECON1 register bits WRERR equ 3h ;16F84A EECON1 register bits WREN equ 2h ;16F84A EECON1 register bits WR equ 1h ;16F84A EECON1 register bits RD equ 0 ;16F84A EECON1 register bits ; ; Same equ 1h same equ 1h w equ 0h ; LSB equ 0h lsb equ 0h MSB equ 7h msb equ 7h ; TRUE equ 1h YES equ 1h FALSE equ 0h NO equ 0h ; ;*********************************************************************** ;*********************************************************************** ; ; Equates for this program ; ;*********************************************************************** ; bits lanc equ 4h ; bit 4 of port A lanc_copy equ 3h ; bit 3 of port a lanc_byte equ 2h ; bit 2 of port a (Debugging output pin) seventh_byte equ 0h ; flag to indicate that this is the 7 of 8 byt command_waiting equ 1h ; flag to indicate command waiting command_tx equ 2h ; flag to indicate ready to transmit command key_pressed equ 3h ; flag to indicate that a key has been pressed key_repeats equ 4h ; flag to indicate that key repeats ; bytes counter equ 0ch ; scratch counter n_bits equ 0dh ; count number of bits for recieve routine recv_reg equ 0eh ; assemble recieved LANC byte here... n_bytes equ 0fh ; keep track of which LANC byte we are on (+1) flag_store equ 10h ; various flags timer equ 11h ; com_byte_1 equ 12h ; byte one of the command to be sent com_byte_2 equ 13h ; byte two of the command to be sent com_sent_ctr equ 14h ; Number of fields to send the command in send_reg equ 15h ; store for byte in transmission key_temp equ 16h ; Temporary key storage key_store equ 17h ; Last key pressed was... key_debounce equ 18h ; Key debounce counter portAtris equ 10h ; Default for Port A I/O pin assignments portAtrislanc equ 00h ; Default for Port A i/o when sending Lanc portBtris equ 0fh ; Default for Port B i/o pin assignments key_0 equ 0h ; Values returned for key presses key_1 equ 1h key_2 equ 2h key_3 equ 3h key_4 equ 4h key_5 equ 5h key_6 equ 6h key_7 equ 7h key_8 equ 8h key_9 equ 9h key_A equ 0Ah key_B equ 0Bh key_C equ 0Ch key_D equ 0Dh key_E equ 0Eh key_F equ 0Fh key_none equ 0FFh ;******************************************************************* ; Main ; ;******************************************************************* ; Program starts here ; ORG 0000 ; Start at 0 ; Start error_ ; on errors, reset all registers from the start... bcf STATUS,RP1 ; bsf STATUS,RP0 ; Must set RP0 to access page 1 movlw portAtris ; Set PortA pins movwf TRISA ; movlw portBtris ; Set PortB pins movwf TRISB ; bcf STATUS,RP0 ; movlw .1 ; Preset some of the key scan movwf key_debounce ; registers movlw 0ffh movwf key_store ; First we want to synchronize our reception. We do this by waiting ; until the lanc line has been held high for at least 1 word time. ; (1352 us. or more) sync_up clrf counter ; clear sync counter to 0 sync_loop btfss PORTA,lanc ; Wait for interframe gap goto sync_up ; This loop takes 6 us, so if the nop ; counter overflows before incfsz counter, same ; a transition on the LANC goto sync_loop ; line, it is the interframe gap.. ; (1530 us) synced clrf n_bytes ; clear byte counter to 0 bcf flag_store,seventh_byte ; byte flag ; Once synchronized we wait for a start bit to show up. wait_strt btfsc PORTA,lanc ; wait for start bit goto wait_strt ; start_bit movlw .15 ; Constant for start bit time (52us) movwf counter ; set counter l1 decfsz counter, same ; loop on counter (3us/loop) goto l1 ; btfsc PORTA,lanc ; check to be sure the bit is still ; low (make sure this is still a ; start bit. goto error_ ; if not, go start again. ; now we are ready to read bit one.. bsf porta,lanc_byte ;debug pin output pulse bcf porta,lanc_byte movlw .8 ; 8 bits movwf n_bits ; wait_bits movlw .15 ; Wait to start of bit time ; (104us/bit, 52 us/half) movwf counter ; set counter l2 decfsz counter, same ; loop on counter (3us/loop) goto l2 ; ; Now we are ready to decide whether to read or send a ; character in this bit time. ; At this point if we have a command, it is waiting to ; send in Send_reg. Just have to send it one bit at ; a time if the command_tx flag is set bsf porta,lanc_byte ;debug pin output pulse bcf porta,lanc_byte send_bit btfss flag_store, command_tx ; ready to send? goto wait_half btfss send_reg,lsb goto send_0 send_1 bcf porta,lanc bsf STATUS,RP0 ; Must set RP0 to access page 1 movlw portAtrislanc ; Set PortA pins movwf TRISA ; to allow Lanc to be asserted low bcf STATUS,RP0 ; Wait for inputs to charge nop ; Synchronize both branches goto sent_bit send_0 bsf porta,lanc bsf STATUS,RP0 ; Must set RP0 to access page 1 movlw portAtris ; Set PortA pins movwf TRISA ; to allow Lanc to be pulled high bcf STATUS,RP0 ; Wait for inputs to charge nop nop sent_bit rrf send_reg,same ; rotate to position next bit movlw .10 ;allow for time used in sending bit goto jump_half ; (15us on tx code...) wait_half movlw .14 ; Wait till centre of bit time ; (52us) jump_half movwf counter ; set counter l3 decfsz counter, same ; loop on counter (3us/loop) goto l3 ; ; now we are ready to read the next bit read_bits rrf recv_reg,same ; bcf recv_reg,msb ; clear msb receive register btfss PORTA,lanc ; test lanc bit bsf recv_reg,msb ; and set msb if set ; note that we are inverting the bit ; here - +5v becomes 0 and ; +0v becomes 1. bsf porta,lanc_byte ;debug pin output bcf porta,lanc_byte decfsz n_bits,same ; continue to read bits until we have goto wait_bits ; received 8 bits wait_stop movlw .14 ; Wait to end of bit time ; (104us/bit, 52 us/half) movwf counter ; set counter l4 decfsz counter, same ; loop on counter (3us/loop) goto l4 ; bsf porta,lanc_byte ;debug pin output pulse bcf porta,lanc_byte send_stop btfss flag_store, command_tx ; ready to send? goto wait_half_stop bsf porta,lanc bsf STATUS,RP0 ; Must set RP0 to access page 1 movlw portAtris ; Set PortA pins movwf TRISA ; to allow Lanc to be pulled high bcf STATUS,RP0 ; bcf flag_store,command_tx ; Cancel tx,--all sent movlw .11 ;allow for time used in sending bit goto jump_half_stop ; (8us on tx code...) wait_half_stop movlw .14 ; Wait till centre of bit time ; (52us) jump_half_stop movwf counter ; set counter l5 decfsz counter, same ; loop on counter (3us/loop) goto l5 ; ; now we are ready to read the next bit ; now we are ready to read the stop bit read_stop btfss PORTA,lanc ; test lanc bit goto error_ ; if not set we have a framing error bsf porta,lanc_byte ;debug pin output bcf porta,lanc_byte ; now we have received the whole byte - in recv_reg. count ; Count is where we set up certain actions, depending on ; which byte of the string we are looking at. incf n_bytes,same ; increment Lanc byte counter decf n_bytes,w ; decrement/move to W andlw 07h ; mask to prevent overruns on table addwf PC,same ; Jump into table goto check_0 goto check_1 goto check_2 goto check_3 goto check_4 goto check_5 goto check_6 goto check_7 check_0 bsf porta,lanc_byte ;debug pin output bcf porta,lanc_byte btfss flag_store,command_waiting ; Is a command waiting goto end_0 ; to be processed movf com_byte_2,w ; If so, set it up movwf send_reg ; and set the bsf flag_store,command_tx ; command_tx flag end_0 goto wait_strt ; (end_count) check_1 end_1 goto wait_strt ; (end_count) check_2 end_2 goto wait_strt ; (end_count) check_3 end_3 goto wait_strt ; (end_count) check_4 end_4 goto wait_strt ; (end_count) check_5 end_5 goto wait_strt ; (end_count) check_6 end_6 goto wait_strt check_7 clrf n_bytes ; clear byte counter to 0 call Key_Scan ; check if any keys pressed btfsc flag_store,key_pressed ; call Command_Decode ; and take action if so... decfsz com_sent_ctr,same goto mid_7 movlw 01h ; If command times out movwf com_sent_ctr bcf flag_store,command_waiting bcf flag_store,command_tx goto end_7 mid_7 movf com_byte_1,w ; set up for next command movwf send_reg bsf flag_store,command_waiting bsf flag_store,command_tx end_7 goto sync_up ; after last byte, return to top... ;********************************************************************** ; Command_Decode ; Command_Decode takes the value in w and stores ; the appropriate command in com_byte_1 and ; com_byte_2. It sets the command_waiting flag ; and the command_tx flag because the next byte ; needs to have this command transmitted. ; Note that the jump table has to be below 100h ; because it won't work right otherwise... ;********************************************************************** Command_Decode movwf key_temp ; store it andlw 0Fh ; mask w to prevent overrun addwf PC,same ; and jump into table goto command_1D ; 0 goto command_1C ; 1 goto command_1B ; 2 goto command_1A ; 3 goto command_2D ; 4 goto command_2C ; 5 goto command_2B ; 6 goto command_2A ; 7 goto command_3D ; 8 goto command_3C ; 9 goto command_3B ; A goto command_3A ; B goto command_4D ; C goto command_4C ; D goto command_4B ; E goto command_4A ; F ;********************************************************************** ;LANC CODES ;You can change the LANC codes below ;command_XY ; movlw XXh <-- BYTE 0 HEX CODE ; movwf com_byte_1 ; movlw XXh <-- BYTE 1 HEX CODE ; movwf com_byte_2 ; goto end_command ; ; You can also use codes in binary format like 11000010b. ;********************************************************************** command_1A ; this button also works as ON switch by hardware movlw 18h movwf com_byte_1 movlw 5Eh ; power off movwf com_byte_2 goto end_command command_1B movlw 28h movwf com_byte_1 movlw 49h ; WB toggle movwf com_byte_2 goto end_command command_1C movlw 28h movwf com_byte_1 movlw 47h ; focus near movwf com_byte_2 goto end_command command_1D movlw 28h movwf com_byte_1 movlw 04h ; Zoom tele movwf com_byte_2 goto end_command command_2A movlw 28h movwf com_byte_1 movlw 77h ; WB reset movwf com_byte_2 goto end_command command_2B movlw 28h movwf com_byte_1 movlw 51h ; backlight movwf com_byte_2 goto end_command command_2C movlw 28h movwf com_byte_1 movlw 45h ; focus far movwf com_byte_2 goto end_command command_2D movlw 28h movwf com_byte_1 movlw 14h ; Zoom wide movwf com_byte_2 goto end_command command_3A movlw 18h movwf com_byte_1 movlw 9Ah ; Meny movwf com_byte_2 goto end_command command_3B movlw 18h movwf com_byte_1 movlw 11000010b ; Meny right (in binary) movwf com_byte_2 goto end_command command_3C movlw 28h movwf com_byte_1 movlw 41h ; Focus auto/manual movwf com_byte_2 goto end_command command_3D movlw 28h movwf com_byte_1 movlw 61h ; Shutter movwf com_byte_2 goto end_command command_4A movlw 18h movwf com_byte_1 movlw 84h ; Meny up movwf com_byte_2 goto end_command command_4B movlw 18h movwf com_byte_1 movlw 86h ; Meny down movwf com_byte_2 goto end_command command_4C movlw 28h movwf com_byte_1 movlw 53h ; Exposure movwf com_byte_2 goto end_command command_4D movlw 18h movwf com_byte_1 movlw 33h ; Rec/Stb movwf com_byte_2 goto end_command end_command movlw 04h ;send byte over five fields movwf com_sent_ctr return ;********************************************************************** ; Key_Scan ; Key_Scan returns the value of the key pressed in W. ; Key_Pressed flag is set if any key is pressed, ; cleared if no key has been pressed. ; Normally returns one key for each press, but some ; keys autorepeat by returning a key_pressed as ; long as the key is held down. ;********************************************************************** Key_Scan ; return the value of the key pressed in W. bcf flag_store,key_pressed ; clear flag scan_1 movlw 0E0h ; Set scan line 1 low movwf PORTB nop ; wait for row precharge nop comf PORTB,w ; get port b/invert it at the same time andlw 0fh ; mask low nibble btfsc STATUS,Z ; and see if any buttons are pressed goto scan_2 bsf porta,lanc_byte ;debug pin output bcf porta,lanc_byte movwf key_temp ; store in temp btfsc key_temp,0 ; Column 0 Pressed goto key_press_0 btfsc key_temp,1 ; goto key_press_1 btfsc key_temp,2 goto key_press_2 btfsc key_temp,3 goto key_press_3 scan_2 movlw 0D0h ; Set scan line 2 low movwf PORTB nop ; wait for row precharge nop comf PORTB,w ; get port b/invert it at the same time andlw 0fh ; mask low nibble btfsc STATUS,Z ; and see if any buttons are pressed goto scan_3 bsf porta,lanc_byte ;debug pin output bcf porta,lanc_byte movwf key_temp ; store in temp btfsc key_temp,0 ; Column 0 Pressed goto key_press_4 btfsc key_temp,1 ; goto key_press_5 btfsc key_temp,2 goto key_press_6 btfsc key_temp,3 goto key_press_7 scan_3 movlw 0B0h ; Set scan line 3 low movwf PORTB nop ; wait for row precharge nop comf PORTB,w ; get port b/invert it at the same time andlw 0fh ; mask low nibble btfsc STATUS,Z ; and see if any buttons are pressed goto scan_4 bsf porta,lanc_byte ;debug pin output bcf porta,lanc_byte movwf key_temp ; store in temp btfsc key_temp,0 ; Column 0 Pressed goto key_press_8 btfsc key_temp,1 ; goto key_press_9 btfsc key_temp,2 goto key_press_A btfsc key_temp,3 goto key_press_B scan_4 movlw 070h ; Set scan line 4 low movwf PORTB nop ; wait for row precharge nop comf PORTB,w ; get port b/invert it at the same time andlw 0fh ; mask low nibble btfsc STATUS,Z ; and see if any buttons are pressed goto scan_done bsf porta,lanc_byte ;debug pin output bcf porta,lanc_byte movwf key_temp ; store in temp btfsc key_temp,0 ; Column 0 Pressed goto key_press_C btfsc key_temp,1 ; goto key_press_D btfsc key_temp,2 goto key_press_E btfsc key_temp,3 goto key_press_F scan_done bcf flag_store,key_repeats ;if no key pressed, no key to repeat movlw key_none ; and value for no key is defined goto debounce key_press_0 bsf flag_store,key_repeats movlw key_0 goto debounce key_press_1 bsf flag_store,key_repeats movlw key_1 goto debounce key_press_2 bsf flag_store,key_repeats movlw key_2 goto debounce key_press_3 bcf flag_store,key_repeats movlw key_3 goto debounce key_press_4 bsf flag_store,key_repeats movlw key_4 goto debounce key_press_5 bsf flag_store,key_repeats movlw key_5 goto debounce key_press_6 bcf flag_store,key_repeats movlw key_6 goto debounce key_press_7 bcf flag_store,key_repeats movlw key_7 goto debounce key_press_8 bcf flag_store,key_repeats movlw key_8 goto debounce key_press_9 bcf flag_store,key_repeats movlw key_9 goto debounce key_press_A bsf flag_store,key_repeats movlw key_A goto debounce key_press_B bsf flag_store,key_repeats movlw key_B goto debounce key_press_C bcf flag_store,key_repeats movlw key_C goto debounce key_press_D bcf flag_store,key_repeats movlw key_D goto debounce key_press_E bcf flag_store,key_repeats movlw key_E goto debounce key_press_F bsf flag_store,key_repeats movlw key_F goto debounce debounce movwf key_temp ;store key subwf key_store,w ; compare with old key btfsc STATUS,Z ; If same then check repeating goto repeating ; not the same key decfsz key_debounce ; is it debounced yet? goto end_scan ; if not then skip it for this time ; debounce time is up, and this is a ; different key, so reset debounce ; and store the new key value. movlw .3 ; 3 x 16.67ms = 50 ms debounce movwf key_debounce movf key_temp,w ; get key and movwf key_store ; store new key value sublw key_none ; if it is not key_none then btfss STATUS,Z ; set the key_pressed flag bsf flag_store,key_pressed ; goto end_scan ; and return repeating btfss flag_store,key_repeats ;if key doesn't repeat goto end_scan ; then we're done bsf flag_store,key_pressed ; else set it as newly pressed end_scan movf key_temp,w ; get key in W return ; and return END