⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ir_controller.asm

📁 pic单片机对红外设备控制得一个源程序
💻 ASM
📖 第 1 页 / 共 2 页
字号:
;**************************************************************************************************
;********************** 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 + -