; title "rc5tx.asm" ; This is an RC-5 protocol test transmitter. RC-5 is used for Philips remote controls. This device allows to generate any RC-5 code. ; Standard buttons are Volume UP, DOWN and Power. The TX button sends a code set by a bank of 12 DIP switches. ; The system code of the standard buttons is also read from the DIP switches (SW11-15). ; 200529 v0.1 Start project ; 200530 v0.2 Added presleep register ; 200530 v0.3 Implement DIP switch read ; 200530 v1.0 Release ; 200530 v1.1 Forgot the repeat functionality ; 200827 v1.2 Timing (pause from 228 -> 114 ms) ; GPL Copyleft 2020 pic@polonai.se LIST P=16F628A, F=INHX8M #include <p16f628a.inc> __CONFIG _INTRC_OSC_NOCLKOUT & _WDT_OFF & _LVP_OFF & _CP_OFF & _BODEN_OFF ; Equates RESET_V EQU 0x00 ; Address of RESET Vector OSC_FREQ EQU D'4000000' ; Oscillator Frequency is 4 MHz ; Registers SW1 EQU 0x21 ; DIP Switch SW1 SW2 EQU 0x22 ; DIP Switch SW2 BUTTONS EQU 0x23 ; The four buttons COUNT1 EQU 0x24 ; Inner counter for delays COUNT2 EQU 0x25 ; Outer counter for delays PULSE EQU 0x26 ; Pulse counter (could have reused COUNT2) PRESLEEP EQU 0x27 ; Delay for showing toggle LED state before going to sleep FLAGS EQU 0x7F ; Various flags #define IR_OUT PORTA,0 ; Infrared LED output #define SW1SCAN PORTB,0 ; Scan line for DIP SW1 #define SW2SCAN PORTB,1 ; Scan line for DIP SW2 #define TGL PORTB,2 ; Toggle LED (GRN) #define TXLED PORTB,3 ; Transmit LED (RED) #define PWR_L PORTB,4 ; Live "Power" button (system set by DIP switch SW1) #define VOLDN_L PORTB,5 ; Live "Volume Down" button (ditto) #define VOLUP_L PORTB,6 ; Live "Volume Up" button (ditto) #define TX_L PORTB,7 ; Live "Send" button to send the pattern set by the DIP switches #define PWR BUTTONS,4 ; Read "Power" button (system set by DIP switch SW1, read just after interrupt to prevent glitches) #define VOLDN BUTTONS,5 ; Read "Volume Down" button (ditto) #define VOLUP BUTTONS,6 ; Read "Volume Up" button (ditto) #define TX BUTTONS,7 ; Read "Send" button to send the pattern set by the DIP switches #define SW11 SW1,7 ; DIP Switch #1 of SW1, MSB system, RA1 #define SW12 SW1,6 ; DIP Switch #2 of SW1 #define SW13 SW1,4 ; DIP Switch #3 of SW1 #define SW14 SW1,3 ; DIP Switch #4 of SW1 #define SW15 SW1,2 ; DIP Switch #5 of SW1, LSB system #define SW16 SW1,1 ; DIP Switch #6 of SW1, Field bit for extended command code set (64-127) #define SW21 SW2,7 ; DIP Switch #1 of SW2, MSB command (0-63) #define SW22 SW2,6 ; DIP Switch #2 of SW2 #define SW23 SW2,4 ; DIP Switch #3 of SW2 #define SW24 SW2,3 ; DIP Switch #4 of SW2 #define SW25 SW2,2 ; DIP Switch #5 of SW2 #define SW26 SW2,1 ; DIP Switch #6 of SW2, LSB command, RA7 #define TOGGLE FLAGS,0 ; Toggle bit to signify repeated key presses org 0x00 GOTO START org 0x04 ; Interrupt handler BTFSC INTCON,RBIF ; RB Port Change Interrupt GOTO WAKE RETFIE ; If none of the above is true, then just leave the interrupt handler WAKE BCF INTCON,RBIF ; Clear interrupt source MOVLW 0x28 MOVWF PRESLEEP CLRF COUNT1 CLRF COUNT2 ; Restore pre-interrupt conditions MOVLW B'00000001' ; Toggle TOGGLE flag XORWF FLAGS,F MOVFW PORTB ; Read buttons MOVWF BUTTONS BSF SW1SCAN ; Set up scan DIP SW1 (system) NOP ; wait to settle MOVFW PORTA ; Read DIP SW1 MOVWF SW1 BCF SW1SCAN ; Set up scan DIP SW2 (command) BSF SW2SCAN NOP ; wait to settle MOVFW PORTA ; Read DIP SW2 MOVWF SW2 BCF SW2SCAN BTFSS TX ; TX button pressed? GOTO TXDIP ; Yes BTFSS VOLUP ; VOLUP button? GOTO VOL_UP ; Yes BTFSS VOLDN ; VOLDN button? GOTO VOL_DN ; Yes BTFSS PWR ; PWR button pressed? GOTO PWR_BTN ; Yes CALL DELAY133 ; No buttons pressed BCF INTCON,RBIF ; Clear interrupt source (because of debounce glitches) RETFIE PWR_BTN ; Send command code 0x0C (STBY) CALL SENDSYS CALL SEND0 CALL SEND0 CALL SEND1 CALL SEND1 CALL SEND0 CALL SEND0 CALL DELAY66 BCF TXLED BTFSS PWR_L ; PWR button held? GOTO PWR_BTN ; Yes BCF INTCON,RBIF ; Clear interrupt source (because of debounce glitches) RETFIE VOL_UP ; Send command code 0x10 CALL SENDSYS CALL SEND0 CALL SEND1 CALL SEND0 CALL SEND0 CALL SEND0 CALL SEND0 CALL DELAY66 BCF TXLED ; Switch off transmit LED BTFSS VOLUP_L ; VOL+ button held? GOTO VOL_UP ; Yes BCF INTCON,RBIF ; Clear interrupt source (because of debounce glitches) RETFIE VOL_DN ; Send command code 0x11 CALL SENDSYS CALL SEND0 CALL SEND1 CALL SEND0 CALL SEND0 CALL SEND0 CALL SEND1 CALL DELAY66 BCF TXLED ; Switch off transmit LED BTFSS VOLDN_L ; VOL- button held? GOTO VOL_DN ; Yes BCF INTCON,RBIF ; Clear interrupt source (because of debounce glitches) RETFIE TXDIP ; Transmit the pattern set by the DIP switches CALL SENDSYS BTFSS SW21 ; Test for COMMAND bit 5 CALL SEND0 BTFSC SW21 CALL SEND1 BTFSS SW22 ; Test for COMMAND bit 4 CALL SEND0 BTFSC SW22 CALL SEND1 BTFSS SW23 ; Test for COMMAND bit 3 CALL SEND0 BTFSC SW23 CALL SEND1 BTFSS SW24 ; Test for COMMAND bit 2 CALL SEND0 BTFSC SW24 CALL SEND1 BTFSS SW25 ; Test for COMMAND bit 1 CALL SEND0 BTFSC SW25 CALL SEND1 BTFSS SW26 ; Test for COMMAND bit 0 CALL SEND0 BTFSC SW26 CALL SEND1 CALL DELAY66 BCF TXLED ; Switch off transmit LED BTFSS TX_L ; TX button held? GOTO TXDIP ; Yes BCF INTCON,RBIF ; Clear interrupt source (because of debounce glitches) RETFIE ; END Interrupt handler ; Subroutines SENDSYS ; Send the first half of the message BSF TXLED ; Switch on transmit LED BCF TGL ; Clear TOGGLE LED BTFSC TOGGLE ; TOGGLE set? BSF TGL ; Yes, switch on TOGGLE LED CALL SEND1 ; Send preamble first bit BTFSS SW16 ; Test for FIELD bit (preamble second bit or inverted extended command set bit) CALL SEND1 BTFSC SW16 ; Inverted COMMAND bit 6 (NOTE!) CALL SEND0 BTFSS TOGGLE ; Test for TOGGLE bit CALL SEND0 BTFSC TOGGLE CALL SEND1 BTFSS SW11 ; Test for SYSTEM bit 4 CALL SEND0 BTFSC SW11 CALL SEND1 BTFSS SW12 ; Test for SYSTEM bit 3 CALL SEND0 BTFSC SW12 CALL SEND1 BTFSS SW13 ; Test for SYSTEM bit 2 CALL SEND0 BTFSC SW13 CALL SEND1 BTFSS SW14 ; Test for SYSTEM bit 1 CALL SEND0 BTFSC SW14 CALL SEND1 BTFSS SW15 ; Test for SYSTEM bit 0 CALL SEND0 BTFSC SW15 CALL SEND1 RETURN SEND0 ; Send a zero (1.8 ms) MOVLW 0x20 MOVWF PULSE ; Preload pulse counter (32 times) PULSE0 BSF IR_OUT ; Send "high" pulse NOP NOP NOP NOP NOP NOP BCF IR_OUT ; Done send "high" pulse (7 Ás) MOVLW 0x05 MOVWF COUNT1 ; Preload "low" time (20 Ás) PLOW0 DECFSZ COUNT1,F ; Decrement inner counter GOTO PLOW0 NOP ; Done send "low" pulse (21 Ás) DECFSZ PULSE,F ; Decrement pulse counter GOTO PULSE0 ; Done generating pulse train INR0 ; Send first part silent time (0.71 ms) DECFSZ COUNT1,F ; Decrement silent time counter GOTO INR0 MOVLW 0x38 MOVWF COUNT1 ; Preload remaining silent time (0.16 ms) REM0 DECFSZ COUNT1,F ; Decrement silent time counter GOTO REM0 RETURN SEND1 ; Send a one (1.8 ms) INR1 ; Send first part silent time (0.71 ms) DECFSZ COUNT1,F ; Decrement silent time counter GOTO INR1 MOVLW 0x38 MOVWF COUNT1 ; Preload remaining silent time (0.16 ms) REM1 DECFSZ COUNT1,F ; Decrement silent time counter GOTO REM1 MOVLW 0x20 MOVWF PULSE ; Preload pulse count (32 times) PULSE1 BSF IR_OUT ; Send "high" pulse NOP NOP NOP NOP NOP NOP BCF IR_OUT ; Done send "high" pulse (7 Ás) MOVLW 0x05 MOVWF COUNT1 ; Preload "low" time (20 Ás) PLOW1 DECFSZ COUNT1,F ; Decrement inner counter GOTO PLOW1 NOP ; Done send "low" pulse (21 Ás) DECFSZ PULSE,F ; Decrement pulse counter GOTO PULSE1 RETURN ; Done generating pulse train DELAY66 ; Delay 66 ms (114 ms total) MOVLW 0x74 MOVWF COUNT2 DELAY65 DECFSZ COUNT1,F ; Decrement inner counter GOTO DELAY65 ; 512 Ás DECFSZ COUNT2,F ; Decrement outer counter GOTO DELAY65 ; 65.6 ms RETURN DELAY133 ; Delay 0.13 s DECFSZ COUNT1,F ; Decrement inner counter GOTO DELAY133 ; 512 Ás DECFSZ COUNT2,F ; Decrement outer counter GOTO DELAY133 ; 132 ms RETURN START ;Init stuff BCF STATUS,RP0 ; Go to bank 0 BCF STATUS,RP1 ; Go to bank 0 MOVLW 0x07 ; Turn comparators off MOVWF CMCON BSF STATUS,RP0 ; Go to bank 1 MOVLW B'11111110' MOVWF TRISA ; Set port A as all inputs except RA0 MOVLW B'11110000' MOVWF TRISB ; Set RB4-7 as inputs MOVLW B'00000111' MOVWF OPTION_REG ; Weak pullups, prescaler Timer0, 1:256 (0.26ms per count for Timer0) BCF STATUS,RP0 ; Go back to bank 0 ; Enable one interrupt CLRF INTCON ; Reset everything BSF INTCON,RBIE ; Enable RB4-7 port change interrupt BSF INTCON,GIE ; Enable global interrupts ; INIT Registers CLRF SW1 CLRF SW2 CLRF BUTTONS CLRF COUNT1 CLRF COUNT2 CLRF FLAGS ; INIT Ports CLRF PORTB CLRF PORTA WaitForInterrupt MOVLW 0x28 MOVWF PRESLEEP PSLEEP CALL DELAY133 DECFSZ PRESLEEP GOTO PSLEEP BCF TGL ; Switch off Toggle LED SLEEP NOP GOTO WaitForInterrupt ; Do Nothing END