首页 > 其他分享 >STM32之红外遥控信号自学习实现

STM32之红外遥控信号自学习实现

时间:2024-02-14 23:22:31浏览次数:34  
标签:HAL 遥控 Init htim4 STM32 TIM 红外 载波 gsInfrared

一、序言

很早前就想实现这个红外遥控自学习的这个实验,用于来自己控制房子里如空调等红外遥控设备的自动化,NEC的标准到具体的产品上可能就被厂家定义为不一样了,所以自学习就应该是接收到什么就发送什么,不用管内容是什么!

二、硬件实现原理

由上述原理图可知,当IE为高电平时发送红外光,为低电平时不发送红外光。

在NEC协议中,信息传输是基于38K载波,也就是说红外线是以载波的方式传递。

发送波形如下图所示:

NEC协议规定:

发送协议数据“0” = 发送载波560us + 不发送载波560us

发送协议数据“1” = 发送载波560us+ 不发送载波1680us

发送引导码 = 发送载波9000us + 不发送载波4500us

 

在红外接收端,如果接收到红外38K载波,则IR输出为低电平,如果不是载波包括固定低电平和固定高电平则输出高电平。在IR端接收的信号如下所示:

                  

三、软件实现自学习

设计原理:

1、 根据接收波形记录电平和电平持续时间,以便于发送。

2、电平记录采用定时器捕获功能,从下降沿接收引导信号开始,每触发一次改变触发方式,从而使每个电平变化都能捕获到。

源码实现如下:

定时器捕获初始化设置(CubeMax自动配置生成):

void MX_TIM4_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_IC_InitTypeDef sConfigIC = {0};

  htim4.Instance = TIM4;
  htim4.Init.Prescaler = 71;
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = 10000;
  htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_IC_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
  sConfigIC.ICFilter = 0;
  if (HAL_TIM_IC_ConfigChannel(&htim4, &sConfigIC, TIM_CHANNEL_4) != HAL_OK)
  {
    Error_Handler();
  }

}

定时器捕获中断回调处理:

复制代码
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4)
    {
        if(TIM4->CCER & (TIM_CCER_CC4P))   //下降沿触发
        {
            TIM4->CCER &= ~(TIM_CCER_CC4P); //切换
            gu8BitVal = 1;
        }
        else                               //上升沿触发
        {
            TIM4->CCER |= TIM_CCER_CC4P;    //切换
            gu8BitVal = 0;
        }


        if(gsInfrared.State == NONE_STATE)
        {
            gsInfrared.State = RECV_STATE;
        }
        else if(gsInfrared.State == RECV_STATE)
        {
            NowTimCnt = HAL_TIM_ReadCapturedValue(&htim4, TIM_CHANNEL_4);
            gsInfrared.KeepTime[gsInfrared.SampleCount] = Round(NowTimCnt);
            gsInfrared.BitValue[gsInfrared.SampleCount ++] = gu8BitVal;
        }

        TIM4->CNT = 0;
    }
}
复制代码

3、设置的定时器溢出时间为10ms,如果10毫秒内不再接收电平变化则默认接收结束,设置结束标志。

复制代码
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim == &htim4)
    {
        if(gsInfrared.State == RECV_STATE)
        {
            gsInfrared.State = END_STATE;
        }
    }
}
复制代码

至此,实现了红外遥控的学习功能,获得的记录数据为记录长度和电平信号数组与电平信号维持的时间数组。

4、发送实现

设置定时器输出38KPWM信号,在记录电平为0是输出记录时间的38K载波信号,如果为1则不输出载波,实现如下:

PWM生成设置(CubeMax自动配置生成):

复制代码
void MX_TIM5_Init(void)
{
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  htim5.Instance = TIM5;
  htim5.Init.Prescaler = 0;
  htim5.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim5.Init.Period = 1896;
  htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim5.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_PWM_Init(&htim5) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim5, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim5, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_TIM_MspPostInit(&htim5);

}
复制代码

发送实现,注意点就是记录为0时发载波,记录为1时不发载波:

