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

📄 红外线通信.txt

📁 pic单片机对红外设备控制得一个源程序
💻 TXT
📖 第 1 页 / 共 3 页
字号:
PIC Tutorial Five - Infrared Communication红外线通信


IR transmission has limitations, the most important one (for our purposes) being that the receiver doesn't give out the same width pulses that we transmit, so we can't just use a normal, RS232 type, serial data stream, where we simply sample the data at fixed times - the length of the received data varies with the number of ones sent - making receiving it accurately very difficult. Various different schemes are used by the manufacturers of IR remote controls, and some are much more complicated than others.

I've chosen to use the Sony SIRC (Sony Infra Red Control) remote control system, many of you may already have a suitable Sony remote at home you can use, and it's reasonably easy to understand and implement. Basically it uses a pulse width system, with a start bit of 2.4mS, followed by 12 data bits, where a '1' is 1.2mS wide, and a '0' is 0.6mS wide, the bits are all separated by gaps of 0.6mS. The data itself consists of a 7 bit 'command' code, and a 5 bit 'device' code - where a command is Channel 1, Volume Up etc. and a device is TV, VCR etc. This is how the same remote system can be used for different appliances, the same command for 'Power On' is usually used by all devices, but by transmitting a device ID only a TV will respond to 'TV Power On' command.

Start Command Code Device Code 
S
 D0 D1 D2 D3 D4 D5 D6 C0 C1 C2 C3 C4 
2.4mS 1.2 or 0.6mS 1.2 or 0.6mS 
The table to the right shows the data format, after the Start bit the command code is send, lowest bit first, then the device code, again lowest bit first. The entire series is sent repeatedly while the button is held down, every 45mS. In order to decode the transmissions we need to measure the width of the pulses, first looking for the long 'start' pulse, then measuring the next 12 pulses and deciding if they are 1's or 0's. To do this I'm using a simple software 8 bit counter, with NOP's in the loop to make sure we don't overflow the counter. After measuring one pulse we then test it to see if it's a valid pulse, this routine provides four possible responses 'Start Pulse', 'One', 'Zero', or 'Error', we initially loop until we get a 'Start Pulse' reply, then read the next 12 bits - if the reply to any of these 12 is other than 'One' or 'Zero' we abort the read and go back to waiting for a 'Start Pulse'.

Device ID's TV 1 
VTR1 2 
Text 3 
Widescreen 4 
MDP 6 
VTR2 7 
VTR3 11 
Effect 12 
Audio 16 
Pro-Logic 18 
DVD 26 
The device codes used specify the particular device, but with a few exceptions!, while a TV uses device code 1, some of the Teletext buttons use code 3, as do the Fastext coloured keys - where a separate Widescreen button is fitted, this uses code 4. The table to the left shows some of the Device ID codes I found on a sample of Sony remotes. Five bits gives a possible 32 different device ID's, and some devices respond to more than one device ID, for example some of the current Sony VCR's have the Play button in a 'cursor' type of design, surrounded by 'Stop', 'Pause', 'Rewind', and 'Fast Forward' - the ones I tested actually send a DVD ID code when these keys are pressed (along with a different command ID to that used normally used for 'Play' etc.). However, they still respond to an older Sony remote which sends the VTR3 device ID, which despite being labelled VTR3 on TV remotes seems to be the normal standard Sony VCR device ID. It's quite common for Sony remotes to use more than one device ID, a Surround Sound Amplifier Remote I tried used four different device ID's.

If you don't have a Sony remote you can use, I've also built a transmitter, using the second Main Board, second IR Board, and the Switch Board, the four buttons allow you to send four different command codes - I've chosen TV as the device, and Volume Up, Volume Down, Program Up, and Program Down as my four commands, I've confirmed this works on various Sony TV's. Transmitting the SIRC code is quite simple to do, I generate the 38KHz modulation directly  in software, and to reduce current consumption don't use a 50/50 on/off ratio - by using a longer off than on time we still get the 38KHz, but with a reduced power requirement.

 

Tutorial 5.1 - requires one Main Board (with LED set to RB7), one IR Board and LCD Board.

