STM32单片机编程入门实战:HX1838红外遥控模块源码详解
文章目录
一.概要
这是一款新型的超薄38K通用红外遥控器,采用的是NEC编码格式,主要用于车
载 MP3、灯光设配、数码相框、单片机开发板和学习板等场合。因其是基于无
线遥控,因此人们在使用起来显得方便、有效。
二.HX1838红外遥控套件主要参数
红外遥控距离:大于8米
发射管红外波长:940nm
晶振频率:455KHZ的晶振
载波频率:38KHZ
编码:编码格式为NEC
尺寸:86* 40* 6mm
电源:CR2025/1600mAH
模块接口说明:
1.S 信号脚
2.+ 电源正极:电压3.3v
3.- 电源负极:接地
三.NEC协议的红外遥控编码
NEC 载波频率为 38Khz,NEC协议使用脉冲位置调制(PPM)技术。每个比特位的持续时间(高电平与低电平的比例)用于区分逻辑“0”和逻辑“1”。例如,一个比特“1”可能由较短的高电平和较长的低电平组成,而比特“0”则相反。
数据帧格式
同步引导码:9ms 低电平 + 4.5ms 高电平。
逻辑0码 :560us低电平 + 560us高电平。
逻辑1码 :560us低电平 + 1.69 ms 高电平。
结束码 :560us 低电平。
数据帧格式:引导码 + 地址 + 地址反码 + 键值 + 键值反码 + 结束码。
重复连发码格式:9ms 低电平 + 2.25ms高电平 + 结束码。
同步引导码通常由9ms的低电平和接下来的4.5ms的高电平组成,用于标识数据的开始。
结束码不用于数据解析,但有助于分隔不同的数据包。
重复连发码是一直按住遥控器上的一个键,命令帧也只会发送一次。 只要按键保持按下状态,就会每110毫秒发送一次重复连发码。
高位在前,即首先收到的是高位的数据。
四.HX1838红外遥控键值
遥控键值是指遥控器上各个按键在电子设备中对应的特定代码值,这些值用于识别按键操作并执行相应的功能。不同的按键在电子设备中具有不同的键值,以便正确地控制设备的操作。以下是一些常见的遥控键值及其功能说明。
五.红外解码通讯流程图
六.STM32单片机红外遥控接收解码实验
硬件准备:
STLINK接STM32F103C8T6小系统板,STLINK接电脑USB口。
用杜邦线连接板子与OLED显示屏:
板子3.3V–模块VCC
板子GND—模块GND
板子PB10–模块SCL
板子PB11–模块SDA
用杜邦线把红外模块与开发板相连:
板子3.3—-模块+
板子A8—–模块S
板子G——模块-
打开STM32CubeMX软件,新建工程
Part Number处输入STM32F103C8,再双击就创建新的工程
配置下载口引脚
配置外部晶振引脚
配置系统主频
定时器1通道1捕捉打开,PA8脚是输入捕捉脚
打开定时器1中断
配置工程文件名,保存路径,KEIL5工程输出方式
生成工程
用Keil5打开工程
添加OLED驱动文件
添加传感器相关代码
主要代码
void HX1838_demo(void)
{
hx1838_cap_start();//定时器1通道1,输入捕获启动
while(1)
{
if(cap_frame)//标记捕获到新的数据
{
hx1838_proc(hx1838_data_decode());//解析数据
cap_frame = 0;
}
}
}
//根据键码值显示
void hx1838_proc(uint8_t res)
{
if(res == 0)
{
return;
}
if(res == 2)
{
return;
}
switch(rx.data._rev.key_val)
{
case 162:
OLED_ShowNum(48,6,1,3,16);//显示1
break;
case 98:
OLED_ShowNum(48,6,2,3,16);//显示2
break;
case 226:
OLED_ShowNum(48,6,3,3,16);//显示3
break;
case 34:
OLED_ShowNum(48,6,4,3,16);//显示4
break;
case 2:
OLED_ShowNum(48,6,5,3,16);//显示5
break;
case 194:
OLED_ShowNum(48,6,6,3,16);//显示6
break;
case 224:
OLED_ShowNum(48,6,7,3,16);//显示7
break;
case 168:
OLED_ShowNum(48,6,8,3,16);//显示8
break;
case 144:
OLED_ShowNum(48,6,9,3,16);//显示9
break;
case 152:
OLED_ShowNum(48,6,0,3,16);//显示0
break;
case 104:
OLED_ShowChar(48,6,'*');//显示ASCII字符
break;
case 176:
OLED_ShowChar(48,6,'#');//显示ASCII字符
break;
case 24:
OLED_ShowChar(48,6,'^');//显示ASCII字符
break;
case 16:
OLED_ShowChar(48,6,'<');//显示ASCII字符
break;
case 74:
OLED_ShowChar(48,6,'v');//显示ASCII字符
break;
case 90:
OLED_ShowChar(48,6,'>');//显示ASCII字符
break;
case 56:
OLED_ShowString(48,6,"OK");
break;
default:
break;
}
}
/* 电平捕获中断回调 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
static uint16_t tmp_cnt_l,tmp_cnt_h;
if(TIM1 == htim->Instance)
{
switch(cap_pol) //根据极性标志位判断捕获是低电平还是高电平
{
/* 捕获到下降沿 */
case 0:
tmp_cnt_l = HAL_TIM_ReadCapturedValue(&htim1,TIM_CHANNEL_1); //记录当前时刻
TIM_RESET_CAPTUREPOLARITY(&htim1, TIM_CHANNEL_1); //复位极性配置
TIM_SET_CAPTUREPOLARITY(&htim1, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING); //改变极性
cap_pol = 1; //极性标志位改为上升沿
if(sta_idle) //如果当前为空闲状态,空闲捕获到的时序,为第一个下降沿
{
rx_rcv_init();
break; //返回
}
rx_frame[cap_pulse_cnt] = tim_udt_cnt * 10000 + tmp_cnt_l - tmp_cnt_h; //与上次捕获的计时作差,记录值
tim_udt_cnt = 0; //溢出次数清0
RX_DBG("(%2d)%4d us:H\r\n",cap_pulse_cnt,rx_frame[cap_pulse_cnt]); //DBG:打印捕获到的电平及其时长
cap_pulse_cnt++; //计数++
break;
/* 捕获到上升沿 */
case 1:
tmp_cnt_h = HAL_TIM_ReadCapturedValue(&htim1,TIM_CHANNEL_1);
TIM_RESET_CAPTUREPOLARITY(&htim1, TIM_CHANNEL_1);
TIM_SET_CAPTUREPOLARITY(&htim1, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING);
cap_pol = 0;
if(sta_idle)
{
rx_rcv_init();
break;
}
rx_frame[cap_pulse_cnt] = tim_udt_cnt * 10000 + tmp_cnt_h - tmp_cnt_l;
tim_udt_cnt = 0;
RX_DBG("(%2d)%4d us:L\r\n",cap_pulse_cnt,rx_frame[cap_pulse_cnt]);
cap_pulse_cnt++;
break;
default:
break;
}
}
}
//数据解码
uint8_t hx1838_data_decode(void)
{
memcpy(rx.src_data,rx_frame,RX_SEQ_NUM*4);
memset(rx_frame,0x00,RX_SEQ_NUM*4);
RX_DBG("========= rx.src[] =================\r\n");
for(uint8_t i = 0;i<=(RX_SEQ_NUM*2);i++)
{
RX_DBG("[%d]%d\r\n",i,rx.src_data[i]);
}
RX_DBG("========= rx.rec =================\r\n");
if(appro(rx.src_data[0],9000) && appro(rx.src_data[1],4500)) //#1. 检测前导码,9ms,4.5ms
{
uint8_t tmp_idx = 0;
rx.repet_cnt = 0; //按键重复个数清0
for(uint8_t i = 2;i<(RX_SEQ_NUM*2);i++) //#2. 检测数据
{
if(!appro(rx.src_data[i],560))
{
RX_DBG("%d,err:%d != 560\r\n",i,rx.src_data[i]);
return 0;
}
i++;
if(appro(rx.src_data[i],1680))
{
rx.data.rev |= (0x80000000 >> tmp_idx); //第 tmp_idx 为置1
tmp_idx++;
}
else if(appro(rx.src_data[i],560))
{
rx.data.rev &= ~(0x80000000 >> tmp_idx); //第 tmp_idx 位清0
tmp_idx++;
}
else
{
RX_DBG("%d,err:%d != 560||1680\r\n",i,rx.src_data[i+1]);
return 0;
}
}
}
else if(appro(rx.src_data[0],9000) && appro(rx.src_data[1],2250) && appro(rx.src_data[2],560))
{
rx.repet_cnt++;
return 2;
}
else
{
RX_DBG("前导码检测错误\r\n");
return 0;
}
return 1;
}
七.CubeMX工程源代码下载
链接:https://pan.baidu.com/s/1gjSuBfk8WQlEEQnDuYIOQw
提取码:dv24
如果链接失效,可以联系博主给最新链接
程序下载下来之后解压就行
八.小结
HX1838红外接收模块采用HX1838红外接收管,灵敏度高,数字量输出,带有红色指示灯。新型的超薄 38K 通用红外遥控器,采用的是 NEC 编码格式,适合单片机开发板和学习板等场合。
作者:光子物联单片机