基于STM32和EV1527的无线接收解码程序

摘自:

https://blog.csdn.net/Vinccent_/article/details/78955376

https://blog.csdn.net/hzd12368/article/details/80487849  另一参考

一、1527的数据帧结构
无线遥控的编码,从编码类型上来说,分为2类,一类是固定码,也就是编码芯片的地址是不变的,芯片型号以 EV1527、PT2262 为代表。另一种是滚动码,芯片的地址码是变化的,芯片以HS300、HS301为代表。

1 EV1527 数据帧结构
EV1527 是一片由 CMOS 设计制造的可预烧内码的学习码编码IC ,由软件解码;内码共有 20 个位元可预烧 1048576 组内码组合,降低使用上编码重复的机率。
EV1527 每帧数据由 24 个数据位组成,前 20 位为地址码,对于一个芯片来说,地址位的内容是固定的,是出厂前就预制好的,并且理论上每个芯片的地址码是唯一的。后面 4 位为按键码,对应芯片上的K0-K3 4 根数据线,数据线的状态不同,按键码就不同。
在数据位之前,还有一个同步脉冲,也就是每帧数据都是从同步
脉冲开始的。数据位的“1”和“0”是由高低电平宽度(脉冲宽度)的比例决定的。如果高电平宽度为低电平宽度的 3 倍,就表示逻辑“1”,反过来如果低电平为高电平宽度的 3 倍,就表示逻辑“0”。同步脉冲高电平和低电平的比例固定为 4:124.
1527时序
这里写图片描述
这里写图片描述
这里写图片描述

二、中断方式的解码
把串行输入的编码数据帧,还原成编码之前的状态,读取其中
的地址码和按键码,称之为解码。
数据帧都是由同步头开始,然后是 24位的数据码,并且此数据帧在遥控器按键的过程中是重复出现的,我们首先要判断同步码,判断出了同步码,就知道数据码是从那一位开始了。对于一款量产的无线遥控器来说,他的编码芯片匹配的电阻是一个固定值,也就是说它发射的数据帧的脉冲宽度是不变的,所以我们可以通过测量高低脉冲宽度的方式来分辨同步码、逻辑“1”、逻辑“0”。
具体的方法是这样的,首先启用定时器,装入一个初值,打开
定时器中断,让其以固定的间隔进入中断程序。在中断程序中,我们查询数据输入管脚的状态,如果为高电平,就在高电平状态累加计数,反之就在低电平状态计数,当电平发生上升沿变化的时候,判断接收到的高低电平宽度的值是否符合同步信号的要求,如果符合就进入数据位的接收,以同样的方式判断逻辑“1”或逻辑“0”。如果接受过程中出现不符合要求的电平状态,就退出接收,为了增加可靠性,我们一般要求规定时间内,成功接收到完全相同的 2 帧数据才算有效。
接收完成后,24 个数据位被放入 3 个字节中。下一步我们要对接收到的数据进行处理,判断编码的类型,分离地址码和按键码。

三、程序代码

/*main.c*/

#include "stm32f10x.h"
#include "uart.h"
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "timer.h"

uint8_t rf_data[4];
extern uint8_t decode_ok;    //解码成功标志位
extern uint8_t RF;

int main(void)
{   
    LED_Init();
    Uart_Init();
    delay_init();   //延时初始化一定要加上!!!!!!
    EV1527_GPIO_Init();
    TIM6_NVIC_Init();
    TIM6_Mode_Init();

    while(1)
    {
        if(decode_ok == 1)   //解码成功
        {
            switch(rf_data[2])
            {
                case 0xf8:   //解码为0xf8,点亮LED
                {
                    LED1 = LED_ON;
                    LED2 = LED_ON;
                    LED3 = LED_ON;
                    break;
                }
                case 0xf2:   //解码为0xf2,熄灭LED
                {
                    LED1 = LED_OFF;
                    LED2 = LED_OFF;
                    LED3 = LED_OFF;
                    break;
                }

            }

        }
/***调试用代码,查看接收到的编码***/      
//      printf("\r\n EV1527 \r\n");
//      delay_ms(500);
//      printf("i get %x  ",rf_data[0]);
//      delay_ms(500);
//      printf("i get %x  ",rf_data[1]);
//      delay_ms(500);
//      printf("i get %x  ",rf_data[2]);
//      delay_ms(500);
//      printf("i get %x  ",rf_data[3]);
//      delay_ms(500);
    }
}
/************** END OF FILE *****************/


/*Timer.c*/


#include "stm32f10x.h"                  // Device header

#include "timer.h"
#include "led.h"
#include "uart.h"
#include "delay.h"

void EV1527_GPIO_Init() //EV1527 IO口初始化
{
    GPIO_InitTypeDef GPIO_InitStruct;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  // PB9 输入端
    GPIO_InitStruct.GPIO_Pin     = GPIO_Pin_9; 
    GPIO_InitStruct.GPIO_Mode    = GPIO_Mode_IN_FLOATING;
    GPIO_InitStruct.GPIO_Speed   = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
}

