STM32HAL库--红外遥控接收模块,读取其按键值
前言
红外遥控接收模块–基于HAL库,先读取其按键值,并通过串口将其显示出来,从而为进行按键操作其他器件奠定基础.
一. 产品介绍
这是一款新型的超薄 38K 通用红外遥控器,采用的是 NEC 编码格式,主要用于车载 MP3、足浴盆、灯光设配、 数码相框、单片机开发板和学习板等场合。因其是基于无线遥控,因此人们在使用起来显得方便、有效,现在的应用领域也越来越宽.
(1). 技术参数
红外遥控距离:大于 8 米
发射管红外波长: 940Nm
晶振频率: 455KHZ 的晶振
载波频率: 38KHZ
编码:编码格式为 NEC
尺寸: 86* 40* 6mm
电源: CR2025/1600mAH
(2)使用说明
在使用前一定要记得给红外遥控器上电池,还有红外遥控器要结合红外接收模块使用, 它负责将接收红外遥控器发射过来的信息并将其解码成十六进制码,这样才能实现既定的通信。
将红外接收模块与 STM32正确连接, 其中 S 连接 D11, VCC 接+5V, GND 接 GND,并将其固定好;
二. NEC协议
当进行红外信号的发送和接收过程中,需要调制与解调信号,调制用在发送的过程中,解调用在接收的过程中NEC协议是红外遥控协议中的一种,协议构成由引导码,地址码,地址反码,命令码以及命令反码构成.
NEC功能特点包含:
1.地址码与地址反码,以及命令码与命令反码,具有数据校验作用,增强结果的准确性
2.脉冲距离调制,调制占空比
3.载波频率38KHZ
4.逻辑位时间为逻辑0:1.125ms或逻辑1:2.25ms
5.发送的信号与接收到的信号是反向的
NEC 码的位定义:一个脉冲对应 560us 的连续载波,一个逻辑 1 传输需要 2.25ms(560us脉冲+1680us 低电平),一个逻辑 0 的传输需要 1.125ms(560us 脉冲+560us 低电平)
NEC 遥控指令的数据格式为:同步码头、地址码、地址反码、控制码、控制反码。同步码由一个 9ms 的低电平和一个 4.5ms 的高电平组成,地址码、地址反码、控制码、控制反码均是8 位数据格式。按照低位在前,高位在后的顺序发送。采用反码是为了增加传输的可靠性(可用于校验)。
下图为接收到按键的值的波:
三 .CubeMX配置
使用了TIM2的输入捕获功能来读取红外接收器的输入信号
基本工程配置,参考上一篇文章,在此不演示.
四 . HAL库代码
(1)用到的变量
uint16_t Rmtsta=0;//二进制8位分别表示
uint16_t Dval=0;
uint16_t Rmtrec=0;
uint16_t Rmtcnt=0;
(2)定时器更新中断的回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//更新中断
{
if(htim ->Instance ==TIM2 )
{
if(Rmtsta &0x80)
{
Rmtsta &=~0x10;
if((Rmtsta & 0x0F)==0x00)
{
Rmtsta |=1<<6;
}
if((Rmtsta &0x0f)<14)
{
Rmtsta ++;
}
else
{
Rmtsta &=~(1<<7);
Rmtsta &=0xf0;
}
}
}
}
(3)输入捕获中断的回调函数
void HAL_TIM_IC_CaptureCallback ( TIM_HandleTypeDef * htim ) //输入捕获中断
{
if(htim ->Instance == TIM2 )
{
if(HAL_GPIO_ReadPin (GPIOA ,GPIO_PIN_0 )!=0)//上升沿
{
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2 ,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING );//设置极性下降沿
__HAL_TIM_SET_COUNTER (&htim2,0);//设置TIM寄存器值
Rmtsta |=0x10; //位4,表示捕获到上升沿
}
else //下降沿
{
Dval=HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);//读寄存器值
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2 ,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING );//设置极性上升沿
if(Rmtsta &0x10)//第一次捕获到上升沿
{
if(Rmtsta &0x80)//接收到引导
{
//可以解码
if(Dval>300&&Dval <800)
{
Rmtrec <<=1;
Rmtrec |=0;
}
else if(Dval >1400&&Dval <1800)
{
Rmtrec <<=1;
Rmtrec |=1;
}
else if(Dval >2000&&Dval <3000)
{
Rmtcnt ++;
Rmtsta &=0xF0;
}
}
else if(Dval>4200&&Dval <4750)//判断是非接收到引导码
{
Rmtsta |=1<<7; //位7标志为1
Rmtcnt =0; //按键计数清零
}
}
Rmtsta&=~(1<<4);
}
}
__HAL_TIM_CLEAR_FLAG(&htim2,TIM_FLAG_UPDATE );
}
(4)遥控器扫描函数
uint8_t remote_scan(void)
{
uint8_t t1,t2,sta=0;
if (Rmtsta & (1 << 6)) /* 得到一个按键的所有信息了 */
{
t1 = Rmtrec>>24; /* 得到地址码 */
t2 = (Rmtrec >> 16) &0xff; /* 得到地址反码 */
if ((t1 == (uint8_t)t2) && t1 == REMOTE_ID) /* 检验遥控识别码(ID)及地址 && t1 == REMOTE_ID */
{
t1 = Rmtrec >>8;
t2 = Rmtrec ;
if (t1 == (uint8_t)~t2)
{
sta = t1; /* 键值正确 */
}
//printf ("%d\r\n",sta );//利于打印已解码出的十进制值
}
if ((sta == 0) || ((Rmtsta & 0X80) == 0)) /* 按键数据错误/遥控已经没有按下了 */
{
Rmtsta &= ~(1 << 6); /* 清除接收到有效按键标识 */
Rmtcnt = 0;
/* 清除按键次数计数器 */
}
}
return sta;
}
(5)main函数
在主函数中进行不断的扫描,(该代码只是测试代码,其按键值,更具实际情况进行更改)
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
printf ("测试开始:\r\n");
key =remote_scan();
switch(key )
{
case 0:
printf ("未收到数据\r\n");break;
case 162://162
printf ("1\r\n");HAL_Delay (1000);
break;
case 98:
printf ("2\r\n");HAL_Delay (1000);
break;
case 226:
printf ("3\r\n");HAL_Delay (1000);
break;
case 34:
printf ("4\r\n");HAL_Delay (1000);
break;
case 2:
printf ("5\r\n");HAL_Delay (1000);
break;
case 194:
printf ("6\r\n");HAL_Delay (1000);
break;
case 224:
printf ("7\r\n");HAL_Delay (1000);
break;
case 168:
printf ("8\r\n");HAL_Delay (1000);
break;
case 144:
printf ("9\r\n");HAL_Delay (1000);
break;
case 152:
printf ("0\r\n");HAL_Delay (1000);
break;
case 104:
printf ("*\r\n");HAL_Delay (1000);
break;
case 176:
printf ("#\r\n");HAL_Delay (1000);
break;
case 24:
printf ("UP\r\n");HAL_Delay (1000);
break;
case 74:
printf ("DOWN\r\n");HAL_Delay (1000);
break;
case 16:
printf ("Left\r\n");HAL_Delay (1000);
break;
case 90:
printf ("Right\r\n");HAL_Delay (1000);
break;
case 56:
printf ("Ok\r\n");HAL_Delay (1000);
break;
}
HAL_Delay (100);
}