红外遥控接收头和红外遥控发射头在我们生活中是很常见的,大家在家里常用的液晶电视,空调以及无人机等都有遥控发射头的身影,当然有发射头就有接收头。但是他的原理是怎们样子的呢?如何实现的呢?市面上的资料零散,而且一看就要看好久。我已开始学习得时候,也是看得快入睡了,但是小编就从我自己解BUG的经历,来把我遇到的坑分享给大家,如果哪里有问题,请高人指点一下,学习一下。
大概讲一下目前IR发射头,别看一个红外发射头和红外接收头这么小一个东西,生产IR头的很多原材还在国外,也就是说很多技术也都还在国外,现在举几家比较出名的协议,以后你们可以根据他们的协议去找到他们对应产品的规格书,也可以学到不少东西。
一般来说,常用的是NEC码和sharp码,原因是因为早期夏普和NEC在我国国内电视机是主力市场。所以38KHZ的红外遥控器会比较常见。当然也有其他的,在这边我也收集了一些常用的码,来作为补充*1。

收集了一些常用的码,来作为补充*1。
一、那么红外发射头一般按照以下几种方式来分类:
1.1 标准3mm,5mm,8mm,10mm等,分有边和无边,也分圆头,平头,特殊形状。
1.2发射管的波长:
940nm一般用于红外遥控,光电开关等, 850nm一般用红外照明,补光,远距离信号传输等, 890nm一般用于美容,医疗仪器等。
1.3红外发射头根据协议
分为PPM和PWM协议*2,PWM,是英文Pulse Width Modulation的缩写,意思就是脉冲宽度调制。脉冲就是由高、低电平组成的信号序列,其中高电平的时间就是这里所说的脉冲宽度,也就是高电平维持的时间。

PPM是英文Pulse Position Modulation的缩写,意思是脉冲位置调制,又称脉位调制,实质上就是将多个通道的PWM放到“一根线”上进行传输,一个完整的PPM信号帧包含了多个通道的PWM值,下面看一个图解:

图中第一个波形为PPM信号,第二个波形为一通道的PWM,它对应到PPM信号的“K1”,第三个波形为二通道的PWM,它对应到PPM信号的“K2”,依次类推,“K8”对应到第八通道的PWM。
1、 对于红外的接收头也分DIP和SMT。
2、 等等一系列的这个很多种,主要还是根据元器件的特性来分类的,这个说不完。红外发射管主要区别是波长,外形,半功率角(发射角),辐射功率等。
那么话说回来,从遥控器发射端到设备接收端是如何实现这个过程的呢?请让我们根据资料来看这个问题*3。

红外发射电路由555时基电路(IC1)和红外发光二极管(VD1)等组成,如图3-37所示。IC 1 构成自激多谐振荡器,产生频率为38KHz、占空比约为1/3的方波脉冲,驱动红外发光二极管VD1向外发射被40kHz方波脉冲调制的红外光。

SB是遥控按钮,使用时按下SB,接通+6V电源,红外发射电路即发射红外光遥控指令。VD2是可见光发光二极管,作为遥控器工作指示灯。 R3是VD1和VD2的限流电阻。
2.2接收控制电路
接收控制电路如图3-38所示,由红外接收电路、反相器、双稳态触发器、双向晶闸管、电源电路等部分组成。
红外接收电路采用了专用集成电路CX20106(IC11),如图3-39所示。该集成电路内部包含有前置放大器、限幅放大器、带通滤波器、检波器、积分器和整形电路,接收中心频率为40kHz,可通过改变 R1进行微调。VD11是红外光敏二极管。

反正大致的硬件电路原路就是这么一个电路原理,反正芯片厂商也不会开放给我们看,如果有错误的地方请专业的IC厂商指出来,万分感激。如果有详细的资料也可以把大致的框架分享一下。
2.3接收头的外部电路
那么IR接收头以及发射头了,那么就要搭电路了,这个我就简略的说一下,因为这部分其实也就比较简单


接收电路
这边说明一下,由于接收头并不会100%收到来自遥控器的信号,且在芯片内部也出现了一定的偏差,所以一般在规格书内生产的厂商都会有标注High Level Pulse Width& Low Level Pulse Width。

所以在处理软件的时候要务必注意这边的高电平的宽度和低电平的宽度。
2.4遥控器的外部电路
遥控器看似简单的一个设备在里面也是有大量的讲究的,除了我们肉眼可以看到的几个按键和电池以外,在遥控器的内部还有专门的处理芯片。大致的框图如下图:

一般来说,遥控器的频率范围误差相对都会比较小,我看了大部分的IR发射头的误差基本也都在+/-5%左右,因为如果误差比较大的话,可能在做接收的时候就会有错误的信息。
当然除了硬件设计上面,最最关键的,也是我想说的就是软件,由于我们国内的NEC码最为常用,且根据我的测试以及网上资料最多的也是NEC码。所以本文章我就按照NEC的码的方给到大家最详细的方向。
三、 NEC码
3.1 NEC码特征
(1)每次传输两遍地址(用户码)和命令(按键值)(确保可靠性)
(2)8位地址和8位命令长度
(3)通过脉冲串之间的时间间隔来实现信号的调制(PPM)
(4)PWM脉冲宽度调制,以发射红外载波的占空比代表“0”和“1”
(5)38Khz载波,脉冲基本脉宽T周期(参考时间)副载波频率:(455/12)KHz= (37.916KHz)
(6)每位的周期为1.12ms(低电平)或者2.25ms(高电平)按照低位在前,高位在后的顺序发送。
(7)NEC协议典型脉冲链:有时候我们从示波器上量到的波形如下图所示:

3.2原理
3.2.1调制
就是用待传送信号去控制某个高频信号的幅度、相位、频率等参量变化的过程,即用一个信号去装载另一个信号。比如我们的红外遥控信号要发送的时候,先经过38K调制,如图所示

来回顾一下,上面调制的效果:
未调制之前:

调制之后:

3.2.2 NEC载波解调:
因为一体化接收头接收频率是38KHz,约26us,记住这个不是高电平的时间长度,这个是一个脉冲的时间长度也就是一个周期,例如我们利用一个中断产生38K脉冲,占空比是1/2,我们的中断时间就要设置为 1/38000/2 S中断一次,然后通过相隔一次中断电平翻转一次就形成了一个频率为38K占空比1/2的脉冲。所以在编程时,每两次中断的间隔时间为26/2us即13us。由上面可以知道,要发射9ms高电平+4.5ms低电平的前导码,由于高电平的发射要产生的是38KHz的脉冲,所以在每次中断中反转输出形成38KHz的脉冲,而低电平的发射只需要将引脚电平拉低即可,这样接收端接收到38KHz的信号则可知接收到的是高电平,而没有接收到38KHz则认为接收到的是低电平。
一体化红外接收头只接受38K信号(误差范围内),我们把接收头看出一个转换器。遇到38K就输出低电平,没有遇到38K就被上拉成高电平。于是所谓的“编码”的概念就这样产生了,我们利用有38K信号跟没有38K信号 这两种状态,利用红外接收头就翻译成低电平、高电平的信号。这就是最主要的东西。

NEC软件方式载波解调:
除了上述方式的硬件一体化红外接收头直接解调之外,还可以用软件的方式做解调。
大致的思路就是通过软件驱动+定时器方式,当收到的脉冲间隔在26us左右时,将其一直作为稳定的电平。
3.2.3 NEC中断处理
当有IR波形发过来时,内部计数器(Counter)会将两个相邻的正边沿触发(如图中红色箭头所示)的时间差值放到寄存器中。

与此同时,正边沿触发一个ISR,去读取这个寄存器的值,并以数组的形式保存起来。等波形获取完毕后,再通过解析这个数组的Data来解析出key值。
3.3协议详解
3.3.1引导码

由9ms高电平闪亮和4.5ms低电平不亮构成,共13.5ms,目的是为了接收方知道要开始编码了。
3.3.2重复码

由9ms高电平闪亮和2.25ms低电平不亮构成,共11.25ms,表示重复之前的数据。当遥控器一直被同一个按键按下的时候,会输出该波形。
3.3.3数据码0

0.56ms高电平闪亮和0.56ms低电平不亮构成,共1.12ms表示数据0。他的高电平与低电平一般是1:1的关系。
3.3.4数据码1

由0.56ms高电平闪亮和1.96ms低电平不亮构成,共2.52ms表示数据1。他的高电平与低电平一般是1:2或者1:3的关系。
3.3.5结束位