复制代码
void InfraredSend(void)
{
    uint16_t Count = 0;
    
    while(Count < gsInfrared.SampleCount &&  gsInfrared.State == END_STATE)
    {
        if(gsInfrared.BitValue[Count] == 0)
        {
            TIM5->CCR2 = 948;
            delay_us(gsInfrared.KeepTime[Count]);
            TIM5->CCR2 = 0;
        }
        else
        {
            TIM5->CCR2 = 0;
            delay_us(gsInfrared.KeepTime[Count]);
            TIM5->CCR2 = 0;
        }

        Count ++;
    }

    delay_us(20000);
}
复制代码

 往PWM比较寄存器设置948即为设置38KPWM波,也可在初始化时固定948,在此函数内启停定时器即可;

至此,自学习功能的全部思路已实现,通过对各个不同类型的红外遥控进行功能测试,均成功。

 

PS:查看很多资料发现很多红外解码未判断低电平时间,个人感觉不是很好,应该是不仅高电平时间得符合,低电平时间也应该符合。

自己写了一个小函数验证了一下,这个函数只是验证,未经仔细推敲,还可优化,仅供参考这一思想。

误差设计:±200us(拍脑袋值)

void InFraredDataDeal(void)
{
    uint32_t DataBuff = 0;
    uint16_t Count = 0;

    if(gsInfrared.State == END_STATE)
    {
        gsInfraredData.State = 0;

        do
        {
            switch(gsInfraredData.State)
            {
            case 0:   //引导码识别
            {

                if(gsInfrared.KeepTime[0] >= 8800 && gsInfrared.KeepTime[0] <= 9200 && gsInfrared.BitValue[0] == 0)
                {
                    if(gsInfrared.KeepTime[1] >= 4300 && gsInfrared.KeepTime[1] <= 4700 && gsInfrared.BitValue[1] == 1)
                    {
                        if(gsInfrared.KeepTime[2] >= 360 && gsInfrared.KeepTime[2] <= 760 && gsInfrared.BitValue[2] == 0)
                        {
                            Count = 3;
                            gsInfraredData.State = 1;
                        }
                    }
                    else if(gsInfrared.KeepTime[1] >= 2300 && gsInfrared.KeepTime[1] <= 2700 && gsInfrared.BitValue[1] == 1)
                    {
                        if(gsInfrared.KeepTime[2] >= 360 && gsInfrared.KeepTime[2] <= 760 && gsInfrared.BitValue[2] == 0)
                        {
                            gsInfraredData.ReDataCount ++;
                            gsInfraredData.State = 3;
                        }
                    }
                    else
                    {
                        gsInfraredData.State = 3;
                    }

                }
                else
                {
                    gsInfraredData.State = 3;
                }


            }
            break;


            case 1:   //数据解析
            {

                if(gsInfrared.KeepTime[Count + 1] >= 360 && gsInfrared.KeepTime[Count + 1] <= 760 && gsInfrared.BitValue[Count + 1] == 0)
                {

                    if(gsInfrared.BitValue[Count] == 1)
                    {
                        if(gsInfrared.KeepTime[Count] >= 1480 && gsInfrared.KeepTime[Count] <= 1880)
                        {
                            DataBuff <<= 1;
                            DataBuff |= 1;
                        }
                        else if(gsInfrared.KeepTime[Count] >= 360 && gsInfrared.KeepTime[Count] <= 760 && gsInfrared.BitValue[Count] == 1)
                        {
                            DataBuff <<= 1;
                            DataBuff |= 0;
                        }
                        else
                        {
                            gsInfraredData.State = 3;
                        }
                    }
                }

                if(Count < gsInfrared.SampleCount)
                {
                    Count += 2;
                }
                else
                {
                    gsInfraredData.State = 2;
                }

            }
            break;

            case 2:   //成功解析
            {
                gsInfraredData.Data = DataBuff;
                gsInfraredData.State = 3;

            }
            break;

            default:
            {
                gsInfraredData.State = 3;   //解析结束

            }
            break;
            }

        }
        while(gsInfraredData.State != 3);

        gsInfrared.State = NONE_STATE;
        gsInfrared.SampleCount = 0;
    }

}

解析的话一般高位在前,所以左移,经测试帧格式为:引导码+用户码+用户码反码+命令码+命令码反码,能成功解析数据!解析的话根据具体协议,具体分析。

标签:HAL,遥控,Init,htim4,STM32,TIM,红外,载波,gsInfrared
From: https://www.cnblogs.com/FBsharl/p/18015844

