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中实现解码:
-
下降沿:启动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; //是对码的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);
}