This program uses the LCD module to give a decimal display of the values of the Device and Command bytes transmitted by a Sony SIRC remote control, it can be easily altered to operate port pins to control external devices, as an example the main board LED is turned on by pressing button 2, turned off by pressing button 3, and toggled on and off by pressing button 1 (all on a TV remote, you can change the device ID for a different remote if you need to). As it stands it's very useful for displaying the data transmitted by each button on your Sony remote control - the Device ID's table above was obtained using this design.

;Tutorial 5_1
;Read SIRC IR with LCD display
;Nigel Goodwin 2002

	LIST	p=16F628		;tell assembler what chip we are using
	include "P16F628.inc"		;include the defaults for the chip
	ERRORLEVEL	0,	-302	;suppress bank selection messages
	__config 0x3D18			;sets the configuration settings (oscillator type etc.)




		cblock	0x20			;start of general purpose registers
			count			;used in looping routines
			count1			;used in delay routine
			counta			;used in delay routine
			countb			;used in delay routine
			LoX
			Bit_Cntr
			Cmd_Byte
			Dev_Byte
			Timer_H
			Flags
			Flags2
			tmp1			;temporary storage
			tmp2
			tmp3
			lastdev
			lastkey

        		NumL			;Binary inputs for decimal convert routine
	        	NumH	

        		TenK			;Decimal outputs from convert routine
	        	Thou	
        		Hund	
	        	Tens	
        		Ones

			templcd			;temp store for 4 bit mode
			templcd2	
		endc

LCD_PORT	Equ	PORTA
LCD_TRIS	Equ	TRISA
LCD_RS		Equ	0x04			;LCD handshake lines
LCD_RW		Equ	0x06
LCD_E		Equ	0x07

IR_PORT		Equ	PORTB
IR_TRIS		Equ	TRISB
IR_In		Equ	0x02			;input assignment for IR data

OUT_PORT	Equ	PORTB
LED		Equ	0x07

ErrFlag		Equ	0x00
StartFlag	Equ	0x01			;flags used for received bit
One		Equ	0x02
Zero		Equ	0x03

New		Equ	0x07			;flag used to show key released

TV_ID		Equ	0x01			;TV device ID

But1		Equ	0x00			;numeric button ID's
But2		Equ	0x01
But3		Equ	0x02
But4		Equ	0x03
But5		Equ	0x04
But6		Equ	0x05
But7		Equ	0x06
But8		Equ	0x07
But9		Equ	0x08

		org	0x0000
		goto	Start

            	org     0x0004
            	retfie

;TABLES - moved to start of page to avoid paging problems,
;a table must not cross a 256 byte boundary.
HEX_Table  	addwf   PCL       , f
            	retlw   0x30
            	retlw   0x31
            	retlw   0x32
            	retlw   0x33
            	retlw   0x34
            	retlw   0x35
            	retlw   0x36
            	retlw   0x37
            	retlw   0x38
            	retlw   0x39
            	retlw   0x41
            	retlw   0x42
            	retlw   0x43
            	retlw   0x44
            	retlw   0x45
            	retlw   0x46

Xtext		addwf	PCL, f
		retlw	'D'
		retlw	'e'
		retlw	'v'
		retlw	'i'
		retlw	'c'
		retlw	'e'
		retlw	' '
		retlw	' '
		retlw	' '
		retlw	'C'
		retlw	'o'
		retlw	'm'
		retlw	'm'
		retlw	'a'
		retlw	'n'
		retlw	'd'
		retlw	0x00

;end of tables

Start		movlw	0x07
		movwf	CMCON			;turn comparators off (make it like a 16F84)

Initialise	clrf	count
		clrf	PORTA
		clrf	PORTB
		clrf	Flags
                clrf    Dev_Byte
		clrf	Cmd_Byte	



SetPorts	bsf 	STATUS,		RP0	;select bank 1
		movlw	0x00			;make all LCD pins outputs
		movwf	LCD_TRIS
		movlw	b'01111111'		;make all IR port pins inputs (except RB7)
		movwf	IR_TRIS
		bcf 	STATUS,		RP0	;select bank 0

		call	LCD_Init		;setup LCD module
		call	Delay255		;let IR receiver settle down