//中断函数使用定时器6

void TIM6_NVIC_Init()   //中断分组初始化
{
NVIC_InitTypeDef NVIC_InitStructure;    
                         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
//TIM6中断
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn; 
//先占优先级2级
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  
//从优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 
//IRQ通道被使能
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
//根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 
NVIC_Init(&NVIC_InitStructure); 
}

void TIM6_Mode_Init()
{    
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    //使能TIM6时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);    
    //初始化定时器6
    //设定计数器自动重装值     
    TIM_TimeBaseStructure.TIM_Period = 100; 
    //时钟预分频系数 驱动计数器的时钟 CK_CNT=CK_INT/(71+1) = 1M
    //计数器计数1次时间等于1/CK_CNT = 1us
    TIM_TimeBaseStructure.TIM_Prescaler =71; 
    //设置时钟分割:TDTS = Tck_tim                                                                                   
    TIM_TimeBaseStructure.TIM_ClockDivision =        
    TIM_CKD_DIV1; 
    //TIM向上计数模式
    TIM_TimeBaseStructure.TIM_CounterMode = 
    TIM_CounterMode_Up; 
    //根据指定的参数初始化TIMx的时间基数单位
    TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); 
    //允许更新中断 
    TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);
    TIM_ClearFlag(TIM6,TIM_FLAG_Update);
    //使能定时器6
    TIM_Cmd(TIM6,ENABLE );  
}

uint8_t RF;
uint8_t decode_ok;            //解码成功
uint8_t  hh_w,ll_w;           //高,低电平宽度
uint8_t  ma_x;                //接收到第几位编码了
uint8_t  bma1,bma2,bma3,bma4; //用于接收过程存放遥控编码,编码比较两次,这是第一次
uint8_t  mma1,mma2,mma3,mma4;
uint8_t mmb1,mmb2,mmb3,mmb4; // 用于接收过程存放遥控编码,第二次
//extern uint8_t mmb1,mmb2,mmb3,mmb4;

uint8_t rf_ok1,rf_ok2,rf_ok;         //解码过程中的临时接收成功标志,接收到一个完整的遥控命令后置1,通知解码程序可以解码了
uint8_t old_rc5;             //保存上一次查询到的电平状态
uint8_t tb_ok;               //接收到同步的马时置1   
uint8_t D0,D1,D2,D3 ;
uint16_t s ,s1; 
uint8_t bt_auto;     //自动设置遥控接收波特率标志
extern uint8_t rf_data[4];  

