最近用到了一种常见的低成本红外遥控器:
这种遥控器的编码方式为NEC,它的特征如下:
1、8 位地址和 8 位指令长度;
2、地址和命令 2 次传输(确保可靠性)
3、PWM 脉冲位置调制,以发射红外载波的占空比代表“0”和“1”;
4、载波频率为 38Khz;
5、位时间为 1.125ms 或 2.25ms;
NEC 码的位定义:一个脉冲对应 560us 的连续载波,一个逻辑 1 传输需要 2.25ms(560us 脉冲+1680us 低电平),一个逻辑 0 的传输需要 1.125ms(560us 脉冲+560us 低电平)。而遥控 接收头在收到脉冲的时候为低电平,在没有脉冲的时候为高电平,这样,我们在接收头端收到 的信号为:逻辑 1 应该是 560us 低+1680us 高,逻辑 0 应该是 560us 低+560us 高。
NEC 遥控指令的数据格式为:同步码头、地址码、地址反码、控制码、控制反码。同步码 由一个 9ms 的低电平和一个 4.5ms 的高电平组成,地址码、地址反码、控制码、控制反码均是8 位数据格式。按照低位在前,高位在后的顺序发送。采用反码是为了增加传输的可靠性(可 用于校验)。
一个实际的通信例子如下:
根据通信协议,逻辑0和逻辑1的高电平时间时不同的,由此我们想到用单片机定时器的输入捕获功能来进行解码。思路如下:初始化定时器后配置为上升沿捕获,发送捕获中断后记录捕获值,再捕获下降沿,下降沿捕获到的值与上升沿的值之差即为高电平时间,根据高电平时间得到是逻辑0、逻辑1还是连续发送。
基于MSP432P401单片机的红外解码程序如下:
//红外遥控器
#define IR_RXD GPIO_PORT_P5, GPIO_PIN7
#define IR_Romate GPIO_PORT_P4, GPIO_PIN4
#define REMOTE_ID 0
uint8_t IRcount=0;
uint16_t IRCapValue1=0;
uint16_t IRCapValue2=0;
uint16_t IRCapValue=0;
void Romate_Init(void)
{
/* 定时器配置参数*/
Timer_A_ContinuousModeConfig continuousModeConfig =
{
TIMER_A_CLOCKSOURCE_SMCLK, // SMCLK Clock Source
TIMER_A_CLOCKSOURCE_DIVIDER_6, // SMCLK/6 = 1MHz
TIMER_A_TAIE_INTERRUPT_ENABLE, // Enable Timer ISR
TIMER_A_SKIP_CLEAR // Skup Clear Counter
};
/* Timer_A 捕获模式参数配置*/
Timer_A_CaptureModeConfig captureModeConfig1 =
{
TIMER_A_CAPTURECOMPARE_REGISTER_2, // CC Register 2
TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE,//上升沿和下降沿
TIMER_A_CAPTURE_INPUTSELECT_CCIxA, // CCIxB Input Select
TIMER_A_CAPTURE_SYNCHRONOUS, // Synchronized Capture
TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE, // Enable interrupt
TIMER_A_OUTPUTMODE_OUTBITVALUE // Output bit value
};
GPIO_setAsPeripheralModuleFunctionInputPin(IR_RXD,GPIO_PRIMARY_MODULE_FUNCTION);
GPIO_setAsOutputPin(IR_Romate);
GPIO_setOutputLowOnPin(IR_Romate);
Timer_A_initCapture(TIMER_A2_BASE, &captureModeConfig1);
Timer_A_configureContinuousMode(TIMER_A2_BASE, &continuousModeConfig);
Interrupt_enableInterrupt(INT_TA2_N);
Timer_A_startCounter(TIMER_A2_BASE, TIMER_A_CONTINUOUS_MODE);
}
//遥控器接收状态
//[7]:收到了引导码标志
//[6]:得到了一个按键的所有信息
//[5]:保留
//[4]:0表示捕获上升沿,1表示捕获下降沿
//[3:0]:溢出计时器
uint8_t Romsta;
uint32_t RmtRec=0; //红外接收到的数据
uint8_t RmtCnt=0; //按键按下的次数
void TA2_N_IRQHandler(void)
{
/*溢出中断*/
if(Timer_A_getEnabledInterruptStatus(TIMER_A2_BASE))
{
Timer_A_clearInterruptFlag(TIMER_A2_BASE);
if(Romsta&0x80)//上次有数据被接收到了
{
IRcount++;
Romsta&=~0X10;//取消上升沿已经被捕获标记
if((Romsta&0X0F)==0X00)
Romsta|=1<<6;//标记已经完成一次按键的键值信息采集
if((Romsta&0X0F)<14)
Romsta++;
else
{
Romsta&=~(1<<7);//清空引导标识
Romsta&=0XF0; //清空计数器
}
}
}
/*捕获中断*/
if(Timer_A_getCaptureCompareEnabledInterruptStatus(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2))
{
Timer_A_clearCaptureCompareInterrupt(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2);
/*捕获到下降沿*/
if(Timer_A_getSynchronizedCaptureCompareInput(TIMER_A2_BASE,
TIMER_A_CAPTURECOMPARE_REGISTER_2,TIMER_A_READ_CAPTURE_COMPARE_INPUT)
==TIMER_A_CAPTURECOMPARE_INPUT_LOW)
{
IRCapValue2=Timer_A_getCaptureCompareCount(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2);
IRCapValue=IRCapValue2-IRCapValue1+IRcount*65536;
IRcount=0;
/*接收到引导码*/
if(Romsta&0x80)
{
if(IRCapValue>300&&IRCapValue<800)//560为标准值,560us
{
RmtRec<<=1; //左移一位.
RmtRec|=0; //接收到0
}else if(IRCapValue>1400&&IRCapValue<1800) //1680为标准值,1680us
{
RmtRec<<=1; //左移一位.
RmtRec|=1; //接收到1
}else if(IRCapValue>2200&&IRCapValue<2600) //得到按键键值增加的信息 2500为标准值2.5ms
{
RmtCnt++; //按键次数增加1次
Romsta&=0XF0; //清空计时器
}
}
/*接收引导码*/
else if(IRCapValue>4200&&IRCapValue<4700) //4500为标准值4.5ms
{
Romsta|=1<<7; //标记成功接收到了引导码
RmtCnt=0; //清除按键次数计数器
RmtRec=0;
}
Romsta&=~(1<<4);
}
/*捕获到上升沿*/
else
{
IRCapValue1=Timer_A_getCaptureCompareCount(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2);
Romsta|=0x10;
IRcount=0;
}
}
}
//扫描遥控器
uint8_t RomateScan(void)
{
uint8_t sta=0;
uint8_t t1,t2;
if(Romsta&0x40)
{
t1=RmtRec>>24;//得到地址码
t2=(RmtRec>>16)&0xff;//得到地址反码
if((t1==(uint8_t)~t2)&&t1==REMOTE_ID)//检验遥控识别码(ID)及地址
{
t1=RmtRec>>8;
t2=RmtRec;
if(t1==(uint8_t)~t2) sta=t1;//键值正确
}
if((sta==0)||((Romsta&0X80)==0))//按键数据错误/遥控已经没有按下了
{
Romsta&=~(1<<6);//清除接收到有效按键标识
RmtCnt=0; //清除按键次数计数器
}
}
return sta;
}
一个用这种遥控器遥控小车的例子:
https://v.youku.com/v_show/id_XNDA4Nzk4OTEwNA==.html?spm=a2h3j.8428770.3416059.1