MSP430G2553 应用之红外遥控器按键编码的破解(ls_core)
之前笔者利用 51 单片机、FPGA 和 S3C2440 对红外遥控器的编码破解过。由于最近手里
使用的单片机为 MSP430G2553,同时也为了扩展 LaunchPad 开发板按键所需,笔者还是将
之前弄使用过的红外遥控器拿了起来。使用遥控器作为开发板的按键使有个好处就是,占用
一个 IO 口即可扩展出很多按键。但是,这样做的不足就是,占用了一个定时器和相应中断
的资源。所以,建议大家应该依据具体的项目工程而确定具体的解决方案。好了进入正题。
一 红外时序
在这里笔者探讨的问题是破解红外遥控器的编码,而不是对其编码。所以,我们直接谈
谈红外接收头 1838T 接收到红外遥控器发送出的按键编码时序。笔者在普源(RIGOL)示波器
上观察到的时序波形如图 1 红外遥控器按键编码时序所示:
图 1 红外遥控器按键编码时序
面对这样一列串行的序列,笔者将其测量、记录、整理并为其制作了一张时序图以便讲
解,绘制的时序图如下图 2 红外编码时序图 所示:
图 2 红外编码时序图
接下来,让我们一起详细地探讨一下这一列时序波形。首先当我们手中的遥控器的按键
被按下时,其红外发射头会发射出红外线(该红外线载有数据信息,即对应的按键编码),
然后红外接收头 1838T 会接收该红外线对其解码还原载波信息。所还原的信息即为按键编码
的串行时序信息,如上图 2 所示。
那笔者所讲的破解编码是指的什么呢?很显然,笔者所讲的破解就是要把图 2 所示的串
行数据转化成方便微机或者是人记忆识别的并行数据。好,接着让我们一起分析一下这个时
序。
⑴ 空闲状态:
当红外接收头 1838T 没有数据时(无按键按下,或是数据转化完成),红外接收头的输
出引脚会一直保持高电平,即上图 2 所指的空闲状态。
⑵ 引导码:
当红外接收头 1838T 接收到了数据,其输出引脚首先会由空闲的高电平状态跳转为低电
平状态,该低电平状态会保持 9ms,那么着 9ms 的高电平状态即称之为引导码。
⑶ 结果码:
引导码过后,红外接收头的输出引脚会由低电平状态跳回到高电平状态并保持 4.5 毫秒,
那么这 4.5ms 的高电平状态即称之为结果码。
⑷ 逻辑编码区:
结果码过后,红外接收头的输出引脚便会输出一段高低电平跳转维持 53.76ms 的时序区
(该区内容之后详细探讨),之后再次回答空闲区,标志的一次转化完成。
二 逻辑编码
为了更好的说明逻辑编码区的信息,笔者将逻辑编码区放大进行讲解,如图 3 逻辑编
码区所示:
图 3 逻辑编码区
凡是在逻辑编码区的时序列,其低电平保持时间全部为 0.56ms,高电平保持时间不是
0.56ms 即为 1.68ms(没有任何其他情况)。
那么当单片机接收到这一串行的数据之后是按照什么样的规则将其转化成相应的并行
数据的呢?规则是这样的,凡是在逻辑编码区内的串行数据,将连续的 0.56ms 的低电平和
0.56ms 的高电平编码为‘0’,将连续的 0.56ms 的低电平和 1.68ms 的高电平编码为‘1’。
如果按照这样的规则对逻辑去内的串行数据进行编码,编码完成后会形成一个 32 为的编码,
其编码图如下图 4 逻辑编码区编码结果所示:
图 4 逻辑编码区编码结果
该编码结果共 32 位,占用 4 个字节,其高字节 C31-C24 为遥控器识别码,C23-C16 为
遥控器识别码的反码,即遥控识别码和遥控识别反码之和为 0xFFFF,按键操作码是不同遥控
器的识别码,即不同遥控器的遥控识别码不同,同一遥控器不同按键的遥控识别码相同。
其低字节 C15-C8 为按键操作码,C7-C0 为按键操作码的反码,即按键操作码和按键操作
反码之和为 0xFFFF,同一遥控器不同按键的按键操作码不同。
因此可以推断,理论上同一遥控器可以接入 255 个按键。呵呵,如果需要多按键的项目
建议使用此方案哦。
三 破解算法
明白了基本原理就可以动手借助单片机这个平台编程对其破解了。笔者在这里利用的是
MSP430g2553 这款单片机。但是在编程之前还是要确定一下破解方案最为重要。
⑴ 硬件条件
MSP430G2553 拥有两个定时器,每个定时器的比较捕获模块儿都支持捕获功能,捕获
方有:捕获上升沿、捕获下降沿和捕获上升沿和下降。在本文里笔者选用 Timer1 的捕获模
块儿 CCR1 的下降沿捕获功能来记录每个下降沿到来时定时器 Timer1 中的计数值。
⑵ 软件算法
利用已有的硬件条件制作软件算法流程图如下图 5 软件流程图所示:
图 5 软件流程图
笔者的定时器 Timer1 的驱动输入 时钟配置为 ACLK,其是有外部的振荡器输入的时钟
大小为 32.768KHz,每个时钟周期为 0.0305ms。由于每个周期的编码序列为(9+4.5+53.7)
ms=67.2ms。所以笔者设置的定时值为 67.2/0.0305=2203。为了安全起见,该值稍微设置大
了一些,这里设置为 3000。
这样当系统上电之后,进行必要的初始化后进入主函数工作。当有按键按下时,捕获模
块 CCR1 会捕获到引导码的下降沿,产生中断。当第一次中断时,初始化红外编码数据并开
启定时器 Timer1。对于红外数据笔者定义了一个结构体如下:
typedef struct CODE
{
char ir_flag;
int code_time[33];
int code_num;
int code;
} IrStruct;
/*如果有有效的红外数据过来,该位置1*/
/*数组记录红外编码的33组逻辑编码*/
/*数组记录的逻辑编码个数*/
/*编码值*/
之后的每次中断中通过读取 CCR1 将读取到的定时器计数值记录在结构体的数组中。这
样,记满 33 次后就记好了一个按键的全部计数值,然后通过一定的算法当把 32 位编码的时
间全部记录好后。对记录好的时间进行处理(相邻两个做差、比较),处理后比较,若其时
间差大于 1.525ms 可认为是逻辑编码'1',否则为逻辑编码‘0’。确定红外编码记录于结构体的
code 中并置位 ir_flag 位,表示有按键按下,等待主程序将数据读走。
在这里笔者给出计算按键的子函数:
pIr->code |=0x1;
for(pIr->code_num=NUM-1;pIr->code_num>24;pIr->code_num--){
if((pIr->code_time[pIr->code_num]-pIr->code_time[pIr->code_num-1]
static void CalCode()
{
)>50)/*如果记录数据大于50即时间差大于50*0.0305ms,则认为是逻辑编码‘1’*/
}
pIr->code_num=-1;
pIr->ir_flag=1; /*该位置1表示,有有效的按键信息录入,等待CPU读走*/
else
if(pIr->code_num>25)
pIr->code<<=0x1;
pIr->code_time[pIr->code_num]=0;
pIr->code &=~(0x1);
}
好啦,今天的博文就写到这里,谈到这里,笔者个人认为已经把红外遥控器的编码已经
解释很是清楚了。剩下的事儿就是根据算法将程序编写出来,然后在硬件上调试出来就 OK
了!当你破解了红外遥控器编码,以后红外遥控器你想怎么用就怎么用了。占用一个 IO 口
便可实现对几十个按键利用。当然了,这是以牺牲定时器和中断的资源为代价的哦!
在下面附出定时器 Timer1 的初始化程序:
: timer1.c
: 李帅
: 亦然
/********************************************************************
* File name
* Creating time : 2012-7-22
* Author
* pen-name
* Organization : 济南大学(2013年本科毕业)
* Function
*
* Declareing : 如有错误的地方请各位指出,交流。交流使我们共同进步!
: ls_core@sina.cn
* E-mail
: QQ:1021480125 客:http://blog.sina.com.cn/lscore
* Contact way
********************************************************************/
#include
#include "uart.h"
#include "ir.h"
: 该文件可用作模块儿化编程作为MSP430G2553的定时器
Timer1捕获模块儿CCR1的初始化。
/********************************************************************
* 名称 : Timer1A3Init()
* 功能 : Timer1捕获模块儿CCR1的初始化
* 输入 : 无
* 返回值: 无
********************************************************************/
void Timer1A3Init()
{
/****************************************************************
* 定时器Timer1的TA1CCR1捕获信号选择为TA1.1,由P2.1输入
***************************************************************/
P2DIR &=~BIT1 ;
P2SEL |= BIT1;
/****************************************************************
* 设置定时器Timer1_A
* TASSEL_1:Timer A clock source select: 1 - ACLK
* MC_1 :Timer A mode control: 1 - Up to CCR0
* TAIE :允许主计数器TA溢出中断
* TACLR :Timer A counter clear
* *************************************************************/
TA1CTL |= TASSEL_1 + MC_1 + TACLR; //时钟源:SMCLK;增计数模式//+ TAIE
/****************************************************************
* 设置定时器Timer1_A的捕获/比较模块1
* CCIE :允许定时器Timer0_A的捕获/比较模块1中断
* CM1 :捕获下降沿
* CAP :设为捕获功能
* SCS :同步捕获
* *************************************************************/
TA1CCTL1 |= CCIE +CM1 + CAP + SCS ;
/****************************************************************
* 设置定时器Timer1_A的捕获/比较模块0的计数值
* 计数值=(计数周期)*(32.768KHz)
* **************************************************************/
TA1R=0;
TA1CCR0 =0;
}
/********************************************************************
* 名称 : TA1_ISR
* 功能 : Timer1捕获模块儿CCR1中断服务程序
* 输入 : 无
* 返回值: 无
********************************************************************/
#pragma vector = TIMER1_A1_VECTOR
__interrupt void TA1_ISR(void)
{
}
/********************** end of file *********************************/
switch(TA1IV){
}
Record();
break;
case 0x02: {
}
default: break;
好啦,今天就将这些,希望前辈能多多指正,谢谢!我在后面还会将我的学习心得整理
成文,包括 FPGA 和 ARM 等。再次声明,文中若有技术错误或是不足望各位多多指正,多
多交流。共同交流使得我们共同进步!希望将我的学习心得与您分享,谢谢!下次总结再见。
Contact way
Blog :http://blog.sina.com.cn/lscore
E-mail :ls_core@sina.cn
微博 :http://weibo.com/liscore
QQ 号 :1021480125
QQ 交流群:249905429(亦然)
李 帅
2012/7/23