[STM32F1]

stm32 LL库实现定时器捕获红外NEC解码

[复制链接]
5301|34
手机看帖
扫描二维码
随时随地手机跟帖
xiaoqi976633690|  楼主 | 2024-3-18 17:58 | 显示全部楼层 |阅读模式
一. CUBEMX配置使用内部HSI时钟源64mhz

03.png
TIME 配置
01.png

02.png

二. NEC红外原理

04.png
05.png

引导码:  由9ms的电平+4.5ms的电平组成。
收到数据位0:   0.56m电平+ 0.56ms的电平。
收到数据位1: 0.56ms电平+1.68ms的电平。


NEC协议一次完整的传输包含:    引导码、8位用户码、8位用户反码、8位数据码、8位数据反码。


三. 代码说明
初始化time
void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  LL_TIM_InitTypeDef TIM_InitStruct = {0};

  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* Peripheral clock enable */
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);

  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA);
  /**TIM2 GPIO Configuration
  PA0-WKUP   ------> TIM2_CH1
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_0;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_FLOATING;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* TIM2 interrupt Init */
  NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  NVIC_EnableIRQ(TIM2_IRQn);

  /* USER CODE BEGIN TIM2_Init 1 */
   
  /* USER CODE END TIM2_Init 1 */
  TIM_InitStruct.Prescaler = 64-1;
  TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
  TIM_InitStruct.Autoreload = 65535;
  TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
  LL_TIM_Init(TIM2, &TIM_InitStruct);
  LL_TIM_DisableARRPreload(TIM2);
  LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL);
  LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET);
  LL_TIM_DisableMasterSlaveMode(TIM2);
  LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI);
  LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1);
  LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1);
  LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_FALLING);
  /* USER CODE BEGIN TIM2_Init 2 */
       
        //自己添加的
        LL_TIM_ClearFlag_CC1(TIM2);
        LL_TIM_ClearFlag_UPDATE(TIM2);
        LL_TIM_EnableIT_CC1(TIM2);
        LL_TIM_EnableIT_UPDATE(TIM2);
        LL_TIM_CC_EnableChannel(TIM2,LL_TIM_CHANNEL_CH1);  //这个不要忘记打开了,不然无法捕获
        LL_TIM_EnableCounter(TIM2);
       
  /* USER CODE END TIM2_Init 2 */

}
中断函数
uint16_t IR_time=0; //计数保存
uint32_t  IRDATA=0;//红外解码保存

void TIM2_IRQHandler(void)
{
  /* USER CODE BEGIN TIM2_IRQn 0 */
       
        if(LL_TIM_IsActiveFlag_CC1(TIM2))//边沿捕获中断
        {
                //如果为上升沿
                if (LL_TIM_IC_GetPolarity(TIM2,LL_TIM_CHANNEL_CH1)==LL_TIM_IC_POLARITY_RISING)//获取捕获边沿
                {
                        LL_TIM_SetCounter(TIM2,0);//计数器归零
                        LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_FALLING);//切换为下降沿
                }
               
                else//如果为下降沿
                {
                        LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_RISING);//切换为上升沿

                        IR_time=LL_TIM_GetCounter(TIM2);//获取上升沿时间
                        if(((IR_time>3500)&&(IR_time<5000)))//获取到起始码9ms低电平+4ms高电平
                        {

                                IRDATA=0;
                                //LL_GPIO_TogglePin(GPIOC,LL_GPIO_PIN_15);
                        }
                        else if((IR_time>460)&&(IR_time<760))//获取到‘0’高电平,560us高电平
                        {
                                IRDATA<<=1;//左移置0
                        }
                        else if((IR_time>1500)&&(IR_time<1980))//获取到‘1’高电平,1690us高电平
                        {
                                IRDATA<<=1;
                                IRDATA|=0x01;//置1
                        }
                }
               
        }

        if(LL_TIM_IsActiveFlag_UPDATE(TIM2))//溢出中断
                {
                        LL_TIM_ClearFlag_UPDATE(TIM2);
                }

        LL_TIM_ClearFlag_CC1(TIM2);

       
  /* USER CODE END TIM2_IRQn 0 */
  /* USER CODE BEGIN TIM2_IRQn 1 */

  /* USER CODE END TIM2_IRQn 1 */
}
main函数
int main(void)
{
  /* USER CODE BEGIN 1 */
        uint16_t i=100;
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_AFIO);
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);

  /* System interrupt init*/
  NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

  /* SysTick_IRQn interrupt configuration */
  NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),15, 0));

  /** NOJTAG: JTAG-DP Disabled and SW-DP Enabled
  */
  LL_GPIO_AF_Remap_SWJ_NOJTAG();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
        printf("stm32 hello\n");
  while (1)
  {
                // LL_GPIO_TogglePin(GPIOC,LL_GPIO_PIN_14);
                // LL_mDelay(500);
                // LL_GPIO_TogglePin(GPIOC,LL_GPIO_PIN_14);
                // LL_mDelay(500);
                                LL_mDelay(10);
                if (0!=IRDATA)
                {
                        LL_mDelay(500);
                        printf("0x%08x\n",IRDATA);
                }
                switch(IRDATA)
    {
      case (0xffa25d): LL_GPIO_TogglePin(GPIOC,LL_GPIO_PIN_13);IRDATA=0; break;
      case (0xff629d): LL_GPIO_TogglePin(GPIOC,LL_GPIO_PIN_14);IRDATA=0;  break;
      case (0xffe21d): LL_GPIO_TogglePin(GPIOC,LL_GPIO_PIN_15);IRDATA=0; break;
                        case (0xff22dd): LL_GPIO_TogglePin(GPIOC,LL_GPIO_PIN_15|LL_GPIO_PIN_14|LL_GPIO_PIN_13);IRDATA=0;break;
                        case (0xff02fd): LL_GPIO_TogglePin(GPIOC,LL_GPIO_PIN_15|LL_GPIO_PIN_14|LL_GPIO_PIN_13);IRDATA=0; break;
    }

               
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */
}