由0.63ms高电平闪亮构成用于数据帧或重复码之后的占位。
3.4数据结构
在NEC协议中,一个完整的全码 = 引导码 +地址码(8位) +地址反码(8位) + 操作码(8位) + 操作反码(8位) 。,但目前很多厂商并不使用标准的NEC数据结构,可能有5byte数据,可能全部4byte都用于数据传输等等。
但目前很多厂商并不使用标准的NEC数据结构,可能有5byte数据,可能全部4byte都用于数据传输等等。典型的NEC协议数据帧格式时序,包括引导码、用户码、用户反码、按键数据码和按键数据反码。用户码的用户反码用来校验用户码,按键数据反码的作用类似。

NEC协议数据发送顺序,从LSB(低位)到MSB(高位)

NEC 类型遥控器所截获的波形:遥控器的识别码是 Address=0xDD20;其中一个键值是Command=0x0E;波形先是发低位地址再发高位地址。所以0000,0100,1011,1011 反转过来就是1101,1101,0010,000 十六进制的DD20;也就是说接收的数据是反相的,即上文协议层写的高低电平对调。
3.5仿真波形
3.5.1接收波形

3.5.2引导码

3.5.3数据码0

3.5.4数据码1

3.5.5重复码

3.5.6结束位

一、 常见问题
一般来说常见的就是按键无效,按键不灵敏等问题,一般我们从几个方面入手来排除问题。
4.1判断IR接收头是否有问题
我们要先诊断出IR接收头,是否有问题。当我们使用遥控器的时候,我们可以测试IR头的输出,引脚是否可以得到符合NEC协议的波形。
4.2 判断IR发射头是否有问题
我们可以测试一下遥控器输出的波形是否正常,一般我们是测试遥控器发射管的发射端。
4.3 判断软件是否有问题
4.3.1软件判断0/1以及引导码等是否有问题
一般来说,软件的判断0或者1的机制是否有无问题,在此基础上要先确认,高电平或者低电平是否符合接收头的规格书内。接着在确认引导码等是否正常,另外最好要实际去用示波器测量一下波形,再来写代码,至于软件无非就是使用GPIO口来进行一个中断。
4.3.2要判断按键编码是否正确
要按照规格书内的来,确认编码是否符合遥控器的要求。
4.3.3 要判断软件的兼容性是否够强大
一般在大规模生产的情况下,由于IR发射头以及IR接收头属于模拟的一个器件,所以在软件上一定要保持好足够的余量,不然可能会出现部分的IR头失效或者不灵敏的问题,当然可以找供应商确认一下,他们的范围到底在哪里,方便我们做软件的解码。
4.3.4要判断在各个模式下是否使用的是相同逻辑的代码
由于IR头在产品过程中使用,会被软件不同的时候调用,所以这个时候我们就要确认各个模式下IR头写代码的逻辑是否一样的。如果不一样,要确保在各个场景下都要可以正常的使用这个IR头
4.3.5确认主芯片的时间t
针对不同的芯片他们的时间上,可能会有一点差异,所以我们也要核对一下时间t这个参数,虽然这个出现问题的可能性比较小,因为几乎整个系统时钟的t都会是一样的。但还是有可能出现临界的问题,这个是要小心的一个点。
五、参考软件
表示数据帧的开始
表示数据帧的开始
//遥控器接收状态
//bit7:收到了引导码标志
//bit6:得到了一个按键的所有信息
//bit5:保留
//bit4:标记上升沿是否已经被捕获
//bit[3:0]:溢出计时器
u8 remoteState=0;
u16 captureva lue;//下降沿时计数器的值
u32 remoteCode=0;//红外接收到的数据
u8 remoteCnt=0;//按键按下的次数
void TIM2_IRQHandler(void)
{
u16 state;
if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET)
{
if(remoteState&0x80)//上次有数据被接收到了
{
remoteState&=~0X10;//取消上升沿已经被捕获标记
if((remoteState&0X0F)==0X00)remoteState|=1<<6;//标记已经完成一次按键的键值信息采集
if((remoteState&0X0F)<14)remoteState++;
else
{
remoteState&=~(1<<7);//清空引导标识
remoteState&=0XF0;//清空计数器
}
}
}
if(TIM_GetITStatus(TIM2,TIM_IT_CC2)!=RESET)
{
if(RDATA)//上升沿捕获
{
TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Falling);//CC1P=1 设置为下降沿捕获
TIM_SetCounter(TIM2,0); //清空定时器值
remoteState|=0X10;//标记上升沿已经被捕获
}
else //下降沿捕获
{
captureva lue=TIM_GetCapture2(TIM2);//读取CCR2也可以清CC1IF标志位
TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Rising); //CC4P=0设置为上升沿捕获
if(remoteState&0X10)//完成一次高电平捕获
{
if(remoteState&0X80)//接收到了引导码
{
if(captureva lue>300&&captureva lue<800)//560为标准值,560us
{
remoteCode<<=1;//左移一位.
remoteCode|=0;//接收到0
}
else if(captureva lue>1400&&captureva lue<1800)//1680为标准值,1680us
{
remoteCode<<=1;//左移一位.
remoteCode|=1;//接收到1
}
else if(captureva lue>2200&&captureva lue<2600)//得到按键键值增加的信息 2500为标准值2.5ms
{
remoteCnt++; //按键次数增加1次
remoteState&=0XF0;//清空计时器
}
}
else if(captureva lue>4200&&captureva lue<4700)//4500为标准值4.5ms
{
remoteState|=1<<7;//标记成功接收到了引导码
remoteCnt=0;//清除按键次数计数器
}
}
remoteState&=~(1<<4);
}
}
TIM_ClearFlag(TIM2,TIM_IT_Update|TIM_IT_CC2)
}
u8 Remote_Scan(void)
{
u8 state=0;
u8 t1,t2;
if(remoteState&(1<<6))//得到一个按键的所有信息了
{
printf("收到的数据是:0x%X\r\n",remoteCode);
t1=remoteCode>>24;//得到地址码
t2=(remoteCode>>16)&0xff;//得到地址反码
if((t1==(u8)~t2)&&t1==REMOTE_ID)//检验遥控识别码(ID)及地址
{
t1=remoteCode>>8;
t2=remoteCode;
if(t1==(u8)~t2)state=t1;//键值正确
}
if((state==0)||((remoteState&0X80)==0))//按键数据错误/遥控已经没有按下了
{
remoteState&=~(1<<6);//清除接收到有效按键标识
remoteCnt=0;//清除按键次数计数器
}
}
return state;
}
PWM红外编码:
void remote_repeat(u8 cnt)
{
for(;cnt;cnt--)
{
Remote_H;
Delay_ms(97);
Delay_us(940); //97.94ms高电平
Remote_L;
Delay_ms(9); //9ms低电平
Remote_H;
Delay_us(2500); //2.5ms高电平
Remote_L;
Delay_us(560); //560us低电平
}
}
/*
u8 addr:地址码
u8 cmd :控制码
u8 cnt :连发码个数
*/
void remote_send(u8 addr,u8 cmd,u8 cnt)
{
remote_start();
remote_send_byte(addr);
remote_send_byte(~addr);
remote_send_byte(cmd);
remote_send_byte(~cmd);
remote_repeat(cnt);
remote_end();
}
void remote_init(void)
{
RCC->AHB1ENR |=1<<0; //GPIOA时钟使能
GPIOA->MODER &=~(0x3<<(1*2)); //GPIOA1模式配置
GPIOA->MODER |=1<<(1*2); //输出模式
GPIOA->OTYPER &=~(1<<1); //
GPIOA->OSPEEDR &=~(0x3<<(1*2));
GPIOA->OSPEEDR |=1<<(1*2); //25MHz
GPIOA->PUPDR &=~(0x3<<(1*2)); //无上下拉
GPIOA->ODR &=~(1<<1);
}
void remote_start(void) //红外同步码头
{
Remote_L;
Delay_ms(9); //9ms低电平 (发送端脉冲 )
Remote_H;
Delay_ms(4); //4.5ms高电平 (发送端低电平)
Delay_us(500);
Remote_L;
Delay_us(560); //560us脉冲 //没有这560us码值会错OK?
}
void remote_end(void)
{
Remote_H;
}
//高位在前你敢信?
void remote_send_byte(u8 byte)
{
u8 i=0;
for(i=0;i<8;i++)
{
Remote_H;
if( byte & (0x80>>i) ) Delay_us(1680); //1680us低电平
else Delay_us(560); //1680us低电平
Remote_L;
Delay_us(560); //560us脉冲
}
}
