📄 ir_controller.asm
字号:
;**************************************************************************************************
;********************** Infrared Controller for Klaus Schmidinger's VDR ***************************
;**************************************************************************************************
;
; Author: Thomas Breuer (tb@tb-electronic.de)
; Version: 1.02
; Date: 04 October 2003
;
;
; History:
; V1.02
; Self-synchronizing RC5 receive code which tolerates inaccurate RC5 timings.
;
; V1.01
; Brown out detect deactivated. Some ATX power supplies exhibit a brown out on 5V_stby when turned
; on from standby. PIC will reset and LED will blink red instead of green ...
;
;
; Assembler source code for Microchip PIC16F628
; Compile with Microchip MPASM
;
; Tab distance: 8 spaces
; Width: 100 chrs (for printing, courier 8pt fits on A4 portrait)
;
; instructions: lower case
; labels: lower case
; VARIABLES: UPPER CASE
; Macros: Mixed Case
; Definitions: Mixed Case
;
;
; Some notes on RC5
;
; 14 RC5 bits:
; SSTAAAAACCCCCC
;
; S: 2 start bits, T: 1 toggle bit, A: 5 address bits, C: 6 command bits
;
; Usually both start bits are high. Extended RC5 uses the 2nd start bit for expanding
; the 6 command bits to 7 bits. After receiving a complete 14 bit word, this bit
; is inverted and added as bit 6 to the register 'RC5_CMD'. The toggle bit is
; copied to bit 7 of 'RC5_CMD'. The 5 LSBs of register 'RC5_ADR' contain the
; 5 address bits; the 3 MSBs are set to 0.
;
; Result after a valid code has been received: RC5_ADR: 000AAAAA RC5_CMD: TCCCCCCC
;
; Note that most IR receiver chips (e.g. SFH5110-xx) have an active low output, however, the
; PIC's internal comparator inverts the signal. An inverting driver transistor for the RS232
; interface finally inverts and level shifts the signal again so that the standard LIRC
; configuration (i.e. active low) must be used.
;
;--------------------------------------------------------------------------------------------------
;
; PIC16F628 connections
;
; PIN FUNCTION
;
; RB7 ICSP
; RB6 ICSP
; RA5 ICSP
;
; RB5 TestOut -- debug output for scope (active high)
; RB4 PWRin -- input for PC pwr switch (active low)
; RB3 RESETout -- output to drive transistor for MB reset (active high)
; RB2 PWRout -- output to drive transistor for MB ATX pwr on/off (active high)
; RB1 LEDgrn -- output for bicolor LED green anode (active high)
; RB0 LEDred -- output for bicolor LED red anode (active high)
;
; RA7 4.000 MC crystal
; RA6 4.000 MC crystal
;
; RA4 (unused)
; RA3 comparator C1 output -- transistor base drive for RS232 TX
; RA2 (internally connected to Vref = 1.25 volts)
; RA1 ATXin -- comparator C2 inverting input for sensing -5 volts of ATX power supply
; RA0 IRin -- comparator C1 inverting input for IR receiver chip
;
;--- Configuration --------------------------------------------------------------------------------
;
; PIC16F628, Power up timer, no watchdog, HS-oscillator, *no* brown out detect, LVP off, CP off,
; MCLRE off, f = 4MHz
list p=16f628
__CONFIG _pwrte_on & _wdt_off & _hs_osc & _boden_off & _lvp_off & _cp_off & _mclre_off
include "p16f628.inc"
;--- Variables [all UPPER CASE] -------------------------------------------------------------------
cblock h'20'
DATA_1 ; 16-bit shift register for incoming RC5 bits
DATA_2 ;
DATA_TMP1 ; temporary register for RC5 codes
DATA_TMP2 ; temporary register for RC5 codes
BITCOUNT ; counter for the RC5 bits
COUNT ; universal temporary count register
TMP ; universal temporary registers
TMP1 ;
TMP2 ;
RC5_ADR ; received RC5 address after clean up: '000AAAAA'
RC5_CMD ; received RC5 command after clean up: '0CCCCCCC'
RC5_CMD_TMP ; temporary register for RC5 command
RC5_CMD_TMP_1 ; temporary register for RC5 command
KEYCOUNT ; counts the incoming RC5 pwr-key packets to set up a delay
KEYCOUNT_1 ; counts the incoming RC5 0-key packets to set up a delay
RC5_TX_1 ; 16-bit shift register for outgoing RC5 bits
RC5_TX_2 ;
EEADR_TMP ; holds the EEPROM address when calling the EEPROM write subroutine
EEDATA_TMP ; holds the EEPROM data when calling the EEPROM write subroutine
PWR_ON_DELAY ; 00...99 (recalled from EEPROM location h'00')
PWR_KEY_ADR ; assigned RC5 pwr key address '000AAAAA' (recalled from EEPROM location h'01')
PWR_KEY_CMD ; assigned RC5 pwr key command '0CCCCCCC' (recalled from EEPROM location h'02')
D1 ; temporary registers for delay routines
D2 ;
D3 ;
FLAGS ; flags, see definitions
endc
;--- EEPROM default data --------------------------------------------------------------------------
org h'2100'
; adr content
de d'45' ; h'00' PWR_ON_DELAY
de b'00000101' ; h'01' PWR_KEY_ADR
de b'00001100' ; h'02' PWR_KEY_CMD
;--- Definitions [all Mixed Case] -----------------------------------------------------------------
#define ATX_C_out cmcon,7 ; comparator 2 output
#define IRin porta,0 ; input for IR receiver chip (active low)
#define IRinTris trisa,0 ; tris register bit for IRin
#define IR_C_out cmcon,6 ; comparator 1 output
#define LEDred portb,0 ; output for bicolor LED red anode
#define LEDgrn portb,1 ; output for bicolor LED green anode
#define PWRout portb,2 ; output to drive transistor for MB ATX pwr on/off
#define RESETout portb,3 ; output to drive transistor for MB reset
#define PWRin portb,4 ; input for PC pwr switch
#define TestOut portb,5 ; debug output for scope
#define TurnOnDelay d'9' ; turn on delay when pressing remote pwr key to
; wake up from standby (9 makes approx. one second)
#define RebootDelay d'15' ; additional reboot delay (in seconds)
#define RC5_Flag FLAGS,0 ; 0: RC_5 code valid, 1: RC_5 code invalid
#define Reboot_Flag FLAGS,1 ; 0: normal boot delay, 1: additional delay needed
;--- Macros [all Mixed Case] ----------------------------------------------------------------------
Bank_0 macro
bcf status,5
bcf status,6
endm
Bank_1 macro
bsf status,5
bcf status,6
endm
Test macro
bsf TestOut
bcf TestOut
endm
LED_red macro
bsf LEDred
bcf LEDgrn
endm
LED_grn macro
bsf LEDgrn
bcf LEDred
endm
LED_off macro
bcf LEDred
bcf LEDgrn
endm
;--- Reset ----------------------------------------------------------------------------------------
org h'00'
goto init ; reset -> init
;--- Interrupt ------------------------------------------------------------------------------------
org h'04'
goto init ; no interrupt
;**************************************************************************************************
; Initialization
;**************************************************************************************************
init
; configuration of porta and portb ----------------------------------------------------------------
Bank_0
clrf porta ; clear porta register
clrf portb ; clear portb register
Bank_1
movlw b'00000111' ; RA0...RA2 input, RA3...RA7 output
movwf trisa
movlw b'00010000' ; RB0...RB3 output, RB4 input, RB5...RB7 output
movwf trisb
bcf option_reg,7 ; enable portb weak pullups
Bank_0
; configuration of analog comparators -------------------------------------------------------------
movlw b'00000110' ; two common reference comparators with outputs
movwf cmcon
Bank_1
movlw b'11100110' ; Vref = 1.25 volts, connected to RA2
movwf vrcon
Bank_0
; timer0 ------------------------------------------------------------------------------------------
Bank_1
movlw b'01000000' ; timer0 internal clock, prescaler 1:2, enable portb weak pullups
movwf option_reg ;
Bank_0
; timer1 ------------------------------------------------------------------------------------------
movlw b'00110001' ; prescaler = 8, internal clock, enabled
movwf t1con
;**************************************************************************************************
; Main program
;**************************************************************************************************
start
clrf FLAGS ; clear all flags
call copy_ee ; copy default eeprom values to RAM registers
main_loop
btfsc ATX_C_out ; check if ATX is standby
goto green ; on --> LED green
LED_red ; standby --> LED red
goto pwr_sw
green
LED_grn
pwr_sw
btfss PWRin ; test PWRin (active low)
goto pwr_sw_1 ; if low goto pwr_sw_1
btfss IR_C_out ; wait for high level at IR_C_out
goto main_loop ;
call rc5_rx ; call rc5_rx subroutine
btfsc RC5_Flag ; RC5 code OK?
goto main_loop ; no, goto main_loop
LED_off ; turn off green LED for 50ms each time a valid code
call delay_t4 ; has been received
LED_grn
pwr_key ; check if pwr key of remote control is pressed
movfw RC5_ADR ; load RC5_ADR into w
subwf PWR_KEY_ADR,w ;
btfss status,z ; does PWR_KEY_ADR match?
goto no_match ; - no, goto no_match
;
movfw RC5_CMD ; - yes, load RC5_CMD into w
andlw b'01111111' ; and clear toggle bit
subwf PWR_KEY_CMD,w ;
btfss status,z ; does PWR_KEY_CMD match?
goto no_match ; - no, goto no_match
;
movfw RC5_CMD_TMP ; - yes, toggle bit also unchanged?
subwf RC5_CMD,w ;
btfss status,z ;
goto no_match ; - no, goto no_match
;
btfsc ATX_C_out ; activate PWRout only if ATX is standby to power up PC
goto vdr_pwr_down ; if on, VDR's shutdown script will turn off PC
; ATX is standby, now check if pwr key of remote control is
; pressed long enough (approx. TurnOnDelay * 114ms)
incf KEYCOUNT,f ; - yes, unchanged, increment KEYCOUNT
movfw KEYCOUNT ;
sublw TurnOnDelay ; if reached TurnOnDelay, activate PWRout
btfss status,z
goto cont
bsf PWRout ; activate PWRout for 250ms
call delay_t6
bcf PWRout
goto boot_delay ; and goto boot_delay
no_match
clrf KEYCOUNT ; clear KEYCOUNT
cont
movfw RC5_CMD ; copy RC5_CMD to temporary register
movwf RC5_CMD_TMP ; for next toggle bit comparison
zero_key ; check if 0 key on remote control is pressed
; at least 44 * 114ms (RC5 code repetition rate) = approx. 5s
movfw RC5_CMD ; load RC5_CMD into w
andlw b'01111111' ; and clear toggle bit
btfss status,z ; does O key (command '0000000', any address) match?
goto no_match_1 ;
movfw RC5_CMD_TMP_1 ; toggle bit also unchanged?
subwf RC5_CMD,w ;
btfss status,z ;
goto no_match_1 ; - no, has changed
incf KEYCOUNT_1,f ; - yes, unchanged, increment KEYCOUNT_1
movfw KEYCOUNT_1 ;
sublw d'44' ;
btfss status,z ; reached 44 (approx. 5s)?
goto cont_1 ; - no, loop
goto pgm_or_reboot ; - yes, goto pgm_or_reboot
no_match_1
clrf KEYCOUNT_1 ; clear KEYCOUNT_1
cont_1
movfw RC5_CMD ; copy RC5_CMD to temporary register
movwf RC5_CMD_TMP_1 ; for next toggle bit comparison
goto main_loop
pgm_or_reboot
btfss ATX_C_out
goto pgm_mode ; PC is in standby --> enable program mode
LED_red ; turn LED red to indicate that reboot has been initialized
movlw h'1f' ; set address to h'1f'
movwf RC5_TX_2 ;
movlw h'3f' ; set command to h'3f'
movwf RC5_TX_1 ; This combination is not used by the remote control. Suitable
; entries in lircd.conf and lircrc call a reboot script via irexec
call rc5_tx
bsf Reboot_Flag ; set Reboot_flag so that additional delay for green LED flashing
goto boot_delay ; will be added and goto boot_delay
; ------------------------------------------------------------------------------------------------
pwr_sw_1 ; checks if pwr switch of PC is pressed for less or more than
; 5 seconds: if less --> power on/off, if more --> reset
call delay_t4 ; 50ms delay
btfsc PWRin ; still low after 50ms?
goto main_loop ; if not, assume spike and goto main_loop
btfss ATX_C_out ; ATX on or standby?
goto turn_on ; standby, a reset would be quite useless, so turn on VDR
clrf tmr1h ; clear timer1 registers
clrf tmr1l ;
movlw d'19' ; set COUNT to d'19', this makes approx. 19 * 262ms = 5 seconds
movwf COUNT ;
chk_low
btfsc PWRin ; still low?
goto vdr_pwr_down ; if not, pwr key was pressed < 5s --> turn off VDR
btfsc tmr1h,7 ; check timer1 h register bit 7 (set after 262ms)
goto dec_cnt1
goto chk_low
dec_cnt1
clrf tmr1h ; clear timer1 registers
clrf tmr1l
decfsz COUNT,f
goto chk_low ; not yet 5s, loop
goto reset ; power key pressed > 5s
turn_on
bsf PWRout ; activate PWRout for 250ms
call delay_t6 ;
bcf PWRout ;
goto boot_delay ; and goto boot_delay
reset bsf RESETout ; activate RESETout for 250ms
call delay_t6
bcf RESETout
boot_delay ; variable delay from 0 to 127 s while LED is flashing green
movfw PWR_ON_DELAY ; and no command is accepted, delay derived from user preset (0..99)
btfsc Reboot_Flag ; add additional time (defined in RebootDelay) if Reboot_Flag is set
addlw RebootDelay ;
movwf COUNT
bcf status,c
rlf COUNT ; multiply COUNT by two as the g_flash routine takes only 0.5s
sublw d'0' ; if COUNT=0 stop immediately
btfss status,z
goto g_flash
bcf Reboot_Flag ; clear Reboot_Flag
goto main_loop
g_flash
LED_grn
call delay_t6
LED_off
call delay_t6
decfsz COUNT,f
goto g_flash
goto main_loop
vdr_pwr_down
LED_red ; turn LED red
movlw h'1f' ; set RC5 address to h'1f' and command to h'3e' and send the code
movwf RC5_TX_2 ; This combination is not used by the remote control and will
movlw h'3e' ; be send to LIRC instead of the remote's normal pwr key code.
movwf RC5_TX_1 ; This way exactly *one* command can be sent instead of multiple
; (autorepeat of RC5 codes) -- VDR would start and immediately
; abort the shutdown if the pwr key is pressed a bit too long ...
; A corresponding entry must be added to lircd.conf and the
; original pwr key code must be removed.
call rc5_tx ;
; Flash red LED while checking if a key on the remote control is
; pressed (which stops VDR from executing the shutdown script).
; If so, the programm returns to the main loop and the LED
; turns green again. Otherwise flash LED until ATX is in standby
; and finally turn LED red. Note: The remote's pwr key will be
; ignored (also to avoid problem with RC5/repeat and VDR).
movlw d'57' ; set COUNT to d'57' for timeout couter
movwf COUNT ; timeout is approx. 2 * 262ms * 57 = 30 seconds
r_flash
LED_red ; turn on red LED
call tim_sub ; call timer subroutine and check if any remote key is pressed
LED_off ; turn off LED
call tim_sub ; call timer subroutine and check if any remote key is pressed
decfsz COUNT,f
goto r_flash ; and loop
goto main_loop ; timeout after approx. 30 seconds (if shutdown fails)
tim_sub ;
clrf tmr1h ; clear timer1 registers
clrf tmr1l ;
ir_chk
btfss IR_C_out ; high level at IR?
goto tim_chk ; - no, check timer1
call rc5_rx ; - yes, call rc5_rx subroutine
btfsc RC5_Flag ; RC5 code OK?
goto tim_chk ; - no, check timer1
movfw RC5_CMD ; copy RC5_CMD to w and
andlw b'01111111' ; clear toggle bit
bcf status,c ; clear carry bit
subwf PWR_KEY_CMD,w ; check if command is pwr key; this will be ignored
btfss status,z ;
goto main_loop ; key pressed, abort shutdown and goto main_loop
tim_chk ;
btfss tmr1h,7 ; check timer1 h register bit 7 (set after 262ms)
goto ir_chk ; loop if not yet set
atx_chk
btfsc ATX_C_out ; wait until ATX is standby
return ; still on, continue flashing
goto main_loop ; now standby, goto main_loop
;**************************************************************************************************
; Program mode
;**************************************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -