|
作者:sword__yang
红外遥控已经广泛地用在音响产品中,下面我们将以NEC的红外遥控发射芯片uPD6121的编码格式为例,介绍如何用MCU来做NEC格式的红外遥控解码。
uPD6121红外遥控发射集成电路采用用NEC的传输格式,目前广泛地应用在电视机,录像机,音响设备,空调机等家电产品上。结合外部二极管和电阻器可以做成客户自己定义的编码,最高可以获得65536种遥控编码。该芯片体积小,功耗低,可以做成外形小巧的红外遥控发射器。图II-4.0是该芯片的引脚及功能方框图,遥控器的应用电路图请参见图II-4.1,客户编码电阻和二极管接入位置的改变,可以改变数据流的客户编码部分,可以用来区分不同厂家、不同种类产品的遥控器。
NEC的传输格式由引导码、客户编码( 16位)、数据码( 16位)和持续脉冲等部分。图II-4.2和图II-4.2是它们各个部分的波形,对于这些波形,一定要仔细地分析,否则解码就无从入手了 。
(原文件名:1.jpg)
(原文件名:2.jpg)
(原文件名:3.jpg)
(原文件名:4.jpg)
分析:
NEC格式的红外遥控码的主要特征:
以两个脉冲之间的间隔时间长短来区分各种不同的遥控指令的信息含义。
1)引导码:前高(9mS)+ 后低(4.5mS) = 13.5mS。
2)信息码:信息码包括客户编码和数据码,它们都是以两个脉冲上升沿之间的间隔长短为“BIT 0”或者“BIT 1”的识别特征的:
a)两个脉冲上升沿之间的间隔 = 1.125mS: 数据BIT = 0;
b)两个脉冲上升沿之间的间隔 = 2.25mS: 数据BIT = 1。
3)持续码:当按键一直按下时,遥控指令在发送了第一组信息码后,就不再重复发送信息吗,这时改为发送一种持续码:
“前高(9mS)”+ “后低(2.25mS)” = 11.25mS
抓住了这三个主要特征,我们就可以利用16F873A MCU的CCP(Capture/Compare/PWM 捕捉/ 比较/ 脉宽调制) 模块的“时间捕捉”来实现脉冲间隔的捕捉。
每个16F873A的CCP模块有一个16位的捕捉寄存器:CCPRxH/CCPRxL,和一个CCPxCON控制寄存器,可以设定CCPxCON为对应于CCP引脚上每一个上升沿到来就产生一次捕捉中断,这时候MCU内部的定时器TIMER1的计数值就自动赋给捕捉寄存器CCPRxH/CCPRxL,第N+1次捕捉寄存器的值减去第N次的捕捉寄存器的值,就是这两次上升沿之间的间隔时间。利用CCP的时间捕捉功能,我们就可以把遥控码的信息解调出来了。
解码算法:
第一步:通过标志位变量FLG2,FIRST,以及一个复位计时器完成接收准备。当遥控脉冲串停止150 mS后,复位计时器减数为0, 复位FLG2,FIRST,这样就可以在下一个遥控指令到来时,把遥控码的第一个上升沿识别出来。
1-1:每次遥控接收头来的上升脉冲产生一次CCP中断,中断服务子程序检测是否第一个脉冲上升沿(FLG2,FIRST为低)?
1-2:不是,跳去2-1做宽度判别;是第一个脉冲上升沿,清TIMER1定时器、清CCP寄存器、清上次时间暂存变量打开开TIMER1为捕捉做准备。
第二步:识别引导码:
2-1:读出CCP寄存器捕捉到的时间值,减去上一次的时间值,判断标志变量FLG2,DATA_EN数据接收是否开始?
2-2:已经开始,转3-1判断是数据“0”还是数据“1”的判断;没有开始,比较捕捉到的时间是否大于11.25mS?
2-3:若不大于,说明是持续脉冲,转5-1持续脉冲处理;若大于,说明是引导码,设数据接收开始标志位FLG2,DATA_EN为高,准备接收数据。
第三步:是数据“0”还是数据“1”的判断:
3-1:捕捉到的时间值是否大于1.125mS ?
3-2:大于,设标志位变量FLG2,C_STATS为高;不大于,设为低(把判断结果带到后面的处理);
3-3:判断是否接收完客户码1(8个BIT)?
3-4:是,存入客户码1,转3-5;不是,继续接收;
3-5:是否接收完客户码2(8个BIT)?
3-6:是,存入客户码2,转3-7;不是,继续接收;
3-7:是否接收完数据原码(8个BIT)?
3-8:是,存入数据原码,转3-9;不是,继续接收;
3-9:是否接收完数据反码(8个BIT)?
3-10:是,存入数据反码,转4-1;不是,继续接收;
第四步:比较客户码是否有效(客户码是客户设定的常量);
4-1:客户码1=设定值吗?
4-2:等于,转4-3;不等于设定值,接收无效退出(不是我的遥控器!);
4-3:客户码2=设定值吗?
4-4:等于,转4-5;不等于设定值,接收无效退出(两个客户码不相等,有误码);
4-5:遥控数据比较:原码异或(XOR)反码=0FFH ?(数据是否相等);
4-6:是,数据有效,遥控码成功解出;不是,数据无效退出。
第五步:持续码处理:
5-1:持续脉冲是否连续3次?(这是调整持续按键动作的间隔用的,例如调整音量持续改变的快慢);
5-2:是,转5-3;不是,退出;
5-3:是否不能持续操作的遥控码?(如电源开关、静音等是不能持续操作的);
5-4:不是,转5-4;是,不做持续处理,退出;
5-5:从备份寄存器恢复有效接收码,退出。
5-6:若持续脉冲还在发送,继续5-1。
算法完成。
【小结】:看似很复杂的NEC码流,其实我们只需要抓住是“持续脉冲”还是“引导码”;是数据“0”还是数据“1”这两个关键的判断点,就可以轻松解调出遥控信息了。
NEC格式遥控解码例程如下:
变量说明:
TIMR1H/TIMR1L: MCU的TIMER1定时寄存器
CCPR1H/CCPR1L: MCU的CCP捕捉寄存器
TLAH/TLAL: 上次捕捉到的时间值
DELTH/DELTL: 本次-上次=本次时间增量
CUSTOI: 客户码1
CUSTOB: 客户码2
DATAI: 数据原码
DATAB: 数据原码
RX: 数据类型导向计数
VALID: 有效遥控码
VALIB: 有效遥控码备份
位变量:
FLG2,FIRST: 首个脉冲标志位(当收到CCP中断时,如果本位为低,说明是第一个脉冲)
FLG2,DATA_EN: 数据接收开始标志位,本位为高,数据串接收开始
FLG2,C_STATUS:数据“1”标志,当收到的数据BIT判定为1,本位为高
;===========================================
; TIMER CAPTURE MODE
; REMOCON RECEIVE & DECODE
;===========================================
CCP_INT:
MOVWF W_TEMP ; 保护W寄存器现场
SWAPF STATUS,W
BCF STATUS,RP0
MOVWF STATUS_TEMP ; 保护状态寄存器现场
BCF PIR1,CCP1IF
MOVLW .3 ; 给遥控复位计数器赋值
MOVWF FIRST_RESET ; 3X50mS=150mS(基本定时中断为50mS一次)
BTFSC FLG2,FIRST ; 判断是否是第一个脉冲?
GOTO RC_0 ; 不是,跳去做宽度鉴别
BSF FLG2,FIRST ; 是,取消第一脉冲标志
CLRF TMR1H ; 清TIMER1定时寄存器高位
CLRF TMR1L ; 清TIMER1定时寄存器低位
CLRF CCPRL ; 清CCP捕捉寄存器低位
CLRF CCPRH ; 清CCP捕捉寄存器高位
CLRF TLAL ; 清上次时间值低位
CLRF TLAH ; 清上次时间值高位
BSF T1CON,TMR1ON ; 开定时器1
GOTO RC_EX ; 退出
RC_0:
MOVF TLAH,W ; 脉冲宽度鉴别开始
SUBWF CCPR1H,W ; 计算时间增量
MOVWF DELTH
MOVF CCPR1H,W
MOVWF TLAH ; 刷新“上次”时间值
RC_1:
MOVF DELTH,W
BTFSC FLG2,DATA_EN ; 数据接收开始?
GOTO DATAIN ; 是,去数据接收脉宽判别
SUBLW 0X30 ; 引导码脉宽判别
BTFSC STATUS,C ; 是引导码?
GOTO CONTIN ; 不是,跳到持续脉冲处理
MOVLW 0X80 ; 是,清理数据接收寄存器
MOVWF CUSTOI ; 为数据接收做好准备
MOVWF CUSTOB
MOVWF DATAI ; 设最高位为1是为了后面利用数据右移位来移入BIT串
MOVWF DATAB
BSF FLG2,DATA_EN ; 设数据开始标志
CLRF RX
CLRF CONTC ; 清持续脉冲计数器
GOTO RC_EX ; 退出
DATAIN:
MOVF DELTH,W
SUBLW .7
BTFSC STATUS,C ; 数据位“0”/“1”判别
GOTO RC_2
BSF FLG2,C_STATUS ; 为“1”,设“1”标志位
GOTO RC_3
RC_2:
BCF FLG2,C_STATUS ; 为“0”,清“1”标志位
RC_3:
MOVF RX,W
SUBLW .0 ; 数据类别导向
BTFSC STATUS,C
GOTO CUSTO_I ; RX=0:客户码1
MOVF RX,W
SUBLW .1
BTFSC STATUS,C
GOTO CUSTO_B ; RX=1:客户码2
MOVF RX,W
SUBLW .2
BTFSC STATUS,C
GOTO DATA_I ; RX=2:数据原码
MOVF RX,W
SUBLW .3
BTFSC STATUS,C
GOTO DATA_B ; RX=3:数据反码
GOTO RC_EX ; 以上都不是=误码,退出
CUSTO_I:
BTFSS FLG2,C_STATUS ; 数据位标志为高?
GOTO CI_0
BSF STATUS,C ; 是,设进位位为高
GOTO CI_1
CI_0:
BCF STATUS,C ; 不是,清进位位
CI_1:
RRF CUSTOI ; 客户码1右移一位
BTFSS STATUS,C ; 共移动了8次吗?
GOTO RC_EX ; 不是,退出
INCF RX ; 是,客户码1接收完成,导向变量加1
GOTO RC_EX
CUSTO_B:
BTFSS FLG2,C_STATUS ; 客户码2移位接收,与客户码1接收到过程相同
GOTO CB_0
BSF STATUS,C
GOTO CB_1
CB_0:
BCF STATUS,C
CB_1:
RRF CUSTOB
BTFSS STATUS,C
GOTO RC_EX
INCF RX
GOTO RC_EX
DATA_I:
BTFSS FLG2,C_STATUS ; 数据原码移位接收,与客户码1接收到过程相同
GOTO DI_0
BSF STATUS,C
GOTO DI_1
DI_0:
BCF STATUS,C
DI_1:
RRF DATAI
BTFSS STATUS,C
GOTO RC_EX
INCF RX
GOTO RC_EX
DATA_B:
BTFSS FLG2,C_STATUS ; 数据反码移位接收,与客户码1接收到过程相同
GOTO DB_0
BSF STATUS,C
GOTO DB_1
DB_0:
BCF STATUS,C
DB_1:
RRF DATAB
BTFSS STATUS,C
GOTO RC_EX
CLRF RX
CUST:
BCF FLG2,DATA_EN ; 客户码对照,清数据接收允许标志
BCF FLG2,FIRST ; 清第一个脉冲标志,准备下次接收
MOVLW #CUSTOM_CODE
SUBWF CUSTOI,W ; 比较客户码1
BTFSS STATUS,Z
GOTO RC_EX ; 不同,不是本机的遥控器
MOVF CUSTOB,W
XORLW #CUSTOM_CODE ; 相同,比较客户码2(通常是客户码1的反码)
SUBLW 0XFF
BTFSS STATUS,Z
GOTO RC_EX ; 不同,不是本机的遥控器
DATACM:
MOVF DATAI,W ; 相同,验证数据码
XORWF DATAB,W
SUBLW 0XFF
BTFSS STATUS,Z
GOTO RC_EX ; 原码和反码验证失败,退出
MOVF DATAI,W
MOVWF VALID ; 原码和反码验证OK,保存码值到VALID
MOVWF VALIB ; 备份码值到VALIB,为持续按键处理做准备
GOTO RC_EX
CONTIN:
INCF CONTC ; 持续脉冲处理,持续计数器加1
MOVF CONTC,W
SUBLW .3
BTFSC STATUS,C ; 持续收到3次?
GOTO RC_4 ; 不是,去清理标志
MOVLW .0 ; 是,清计数器
MOVWF CONTC
MOVF VALIB,W
SUBLW #ON/OFF_CODE ; 检验是否不允许做持续操作的遥控码
BTFSC STATUS,Z ; 是 ON/OFF 键吗?
GOTO RC_4 ; 是,不做持续处理退出
MOVF VALIB,W
SUBLW #MUTE_CODE
BTFSC STATUS,Z ; 是 MUTE 键吗?
GOTO RC_4 ; 是,不做持续处理退出
MOVF VALIB,W
MOVWF VALID ; 不是,把原来备份数据恢复到键值寄存器VALID
RC_4:
BCF FLG2,FIRST ; 清第一个脉冲标志
BCF FLG2,DATA_EN ; 清数据接收允许标志
RC_EX:
SWAPF STATUS_TEMP,W ; 恢复状态寄存器
MOVWF STATUS
SWAPF W_TEMP,F
SWAPF W_TEMP,W ; 恢复W寄存器
RETFIE ; 退出CCP中断服务子程序 |
阿莫论坛20周年了!感谢大家的支持与爱护!!
如果想吃一顿饺子,就得从冰箱里取出肉,剁馅儿,倒面粉、揉面、醒面,擀成皮儿,下锅……
一整个繁琐流程,就是为了出锅时那一嘴滚烫流油的热饺子。
如果这个过程,禁不住饿,零食下肚了,饺子出锅时也就不香了……《非诚勿扰3》
|