Main
		call	LCD_Line1		;set to first line
		call	String1			;display IR title string

		call	ReadIR			;read IR signal
		movlw	d'2'
		call	LCD_Line2W		;set cursor position
		clrf	NumH
		movf	Dev_Byte,	w	;convert device byte
		movwf	NumL
		call	Convert		
		movf	Tens,	w
		call	LCD_CharD
		movf	Ones,	w
		call	LCD_CharD

		movlw	d'11'
		call	LCD_Line2W		;set cursor position
		clrf	NumH
		movf	Cmd_Byte,	w	;convert data byte
		movwf	NumL
		call	Convert
		movf	Hund,	w
		call	LCD_CharD		
		movf	Tens,	w
		call	LCD_CharD
		movf	Ones,	w
		call	LCD_CharD

		call	ProcKeys		;do something with commands received

		goto	Main			;loop for ever

ProcKeys
		btfss	Flags2,	New
		retlw	0x00			;return if not new keypress
		movlw	TV_ID			;check for TV ID code
		subwf   Dev_Byte,	w
		btfss   STATUS    , Z
		retlw	0x00			;return if not correct code

		movlw	But1			;test for button 1
		subwf   Cmd_Byte, w
		btfss   STATUS    , Z
		goto	Key1			;try next key if not correct code

		movf	OUT_PORT,	w	;read PORTB (for LED status)
		movwf	tmp3			;and store in temp register
		btfss	tmp3,	LED		;and test LED bit for toggling
		bsf	OUT_PORT,	LED	;turn on LED
		btfsc	tmp3,	LED
		bcf	OUT_PORT,	LED	;turn off LED
		bcf	Flags2,	New		;and cancel new flag		
		retlw	0x00

Key1		movlw	But2			;test for button 2
		subwf   Cmd_Byte, w
		btfss   STATUS    , Z
		goto	Key2			;try next key if not correct code
						;this time just turn it on
		bsf	OUT_PORT,	LED	;turn on LED
		bcf	Flags2,	New		;and cancel new flag		
		retlw	0x00

Key2		movlw	But3			;test for button 3
		subwf   Cmd_Byte, w
		btfss   STATUS    , Z
		retlw	0x00			;return if not correct code
						;this time just turn it off
		bcf	OUT_PORT,	LED	;turn off LED
		bcf	Flags2,	New		;and cancel new flag		
		retlw	0x00

String1		clrf	count			;set counter register to zero
Mess1		movf	count, w		;put counter value in W
		call	Xtext			;get a character from the text table
		xorlw	0x00			;is it a zero?
		btfsc	STATUS, Z
		retlw	0x00			;return when finished
		call	LCD_Char
		incf	count, f
		goto	Mess1

;IR routines

ReadIR		call	Read_Pulse
		btfss	Flags,	StartFlag
		goto	ReadIR			;wait for start pulse (2.4mS)

Get_Data	movlw   0x07			;set up to read 7 bits
                movwf   Bit_Cntr
                clrf    Cmd_Byte
Next_RcvBit2    call	Read_Pulse
		btfsc	Flags,	StartFlag	;abort if another Start bit
		goto	ReadIR
		btfsc	Flags,	ErrFlag		;abort if error
		goto	ReadIR

                bcf     STATUS    , C
                btfss   Flags, 	Zero
                bsf     STATUS    , C
                rrf     Cmd_Byte  , f
                decfsz  Bit_Cntr  , f
                goto    Next_RcvBit2

                rrf     Cmd_Byte  , f		;correct bit alignment for 7 bits

Get_Cmd		movlw   0x05			;set up to read 5 bits
                movwf   Bit_Cntr
                clrf    Dev_Byte