相关文章

  • 【STM32】成功创建Keil MDK工程的条件(可对照查缺补漏)
    文中所有文件夹数量和名称没有限制,按自己理解建也OK。首先:确保编码格式正确(UTF-8),可在小扳手那里更改。安装对应芯片器件支持包。建启动文件夹Start(记得在Keil项目界面添加同名分组导入文件),启动文件的最后字母为型号缩写。STM32F1系列的具体芯片型号缩写参照下表:建......
  • STM32系统开发--基于LL库的多串口Printf使用
    MDK:Keilv5.38/STM32CubeMXMCU:STM32G431CBUx外设:串口USART1、2使用多串口Printf,基于C语言中的函数可变参数,首先要包含头文件"stdarg.h"。基于LL库,编写多串口打印函数:/************************************************函数名称:USART_Printf功能:多串口Printf函数......
  • stm32 esp8266测试问题原因记录
    现象:连上WIFI但发送数据失败 原因:WIFI网络延时过大,或者程序设置的等待超时时间过小解法:换个网络延时小的WIFI连,或者增加程序等待超时的时间 现象:连不上WIFI 原因:esp8266_mqtt_init()中的的延迟过长,测试4S不行,要2S解法:将4秒延时改回2S1int32_tesp8266_mqtt_init(v......
  • STM32超声波模块问题
    先写没问题用法,有问题的语法就不示范voidSr04_Init(void){GPIO_InitTypeDefGPIO_InitStruct;TIM_TimeBaseInitTypeDefTIM_TimeBaseInitStruct;//打开GPIO组时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);RCC_AHB1PeriphClockCm......
  • STM32打印掺杂乱码
    问题:STM32打印掺杂乱码 原因:时钟太快了(不要以为是电磁干扰,接触不良,硬件出问题,多想想在发现这种情况之前做了什么操作)问题:为什么之前好好的,现在不行了原因:安装CubeMX导致的,具体原因不清楚解法:根据外部晶振调对时钟频率 效果: ......
  • 【STM32+HAL库】---- 硬件IIC驱动0.96OLED
    硬件开发板:STM32G0B1RET6软件平台:cubemax+keil+VScode内容原著声明部分代码借鉴学习于以下视频和文章:https://www.bilibili.com/video/BV1MV411o7P5/?spm_id_from=333.999.0.0&vd_source=2c974fb85c05e13d278d1bbe4cddc944https://blog.csdn.net/weixin_56565733/article/de......
  • STM32MP135开发板助力电力行业,IEC61850协议移植笔记
    1.概述IEC61850是变电站自动化系统(SAS)中通信系统和分散能源(DER)管理的国际标准。它通过标准的实现,实现了智能变电站的工程运作标准化。使得智能变电站的工程实施变得规范、统一和透明,在电力和储能系统中应用非常广泛。本文基于米尔MYD-YF13X开发板,在Linux系统上移植和使用开源的l......
  • STM32MP135开发板助力电力行业,IEC61850协议移植笔记
    1.概述IEC61850是变电站自动化系统(SAS)中通信系统和分散能源(DER)管理的国际标准。它通过标准的实现,实现了智能变电站的工程运作标准化。使得智能变电站的工程实施变得规范、统一和透明,在电力和储能系统中应用非常广泛。本文基于米尔MYD-YF13X开发板,在Linux系统上移植和使用开源的libI......
  • STM32仿真调试停在B.
    STM32调试停在了startup文件的B.处,如下: 经排查是由于在Keil中打开了串口3的中断,并且失能了串口回调函数,自己没有写串口中断处理函数如下:添加中断Handler之后正常/***@FunctionnameUSART3_IRQHandler*@IntroduceBLE串口接收回调函数*@ReturnN......
  • STM32CubeMX教程31 USB_DEVICE - HID外设_模拟键盘或鼠标
    1、准备材料正点原子stm32f407探索者开发板V2.4STM32CubeMX软件(Version6.10.0)keilµVision5IDE(MDK-Arm)ST-LINK/V2驱动野火DAP仿真器XCOMV2.6串口助手2、实验目标使用STM32CubeMX软件配置STM32F407开发板USB_OTG_FS为工作在HumanInterfaceDeviceClass(HID)(人机接口......