; Casio Digital Camera Remote Control ; Using PIC12C508 ; Copyright (c) 2001 by Andrew Gregory ; ; 16 Jun 2001 - Initial version ; 6 Sep 2001 - Modified to support low battery detection list p=12c508 include __config _IntRC_OSC & _WDT_OFF & _CP_OFF & _MCLRE_OFF ; Inputs '2134v-B-' inpBtn1 equ 6 ; \ inpBtn2 equ 7 ; \__for all buttons, 1=button is down,0=button is up inpBtn3 equ 5 ; / inpBtn4 equ 4 ; / inpBtnValid equ 3 ; 1=button data is valid,0=button data is invalid inpBtnMask equ B'11111000' inpBattOk equ 1 ; 1=battery OK,0=battery low ; LED control commonCathode equ B'00000000' commonAnode equ B'11111111' ledType equ commonAnode buttonLedOn macro ; turn the button LED on if ledType == commonAnode bcf led,7 endif if ledType == commonCathode bsf led,7 endif endm buttonLedOff macro ; turn the button LED off if ledType == commonAnode bsf led,7 endif if ledType == commonCathode bcf led,7 endif endm ; display patterns 1gfedcba (bits 7..0 of the 74595) led_S equ B'01101101' ^ ledType led_t equ B'01111000' ^ ledType led_P equ B'01110011' ^ ledType led_n equ B'01010100' ^ ledType led_d equ B'01011110' ^ ledType led_L equ B'00111000' ^ ledType led_F equ B'01110001' ^ ledType led_AllOn equ B'11111111' ^ ledType led_AllOff equ B'00000000' ^ ledType ; bit numbers for the I/O pins camdata equ 0 ; Pin 7 : Camera TTL serial data out leddata equ 1 ; Pin 6 : Serial data out to LED 74595 inpload equ 2 ; Pin 5 : Parallel load of 74165 (decoder) inpdata equ 3 ; Pin 4 : Serial data in from 74165 ledset equ 4 ; Pin 3 : Latch of 74595 (set LED display) clock equ 5 ; Pin 2 : Clock of both 74165 and 74595 ; general purpose registers start at 0x07 led equ 0x07 ; 7-seg LED display bits 7-0 = 1gfedcba work equ 0x08 ; update/serialOut routine working storage inputs equ 0x09 ; inputs '2134v-B-' cnt equ 0x0A ; update/serialOut routine bit counter mode equ 0x0B ; current mode previnput equ 0x0C ; previous input data inputcount equ 0x0D ; input count camcmd equ 0x0E ; camera command tenths equ 0x0F ; 0.1sec counter battlow equ 0x10 ; battery low state, latches into low state when low state detected : 0=battery OK,1=battery low zero equ 0x1F ; zero constant ; reset vector org 0x00 reset movwf OSCCAL ; set internal RC calibration movlw B'11011111' ; set timer0 to use internal clock option movlw B'00001000' ; set GP0,1,2,4,5 to be outputs tris GPIO ; initialise the outputs movlw B'00000101' ; Bit 0 : camera data to high movwf GPIO ; Bit 2 : load signal of 74165 to high ; Bit 4 : load signal of 74595 to low ; Bit 5 : clock to low ; initialise variables clrf mode clrf previnput clrf inputcount clrf battlow clrf zero ; turn on all the LEDs for testing movlw led_AllOn call updatew ; delay for 400ms clrf cnt tstloop clrw call delay decfsz cnt,F goto tstloop goto modeOk ; * ; * This mainline continuously reads the buttons and updates the LED display ; * The buttons are debounced by ensuring the button state stays the same for ; * long enough for a counter to reach 256. ; * For debouce of 0.1s (100,000us), each of the 256 loops should take about ; * 390us. The update takes 123us, so a delay of about 267us is required. ; * main movlw 0x2C ; delay for 268us call delay call update movf inputs,W ; same as the last one? subwf previnput,W btfsc STATUS,Z goto inpsame ; yes movf inputs,W ; no movwf previnput ; - save the button state goto inpdiff ; - and reset the counter inpsame incfsz inputcount,F ; must be the same 256 times in a row goto main incf tenths,F ; 256 loops ~= 0.1sec ; latch battery state to low if it's low btfss inputs,inpBattOk bsf battlow,0 ; LEDs are on if ((inpBtnValid==1) || (battlow==0) || (tenths:bit3 == 1)) ; otherwise they're off. ; This ensures the display is on while a button is held down, but allows ; it to blink (0.8sec on, 0.8sec off) if the battery is low. ; Note that the state of tenths:bit3 is arbitrary - it just needs to change ; at ~0.8sec intervals. movf mode,W call lookupTable movwf led movlw led_AllOff ; default to LEDs all off btfsc inputs,inpBtnValid movf led,W btfss battlow,0 movf led,W btfsc tenths,3 movf led,W movwf led btfsc inputs,inpBtnValid ; skip button handling if not valid goto handleButton inpdiff clrf inputcount goto main ; * ; * Button handling ; * handleButton buttonLedOn call update ; Check the button state movf inputs,W ; mask the inputs so only button data remains andlw inpBtnMask movwf inputs movlw (1 << inpBtn1) | (1 << inpBtnValid) ; button 1? subwf inputs,W btfsc STATUS,Z goto hdlbtn1 movlw (1 << inpBtn2) | (1 << inpBtnValid) ; button 2? subwf inputs,W btfsc STATUS,Z goto hdlbtn2 movlw (1 << inpBtn3) | (1 << inpBtnValid) ; button 3? subwf inputs,W btfsc STATUS,Z goto hdlbtn3 movlw (1 << inpBtn4) | (1 << inpBtnValid) ; button 4? subwf inputs,W btfsc STATUS,Z goto hdlbtn4 goto waitbr ; no valid buttons (could be multiple buttons) - wait for them to be released hdlbtn1 movlw 0x01 goto sendCommand hdlbtn2 movlw 0x02 goto sendCommand hdlbtn3 movlw 0x03 goto sendCommand hdlbtn4 ; change modes movlw modeEntrySize ; increment mode by the size of a mode entry addwf mode,F movlw modeTableSize ; if the mode is now equal to the size of the table subwf mode,W btfsc STATUS,Z clrf mode ; reset it back to zero modeOk ; display current mode movf mode,W call lookupTable movwf led buttonLedOn goto waitbr sendCommand addwf mode,W call lookupTable ; W now has the camera command movwf camcmd movf camcmd,F ; if camcmd==0 then skipSend btfsc STATUS,Z goto skipSend movf camcmd,W call serialOut ; send to camera btfss camcmd,7 ; if camcmd.bit7==0 then skipWait goto skipWait skipSend call update ; wait for button release (i.e. become invalid) btfsc inputs,inpBtnValid goto skipSend skipWait movf camcmd,F ; if camcmd==0 then buttonDone btfsc STATUS,Z goto buttonDone movf camcmd,W iorlw 0x20 ; make command lowercase call serialOut ; send to camera btfsc camcmd,7 ; if camcmd.bit7==1 then buttonDone goto buttonDone waitbr call update ; wait for button release (i.e. become invalid) btfsc inputs,inpBtnValid goto waitbr buttonDone buttonLedOff goto main ; * ; * Send LED data via the 74595 and read the button inputs via the 74165. ; * Shifts button data into the work byte at the same time it shifts LED data out. ; * The 74595 shifts data into the Q0 output first. This means that the final Q0 ; * value has to be shifted out *last*. Therefore the LED data is shifted MSB first. ; * The 74165 shifts data out of Q7 first. Therefore the button data is shifted MSB ; * first also. ; * ; * (execution time, including originating CALL = 123us) ; * update movf led,W updatew movwf work bcf GPIO,inpload ; pulse parallel load of 74165 low to latch input states bsf GPIO,inpload movlw 0x08 movwf cnt updtloop clrw ; read current input state bit into the carry btfss GPIO,inpdata movlw 0x01 subwf zero,W rlf inputs,F ; and rotate into inputs data file register rlf work,F ; rotate the next LED data bit into the carry bcf GPIO,leddata ; and set data line with it btfsc STATUS,C bsf GPIO,leddata bsf GPIO,clock ; pulse the clock bcf GPIO,clock decfsz cnt,F ; loop again if more to do goto updtloop bsf GPIO,ledset ; pulse output latch of 74595 high to update LED display bcf GPIO,ledset retlw 0x00 ; * ; * Send the character in W as RS-232 serial at 9600 baud, 8 data bits, 1 stop bit, no parity. ; * TTL is normally one, the start bit is a zero, the stop bit a one. ; * Bit 0 (LSB) is sent first. ; * ; * Timing is critical. The numbers in the comments show the number of ; * microseconds (instruction cycles) to the next bit transmission. There ; * should be 104us between bits. ; * serialOut movwf work ; work = W & 127 bcf work,7 movlw 0x08 movwf cnt bcf GPIO,camdata ; 0/ 0 <--- start bit movlw 0x0F ; 103/103 <--- 94us call delay ; 102/102 soutloop call shrtdly ; 8/ 8 <--- 4us rrf work,F ; 4/ 4 <--- LSB first btfsc STATUS,C ; 3/ 3 goto out1 ; **/ 2 out0 nop ; 1/ ** bcf GPIO,camdata ; 0/ ** goto outwait ; 103/ ** out1 bsf GPIO,camdata ; **/ 0 goto outwait ; **/103 outwait movlw 0x0E ; 101/101 <--- 88us call delay ; 100/100 nop ; 12/ 12 decfsz cnt,F ; 11/ 11 <--- loop again if more to do goto soutloop ; **/ 10 call shrtdly ; 9 <--- 4us call shrtdly ; 5 <--- 4us nop ; 1 bsf GPIO,camdata ; 0 <--- stop bit ; delay for 50ms to ensure a good stop bit and to ensure any subsequent ; characters aren't sent too soon for the camera movlw 0x20 movwf cnt sbloop clrw call delay decfsz cnt,F goto sbloop retlw 0x00 ; 2 ; * ; * Delay for (6W+4)us (if W=0, then pretend W=256) (10..1540us), including the CALL to it. ; * ; * Comments show times through the loops ; * delay movwf zero ; 2 <-- starts at 2 because of originating CALL dlyloop nop ; 3 / 9 / 15 / etc nop ; 4 / 10 nop ; 5 / 11 decfsz zero,F ; 6 / 12 goto dlyloop ; * Short delay (4us) entry point shrtdly retlw 0x00 ; 8 / 14 ; 10 / 16 <--- instruction cycle count upon return ; * ; * Command mode table ; * numberOfModes equ 0x07 modeEntrySize equ 0x04 modeTableSize equ numberOfModes * modeEntrySize lookupTable addwf PCL,F modeTable dt led_S, 'B' , 'A' , 'B' | 0x80 ; S - shutter, focus lock, held shutter dt led_t, 'P' , 'D' | 0x80, 'C' | 0x80 ; t - timer, tele, wide dt led_P, 'N' , 'H' , 'I' ; P - mode, right, set dt led_n, 'E' , 'J' , 'I' ; n - menu, down, set dt led_d, 'Q' | 0x80, 'O' , 0 ; d - preview, display dt led_L, 'K' , 'F' , 'J' ; L - flash, up, down dt led_F, 'L' , 'G' , 'H' ; F - focus, left, right end