红外遥控简介
红外遥控是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,功耗低,成本低,易实现等显著优点,被诸多电子设备特别是家用电器广泛采用,并越来越多的应用到计算机系统中。由于红外线遥控不具有像无线电遥控那样穿过障碍物去控制被控对象的能力,所以,在设计红外线遥控器时,不必要像无线电遥控器那样,每套(发射器和接收器)要有不同的遥控频率或编码(否则,就会隔墙控制或干扰邻居的家用电器),所以同类产品的红外线遥控器,可以有相同的遥控频率或编码,而不会出现遥控信号“串门”的情况。这对于大批量生产以及在家用电器上普及红外线遥控提供了极大的方面。由于红外线为不可见光,因此对环境影响很小,再由红外光波动波长远小于无线电波的波长,所以红外线遥控不会影响其他家用电器,也不会影响临近的无线电设备。
红外遥控的编码方式目前广泛使用的是: PWM(脉冲宽度调制)的 NEC 协议和 Philips PPM(脉冲位置调制) 的 RC-5 协议的。
NEC 协议,其特征如下:
- 8 位地址和 8 位指令长度;
- 地址和命令 2 次传输(确保可靠性)
- PWM 脉冲位置调制,以发射红外载波的占空比代表“0”和“1”;
- 载波频率为 38Khz;
- 位时间为 1.125ms 或 2.25ms;
RGB超薄遥控器,1-32键遥控器,用于USB卡小音响遥控器/车载MP3遥控器/足浴器遥控器/灯具遥控器/数码相框遥控器/单片机遥控器/开发板遥控器等。详细参数如下:
尺寸:84.556.56.0mm。
产品内含1个CR2025纽扣电池。
有效角度:60度。
面贴材料:0.125mmPET,有效寿命2万次 。
含CR2025纽扣电池,有绝缘片(以免不用时耗电)。
NEC 码的位定义
一个脉冲对应 560us 的连续载波,一个逻辑 1 传输需要 2.25ms(560us 高+1680us 低),一个逻辑 0 的传输需要 1.125ms(560us 高+560us 低)。而红外接收头在收到脉冲的时候为低电平,在没有脉冲的时候为高电平,这样,我们在接收头端收到的信号为:逻辑 1 应该是 560us 低+1680us 高,逻辑 0 应该是 560us 低+560us 高(接受头接受到的电平值取反)。
NEC 遥控指令的数据格式为:同步码头(引导码/起始码)、地址码(遥控ID)、地址反码、控制码(键值)、控制反码。同步码由一个 9ms 的低电平和一个 4.5ms 的高电平组成,地址码、地址反码、控制码、控制反码均是8 位数据格式。按照低位在前,高位在后的顺序发送。采用反码是为了增加传输的可靠性(可用于校验)。
我们遥控器的按键“OFF”按下时,从红外接收头端收到的波形如下图所示:
从上图中可以看到,其地址码为 0,控制码为96。可以看到在 100ms 之后,我们还收到了几个脉冲,这是 NEC 码规定的连发码(由 9ms 的低电平、2.5ms的高电平、0.56ms 的低电平、97.94ms 的高电平组成),如果在一帧数据发送完毕之后,按键仍然没有放开,则发射重复码,即连发码,可以通过统计连发码的次数来标记按键按下的长短/次数。
软件设计
当接受到同步码头就知道有按键被按下
开始接受地址码+地址反码+控制码+控制反码
逻辑 高电平时间
逻辑1 1680us
逻辑0 560us
同步码头 4500us
连发码 2500us
重点就是通过捕获一段的脉冲的高电平时间来区别是逻辑1还是逻辑0还是同步码还是连发码检测高电平。
uint8_t dir_f_r = 0;
uint16_t dat = 0;
uint32_t buf_vaule = 0; //接收数据
uint8_t dat_flag = 0; //可以读取数据标志
uint8_t flag_key = 0;
//中断服务函数
void EXTI1_IRQHandler(void)
{
static uint8_t i = 0;
EXTI->PR |= (0x1 << 1);//清标志
while(EXTI->PR & (0x1 << 1));//等待标志清除完毕
if(dir_f_r == 0)
{
dir_f_r = 1;
EXTI->FTSR |= (0x1 << 1);//允许输入线1上的下降沿触发
TIM1->CNT = 0;//清除计数器的值
}
else if(dir_f_r == 1)
{
dir_f_r = 0;
EXTI->RTSR |= (0x1 << 1);//允许输入线1上的上升沿触发
dat = TIM1->CNT;
if((dat >= 400) && (dat <= 500))//引导码
{
dat_flag = 1; //当接收到引导码后才就收数据
}
else if(dat_flag && (i < 32))
{
if((dat >= 40) && (dat < 80))//逻辑0
{
buf_vaule >>= 1;
}else if((dat >= 150) && (dat <= 200))//逻辑1
{
buf_vaule >>= 1;
buf_vaule |= 0x80000000;
}
i++;
}else if((dat >= 200) && (dat <= 250))//连发码
{
i = 0;
dat_flag = 0;
flag_key = 1; //按键松开标志位
// printf("--%#x--\r\n", buf_vaule);
Contorl_dat( );
}
}
}
uint8_t Contorl_dat(void)
{
uint8_t t1 = 0;
uint8_t tmp = 0;
t1 = (uint8_t)(buf_vaule & 0x000000ff);
tmp = (uint8_t)((buf_vaule & 0x0000ff00) >> 8);
if((tmp&0xff) != ((~t1)&0xFF))
{
return 1;
}
t1 = 0;
tmp = 0;
t1 = (buf_vaule & 0x00ff0000) >> 16;
tmp = (buf_vaule & 0xff000000) >> 24;
if((tmp&0xff) == ((~t1)&0xFF))
{
printf("---%#x--\r\n ", buf_vaule);
printf("红外码:%#x\r\n", t1);
// Key_Scan(t1);
}
return 0;
}