program CHDK3Sw '* Author : Stuart Robinson '* Notice : Copyright (c) 2011. All Rights Reserved '* : Free to use for non non commercial or non business purposes only '* : If you choose to use it, don't expect free support '* '* Date : 05/02/2011 '* Version : 1.4 for 12F683, 3 switch position version '* '* Notes : This program reads a RC pulse of nominal 1ms to 2ms and converts it to USB Power pulses for CHDK '* : Pulses outside limits are ingored and flaged as errors via RS232 and morse audio '* : Stuck low, high and stuck pulse conditions are detected with approx 127ms timeout '* : Pulses that are too short and too long are also detected '* : Uses PIC internal RC 4Mhz oscillator, accurate to 1% '* : RC +5v to VDD, pin 1, RC 0v to VSS, pin 8 '* : RC Pulse read on GPIO.4, pin 3 '* : USB for camera +5v on GPIO.1, pin 6 '* : USB for camera +0v on VSS, pin 8 '* : Sends RS232 debug to serial port, GPIO.5 is TX '* : RS232 UART is set to 2400, 8, n, 1 '* : Simple serial lead for 25 pin D PC connector, connect interface gnd to pin 7 and '* : a 1K2 resistor in series with GPIO.5(TX) to pin 3 '* : For RX (not used here) you need a 24K resistor in series with pin 2 '***************************************************************************** 'Start morse parameters const perioddit as byte = 30 'lenght of one dot, this controls the speed of the morse const perioddah as word = (perioddit*3) 'lenght of one dah const period0 as word = (perioddit*3) 'lenght between dahs and dits const period1 as word = (perioddit*8) 'gap between characters const freq as word = 750 'sets freq for pulse ip to radio 'encoded constants for morse characters const morse_e as byte = $01 const morse_h as byte = $04 const morse_k as byte = $2b const morse_l as byte = $14 const morse_o as byte = $3b const morse_p as byte = $34 const morse_s as byte = $03 const morse_0 as byte = $fd const morse_1 as byte = $f5 const morse_2 as byte = $e5 const morse_3 as byte = $c5 dim bits as byte 'number of bits to send dim numchars as byte 'loop counter dim beepcount as byte 'length of beep (dit) 'End morse parameters dim pulsewidth as word 'timeout measured width of Channel 1 RC input pulse dim switchnow as byte 'used to store the current RC decode dim lastusb as byte 'used to store the last USB power pulse type sent, only changes in input pulse result in a USB power pulse dim switchlast as byte 'records the last switch value decoded dim switchcount as byte 'the number of same switch decodes in a row dim num as byte 'used in printword routine dim remainder as word const P1low as word = 750 'below this and pulse not valid P1High as word = 1250 'max width of RC Switch 1 pulse P2Low as word = 1350 'min width of RC Switch 2 pulse P2High as word = 1650 'max width of RC Switch 2 pulse P3Low as word = 1750 'min width of RC Switch 3 pulse P3High as word = 2250 'max width of RC Switch 3 pulse switchvalid as byte = 4 'one less han number of switches decodes in a row required for valid switch adjust as byte = 0 'value to add to pulse to fine tune pulse width pulseshort as word = 500 pulselong as word = 3000 '***************************************************************************** '* Morse Routines, Sends a character as morse, piezo sounder or radio assumed '***************************************************************************** sub procedure senddit() 'this is used for sending dits and dahs goes to piezo (or radio) for beepcount = 1 to perioddit delay_us(freq) gpio.2 = 1 'piezo output delay_us(freq) gpio.2 = 0 next beepcount end sub sub procedure sendmorse(dim character as byte) 'send a morse character bits = character AND %00000111 'isolates bottom 3 bits character = character >> 2 'shift bits to send to .1 to .5 for numchars = 1 to bits character = character >> 1 'shift the bit to send into character.0 if character.0 = 1 then 'send a dah = 3 dits senddit() senddit() senddit() else senddit() end if delay_ms(period0) 'delay between dits and dahs next numchars delay_ms(period1) 'pause for period between characters end sub '***************************************************************************** '* General Routines '***************************************************************************** 'general purpose 100ms delay sub procedure delay(dim times as byte) while times > 0 delay_ms(100) times = times - 1 wend end sub sub procedure sendUSB (dim times as byte) gpio.0 = 0 'Start the USB power pulse gpio.1 = 1 delay(times) gpio.0 = 1 gpio.1 = 0 'Stop the USB power pulse end sub sub function convertRC (dim pulsecheck as word) as byte switchnow = 0 'switchnow starts at 0 if (pulsecheck > P1low) AND (pulsecheck < P1high) then result = 1 end if if (pulsecheck > P2low) AND (pulsecheck < P2high) then result = 2 end if if (pulsecheck > P3low) AND (pulsecheck < P3high) then result = 3 end if end sub sub procedure CRLF Soft_Uart_Write($0a) 'send cr lf to uart Soft_Uart_Write($0d) end sub sub procedure printword (dim pword as word) num = pword div 10000 remainder = pword - (num*10000) Soft_Uart_Write($30+num) num = remainder div 1000 remainder = remainder - (num*1000) Soft_Uart_Write($30+num) num = remainder div 100 remainder = remainder - (num*100) Soft_Uart_Write($30+num) num = remainder div 10 remainder = remainder - (num*10) Soft_Uart_Write($30+num) num = remainder Soft_Uart_Write($30+num) Soft_Uart_Write($20) end sub sub procedure pulse(dim state as byte) T1CON.0 = 0 'turn off t1 PIR1.0 = 0 'clear the T1 overflow flag TMR1H=0 'ensure set T1 to 0, note this clears the prescaler TMR1L=0 T1CON.4 = 1 'set prescaler to 1:2, this gives approx 127ms timeout T1CON.6 = 1 'timer 1 gate control active T1CON.7 = state 'set the logic level for the T1 gate control T1CON.0 = 1 'turn on t1 while (gpio.4 = state) AND (PIR1.0 = 0) 'loop till pulse changes or T1 overflows Wend T1con.0 = 0 'turn off t1 end sub '***************************************************************************** '* Main Program '***************************************************************************** main: INTCON = 0 ' disable all ints OPTION_REG.7 = 0 'global Weak pull up enable WPU = %00010000 'weak pull ups on GPIO.4 ADCON0= %00000000 CMCON0 = %00000111 'Comparator off on all IPs and OPs ANSEL = %00000000 'analogue off 'set IO port direction, 1 = input, 0 = output TRISIO = %11011000 gpio.0 = 1 'ensure output pulse is in off state gpio.1 = 0 lastusb = 0 switchcount = 0 soft_uart_init(gpio, 3, 5, 2400, 1) 'init for soft RS232, RX gpio.3 (not used), TX gpio.5 crlf() crlf() soft_uart_Write($43) 'send C Soft_Uart_Write($48) 'send H Soft_Uart_Write($44) 'send D Soft_Uart_Write($4B) 'send K Soft_Uart_Write($20) 'send space Soft_Uart_Write($4f) 'send O Soft_Uart_Write($4B) 'send K sendmorse(morse_O) sendmorse(morse_K) delay(5) 'wait 0.5 seconds loop1: PIE1.0 = 0 'make sure T1 int is off pulsewidth = 0 crlf() pulse(1) 'check for high and wait till it goes low if PIR1.0 = 1 then 'T1 did verflow Soft_Uart_Write($53) 'print SH to indicate T1 overflow Soft_Uart_Write($48) sendmorse(morse_S) 'send SH in morse sendmorse(morse_H) lastusb = 0 delay(20) 'wait a while for another go goto loop1 end if pulse(0) 'pulse is low, so wait for it to go high then measure if PIR1.0 = 1 then 'T1 did verflow, RC pulses should be approx 50Hz, if its timed out pulse has been low for approx 127ms Soft_Uart_Write($53) 'print SL to indicate t1 overflow reading low more than 127ms Soft_Uart_Write($4C) sendmorse(morse_S) 'send SL in morse sendmorse(morse_L) lastusb = 0 delay(20) 'wait a while for another go goto loop1 end if pulse(1) 'pulse has gone from low to high, so measure it if PIR1.0 = 1 then 'T1 did overflow, not a valid pulse Soft_Uart_Write($53) 'print SP to indicate T1 overflow on pulse read, there was a pulse but its stuck high Soft_Uart_Write($50) sendmorse(morse_S) 'send SP in morse sendmorse(morse_P) lastusb = 0 delay(20) 'wait a while for another go goto loop1 end if pulsewidth = (((TMR1H*256) + TMR1L) * 2) + adjust if pulsewidth > pulselong then 'check for pulse too long. Soft_Uart_Write($50) 'ascii P Soft_Uart_Write($4C) 'ascii L sendmorse(morse_P) 'send PL in morse sendmorse(morse_L) lastusb = 0 goto loop1 end if if pulsewidth < pulseshort then 'check for pulse too short Soft_Uart_Write($50) 'ascii P Soft_Uart_Write($53) 'ascii S sendmorse(morse_E) 'send an E in morse, a single dit lastusb = 0 goto loop1 end if Soft_Uart_Write($50) 'ASCII P Soft_Uart_Write($57) 'ASCII W printword(pulsewidth) switchnow = convertRC(pulsewidth) if switchnow = switchlast then 'if two successive same switch decodes then inc by 1 switchcount = switchcount + 1 else switchcount = 0 end if 'record the current switch decode switchlast = switchnow Soft_Uart_Write($53) 'ascii s Soft_Uart_Write($57) 'ASCII W Soft_Uart_Write($30+switchnow) 'ascii switch no. Soft_uart_write($20) if switchnow = 0 then 'do nothing if switchnow = 0 switchcount = 0 goto loop1 end if Soft_Uart_Write($4c) 'ascii l Soft_Uart_Write($53) 'ascii s soft_Uart_Write($30+switchlast) 'last switch value Soft_uart_write($20) 'print count of same switch decode in sequence Soft_Uart_Write($53) 'ascii s Soft_Uart_Write($43) 'ascii c soft_Uart_Write($30+switchcount) 'switchcount value Soft_uart_write($20) if switchcount < switchvalid then 'check if enough pulses recvd in sequence goto loop1 end if 'if here then have received enough switch decodes in sequence 'print out the last USB power pulse sent, i.e. the last valid decode Soft_Uart_Write($4C) 'ascii L Soft_Uart_Write($55) 'ascii U Soft_Uart_Write($53) Soft_Uart_Write($42) soft_Uart_Write($30+lastusb) Soft_uart_write($20) if switchnow <> lastusb then 'if the switch number is different, send the new USB powerpulse if lastusb > 0 then sendUSB(switchnow) Soft_Uart_Write($3E) Soft_Uart_Write($53) Soft_Uart_Write($55) 'write out the sent USB pulse to UART Soft_Uart_Write($53) Soft_Uart_Write($42) Soft_Uart_Write($30+switchnow) 'now send the USB power pulse sent as morse select case switchnow case 1 sendmorse(morse_1) case 2 sendmorse(morse_2) case 3 sendmorse(morse_3) end select end if lastusb = switchnow 'save the number of this USB power pulse being sent end if 'if here valid decode & USB sent, so zero and back to start switchnow = 0 switchlast = 0 switchcount = 0 goto loop1 'read another pulse end.