当前位置: 首页 > news >正文

PY32F003+TIM+外部中断实现对1527解码

1. 引言:为什么需要学习EV1527解码?

在物联网和智能家居快速发展的今天,无线遥控技术成为了设备控制的重要手段。EV1527作为一种经典的无线编码协议,因其简单可靠、成本低廉的特点,被广泛应用于:

  • 车库门遥控系统

  • 无线门禁控制

  • 智能家居遥控器

  • 无线安防系统

         EV1527是一种常见的无线遥控编码协议,广泛应用于门禁、车库门、无线开关等场景。本文将详细介绍如何通过 STM32 的 外部中断 + 定时器 实现EV1527信号的解码,并提供完整的代码解析。

2. EV1527协议简介

        EV1527采用 OOK(On-Off Keying) 调制,数据格式如下:

        1.引导码:1个长低电平(约12ms) + 1个长高电平。

        2.数据位:24位(20位地址 + 4位按键码),每位通过 脉冲宽度 区分。

        3.逻辑0:高电平宽度为低电平宽度的3倍。

        4.逻辑1:低电平宽度为高电平宽度的3倍。

3. 硬件设计

3.1 硬件连接

  • 433解码芯片输出端接 PY32F003的GPIO(PA12)

  • 配置PA12为 外部中断(上升沿/下降沿触发)

  • 使用 TIM17 测量低电平脉冲宽度。

3.2 关键硬件配置

/********************************************************************************************************
**函数信息 :void Configure_EXTI(void)
**功能描述 :配置外部中断引脚
**输入参数 :
**输出参数 :
**    备注 :
********************************************************************************************************/
void Configure_EXTI(void)
{GPIO_InitTypeDef  GPIO_InitStruct;__HAL_RCC_GPIOA_CLK_ENABLE();                                //使能GPIOA时钟GPIO_InitStruct.Mode  = GPIO_MODE_IT_RISING_FALLING;         //模式为上升沿/下降沿中断GPIO_InitStruct.Pull  = GPIO_PULLUP;                         //上拉GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;                //速度为高速GPIO_InitStruct.Pin   = GPIO_PIN_12;HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);                           //使能EXTI中断HAL_NVIC_SetPriority(EXTI4_15_IRQn, 2, 2);                   //配置中断优先级
}

4. 软件实现  

4.1 定时器初始化

  • TIM17:用于测量低电平脉冲宽度(24MHz时钟,无分频)。

void TIM17_Init(void)
{TimHandle17.Instance               = TIM17;                          // 选择TIM17TimHandle17.Init.Period            = 65535-1;                        // 自动重装载值TimHandle17.Init.Prescaler         = 24-1;                           // 预分频为    TimHandle17.Init.ClockDivision     = TIM_CLOCKDIVISION_DIV1;         // 时钟不分频TimHandle17.Init.CounterMode       = TIM_COUNTERMODE_UP;             // 向上计数TimHandle17.Init.RepetitionCounter = 1 - 1;                          // 不重复计数TimHandle17.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; // 自动重装载寄存器没有缓冲if (HAL_TIM_Base_Init(&TimHandle17) != HAL_OK)                          // TIM17初始化{Error_Handler();}if (HAL_TIM_Base_Start_IT(&TimHandle17) != HAL_OK)                      // TIM17使能启动,并使能中断{Error_Handler();}
}

4.2 外部中断解码逻辑

       在 HAL_GPIO_EXIT_Callback中实现解码:

  1. 下降沿:启动TIM17计时。

  2. 上升沿:停止TIM17,记录低电平时间,判断是否为引导码或数据位。

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{static uint8_t ucLeadCodeFind = 0;static uint8_t ucTimePos;    usLowTime=0;WaitCnt=50;usPortLevel = (GPIOA->IDR>>12)&0x01;   if(usPortLevel)                                            /*上升沿,完成低脉冲检测*/{usLowTime = __HAL_TIM_GET_COUNTER(&TimHandle17);__HAL_TIM_DISABLE(&TimHandle17);if(usLowTime > 11500 &&  usLowTime < 12500)        {ucLeadCodeFind = 1;ucTimePos = 0;}else{if(ucLeadCodeFind)/*只有找到引导码的情况下,才进行数据接收*/{g_tFB1527Rx.usaLowTime[ucTimePos++] = usLowTime;if(ucTimePos >= 24){ucTimePos = 0;ucLeadCodeFind = 0;g_tFB1527Rx.ucRecOK = 1;                    /*置位接收完成标志*/}}}}else                /*下降沿,启动低脉冲宽度检测*/{__HAL_TIM_SET_COUNTER(&TimHandle17,0);    __HAL_TIM_ENABLE(&TimHandle17);}    
}

4.3 数据解析

在 FB1527_Decode中解析24位数据:

  • 逻辑0:低电平时间约0.3ms(250-450us)。根据自己的实际脉冲来,用逻辑分析仪测。

  • 逻辑1:低电平时间约0.6ms(900-1200us)。根据自己的实际脉冲来,用逻辑分析仪测

void FB1527_Decode(fb1527Type_T *tpFB1527)
{uint8_t i,j=0;uint32_t ulCombinedCode = 0;for(i=0; i< 24; i++){ulCombinedCode <<= 1; if(tpFB1527->usaLowTime[i] > 250 && tpFB1527->usaLowTime[i] < 450)        {ulCombinedCode |= 0x01;}else if(tpFB1527->usaLowTime[i]>900 && tpFB1527->usaLowTime[i] < 1200){}else{ulCombinedCode=0;break;}}tpFB1527->ucKeyCode = ulCombinedCode & 0x0000000f;tpFB1527->ulChipID = (ulCombinedCode & 0xfffffff0) >> 4;if(tpFB1527->ulChipID){tpFB1527->ParseOK=1;                //数据解析完成for(i=0;i<FLASH_NUM;i++)            //判断ID是不是自己对码后的ID{if(tpFB1527->ulChipID == FlashData[i])j = 1;}if(j)tpFB1527->ParseIDOK=1;          //是对码的IDelsetpFB1527->ParseIDOK=0;          //没有对过码}else                                    //数据不对tpFB1527->ParseOK=0;
}

5. 主程序逻辑

        在主循环中检查 g_tFB1527Rx.ucRecOK标志,解析成功后处理数据:

	while(1){if(GetSysTimer()>=1)							//1ms运行一次{ResetSysTimer();ReadInput();Relay_Control();KeyClear();}if(g_tFB1527Rx.ucRecOK)                        //外部中断接收好了,进入解析函数{g_tFB1527Rx.ucRecOK=0;FB1527_Decode(&g_tFB1527Rx);}if (HAL_IWDG_Refresh(&IwdgHandle) != HAL_OK)	/*喂狗*/{Error_Handler();}}

8. 总结

        本文通过 外部中断 + 定时器 实现了EV1527无线信号的可靠解码,适用于智能家居、遥控器等场景。读者可根据实际需求调整参数,并进一步优化解码稳定性。

#ifndef __TIMER_H__
#define __TIMER_H__#include "main.h"
#include "Flash.h"typedef struct
{uint8_t Mode;                      //模式uint8_t ParseOK;                   //解析完成uint8_t ParseIDOK;                 //ID合法uint8_t ucRecOK;                   /*接收成功*/uint8_t ucKeyCode;                 /*按键码*/uint32_t ulChipID;                 /*芯片ID*/uint16_t usaLowTime[24];           /*24位低电平数据时间长度*/
}fb1527Type_T;extern TIM_HandleTypeDef TimHandle;extern fb1527Type_T g_tFB1527Rx;void TIM16_Init(void);
void TIM17_Init(void);
uint16_t GetSysTimer(void);
void ResetSysTimer(void);
void FB1527_Decode(fb1527Type_T *tpEV1527);
void Configure_EXTI(void);#endif#include "timer.h"TIM_HandleTypeDef TimHandle;TIM_HandleTypeDef TimHandle17;uint16_t systemTimer = 0;
uint16_t usPortLevel=0;
uint16_t usLowTime=0;
uint16_t WaitCnt=0;fb1527Type_T g_tFB1527Rx;/********************************************************************************************************
**函数信息 :void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
**功能描述 :TIM执行函数,计数值+1ms
**输入参数 :TIM_HandleTypeDef *htim
**输出参数 :
**    备注 :
********************************************************************************************************/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance==TIM16){systemTimer++;}
//    if(htim->Instance==TIM17)
//    {
//        HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_1);
//    }
}void TIM16_Init(void)
{TimHandle.Instance               = TIM16;                          // 选择TIM16TimHandle.Init.Period            = 240- 1;                         // 自动重装载值TimHandle.Init.Prescaler         = 100 - 1;                        // 预分频为100-1    Tout=(100*240)/24M=0.001S=1MSTimHandle.Init.ClockDivision     = TIM_CLOCKDIVISION_DIV1;         // 时钟不分频TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;             // 向上计数TimHandle.Init.RepetitionCounter = 1 - 1;                          // 不重复计数TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; // 自动重装载寄存器没有缓冲if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)                       // TIM16初始化{Error_Handler();}if (HAL_TIM_Base_Start_IT(&TimHandle) != HAL_OK)                    // TIM16使能启动,并使能中断{Error_Handler();}
}void TIM17_Init(void)
{TimHandle17.Instance               = TIM17;                          // 选择TIM17TimHandle17.Init.Period            = 65535-1;                        // 自动重装载值TimHandle17.Init.Prescaler         = 24-1;                            // 预分频为    TimHandle17.Init.ClockDivision     = TIM_CLOCKDIVISION_DIV1;         // 时钟不分频TimHandle17.Init.CounterMode       = TIM_COUNTERMODE_UP;             // 向上计数TimHandle17.Init.RepetitionCounter = 1 - 1;                          // 不重复计数TimHandle17.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; // 自动重装载寄存器没有缓冲if (HAL_TIM_Base_Init(&TimHandle17) != HAL_OK)                          // TIM17初始化{Error_Handler();}if (HAL_TIM_Base_Start_IT(&TimHandle17) != HAL_OK)                      // TIM17使能启动,并使能中断{Error_Handler();}
}uint16_t GetSysTimer(void)
{return systemTimer;
}void ResetSysTimer(void)
{systemTimer = 0;
}/********************************************************************************************************
**函数信息 :void Configure_EXTI(void)
**功能描述 :配置外部中断引脚
**输入参数 :
**输出参数 :
**    备注 :
********************************************************************************************************/
void Configure_EXTI(void)
{GPIO_InitTypeDef  GPIO_InitStruct;__HAL_RCC_GPIOA_CLK_ENABLE();                              //使能GPIOA时钟GPIO_InitStruct.Mode  = GPIO_MODE_IT_RISING_FALLING;       //模式为上升沿/下降沿中断GPIO_InitStruct.Pull  = GPIO_PULLUP;                       //上拉GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;              //速度为高速GPIO_InitStruct.Pin   = GPIO_PIN_12;HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);                         //使能EXTI中断HAL_NVIC_SetPriority(EXTI4_15_IRQn, 2, 2);                 //配置中断优先级
}void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{static uint8_t ucLeadCodeFind = 0;static uint8_t ucTimePos;    usLowTime=0;WaitCnt=50;usPortLevel = (GPIOA->IDR>>12)&0x01;   if(usPortLevel)        /*上升沿,完成低脉冲检测*/{usLowTime = __HAL_TIM_GET_COUNTER(&TimHandle17);__HAL_TIM_DISABLE(&TimHandle17);if(usLowTime > 11500 &&  usLowTime < 12500)        {ucLeadCodeFind = 1;ucTimePos = 0;}else{if(ucLeadCodeFind)/*只有找到引导码的情况下,才进行数据接收*/{g_tFB1527Rx.usaLowTime[ucTimePos++] = usLowTime;if(ucTimePos >= 24){ucTimePos = 0;ucLeadCodeFind = 0;g_tFB1527Rx.ucRecOK = 1;                    /*置位接收完成标志*/}}}}else                /*下降沿,启动低脉冲宽度检测*/{__HAL_TIM_SET_COUNTER(&TimHandle17,0);    __HAL_TIM_ENABLE(&TimHandle17);}    
}void FB1527_Decode(fb1527Type_T *tpFB1527)
{uint8_t i,j=0;uint32_t ulCombinedCode = 0;for(i=0; i< 24; i++){ulCombinedCode <<= 1; if(tpFB1527->usaLowTime[i] > 250 && tpFB1527->usaLowTime[i] < 450)        {ulCombinedCode |= 0x01;}else if(tpFB1527->usaLowTime[i]>900 && tpFB1527->usaLowTime[i] < 1200){}else{ulCombinedCode=0;break;}}tpFB1527->ucKeyCode = ulCombinedCode & 0x0000000f;tpFB1527->ulChipID = (ulCombinedCode & 0xfffffff0) >> 4;if(tpFB1527->ulChipID){tpFB1527->ParseOK=1;for(i=0;i<FLASH_NUM;i++){if(tpFB1527->ulChipID == FlashData[i])j = 1;}if(j)tpFB1527->ParseIDOK=1;elsetpFB1527->ParseIDOK=0;}elsetpFB1527->ParseOK=0;
}if(g_tFB1527Rx.ucRecOK)
{g_tFB1527Rx.ucRecOK=0;FB1527_Decode(&g_tFB1527Rx);
}


 

http://www.xdnf.cn/news/13015.html

相关文章:

  • 【Test Test】灰度化和二值化处理图像
  • 6TOPS算力NPU加持!RK3588如何重塑8K显示的边缘计算新边界
  • 嵌入式音视频开发指南:从MPP框架到QT实战全解析
  • 3D 视觉赋能仓储精准高效:ID Logistics 与 Stereolabs 的创新合作之旅
  • Java开发中的常用注解
  • 字符串系列一>最长回文子串
  • 给予FLUX更好的控制:FLUX.1-dev-ControlNet-Union-Pro-2.0
  • Redis——网络模型之IO讲解
  • 大模型微服务架构模块实现方案,基于LLaMA Factory和Nebius Cloud实现模型精调的标准流程及代码
  • Android——动画
  • IPTV电视信息发布直播点播系统:营造数字化个性化融合化多媒体IPTV电视信息发布平台
  • 预训练与微调:大模型如何“学习知识”?
  • Python 网络爬虫基础理论与实战指南
  • 【每日八股】复习计算机网络 Day1:TCP 的头部结构 + TCP 确保可靠传输 + TCP 的三次握手
  • 【漫话机器学习系列】209.均值的标准误差(Standard Error of the Mean)
  • 完整的 .NET 6 分布式定时任务实现(Hangfire + Redis 分布式锁)
  • 故障诊断常用算法
  • 2025妈妈杯数学建模D题完整分析论文
  • Kubernetes Pod 调度策略:从基础到进阶
  • java面向对象09:方法的重写
  • PyTorch入门------卷积神经网络
  • TCP/IP和UDP协议的发展历程
  • POSIX 信号量(Semaphore)
  • MacOS怎么显示隐藏文件
  • Vue3 实战:打造多功能旅游攻略选项卡页面
  • 记录学习的第二十九天
  • unity TEngine学习记录3
  • 精准计量+AI管控——安科瑞助力高校水电管理数字化转型
  • C#插件与可扩展性
  • 闲来无事,用HTML+CSS+JS打造一个84键机械键盘模拟器