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;                          // 选择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中实现解码:

  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;          //是对码的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);
}




 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值