PIC16F887 红外接收器,汇编语言
IR receiver with PIC16F887, assembly language
我一直在为学校做一个项目。涉及到PIC汇编编程。我使用 44 针演示板,PIC16F887。
我必须做一个红外接收器,它的输出可以改变 LED 亮度。我知道到目前为止我必须为此进行 PWM 控制。但是我仍在努力解码按钮。
我正在使用具有 NEC 编码的发射器。我的输入设置是数字的,通过内部电阻 PORTB 上拉,0。我正在尝试使用 TMR0 中断轮询输入。
系统设置为 4MHz 振荡器,TMR0 每 Osc/4 递增一次。预分频器为 1:2,因此定时器每 2μs 递增 1。Timer0 预加载为 D'206',因此中断 50*2μs = 100μs。根据 NEC 协议,逻辑 0 有 562.5μs 低信号,逻辑 1 有 1687.5μs 低信号,在 562.5 高信号之后。
所以 1687.5μs /100μs = 16,562.5μs / 100μs = 5。我试图从 8 中减去它们。所以我可以检查什么是状态,零位是活动的还是低的。
我不知道我哪里出错了。我将在下面留下我的代码。此代码有一个 LED 闪烁,而如果按下音量 + 按钮,它应该将 PORTD,0 LED 设置为亮起。所以通过这种方式我会知道我是否可以检测到按钮,并在 PWM 上工作。
感谢每个回答。
ISR: ;IF ISR GLOBAL INT 0
btfss INTCON,T0IF
retfie ;if there is no interrupt
banksel 0 ;ISR occur in Bank0
movwf W_save ;save WORK register's value
movf STATUS,W
movwf STATUS_save ;save STATUS register's value
call IR ;call IR
goto ISR_EXIT
ISR_EXIT:
bcf INTCON,T0IF ;TMR0 interrupt flag clear
movlw b'01100110' ;preload 206
movwf TMR0
movf STATUS_save,W
movwf STATUS ;STATUS register original value reload
swapf W_save,f ;WORK register original value reload
swapf W_save,W
retfie ;retfie -> global int = 1
IR:
btfss PORTB,0 ;testing IR input
bsf ir_reg,0 ;button was pressed
btfss ir_reg,0 ;button was pressed?
goto NO_BUTTON
btfsc PORTB,0 ;HIGH signal?
goto HIGH_P
btfss ir_reg,1 ;previous was HIGH?
goto HIGH_TO_LOW
incf time,f ;increment time
goto ISR_EXIT
HIGH_P:
btfsc ir_reg,1 ;was previous LOW?
goto LOW_TO_HIGH
incf time,f ;increment time
goto ISR_EXIT
HIGH_TO_LOW: ;transition between HIGH to LOW pulses
bsf PORTD,3
movf time,W
movwf high_pulse ;saving HIGH pulse's time
clrf time ;time variable clear
bcf ir_reg,1 ;previous pulse was HIGH
goto CALC
CALC:
movf high_pulse,W ;high pulse's time into Work
bcf STATUS,Z ;STATUS ZERO CLEAR
sublw D'10' ;LOW_P -> 5-10 = -5,HIGH_P - > 16-10 = 6
btfsc STATUS,Z ;if subtraction = +
bsf ir_reg,3 ;subtraction ended positive -> LOGIC 1
bcf ir_reg,3 ;subtraction ended negative -> LOGIC 0
goto ADD_BITS
ADD_BITS:
bsf PORTD,2
btfsc ir_reg,3 ;if LOGIC 1
bsf STATUS,C ;carry bit 1
bcf STATUS,C ;carry bit 0
goto ROTATE
ROTATE:
bsf PORTD,1
rlf naddress ;Carry is rotated to naddress LSB
rlf address ;naddress MSB rotated to address LSB through Carry
rlf ncommand ;address MSB rotated to ncommand LSB through Carry
rlf command ;ncommand MSB rotated to command LSB through Carry
incf pulses ;every time we have a rotation increment variable
movf pulses,W
bcf STATUS,Z ;status zero clear
sublw D'32' ;33-pulses,we have a decoded signal
btfss STATUS,Z ;if Zero set
goto ISR_EXIT ;goto NO_button
goto LED_FLASH
LED_FLASH:
movf command,W
bcf STATUS,Z
sublw b'10101000' ;+ button command: b'10101000'
btfss STATUS,Z
goto NO_BUTTON
bsf PORTD,0
goto ISR_EXIT
LOW_TO_HIGH: ;transition between LOW to HIGH pulses
movf time,W
movwf low_pulse ;saving LOW pulse's time
clrf time ;time variable clear
bsf ir_reg,1 ;previous pulse was LOW
goto ISR_EXIT
NO_BUTTON:
btfsc PORTB,0
goto ISR_EXIT
clrf pulses ;clearing variables
clrf ir_reg
clrf time
clrf address
clrf naddress
clrf address
clrf ncommand
clrf command
goto ISR_EXIT
INIT:
;OSCCON INIT
banksel OSCCON
movlw b'01100000' ;4Mhz oscillator
movwf OSCCON
;OUTPUT INIT
banksel TRISD
clrf TRISD ;TRISD OUTPUT
banksel PORTD
clrf PORTD ;PORTD LOW
;INPUT INIT
banksel TRISB
bsf TRISB,RB0 ;RB0 INPUT
bsf WPUB,RB0
movlw 0x00
banksel ANSELH
movwf ANSELH ;RB0 DIGITAL
call Delay
;OPTION REG INIT / TMR0
banksel OPTION_REG
movlw b'00000000' ;TMR0 prescale 1:2 increment every 2us
movwf OPTION_REG
movlw b'01100110' ;preload 206
movwf TMR0 ;50 tick until overflow 50*2us = 100us
;INTCON INIT
banksel INTCON
bcf INTCON,T0IF ;TMR0 overflow flag clear
bsf INTCON,T0IE ;TMR0 overflow enable
bsf INTCON,GIE ;global interrupt enable
return
MAIN:
call INIT
call FLASH ;LED FLASH
goto $-1
END
在我的傲慢中,我认为你的任务简单明了。
我大错特错了。我花了三天时间编写和测试一个可以解码 NEC 红外遥控协议的应用程序。
仅仅试图理解在各种网站上发现的所谓文档就存在重大挑战。所有这些都是误导和不完整的。光是整理那堆乱七八糟的东西就花了一整天。
这就是我的工作:
list n=0,c=255,r=dec ; Make .LST file look nice
errorlevel -302 ; Suppress Register in operand not in bank 0 warning.
#define MAIN_ASM
;
; File: main.asm
; Date: 2020-05-23
; Target: PIC16F887
; Author: dan1138
;
; Description:
; Decoder for NEC Infrared Remote control protocol.
;
; Physical transport:
; Long flash (> 8ms)
; Pause (COMMAND when pause is more than 4ms),
; (REPEAT when pause is less than 4ms but greater than 2ms)
; Short flash (0.5 to 0.6ms)
; Repeats 32 times:
; Pause DATA is one when pause is more than 1ms, else DATA is zero.
; Short flash (0.5 to 0.6ms)
;
;
; PIC16F887
; +----------:_:----------+
; VPP -> 1 : RE3/MCLR/VPP PGD/RB7 : 40 <> PGD
; <> 2 : RA0/AN0 PGC/RB6 : 39 <> PGC
; <> 3 : RA1/AN1 AN13/RB5 : 38 <>
; <> 4 : RA2/AN2 AN11/RB4 : 37 <>
; <> 5 : RA3/AN3 PGM/AN9/RB3 : 36 <>
; <> 6 : RA4/T0CKI AN8/RB2 : 35 <>
; <> 7 : RA5/AN4 AN10/RB1 : 34 <>
; <> 8 : RE0/AN5 INT/AN12/RB0 : 33 <> IR_RECEIVERn
; <> 9 : RE1/AN6 VDD : 32 <- 5v0
; <> 10 : RE2/AN7 VSS : 31 <- GND
; PWR -> 11 : VDD RD7 : 30 -> LCD_ON
; GND -> 12 : VSS RD6 : 29 -> LCD_E
; -> 13 : RA7/OSC1 RD5 : 28 -> LCD_RW
; <- 14 : RA6/OSC2 RD4 : 27 -> LCD_RS
; <> 15 : RC0/SOSCO RX/DT/RC7 : 26 <>
; <> 16 : RC1/SOSCI TX/CK/RC6 : 25 <>
; <> 17 : RC2/CCP1 RC5 : 24 <>
; <> 18 : RC3/SCL SDA/RC4 : 23 <>
; LCD_D4 <> 19 : RD0 RD3 : 22 <> LCD_D7
; LCD_D5 <> 20 : RD1 RD2 : 21 <> LCD_D6
; +-----------------------:
; DIP-40
;
; Include Special Function Register definitions
;
#include "p16f887.inc"
#include "main.inc"
#include "lcd.inc"
;
; PIC16F887 Configuration Bit Settings
; Assembly source line config statements
;
__CONFIG _CONFIG1, _FOSC_INTRC_NOCLKOUT & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF & _IESO_ON & _FCMEN_OFF & _LVP_OFF
__CONFIG _CONFIG2, _BOR4V_BOR21V & _WRT_OFF
;
; Power on reset vector
;
RES_VECT CODE 0x0000 ; processor reset vector
pagesel START
GOTO START ; go to beginning of program
;
; Interrupt context save area
;
ISR_DATA UDATA_SHR
WREG_SAVE res 1
STATUS_SAVE res 1
PCLATH_SAVE res 1
NEC_IR_State res 1
NEC_IR_StartFlash res 1
NEC_IR_CdPause res 1
;
; Data area for protocol decoder
;
NEC_IR_DATA UDATA
NEC_IR_RawData res 4
NEC_IR_Address res 1
NEC_IR_Command res 1
NEC_IR_Flags res 1
#define BIT_NEC_IR_Flags_COMMAND NEC_IR_Flags,0
#define BIT_NEC_IR_Flags_REPEAT NEC_IR_Flags,1
;
; Interrupt Service Routine
;
ISR_VECT CODE 0x0004 ; interrgot vector
ISR:
movwf WREG_SAVE ;
movf STATUS,W ; These register: WREG, STATUS, PCLATH
movwf STATUS_SAVE ; are what, at the minimum, must be saved
movf PCLATH,W ; and restored on an interrupt.
movwf PCLATH_SAVE ;
clrf STATUS ; Force to memory bank 0
clrf PCLATH ; Force to code page 0
;
; Handle external INT interrupt request
;
btfsc INTCON,INTE
btfss INTCON,INTF
goto INT_End
bcf INTCON,INTF
;
; Block flash detection until application loop is done
;
btfss BIT_NEC_IR_Flags_COMMAND
btfsc BIT_NEC_IR_Flags_REPEAT
goto INT_End
movf NEC_IR_State,F
skpz
goto NEC_IR_NextState
;
; Look for initial long flash
;
clrf NEC_IR_StartFlash
clrf TMR0
bcf INTCON,T0IF
MeasureStartFlash:
btfsc PORTB,0 ; Skip if flash still on
goto EndOfFlash
btfss INTCON,T0IF
goto MeasureStartFlash
bcf INTCON,T0IF
incfsz NEC_IR_StartFlash,W
movwf NEC_IR_StartFlash
goto MeasureStartFlash
EndOfFlash:
clrf TMR0
bcf INTCON,T0IF
clrf NEC_IR_CdPause
movlw 8
subwf NEC_IR_StartFlash,W
btfss STATUS,C ; Skip if count equal or greater than 8 T0IF ticks
goto INT_End
;
; Measure pause after flash
;
MeasurePause:
btfss PORTB,0 ; Skip if flash still off
goto EndOfPause
btfss INTCON,T0IF
goto MeasurePause
bcf INTCON,T0IF
incfsz NEC_IR_CdPause,W
movwf NEC_IR_CdPause
goto MeasurePause
EndOfPause:
btfss PORTB,0 ; Skip when flash goes off
goto EndOfPause
clrf TMR0
bcf INTCON,T0IF
bcf INTCON,INTF
movlw 4
subwf NEC_IR_CdPause,W
btfsc STATUS,C ; Skip if count less than 4 T0IF ticks
goto ReceiveCommandState
banksel NEC_IR_Flags
bsf BIT_NEC_IR_Flags_REPEAT ; Assert this is a REPEAT event
goto INT_End
ReceiveCommandState:
movlw d'32'
movwf NEC_IR_State ; Advnace to state 32 when we expect ADDRESS/COMMAND data
INT_End:
;
movf PCLATH_SAVE,W ;
movwf PCLATH ; Restore the saved context of the
movf STATUS_SAVE,W ; interrupted execution.
movwf STATUS ;
swapf WREG_SAVE,F ;
swapf WREG_SAVE,W ;
retfie ; Exit ISR and enable the interrupts.
;
; Receive COMMAND or REPEAT event
;
NEC_IR_NextState:
banksel PORTB
bcf STATUS,C
btfsc INTCON,T0IF
bsf STATUS,C
banksel NEC_IR_RawData
rlf NEC_IR_RawData,F
rlf NEC_IR_RawData+1,F
rlf NEC_IR_RawData+2,F
rlf NEC_IR_RawData+3,F
EndOfBit:
banksel PORTB
btfss PORTB,0 ; Skip when flash goes off
goto EndOfBit
clrf TMR0
bcf INTCON,T0IF
decf NEC_IR_State,F
btfss STATUS,Z
goto INT_End
;
; Validate ADDRESS and COMMAND
;
banksel NEC_IR_RawData
comf NEC_IR_RawData,W
xorwf NEC_IR_RawData+1,W
btfss STATUS,Z
goto INT_End
comf NEC_IR_RawData+2,W
xorwf NEC_IR_RawData+3,W
btfss STATUS,Z
goto INT_End
movf NEC_IR_RawData+1,W
movwf NEC_IR_Command
movf NEC_IR_RawData+3,W
movwf NEC_IR_Address
bsf BIT_NEC_IR_Flags_COMMAND
goto INT_End
;
; Initialize the PIC hardware
;
START:
clrf INTCON ; Disable all interrupt sources
banksel BANK1
clrf PIE1
clrf PIE2
movlw b'01100000'
movwf OSCCON ; Set internal oscillator at 4MHz
movlw b'10000001' ; Pull-ups off, INT edge high to low, WDT prescale 1:1
movwf OPTION_REG ; TMR0 clock edge low to high, TMR0 clock = FCY, TMR0 prescale 1:4
; TIMER0 will assert the overflow flag every 256*4 (1024)
; instruction cycles, with a 4MHz oscilator this ia 1.024 milliseconds.
movlw b'11111111' ;
movwf TRISA
movlw b'11111111' ;
movwf TRISB
movlw b'11111111' ;
movwf TRISC
movlw b'11111111' ;
movwf TRISD
; Set all ADC inputs for digital I/O
banksel BANK3
movlw b'00000000'
movwf ANSEL
movlw b'00000000'
movwf ANSELH
banksel BANK2
clrf CM1CON0 ; turn off comparator
clrf CM2CON0 ; turn off comparator
banksel BANK1
movlw b'00000000'
movwf ADCON1
clrf VRCON ; turn off voltage reference
banksel BANK0
movlw b'10000000'
movwf ADCON0
pagesel main
goto main
;
; Main data
;
MAIN_DATA UDATA
RepeatCount res 1
;
; Main application code
;
MAIN_PROG CODE
;
; Main application initialization
;
main:
lcall OpenXLCD
movlw LINE_ONE
lcall SetDDRamAddr
movlw LOW(LCD_message1)
movwf pszLCD_RomStr
movlw HIGH(LCD_message1)
movwf pszLCD_RomStr+1
lcall putrsXLCD
banksel NEC_IR_Flags
clrf NEC_IR_Flags
clrf NEC_IR_State
bcf BIT_NEC_IR_Flags_COMMAND
bcf BIT_NEC_IR_Flags_REPEAT
bcf INTCON,INTF
bsf INTCON,INTE
bsf INTCON,GIE
;
; Application process loop
;
AppLoop:
movf NEC_IR_Flags,F ; Check for event
btfsc STATUS,Z ; Skip if any event bit set
GOTO AppLoop ;
banksel NEC_IR_Flags
btfsc BIT_NEC_IR_Flags_REPEAT ; skip of not a REPEAT event
goto IncrementCount
banksel RepeatCount
clrf RepeatCount
;
; Increment repeat count
;
IncrementCount:
banksel RepeatCount
incfsz RepeatCount,W
movwf RepeatCount
;
; Show measurement for Start Of Transmission (SOT) flash
;
movlw LINE_TWO
lcall SetDDRamAddr
movf NEC_IR_StartFlash,W
lcall PutDecXLCD
;
; Show measurement for pause after SOT flash
;
movlw ' '
lcall WriteDataXLCD
movf NEC_IR_CdPause,W
lcall PutDecXLCD
;
; Show decoded ADDRESS and COMMAND
;
movlw ' '
lcall WriteDataXLCD
banksel NEC_IR_Address
movf NEC_IR_Address,W
lcall PutHexXLCD
banksel NEC_IR_Command
movf NEC_IR_Command,W
lcall PutHexXLCD
;
; Show REPEAT count
;
movlw ' '
lcall WriteDataXLCD
banksel RepeatCount
movf RepeatCount,W
lcall PutHexXLCD
;
; Clear event flags to enable capture of next event
;
banksel NEC_IR_Flags
clrf NEC_IR_Flags
lgoto AppLoop
;
; LCD messages
;
MAIN_CONST code
LCD_message1:
dt "NEC IR Decode v0",0
END
我已经用汇编语言为 8 位 PIC 控制器编写了很多代码。该应用程序包含一些非常微妙的技巧。其中没有足够的评论来解释它是如何工作的以及为什么工作。你只需要自己分析一下。
NEC IR 协议的诀窍在于它完全是关于 IR 闪光之间的停顿。如果网上有关于NEC IR 控制协议的准确、完整和易懂的描述我找不到了。
我原以为可以教您如何编写此代码,但我认为我还不够好,无法做到这一点。我只希望这可以作为你的例子。
我一直在为学校做一个项目。涉及到PIC汇编编程。我使用 44 针演示板,PIC16F887。
我必须做一个红外接收器,它的输出可以改变 LED 亮度。我知道到目前为止我必须为此进行 PWM 控制。但是我仍在努力解码按钮。 我正在使用具有 NEC 编码的发射器。我的输入设置是数字的,通过内部电阻 PORTB 上拉,0。我正在尝试使用 TMR0 中断轮询输入。
系统设置为 4MHz 振荡器,TMR0 每 Osc/4 递增一次。预分频器为 1:2,因此定时器每 2μs 递增 1。Timer0 预加载为 D'206',因此中断 50*2μs = 100μs。根据 NEC 协议,逻辑 0 有 562.5μs 低信号,逻辑 1 有 1687.5μs 低信号,在 562.5 高信号之后。
所以 1687.5μs /100μs = 16,562.5μs / 100μs = 5。我试图从 8 中减去它们。所以我可以检查什么是状态,零位是活动的还是低的。
我不知道我哪里出错了。我将在下面留下我的代码。此代码有一个 LED 闪烁,而如果按下音量 + 按钮,它应该将 PORTD,0 LED 设置为亮起。所以通过这种方式我会知道我是否可以检测到按钮,并在 PWM 上工作。
感谢每个回答。
ISR: ;IF ISR GLOBAL INT 0
btfss INTCON,T0IF
retfie ;if there is no interrupt
banksel 0 ;ISR occur in Bank0
movwf W_save ;save WORK register's value
movf STATUS,W
movwf STATUS_save ;save STATUS register's value
call IR ;call IR
goto ISR_EXIT
ISR_EXIT:
bcf INTCON,T0IF ;TMR0 interrupt flag clear
movlw b'01100110' ;preload 206
movwf TMR0
movf STATUS_save,W
movwf STATUS ;STATUS register original value reload
swapf W_save,f ;WORK register original value reload
swapf W_save,W
retfie ;retfie -> global int = 1
IR:
btfss PORTB,0 ;testing IR input
bsf ir_reg,0 ;button was pressed
btfss ir_reg,0 ;button was pressed?
goto NO_BUTTON
btfsc PORTB,0 ;HIGH signal?
goto HIGH_P
btfss ir_reg,1 ;previous was HIGH?
goto HIGH_TO_LOW
incf time,f ;increment time
goto ISR_EXIT
HIGH_P:
btfsc ir_reg,1 ;was previous LOW?
goto LOW_TO_HIGH
incf time,f ;increment time
goto ISR_EXIT
HIGH_TO_LOW: ;transition between HIGH to LOW pulses
bsf PORTD,3
movf time,W
movwf high_pulse ;saving HIGH pulse's time
clrf time ;time variable clear
bcf ir_reg,1 ;previous pulse was HIGH
goto CALC
CALC:
movf high_pulse,W ;high pulse's time into Work
bcf STATUS,Z ;STATUS ZERO CLEAR
sublw D'10' ;LOW_P -> 5-10 = -5,HIGH_P - > 16-10 = 6
btfsc STATUS,Z ;if subtraction = +
bsf ir_reg,3 ;subtraction ended positive -> LOGIC 1
bcf ir_reg,3 ;subtraction ended negative -> LOGIC 0
goto ADD_BITS
ADD_BITS:
bsf PORTD,2
btfsc ir_reg,3 ;if LOGIC 1
bsf STATUS,C ;carry bit 1
bcf STATUS,C ;carry bit 0
goto ROTATE
ROTATE:
bsf PORTD,1
rlf naddress ;Carry is rotated to naddress LSB
rlf address ;naddress MSB rotated to address LSB through Carry
rlf ncommand ;address MSB rotated to ncommand LSB through Carry
rlf command ;ncommand MSB rotated to command LSB through Carry
incf pulses ;every time we have a rotation increment variable
movf pulses,W
bcf STATUS,Z ;status zero clear
sublw D'32' ;33-pulses,we have a decoded signal
btfss STATUS,Z ;if Zero set
goto ISR_EXIT ;goto NO_button
goto LED_FLASH
LED_FLASH:
movf command,W
bcf STATUS,Z
sublw b'10101000' ;+ button command: b'10101000'
btfss STATUS,Z
goto NO_BUTTON
bsf PORTD,0
goto ISR_EXIT
LOW_TO_HIGH: ;transition between LOW to HIGH pulses
movf time,W
movwf low_pulse ;saving LOW pulse's time
clrf time ;time variable clear
bsf ir_reg,1 ;previous pulse was LOW
goto ISR_EXIT
NO_BUTTON:
btfsc PORTB,0
goto ISR_EXIT
clrf pulses ;clearing variables
clrf ir_reg
clrf time
clrf address
clrf naddress
clrf address
clrf ncommand
clrf command
goto ISR_EXIT
INIT:
;OSCCON INIT
banksel OSCCON
movlw b'01100000' ;4Mhz oscillator
movwf OSCCON
;OUTPUT INIT
banksel TRISD
clrf TRISD ;TRISD OUTPUT
banksel PORTD
clrf PORTD ;PORTD LOW
;INPUT INIT
banksel TRISB
bsf TRISB,RB0 ;RB0 INPUT
bsf WPUB,RB0
movlw 0x00
banksel ANSELH
movwf ANSELH ;RB0 DIGITAL
call Delay
;OPTION REG INIT / TMR0
banksel OPTION_REG
movlw b'00000000' ;TMR0 prescale 1:2 increment every 2us
movwf OPTION_REG
movlw b'01100110' ;preload 206
movwf TMR0 ;50 tick until overflow 50*2us = 100us
;INTCON INIT
banksel INTCON
bcf INTCON,T0IF ;TMR0 overflow flag clear
bsf INTCON,T0IE ;TMR0 overflow enable
bsf INTCON,GIE ;global interrupt enable
return
MAIN:
call INIT
call FLASH ;LED FLASH
goto $-1
END
在我的傲慢中,我认为你的任务简单明了。
我大错特错了。我花了三天时间编写和测试一个可以解码 NEC 红外遥控协议的应用程序。
仅仅试图理解在各种网站上发现的所谓文档就存在重大挑战。所有这些都是误导和不完整的。光是整理那堆乱七八糟的东西就花了一整天。
这就是我的工作:
list n=0,c=255,r=dec ; Make .LST file look nice
errorlevel -302 ; Suppress Register in operand not in bank 0 warning.
#define MAIN_ASM
;
; File: main.asm
; Date: 2020-05-23
; Target: PIC16F887
; Author: dan1138
;
; Description:
; Decoder for NEC Infrared Remote control protocol.
;
; Physical transport:
; Long flash (> 8ms)
; Pause (COMMAND when pause is more than 4ms),
; (REPEAT when pause is less than 4ms but greater than 2ms)
; Short flash (0.5 to 0.6ms)
; Repeats 32 times:
; Pause DATA is one when pause is more than 1ms, else DATA is zero.
; Short flash (0.5 to 0.6ms)
;
;
; PIC16F887
; +----------:_:----------+
; VPP -> 1 : RE3/MCLR/VPP PGD/RB7 : 40 <> PGD
; <> 2 : RA0/AN0 PGC/RB6 : 39 <> PGC
; <> 3 : RA1/AN1 AN13/RB5 : 38 <>
; <> 4 : RA2/AN2 AN11/RB4 : 37 <>
; <> 5 : RA3/AN3 PGM/AN9/RB3 : 36 <>
; <> 6 : RA4/T0CKI AN8/RB2 : 35 <>
; <> 7 : RA5/AN4 AN10/RB1 : 34 <>
; <> 8 : RE0/AN5 INT/AN12/RB0 : 33 <> IR_RECEIVERn
; <> 9 : RE1/AN6 VDD : 32 <- 5v0
; <> 10 : RE2/AN7 VSS : 31 <- GND
; PWR -> 11 : VDD RD7 : 30 -> LCD_ON
; GND -> 12 : VSS RD6 : 29 -> LCD_E
; -> 13 : RA7/OSC1 RD5 : 28 -> LCD_RW
; <- 14 : RA6/OSC2 RD4 : 27 -> LCD_RS
; <> 15 : RC0/SOSCO RX/DT/RC7 : 26 <>
; <> 16 : RC1/SOSCI TX/CK/RC6 : 25 <>
; <> 17 : RC2/CCP1 RC5 : 24 <>
; <> 18 : RC3/SCL SDA/RC4 : 23 <>
; LCD_D4 <> 19 : RD0 RD3 : 22 <> LCD_D7
; LCD_D5 <> 20 : RD1 RD2 : 21 <> LCD_D6
; +-----------------------:
; DIP-40
;
; Include Special Function Register definitions
;
#include "p16f887.inc"
#include "main.inc"
#include "lcd.inc"
;
; PIC16F887 Configuration Bit Settings
; Assembly source line config statements
;
__CONFIG _CONFIG1, _FOSC_INTRC_NOCLKOUT & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF & _IESO_ON & _FCMEN_OFF & _LVP_OFF
__CONFIG _CONFIG2, _BOR4V_BOR21V & _WRT_OFF
;
; Power on reset vector
;
RES_VECT CODE 0x0000 ; processor reset vector
pagesel START
GOTO START ; go to beginning of program
;
; Interrupt context save area
;
ISR_DATA UDATA_SHR
WREG_SAVE res 1
STATUS_SAVE res 1
PCLATH_SAVE res 1
NEC_IR_State res 1
NEC_IR_StartFlash res 1
NEC_IR_CdPause res 1
;
; Data area for protocol decoder
;
NEC_IR_DATA UDATA
NEC_IR_RawData res 4
NEC_IR_Address res 1
NEC_IR_Command res 1
NEC_IR_Flags res 1
#define BIT_NEC_IR_Flags_COMMAND NEC_IR_Flags,0
#define BIT_NEC_IR_Flags_REPEAT NEC_IR_Flags,1
;
; Interrupt Service Routine
;
ISR_VECT CODE 0x0004 ; interrgot vector
ISR:
movwf WREG_SAVE ;
movf STATUS,W ; These register: WREG, STATUS, PCLATH
movwf STATUS_SAVE ; are what, at the minimum, must be saved
movf PCLATH,W ; and restored on an interrupt.
movwf PCLATH_SAVE ;
clrf STATUS ; Force to memory bank 0
clrf PCLATH ; Force to code page 0
;
; Handle external INT interrupt request
;
btfsc INTCON,INTE
btfss INTCON,INTF
goto INT_End
bcf INTCON,INTF
;
; Block flash detection until application loop is done
;
btfss BIT_NEC_IR_Flags_COMMAND
btfsc BIT_NEC_IR_Flags_REPEAT
goto INT_End
movf NEC_IR_State,F
skpz
goto NEC_IR_NextState
;
; Look for initial long flash
;
clrf NEC_IR_StartFlash
clrf TMR0
bcf INTCON,T0IF
MeasureStartFlash:
btfsc PORTB,0 ; Skip if flash still on
goto EndOfFlash
btfss INTCON,T0IF
goto MeasureStartFlash
bcf INTCON,T0IF
incfsz NEC_IR_StartFlash,W
movwf NEC_IR_StartFlash
goto MeasureStartFlash
EndOfFlash:
clrf TMR0
bcf INTCON,T0IF
clrf NEC_IR_CdPause
movlw 8
subwf NEC_IR_StartFlash,W
btfss STATUS,C ; Skip if count equal or greater than 8 T0IF ticks
goto INT_End
;
; Measure pause after flash
;
MeasurePause:
btfss PORTB,0 ; Skip if flash still off
goto EndOfPause
btfss INTCON,T0IF
goto MeasurePause
bcf INTCON,T0IF
incfsz NEC_IR_CdPause,W
movwf NEC_IR_CdPause
goto MeasurePause
EndOfPause:
btfss PORTB,0 ; Skip when flash goes off
goto EndOfPause
clrf TMR0
bcf INTCON,T0IF
bcf INTCON,INTF
movlw 4
subwf NEC_IR_CdPause,W
btfsc STATUS,C ; Skip if count less than 4 T0IF ticks
goto ReceiveCommandState
banksel NEC_IR_Flags
bsf BIT_NEC_IR_Flags_REPEAT ; Assert this is a REPEAT event
goto INT_End
ReceiveCommandState:
movlw d'32'
movwf NEC_IR_State ; Advnace to state 32 when we expect ADDRESS/COMMAND data
INT_End:
;
movf PCLATH_SAVE,W ;
movwf PCLATH ; Restore the saved context of the
movf STATUS_SAVE,W ; interrupted execution.
movwf STATUS ;
swapf WREG_SAVE,F ;
swapf WREG_SAVE,W ;
retfie ; Exit ISR and enable the interrupts.
;
; Receive COMMAND or REPEAT event
;
NEC_IR_NextState:
banksel PORTB
bcf STATUS,C
btfsc INTCON,T0IF
bsf STATUS,C
banksel NEC_IR_RawData
rlf NEC_IR_RawData,F
rlf NEC_IR_RawData+1,F
rlf NEC_IR_RawData+2,F
rlf NEC_IR_RawData+3,F
EndOfBit:
banksel PORTB
btfss PORTB,0 ; Skip when flash goes off
goto EndOfBit
clrf TMR0
bcf INTCON,T0IF
decf NEC_IR_State,F
btfss STATUS,Z
goto INT_End
;
; Validate ADDRESS and COMMAND
;
banksel NEC_IR_RawData
comf NEC_IR_RawData,W
xorwf NEC_IR_RawData+1,W
btfss STATUS,Z
goto INT_End
comf NEC_IR_RawData+2,W
xorwf NEC_IR_RawData+3,W
btfss STATUS,Z
goto INT_End
movf NEC_IR_RawData+1,W
movwf NEC_IR_Command
movf NEC_IR_RawData+3,W
movwf NEC_IR_Address
bsf BIT_NEC_IR_Flags_COMMAND
goto INT_End
;
; Initialize the PIC hardware
;
START:
clrf INTCON ; Disable all interrupt sources
banksel BANK1
clrf PIE1
clrf PIE2
movlw b'01100000'
movwf OSCCON ; Set internal oscillator at 4MHz
movlw b'10000001' ; Pull-ups off, INT edge high to low, WDT prescale 1:1
movwf OPTION_REG ; TMR0 clock edge low to high, TMR0 clock = FCY, TMR0 prescale 1:4
; TIMER0 will assert the overflow flag every 256*4 (1024)
; instruction cycles, with a 4MHz oscilator this ia 1.024 milliseconds.
movlw b'11111111' ;
movwf TRISA
movlw b'11111111' ;
movwf TRISB
movlw b'11111111' ;
movwf TRISC
movlw b'11111111' ;
movwf TRISD
; Set all ADC inputs for digital I/O
banksel BANK3
movlw b'00000000'
movwf ANSEL
movlw b'00000000'
movwf ANSELH
banksel BANK2
clrf CM1CON0 ; turn off comparator
clrf CM2CON0 ; turn off comparator
banksel BANK1
movlw b'00000000'
movwf ADCON1
clrf VRCON ; turn off voltage reference
banksel BANK0
movlw b'10000000'
movwf ADCON0
pagesel main
goto main
;
; Main data
;
MAIN_DATA UDATA
RepeatCount res 1
;
; Main application code
;
MAIN_PROG CODE
;
; Main application initialization
;
main:
lcall OpenXLCD
movlw LINE_ONE
lcall SetDDRamAddr
movlw LOW(LCD_message1)
movwf pszLCD_RomStr
movlw HIGH(LCD_message1)
movwf pszLCD_RomStr+1
lcall putrsXLCD
banksel NEC_IR_Flags
clrf NEC_IR_Flags
clrf NEC_IR_State
bcf BIT_NEC_IR_Flags_COMMAND
bcf BIT_NEC_IR_Flags_REPEAT
bcf INTCON,INTF
bsf INTCON,INTE
bsf INTCON,GIE
;
; Application process loop
;
AppLoop:
movf NEC_IR_Flags,F ; Check for event
btfsc STATUS,Z ; Skip if any event bit set
GOTO AppLoop ;
banksel NEC_IR_Flags
btfsc BIT_NEC_IR_Flags_REPEAT ; skip of not a REPEAT event
goto IncrementCount
banksel RepeatCount
clrf RepeatCount
;
; Increment repeat count
;
IncrementCount:
banksel RepeatCount
incfsz RepeatCount,W
movwf RepeatCount
;
; Show measurement for Start Of Transmission (SOT) flash
;
movlw LINE_TWO
lcall SetDDRamAddr
movf NEC_IR_StartFlash,W
lcall PutDecXLCD
;
; Show measurement for pause after SOT flash
;
movlw ' '
lcall WriteDataXLCD
movf NEC_IR_CdPause,W
lcall PutDecXLCD
;
; Show decoded ADDRESS and COMMAND
;
movlw ' '
lcall WriteDataXLCD
banksel NEC_IR_Address
movf NEC_IR_Address,W
lcall PutHexXLCD
banksel NEC_IR_Command
movf NEC_IR_Command,W
lcall PutHexXLCD
;
; Show REPEAT count
;
movlw ' '
lcall WriteDataXLCD
banksel RepeatCount
movf RepeatCount,W
lcall PutHexXLCD
;
; Clear event flags to enable capture of next event
;
banksel NEC_IR_Flags
clrf NEC_IR_Flags
lgoto AppLoop
;
; LCD messages
;
MAIN_CONST code
LCD_message1:
dt "NEC IR Decode v0",0
END
我已经用汇编语言为 8 位 PIC 控制器编写了很多代码。该应用程序包含一些非常微妙的技巧。其中没有足够的评论来解释它是如何工作的以及为什么工作。你只需要自己分析一下。
NEC IR 协议的诀窍在于它完全是关于 IR 闪光之间的停顿。如果网上有关于NEC IR 控制协议的准确、完整和易懂的描述我找不到了。
我原以为可以教您如何编写此代码,但我认为我还不够好,无法做到这一点。我只希望这可以作为你的例子。