零基础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”。每个比特位的持续时间(高电平与低电平的比例)用于区分逻辑“0”和逻辑“1”。例如,一个比特“0”可能由较短的高电平和较长的低电平组成,而比特“1”则相反。
数据帧格式
在这里插入图片描述

同步引导码:9ms 高电平 + 4.5ms 低电平。
1 码 :560us高电平 + 560us低电平。
0 码 :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 编码格式,适合单片机开发板和学习板等场合。

  • 18
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值