Next_RcvBit     call	Read_Pulse
		btfsc	Flags,	StartFlag	;abort if another Start bit
		goto	ReadIR
		btfsc	Flags,	ErrFlag		;abort if error
		goto	ReadIR

                bcf     STATUS    , C
                btfss   Flags, 	Zero
                bsf     STATUS    , C
                rrf     Dev_Byte  , f
                decfsz  Bit_Cntr  , f
                goto    Next_RcvBit

                rrf     Dev_Byte  , f		;correct bit alignment for 5 bits
                rrf     Dev_Byte  , f		
                rrf     Dev_Byte  , f		

		retlw	0x00

;end of ReadIR


;read pulse width, return flag for StartFlag, One, Zero, or ErrFlag
;output from IR receiver is normally high, and goes low when signal received

Read_Pulse      clrf	LoX
		btfss   IR_PORT, 	IR_In	;wait until high
            	goto    $-1
		clrf	tmp1
		movlw	0xC0			;delay to decide new keypress
		movwf	tmp2			;for keys that need to toggle

Still_High	btfss   IR_PORT, 	IR_In	;and wait until goes low
            	goto    Next
		incfsz	tmp1,f
		goto	Still_High
		incfsz	tmp2,f
		goto	Still_High
		bsf	Flags2,	New		;set New flag if no button pressed
		goto	Still_High

Next		nop
		nop
		nop
		nop
		nop				;waste time to scale pulse
		nop				;width to 8 bits
		nop
		nop
		nop
		nop
		nop
		nop
		incf	LoX,	f
        	btfss   IR_PORT, 	IR_In
        	goto    Next			;loop until input high again

; test if Zero, One, or Start (or error)
		
Chk_Pulse	clrf	Flags

TryError	movf 	LoX,	w		; check if pulse too small
  		addlw 	d'255' - d'20'		; if LoX <= 20
  		btfsc   STATUS    , C
  		goto 	TryZero
		bsf	Flags,	ErrFlag		; Error found, set flag
		retlw	0x00

TryZero		movf 	LoX,	w		; check if zero
  		addlw 	d'255' - d'60'		; if LoX <= 60
  		btfsc   STATUS    , C
  		goto 	TryOne
		bsf	Flags,	Zero		; Zero found, set flag
		retlw	0x00

TryOne 		movf 	LoX,	w		; check if one
  		addlw 	d'255' - d'112'		; if LoX <= 112
  		btfsc   STATUS    , C
  		goto 	TryStart
		bsf	Flags,	One		; One found, set flag
		retlw	0x00

TryStart 	movf 	LoX,	w		; check if start
  		addlw 	d'255' - d'180'		; if LoX <= 180
  		btfsc   STATUS    , C
  		goto 	NoMatch
		bsf	Flags,	StartFlag	; Start pulse found
		retlw	0x00
NoMatch						; pulse too long
		bsf	Flags,	ErrFlag		; Error found, set flag		
		retlw	0x00

;end of pulse measuring routines

;LCD routines

;Initialise LCD
LCD_Init	call 	LCD_Busy		;wait for LCD to settle

		movlw	0x20			;Set 4 bit mode
		call	LCD_Cmd

		movlw	0x28			;Set display shift
		call	LCD_Cmd

		movlw	0x06			;Set display character mode
		call	LCD_Cmd

		movlw	0x0c			;Set display on/off and cursor command
		call	LCD_Cmd			;Set cursor off

		call	LCD_Clr			;clear display

		retlw	0x00

; command set routine
LCD_Cmd		movwf	templcd
		swapf	templcd,	w	;send upper nibble
		andlw	0x0f			;clear upper 4 bits of W
		movwf	LCD_PORT
		bcf	LCD_PORT, LCD_RS	;RS line to 1
		call	Pulse_e			;Pulse the E line high

		movf	templcd,	w	;send lower nibble
		andlw	0x0f			;clear upper 4 bits of W
		movwf	LCD_PORT
		bcf	LCD_PORT, LCD_RS	;RS line to 1
		call	Pulse_e			;Pulse the E line high
		call 	LCD_Busy
		retlw	0x00

LCD_CharD	addlw	0x30			;add 0x30 to convert to ASCII
LCD_Char	movwf	templcd
		swapf	templcd,	w	;send upper nibble
		andlw	0x0f			;clear upper 4 bits of W

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -