;zoomer.asm - LANC controller - many zoom speeds, start/stop ; ;assumes this hardware config: ;16C55, RA0 = LANC in/out ; RA1 = sending LED ; RA2 = wakeup (?) ; RA3 = start/stop 18/33 ; RB0 = focus near 47 ; RB1 = focus far 45 ; RB2 = zoom tele 0 (slowest) ; RB3 = zoom tele 1 ; RB4 = zoom tele 2 ; RB5 = zoom tele 3 ; RB6 = zoom tele 4 ; RB7 = zoom tele 5 ; RC0 = zoom tele 6 (fastest) ; RC1 = zoom wide 0 (slowest) ; RC2 = zoom wide 1 ; RC3 = zoom wide 2 ; RC4 = zoom wide 3 ; RC5 = zoom wide 4 ; RC6 = zoom wide 5 ; RC7 = zoom wide 6 (fastest) LIST P = PIC16C55, n = 66 INCLUDE PIC55 equ 1FFH ; Define Reset Vector Same equ 1 same equ 1 TRIS_READ_LANC equ 00dh ;A0, 2, 3 in - 1 out TRIS_WRITE_LANC equ 00ch ;A2, 3 in - 0,1 out TRIS_READ_SWITCHES equ 0ffh ; all inputs INPUT equ 0 ;bit to use for reading LANC - used 2x OUTPUT equ 0 ;bit to use for writing LANC - used 2x SEND_COMM_LED equ 1 ;set when sending commands - used 4x BIT_TIME equ .31 ;for 4 MHz - used 2x ; on my SONY CCD-TR6, values from 33 to 28 worked - mid range ; is 30 or 31 ;send once masks: ; if bit is set to one, then command will be sent only once per ; button press. If bit is zero, command will be sent continuously ; as long as button is held down once_a EQU B'00001100' once_b EQU B'00000000' once_c EQU B'00000000' ; input masks ; a '1' indicates that that bit should be tested as an input ; output-only or non-switch conected I/O should be zero input_a EQU B'00001100' input_b EQU B'11111111' input_c EQU B'11111111' ;================================================================ ;RAM variables org 08h bit_counter RES 1 ;08 bits_to_send RES 1 ;09 byte_to_write RES 1 ;0a command_byte_1 RES 1 ;0b command_byte_2 RES 1 ;0c byte_number RES 1 ;0d command_pass RES 1 ;0e temp RES 1 ;0f index RES 1 ;10 bitmask RES 1 ;11 port RES 1 ;12 ;RAM bit masks to track whether a command has been sent for a particular ; button push. For send once butttons, will be set to one after ; cmd is sent, and will be cleared when button is scanned as released ; for send repetetive buttons, will be cleared after command is sent ; (and re-cleared after button is released...) sent_a RES 1 ;13 sent_b RES 1 ;14 sent_c RES 1 ;15 ;===================================================================== ORG 0 top goto init_real main call wait_for_interframe ;do all switch reading in the ; 6 ms (4 left after this routine) ; between frames .... this is ; lots of time... each machine cycle is ; 1 us - so we have ~4000 to use... goto scan_switches_real ;ends with 'goto main' ;---------------------------------------------------------------------- ; subroutine call table....since 'call' target must be in first 256 bytes ; but goto can go anywhere wait_for_interframe goto wait_for_interframe_real send_command_5 goto send_command_5_real scan_switches goto scan_switches_real get_command_byte_1 goto get_command_byte_1_real get_command_byte_2 goto get_command_byte_2_real ;----------------------------------------------- ; command functions - these do not need the _return label since they ; execute a goto send_command_5_real at their end ;---------------------------------------------------------------------- ;wait_for_interframe routine ; when called will eat time waiting for a roughly 2 ms idle time on ; LANC - reads INPUT bit of PORTA ; uses byte_number byte_to_write wait_for_interframe_real sync_up movlw 3 movwf byte_to_write ; byte_to_write = 3 clrf byte_number ; byte_number = 0 sync_loop btfss PORTA, INPUT ;if lanc = 1, skip jump goto sync_up ; any lanc = 0 resets counters ; lanc == 1 to get here incfsz byte_number, 1 ; inc low byte of byte_number goto sync_loop ; skip jump if byte_number overflows to 0 decfsz byte_to_write, 1 ; decrement byte_to_write goto sync_loop ; skip jump if --byte_to_write == 0 sync_ed retlw 0 ;return to caller ;-------------------------------------------------------------------- ; send_command_5_real sends command in command_byte_1 and command_byte_2 ; the required 5 times. send_command_5_real bsf PORTA, SEND_COMM_LED ;turn on the 'sending command' LED movlw 5 movwf command_pass sc5_1 call wait_for_interframe ;------------------------------------------------------------------ ; send_command ; waits until bit INPUT of PORTA goes low, then delays ; 1 bit time minus a few cycles, then sends the byte in ; command_byte_1, then waits for INPUT to go low again, then ; sends byte in command_byte_2 ; uses: ; bit_counter, bits_to_send, byte_to_write, byte_number send_command movlw 2 movwf byte_number ;initialize outer loop counter movf command_byte_1, 0 movwf byte_to_write ;put command byte into byte_to_write sc_wait_for_LANC_start movlw TRIS_READ_LANC ; A0 = input, A1 = output tris PORTA sc_wfLs_1 btfsc PORTA, INPUT ;waiting for input port to drop - goto sc_wfLs_1 ;is start bit from camcorder movlw BIT_TIME - 1 ; @ 4 MHz movwf bit_counter sc_wfLs_2 ;each loop = 1.5 us @ 8MHz decfsz bit_counter, 1 goto sc_wfLs_2 sc_write_byte movlw 8 movwf bits_to_send movlw TRIS_WRITE_LANC ; A0 = input, A1 = output tris PORTA sc_write_bit movlw BIT_TIME ;34 loops @ 3 clocks @ 1us each @ 4mhz movwf bit_counter btfsc byte_to_write, 0 ;test bit 0 goto sc_wb_set_1 ;skipped if bit 0 = 0 bsf PORTA, OUTPUT ;clear output bit to 0 goto sc_wb_1 sc_wb_set_1 bcf PORTA, OUTPUT ;set output bit to 1 - sc_wb_1 decfsz bit_counter, 1 goto sc_wb_1 rrf byte_to_write, same decfsz bits_to_send, same goto sc_write_bit movlw TRIS_READ_LANC ; A0 = input, A1 = output tris PORTA decfsz byte_number, same goto sc_byte_2 goto sc_done sc_byte_2 movf command_byte_2, 0 movwf byte_to_write goto sc_wait_for_LANC_start sc_done decfsz command_pass, same goto sc5_1 bcf PORTA, SEND_COMM_LED ;turn off the sending comand LED retlw 0 ;---------------------------- ; scan for pressed switches - open switch is pulled up to be a ; 1 - so any zeros will be pressed switches ; index holds the current bit index to be tested - values are: ; PORTA 0 through 7 (even though PORTA is only 4 bits on the 1655) ; PORTB 8 through 15 ; PORTC 16 through 23 ; ; will test the bit index of the input_X masks to determine if we need ; to test the particular bit as an input, scan_switches_real movlw 7 ;0000 0111 andwf index, 0 ; get low 3 bits of index in w movwf temp ; temp == index & 0x7 incf temp, 1 ; temp == (index & 0x7)+ 1 movlw 1 movwf bitmask ;bitmask = 0000 0001 shift_top_1 decfsz temp, 1 goto do_shift goto end_shift do_shift rlf bitmask, 1 goto shift_top_1 end_shift ;bitmask will now have the correct bit ;set to 1 to use to test in masks movf index, 0 movwf port rrf port, 1 rrf port, 1 rrf port, 1 ;>> 3 movlw 01fh ; 0001 1111 andwf port, 1 ; port == (index & 0xf8)>>3 movlw PORTA ; base address for ports addwf port, 1 ; port == 5, 6, or 7 for port A, B, or C ;test to see if port:bit is a switch input movf bitmask, 0 ; used in all tests W = bitmask btfss port, 1 ;bit 1 == 0 only for portA goto test_input_a btfss port, 0 ;bit 0 == 0 only for port b goto test_input_b test_input_c andlw input_c ;Z = 1 if no match goto test_input_comm test_input_b andlw input_b goto test_input_comm test_input_a andlw input_a test_input_comm btfsc STATUS, Z goto next_index check_bit movf port, 0 ;get port into W movwf FSR ;FSR -> port movf INDF, 0 ;read port *FSR into W andwf bitmask, 0 ; W = W & bitmask ; if Z, then button pressed, else next button btfsc STATUS, Z goto process_button ;got a zero on port, process it ;get here if current port:bit is not pressed ;can clear the bit in the 'sent_X' vars since key ;has been released. (even if not pressed, can clear ;an already cleared bit - no harm) comf bitmask, 0 ; used in all bitclears W = !(bitmask) btfss port, 1 ;bit 1 == 0 only for portA goto clear_sent_a btfss port, 0 ;bit 0 == 0 only for port b goto clear_sent_b clear_sent_c andwf sent_c, 1 ;sent_c = (sent_c & !bitmask) goto clear_sent_comm clear_sent_b andwf sent_b, 1 goto clear_sent_comm clear_sent_a andwf sent_a, 1 clear_sent_comm next_index incf index, 1 movf index, 0 ; W = index movwf temp movlw .24 ; 24 total bits to test subwf temp, 0 ; W = temp - W btfsc STATUS, C ; 1 => no borrow, 0 => borrow ; temp >= 24 temp < 24 clrf index goto scan_switches_real ;----------------------------------------------------------------------- process_button ;test to see if this is a "send once command" movf bitmask, 0 ; used in all tests W = bitmask btfss port, 1 ;bit 1 == 0 only for portA goto test_once_a btfss port, 0 ;bit 0 == 0 only for port b goto test_once_b test_once_c andlw once_c ;Z = 1 if no match goto test_once_comm test_once_b andlw once_b goto test_once_comm test_once_a andlw once_a test_once_comm btfsc STATUS, Z goto send_it ;is not a 'once' command - go do it is_once ;_is_ a send once - have we already ;sent it? movf bitmask, 0 ; used in all tests W = bitmask btfss port, 1 ;bit 1 == 0 only for portA goto test_sent_a btfss port, 0 ;bit 0 == 0 only for port b goto test_sent_b test_sent_c andwf sent_c, 0 ;Z = 1 if no match goto test_sent_comm test_sent_b andwf sent_b, 0 goto test_sent_comm test_sent_a andwf sent_a, 0 test_sent_comm btfss STATUS, Z goto next_index ;is a once that we've already sent mark_as_sent ;is a "send once" ; and we haven't already sent it movf bitmask, 0 ;used in all tests W = bitmask btfss port, 1 ;bit 1 == 0 only for portA goto mark_sent_a btfss port, 0 ;bit 0 == 0 only for port b goto mark_sent_b mark_sent_c iorwf sent_c, 1 ;Z = 1 if no match goto test_sent_comm mark_sent_b iorwf sent_b, 1 goto test_sent_comm mark_sent_a iorwf sent_a, 1 mark_sent_comm send_it movf index, 0 ;get index into W call get_command_byte_1 movwf command_byte_1 movf index, 0 call get_command_byte_2 movwf command_byte_2 call send_command_5 goto main ;-------------------------------------------------------------------- de "BYTE 1 " get_command_byte_1_real addwf PCL, 1 retlw 0x00 ;index = 0, PORTA, bit 0 LANC I/O retlw 0x00 ;1 PORTA, bit 1 output only retlw 0x28 ;2 PORTA, bit 2 toggle backlight 28/51 retlw 0x18 ;3 PORTA, bit 3 start/stop 18/33 retlw 0x00 ;4 PORTA, bit 4 non-existent retlw 0x00 ;5 PORTA, bit 5 non-existent retlw 0x00 ;6 PORTA, bit 6 non-existent retlw 0x00 ;7 PORTA, bit 7 non-existent retlw 0x28 ;8 PORTB, bit 0 focus near 28/47 retlw 0x28 ;9 PORTB, bit 1 focus far 28/45 retlw 0x28 ;10 PORTB, bit 2 zoom tele 0 28/00 retlw 0x28 ;11 PORTB, bit 3 zoom tele 1 28/02 retlw 0x28 ;12 PORTB, bit 4 zoom tele 2 28/04 retlw 0x28 ;13 PORTB, bit 5 zoom tele 3 28/06 retlw 0x28 ;14 PORTB, bit 6 zoom tele 4 28/08 retlw 0x28 ;15 PORTB, bit 7 zoom tele 5 28/0a retlw 0x28 ;16 PORTC, bit 0 zoom tele 6 28/0c retlw 0x28 ;17 PORTC, bit 1 zoom wide 0 28/10 retlw 0x28 ;18 PORTC, bit 2 zoom wide 1 28/12 retlw 0x28 ;19 PORTC, bit 3 zoom wide 2 28/14 retlw 0x28 ;20 PORTC, bit 4 zoom wide 3 28/16 retlw 0x28 ;21 PORTC, bit 5 zoom wide 4 28/18 retlw 0x28 ;22 PORTC, bit 6 zoom wide 5 28/1a retlw 0x28 ;23 PORTC, bit 7 zoom wide 6 28/1c de "BYTE 2 " get_command_byte_2_real addwf PCL, 1 retlw 0x00 ;index = 0, PORTA, bit 0 retlw 0x00 ;1 PORTA, bit 1 retlw 0x51 ;2 PORTA, bit 2 toggle backlight (28/51) retlw 0x33 ;3 PORTA, bit 3 start/stop 18/33 retlw 0x00 ;4 PORTA, bit 4 non-existent retlw 0x00 ;5 PORTA, bit 5 non-existent retlw 0x00 ;6 PORTA, bit 6 non-existent retlw 0x00 ;7 PORTA, bit 7 non-existent retlw 0x47 ;8 PORTB, bit 0 focus near 28/47 retlw 0x45 ;9 PORTB, bit 1 focus far 28/45 retlw 0x00 ;10 PORTB, bit 2 zoom tele 0 28/00 retlw 0x02 ;11 PORTB, bit 3 zoom tele 1 28/02 retlw 0x04 ;12 PORTB, bit 4 zoom tele 2 28/04 retlw 0x06 ;13 PORTB, bit 5 zoom tele 3 28/06 retlw 0x08 ;14 PORTB, bit 6 zoom tele 4 28/08 retlw 0x0a ;15 PORTB, bit 7 zoom tele 5 28/0a retlw 0x0c ;16 PORTC, bit 0 zoom tele 6 28/0c retlw 0x10 ;17 PORTC, bit 1 zoom wide 0 28/10 retlw 0x12 ;18 PORTC, bit 2 zoom wide 1 28/12 retlw 0x14 ;19 PORTC, bit 3 zoom wide 2 28/14 retlw 0x16 ;20 PORTC, bit 4 zoom wide 3 28/16 retlw 0x18 ;21 PORTC, bit 5 zoom wide 4 28/18 retlw 0x1a ;22 PORTC, bit 6 zoom wide 5 28/1a retlw 0x1c ;23 PORTC, bit 7 zoom wide 6 28/1c ;----------------------------------------------------------------------- init_real movlw TRIS_READ_LANC ; A0 = input, A2 = output, A1,3,4,5 input tris PORTA clrf PORTA ; clear output bits to 0 movlw TRIS_READ_SWITCHES tris PORTB movlw TRIS_READ_SWITCHES tris PORTC clrwdt movlw 7 ;tmr0 prescale to 1:256 option movlw 08h movwf FSR clrw wipe_top clrf INDF incf FSR,1 movf FSR, 0 ; W = FSR andlw 01fh ; btfss STATUS,2 goto wipe_top ;=================================================================== ;happy_dance ; let user know we're alive by winking send command LED ; about 2HZ for 6 blinks (maybe 5) happy_dance ;turn on send command to start bsf PORTA, SEND_COMM_LED ;turn on the 'sending command' LED movlw .6 ;6 half-seconds (roughly) ;each TMR0 loop is 66ms x 7 ~ 460ms movwf bit_counter ;run for 3 seconds hd_inner movlw 7 movwf bits_to_send tw0 movf TMR0, 0 ;get timer btfss STATUS,2 goto tw0 ;wait for tmr0 to = 0 tw1 movf TMR0, 0 ;get timer btfsc STATUS,2 goto tw1 ;wait for tmr0 to != 0 decfsz bits_to_send, same goto tw0 ;toggle LED movlw 02h ;flip bit 1 xorwf PORTA, same decfsz bit_counter, same goto hd_inner happy_exit bcf PORTA, SEND_COMM_LED clrf bit_counter clrf bits_to_send goto main ORG 1d0h de "Ed's LANC Zoomer v 1.00 (c)2000 " ;-------------------------------------------------------------------- ORG PIC55 goto top END