; 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