. 试验结果

串口打印
stm32 hello
0x00ffa25d
0x00ffa25d
0x00ff629d
0x00ff629d
0x00ffe21d
0x00ffe21d
00和ff互为反码
a25d互为反码
验证OK


使用特权

评论回复
评论
21小跑堂 2024-4-3 17:38 回复TA
奖励500家园币~ 
玛尼玛尼哄| | 2024-3-18 21:39 | 显示全部楼层
越来越多的人用LL库了。

使用特权

评论回复
hjl2832| | 2024-3-19 07:33 | 显示全部楼层
LL库好用啊,代码清晰,没有多余的函数,就是底层都要自己去完善有点麻烦。

使用特权

评论回复
lulugl| | 2024-3-19 09:18 | 显示全部楼层
hjl2832 发表于 2024-3-19 07:33
LL库好用啊,代码清晰,没有多余的函数,就是底层都要自己去完善有点麻烦。 ...

先用HAL库,整好了再去弄LL库吧。

使用特权

评论回复
xch| | 2024-3-19 09:32 | 显示全部楼层

9347865f8e9ea364c4.png 7369165f8e9be02bdc.png

5037965f8ea1b89d59.png
既然已经设置下降沿捕获中断,为啥在中断函数中判断上升沿?

使用特权

评论回复
xiaoqi976633690|  楼主 | 2024-3-19 11:32 | 显示全部楼层
本帖最后由 xiaoqi976633690 于 2024-3-19 11:34 编辑
xch 发表于 2024-3-19 09:32
既然已经设置下降沿捕获中断,为啥在中断函数中判断上升沿?

中断里面要切换上升沿和下降沿触发。初始化里面是为了总线上第一次下降沿触发。

使用特权

评论回复
xiaoqi976633690|  楼主 | 2024-3-19 11:46 | 显示全部楼层
玛尼玛尼哄 发表于 2024-3-18 21:39
越来越多的人用LL库了。

不用写底层啊,比hal好用

使用特权

评论回复
xch| | 2024-3-19 16:27 | 显示全部楼层
xiaoqi976633690 发表于 2024-3-19 11:32
中断里面要切换上升沿和下降沿触发。初始化里面是为了总线上第一次下降沿触发。 ...

NEC 遥控解码只需要下降沿中断即可。那个高电平宽度没必要检测,且不准。
第一个 13.5 ms 是用于修正接收机基准时钟,第一下降沿顺便唤醒MCU。 然后 2.25ms 表示1,1.12ms 表示 0.
每次捕获设置超时中断以便结束解码 进入低功耗。

使用特权

评论回复
评论
xiaoqi976633690 2024-3-19 17:03 回复TA
有道理 
呐咯密密| | 2024-3-19 16:30 | 显示全部楼层
LL库实现起来比HAL简洁太多了

使用特权

评论回复
ingramward| | 2024-4-7 10:49 | 显示全部楼层
配置定时器的模式为捕获模式,并根据需要设置预分频器和自动重装载寄存器来确定定时器的时钟频率和捕获间隔。

使用特权

评论回复
febgxu| | 2024-4-7 19:03 | 显示全部楼层
为定时器的捕获事件配置中断,以便在定时器捕获到红外接收头的信号时,能够及时处理中断事件并读取计数器值。

使用特权

评论回复
hearstnorman323| | 2024-4-8 12:26 | 显示全部楼层
由于红外解码可能需要频繁地使用中断,因此需要合理设置中断优先级,以避免干扰其他重要的系统任务。

使用特权

评论回复
EmmaTT| | 2024-4-8 14:33 | 显示全部楼层
ll的宏函数实在太多了

使用特权

评论回复
burgessmaggie| | 2024-4-9 19:15 | 显示全部楼层
红外信号容易受到环境因素和其它电子设备的干扰。在解码过程中,要注意信号干扰可能导致的错误解码。可以通过增加信号滤波和错误检测机制来提高解码的可靠性。

使用特权

评论回复
houjiakai| | 2024-4-10 13:55 | 显示全部楼层
红外接收引脚可能会因为外界干扰而产生噪声,因此可能需要在软件中实现 debounce 逻辑来过滤这些噪声。

使用特权

评论回复
beacherblack| | 2024-4-11 20:16 | 显示全部楼层
深入理解NEC协议的工作原理,包括起始码、数据码和结束码的特点,以及如何根据脉冲宽度来判断逻辑“0”和逻辑“1”。

使用特权

评论回复
51xlf| | 2024-4-11 23:34 | 显示全部楼层
在实现红外NEC解码时,要考虑到系统的功耗和实时性要求。选择合适的处理器和定时器工作模式,以平衡功耗和实时性需求。

使用特权

评论回复
everyrobin| | 2024-4-12 03:12 | 显示全部楼层
在开始编程之前,你需要了解红外NEC协议的详细规范。NEC协议规定了红外信号的脉冲宽度、重复间隔、引导码、命令码和校验码等细节。只有理解了这些细节,你才能准确地解析出红外信号所代表的信息。

使用特权

评论回复
uptown| | 2024-4-12 07:18 | 显示全部楼层
配置定时器的输入捕获通道以接收红外信号。这通常涉及选择正确的GPIO引脚,并将其连接到定时器的捕获输入。

使用特权

评论回复
lzbf| | 2024-4-12 10:08 | 显示全部楼层
熟悉NEC红外通信协议的编码格式,包括起始码、地址码、数据码、校验码等。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

28

主题

167

帖子

2

粉丝