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; // 选择TIM17
TimHandle17.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中实现解码:
-
下降沿:启动TIM17计时。
-
上升沿:停止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; //是对码的ID
else
tpFB1527->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; // 选择TIM16
TimHandle.Init.Period = 240- 1; // 自动重装载值
TimHandle.Init.Prescaler = 100 - 1; // 预分频为100-1 Tout=(100*240)/24M=0.001S=1MS
TimHandle.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; // 选择TIM17
TimHandle17.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;
else
tpFB1527->ParseIDOK=0;
}
else
tpFB1527->ParseOK=0;
}
if(g_tFB1527Rx.ucRecOK)
{
g_tFB1527Rx.ucRecOK=0;
FB1527_Decode(&g_tFB1527Rx);
}
8261

被折叠的 条评论
为什么被折叠?