void TIM6_IRQHandler()
{
    if(TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)
    {
        TIM_ClearITPendingBit(TIM6, TIM_IT_Update); 

        //接收数据的电平 PB9
        RF = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_9); 
        if (!RF) 
        { 
            ll_w++;   // 检测到低电平 低电平时间加1,记录本 
                      // 次电平状态old_rc5
            old_rc5=0; 
        }               
         else         // 检测到高电平
         { 
            hh_w++;
            if (!old_rc5)  // 检测到从低到高的跳变,已检测
                           // 到一个完整(高-低)电平周期
            {   //判同步码    2/5 100/130
                if (((hh_w>=2)&&(hh_w<=5))&&
                ((ll_w>=100)&&(ll_w<=130))) 
                { 
                    tb_ok = 1 ;
                    ma_x = 0;
                    bma1=0; bma2=0; bma3=0; bma4=0;    
                }
                else if ((tb_ok)&&((ll_w>=8)&&
                                (ll_w<=13))) //8/13
                {   
                    ma_x++; //已经接收到同步码,判0
                    if(ma_x>23)
                    {
                        if(!rf_ok1) //rf_ok1临时接收成功
                        {   //将接收到的编码复制到解码寄存器中 
                            mma1=bma1;
                            mma2=bma2;
                            mma3=bma3;
                            mma4=bma4; 
                            // 通知解码子程序可以解码了                                                        
                            rf_ok1=1;                    
                            tb_ok=0;
                            s=1000;                             
                            }
                            else
                            {//将接收到的编码复制到解码寄存器中  
                                mmb1=bma1;
                                mmb2=bma2;
                                mmb3=bma3;
                                mmb4=bma4;  
                                // 通知解码子程序可以解码了                                             
                                rf_ok2=1;                     
                                tb_ok=0;                                                                        
                            }
                        }
                     }  
                     else if ((tb_ok)&&((ll_w>=2)&&
                                  (ll_w<=7)))   // 2/7
                     { 
                         switch (ma_x)
                         { 
                         case 0 : { bma1=bma1 | 0x80; 
                             break; }   //遥控编码第1位
                         case 1 : { bma1=bma1 | 0x40;  
                             break; }
                         case 2 : { bma1=bma1 | 0x20; 
                             break; }
                         case 3 : { bma1=bma1 | 0x10; 
                             break; }
                         case 4 : { bma1=bma1 | 0x08; 
                             break; }
                         case 5 : { bma1=bma1 | 0x04; 
                             break; }
                         case 6 : { bma1=bma1 | 0x02; 
                             break; }
                         case 7 : { bma1=bma1 | 0x01; 
                             break; }
                         case 8 : { bma2=bma2 | 0x80; 
                             break; }
                         case 9 : { bma2=bma2 | 0x40; 
                             break; }
                         case 10: { bma2=bma2 | 0x20; 
                             break; }
                         case 11: { bma2=bma2 | 0x10; 
                             break; }
                         case 12: { bma2=bma2 | 0x08; 
                             break; }
                         case 13: { bma2=bma2 | 0x04; 
                             break; }
                         case 14: { bma2=bma2 | 0x02; 
                             break; }
                         case 15: { bma2=bma2 | 0x01; 
                             break; }
                         case 16: { bma3=bma3 | 0x80; 
                             break; }
                         case 17: { bma3=bma3 | 0x40; 
                             break; }
                         case 18: { bma3=bma3 | 0x20; 
                             break; }
                         case 19: { bma3=bma3 | 0x10; 
                             break; }
                         case 20: { bma3=bma3 | 0x08; 
                             break; }// 按键状态第1位
                         case 21: { bma3=bma3 | 0x04; 
                             break; }
                         case 22: { bma3=bma3 | 0x02; 
                            break; }
                         case 23: { bma3=bma3 | 0x01;              
                                  if(!rf_ok1)
                                  {
                                      mma1=bma1;
                                      mma2=bma2;
                                      mma3=bma3;
                                   // mma4=bma4;                                           // 将接收到的编码复制到解码寄存器中                             
                                     rf_ok1=1;         // 通知解码子程序可以解码了
                                     tb_ok=0;
//                                   bt_auto=0;
                                     s=1000;
                                     break;                                 
                                  }
                                  else
                                  {
                                      mmb1=bma1;
                                      mmb2=bma2;
                                      mmb3=bma3;
                                    //mmb4=bma4;               // 将再次接收到的编码复制到解码寄存器中,                             
                                    rf_ok2=1;                                      // 通知解码子程序可以解码了
                                    tb_ok=0;
                                    break;                                                                          
                                 }                                    
                         }
                    } 
                    ma_x++; 
                 }
                 else
                 {ma_x=0; tb_ok=0;bt_auto=0;bma1=0;bma2=0; bma3=0; hh_w=1;ll_w=0;}                                      //接收到不符合的高-低电平序列
                 ll_w=0;hh_w=1; 
             }          
             old_rc5=1;      // 记录本次电平状态
       }
       if(rf_ok1)  //规定时间内接受到2帧相同的编码数据才有效
        {
            s--;
            if(!s) rf_ok1=0;
            if(rf_ok2) 
            {
            if((mma1==mmb1)&&(mma2==mmb2)&&(mma3==mmb3))
            {
                rf_ok=1;
                rf_ok1=0;
                rf_ok2=0;                    
            }
            else
            {
                rf_ok=0;
                rf_ok1=0;
                rf_ok2=0;

             }          
        }                   
    }

    if((rf_ok))      //判断是否接收成功
    {   
        TIM_ITConfig(TIM6, TIM_IT_Update, DISABLE);
        rf_ok=0; 
        rf_data[0]=mma1;
        rf_data[1]=mma2;
        rf_data[2]=mma3;

        decode_ok=1;

        TIM_ITConfig(TIM6  , TIM_IT_Update, ENABLE);
        }
    }
}

--------------------- 本文来自 Mascreda 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/Vinccent_/article/details/78955376?utm_source=copy

STM32F1527是意法半导体(STMicroelectronics)推出的一款高性能的32位微控制器。在使用STM32F1527进行编程时,可以使用各种编程语言和开发环境,如C语言和Keil等。如果要编写STM32F1527解码程序,可以按照以下步骤进行: 1. 首先需要了解STM32F1527的硬件功能和特性,包括串口通信、定时器、中断等功能,以便在编码中进行使用。 2. 创建一个新的工程,选择适当的编程语言和开发环境。例如,使用Keil来进行C语言编程。 3. 在程序中添加必要的头文件和宏定义,以便使用STM32F1527的相关功能。 4. 根据具体的解码需求,设计解码算法和数据结构。可以使用状态机、位操作和移位等方法进行解码过程。 5. 初始化STM32F1527的相关硬件功能,如串口、定时器等。 6. 编写一个中断服务函数,用于处理外部中断或定时器中断等触发解码的事件。 7. 在主函数中,编写主要的解码逻辑。根据接收到的码值进行相应的处理,如解码成相应的信号或数据。 8. 编译、下载程序到STM32F1527,并将芯片与其他设备连接。 9. 测试解码程序的功能和正确性。可以通过发送测试码并观察输出结果来验证解码程序的准确性。 10. 如有需要,可以根据实际应用场景进行性能优化和改进。 总之,编写STM32F1527解码程序需要对STM32F1527的硬件和编程语言有一定的了解,并根据具体需求进行程序设计和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值