文章目录

  • 前言
  • 一、EV1527的编码形式
  • 二、代码
    • 1.收码
    • 1.还原
  • 总结

前言

在前面的项目中,使用了STC51单片机,完成了一个小项目,无线门磁报警器。可他通过OOK调幅信号,形成EV1527这样的波形类型,以433M的频率发送。
发送了之后,势必要有接受。
这次就使用STM32单片机,通过一个OOK无线接受模块,接受无线门磁报警器发出的信号,通过解析之后,在OLED屏幕上显示出来。


一、EV1527的编码形式

想要解码,首先就要知道,EV1527的编码形式是怎么样的。
这是一帧数据的波形:

一帧数据,由同步头和数据体组成。
同步头是用来分辨通讯开头的,软解码的时候,首先会通过同步头来分辨一帧数据的开头,然后才能开始解析数据体。
数据体一共3byte大小,也就是24bit,其中20bit是地址码,剩下4bit是数据码。
每一个设备发送过来的地址码都是不同的,数据码可以是相同的。一共4bit的数据码,也就是可以实现15种功能。
可以看到,同步头和bit1,bit0的波形构成。
他们的区别就是高低电平持续时间的不同,也就是说只要解析出高低电平持续的时间,就能实现解码。
其中高低电平的时间其实是有规律的,同步头高低电平的比值是1:31.
bit1中,高低电平的比值是3:1.
bit0中,高低电平的比值是1:3.
这是之后解码的重要依据。

二、代码

1.收码

//获取RFD接收IO口电平状态
static unsigned char hal_GetRFDIOSta(void)
{return (GPIO_ReadInputDataBit(RFD_RX_PORT, RFD_RX_PIN));
}
//RFD脉冲采集,这个作为回调函数放在50us定时器中断里,50um执行一次
static void hal_PulseAQT_Handle(void)
{static unsigned char Temp, Count1 = 0;Temp <<= 1;              //向左移动1位,右侧补零if(hal_GetRFDIOSta()) //无线接受到高电平Temp |= 0x01;     //Temp的最低位置1,其他不变else                   //无线接受到低电平Temp &= 0xFE;      //Temp的最低位置0,其他不变//连续循环8次之后,将Temp存放在队列RFDBuff中if(++Count1 == 8){Count1 = 0;QueueDataIn(RFDBuff, &Temp, 1);//入列}hal_ResetTimer(T_RFD_PULSH_RCV,T_STA_START);//中断标志位复位}

通过GPIO_ReadInputDataBit库函数可得到接受到的高低电平。然后分别根据高低电平的不同,对Temp进行赋值,得到8bit的数据,存入队列当中。
这个函数被放在定时器50um的中断中,也就是每50um读取一次无线接受模块的电平。8bit就是读取了八次,0.4ms,恰好就是电平持续时间的最小值。


1.还原

{unsigned char Temp, Num;
static unsigned char Dsta = 0;
static unsigned short Count = 0;
QueueEmpty(ClkTimeBuff);
while(QueueDataOut(RFDBuff, &Temp))//返回值是队列成员个数,队列里面有成员,方能进循环
{Num = 8;//一个字节while(Num--){if(Dsta)//首次执行为0{//1if(!(Temp&0x80))   //这里检测电平是否为低,如果为低代表高电平脉宽结束{unsigned char Data;Data = Count / 256;           //存储高电平脉宽高字节Data |= 0x80;                      //电平标志 1为高 0为低,一个字节的最高位判断高低电平QueueDataIn(ClkTimeBuff, &Data, 1);Data = Count % 256;            //存储高电平脉宽低字节  Count没有改变QueueDataIn(ClkTimeBuff, &Data, 1);//注意这里Data的值x50us等于脉宽时间Dsta = 0;Count = 0;}}else{//0if(Temp&0x80)   //这里检测电平是否为高,如果为高代表低电平脉宽结束{unsigned char Data;Data = Count / 256;       //存储低电平脉宽高字节   //Data &= 0xFF7F;               //电平标志 1为高 0为低Data &= 0x7F;        //Bit7为脉宽电平标志,1为高 0为低,一个字节的最高位判断高低电平QueueDataIn(ClkTimeBuff, &Data, 1);Data = Count % 256;      //存储低电平脉宽低字节QueueDataIn(ClkTimeBuff, &Data, 1); //注意这里Data的值x50us等于脉宽时间Dsta = 1;Count = 0;}}Count++;Temp <<= 1;//最高位舍弃,第二位改为最高位}
}
}

这段代码,是将高低电平数据,分为高低两个字节。同时高字节的那部分,在第七bit位上,根据高低电平写上1或者0。


while(QueueDataLen(ClkTimeBuff))    //判断有没波形数据
{if(!ReadDataFlag)//同步头{unsigned char Temp;while(!Time1 || !Time2){if(!Time1)       {//获取第一个波形数据while(QueueDataOut(ClkTimeBuff, &Temp))//一直取出数据,直到低电平{//Driver_GUART1SendByByter('*');if(Temp&0x80)        //先获取高电平波形,波形一开始是高电平{Temp &= 0xFF7F;//置0第8位,原来给了一个1代表高电平Time1 = Temp * 256;QueueDataOut(ClkTimeBuff, &Temp);Time1 += Temp;//把拆分成两个队列成员的时间组合Time2 = 0;break;}elseQueueDataOut(ClkTimeBuff, &Temp);    }if(!QueueDataLen(ClkTimeBuff))break;}if(!Time2){//获取低电平波形QueueDataOut(ClkTimeBuff, &Temp);Time2 = Temp * 256;QueueDataOut(ClkTimeBuff, &Temp);Time2 += Temp;//判断高电平*20时间,和高电平*44的时间,有容错,标准是31if((Time2 >= (Time1*RFD_TITLE_CLK_MINL)) && (Time2 <= (Time1*RFD_TITLE_CLK_MAXL))){Time1 = 0;Time2 = 0;Len = 0;ReadDataFlag = 1;//下一步读取数据体break;}     else{Time1 = 0;Time2 = 0;}}}}if(ReadDataFlag)//数据体{unsigned char Temp;if(!Time1){if(QueueDataOut(ClkTimeBuff, &Temp)){//这里经过头验证后,第一个字节肯定是高电平,所以要&0xFF7F把高电平标志位清除Temp &= 0xFF7F;Time1 = Temp * 256;QueueDataOut(ClkTimeBuff, &Temp);Time1 += Temp;Time2 = 0;}elsebreak;}if(!Time2){if(QueueDataOut(ClkTimeBuff, &Temp)){bool RecvSuccFlag;Time2 = Temp * 256;QueueDataOut(ClkTimeBuff, &Temp);Time2 += Temp;//bit1if((Time1 > (Time2*RFD_DATA_CLK_MINL)) && (Time1 <= (Time2*RFD_DATA_CLK_MAXL))){unsigned char i, c = 0x80;//'1'for(i = 0; i < Len%8; i++){c >>= 1;c &= 0x7F;}Code[Len/8] |= c;RecvSuccFlag = 1; }//bit0      else if((Time2 > (Time1*RFD_DATA_CLK_MINL)) && (Time2 <= (Time1*RFD_DATA_CLK_MAXL))){unsigned char i, c = (unsigned char)0xFF7F;//'0'for(i = 0; i < Len%8; i++){c >>= 1;c |= 0x0080;}Code[Len/8] &= c;RecvSuccFlag = 1;}else{//errorRecvSuccFlag = 0;ReadDataFlag = 0;}Time1 = 0;Time2 = 0;if((++Len ==24)  && RecvSuccFlag)//接受到24个bit位{ReadDataFlag = 0;//判断发送过来的是同一帧if((CodeTempBuff[0]==Code[0])&&(CodeTempBuff[1]==Code[1])&&(CodeTempBuff[2]==Code[2])){//过滤同一帧RFD_CodeHandle(Code);}else{memcpy(CodeTempBuff, Code, 3);//内存赋值,3byte}}}elsebreak;}}
}

//引导码脉宽允许误差范围
#define RFD_TITLE_CLK_MINL 20
#define RFD_TITLE_CLK_MAXL 44

//数据码脉宽允许误差范围
#define RFD_DATA_CLK_MINL 2
#define RFD_DATA_CLK_MAXL 5
//同步头
if((Time2 >= (Time1RFD_TITLE_CLK_MINL)) && (Time2 <= (Time1RFD_TITLE_CLK_MAXL)))

//bit1
if((Time1 > (Time2RFD_DATA_CLK_MINL)) && (Time1 <= (Time2RFD_DATA_CLK_MAXL)))

//bit0
else if((Time2 > (Time1RFD_DATA_CLK_MINL)) && (Time2 <= (Time1RFD_DATA_CLK_MAXL)))

这三条判断是很重要的,能判断出数据是同步头、bit1还是bit0。
判断的条件为什么不是之前的31,和3呢。
在实际的应用中,存在干扰因素,其他电波的干扰或者障碍物的阻挡,都会影响实际受到的数据。如果规定的太死,就容易出现接收不到数据的情况。

总结

最后解码得到的3byte数据,就存放在code数据当中,解码完成。

【STM32】OOK软解码相关推荐

  1. 关于stm32的正交解码

    关于正交解码,我先解释何为正交解码,,,,其实名字挺高大上的,,,,还是先说编码器吧 看一下我用过的一种编码器 编码器的 线 数 ,是说编码器转一圈输出多少个脉冲,,,如果一个编码器是500线,,,说 ...

  2. “硬解码”与“软解码”的区别

    关于"硬解码"与"软解码" 忧蓝 发布于: 2010-08-02 11:03 由于高清视频的分辨率远远高于一般格式视频,使得高清视频的码率非常高.再加上VC-1 ...

  3. 关于“硬解码”与“软解码”

    由于高清视频的分辨率远远高于一般格式视频,使得高清视频的码率非常高.再加上VC-1和H.264编码的压缩率很高,解码运算的运算量很大.因此常规地直接用CPU解码(即常说的"软解") ...

  4. 软解码与硬解码区别linux,软解码和硬解码哪个好 软解码和硬解码有什么区别

    喜欢用手机看视频的同学应该都会接触到这样一个概念,手机软解码和硬解码.虽然这两个选项在播放器中再常见不过.不过还是很多机友不知道两者的区别再哪里.就针对这个问题百事网小编给大家普及一下相关的软解和硬解 ...

  5. Android多媒体添加软解码

    1 软解码加载简介 1.1 编解码器信息与配置导入 android中decoder的管理是以plugin的模式,其控制是在OMXMaster内完成的. OMXMaster是在omx被创建时就创建了 O ...

  6. 硬解码和软解码的区别

    我们在计算机上播放的视频文件都是经过压缩的,因为这样有利于节约存储空间:那么在播放过程,就需要进行一个反射的解压缩过程.在以前这项工作都是由CPU来完成的,对于普通分辨率的AVI.RMVB等文件,绝大 ...

  7. HEVC的软解码和硬解码

    1.概念 从数字视频诞生以来,硬解码和软解码的说法一直伴随着它的发展.数字视频的软解码是指在通用CPU上通过专门的播放软件解码并播放视频:而硬解码则是指在专用的硬件解码模块解码视频,然后将解码数据送至 ...

  8. ffmpeg硬解码与软解码的压测对比

    文章目录 ffmpeg硬解码与软解码的压测 一.基本知识 二.压测实验 1. 实验条件及工具说明 2. 压测脚本 3. 实验数据结果 ffmpeg硬解码与软解码的压测 一.基本知识 本文基于intel ...

  9. SkeyeARS 8K视频播放器软解码硬解码功能实现

    SkeyeARS 8K视频播放器软解码&硬解码功能实现 首先,我们简单了解一下软解码&硬解码: 软解码:由CPU负责解码进行播放 优点:不受视频格式限制.画质可能略好于硬解缺点:会占用 ...

  10. 硬解码与软解码的选择

    前言 事物都有两面性,软解码和硬解码的并存,存在即合理,没有哪个最好,以后两者都会更好,而对于如何选择,根据项目需要. 在上篇<快速集成一个视频直播功能> 中提到,"确定需求后进 ...

最新文章

  1. 开发Activex控件安全
  2. What Does TTY Stand for in Linux?
  3. 树莓派安装python模块_树莓派引脚编号、pypi说明和安装
  4. linux远程登录ssh免密码配置方法
  5. java 正则 小数_详解Java判断是否是整数,小数或实数的正则表达式
  6. Celery + Flower + FastAPI + RabbitMQ ,Python实现异步消息队列和监控
  7. smarty5变量修改器
  8. [渝粤教育] 西南科技大学 工程建设监理 在线考试复习资料
  9. springboot filter_SpringBoot(二) :web综合开发
  10. 深度linux登录后界面卡死,Deepin Linux 15(.1)启动即卡死的问题
  11. IT民工金鱼哥从业8年的历程与感悟
  12. Hilbert 变换
  13. 三菱PLC控制步进电机(外部接线原理图)
  14. 如何利用Gmail群发电子邮件
  15. sh_gamit报错:error reading station a priori constrains
  16. bugku 杂项 QAQ
  17. Yielding Processes
  18. 副屏幕全屏_win7双屏电脑主屏副屏设置|Win7系统如何设置双屏显示?
  19. Swift语法学习--数据类型
  20. Unity3D 自动切割动画

热门文章

  1. 编程:获取股票实时行情数据大全
  2. 计算机毕业设计之 疫情防控志愿者管理系统
  3. 线性代数【8】-1 线性方程组 - 非常重要的概念 - 三个基本的问题
  4. 事务故障、系统故障和介质故障的恢复
  5. 盘点一份JS逆向代码转换为Python代码的教程
  6. 对链表进行插入排序。从第一个元素开始,该链表可以被认为已经部分排序。每次迭代时,从输入数据中移除一个元素,并原地将其插入到已排好序的链表中。
  7. Window环境PHP7使用Protobuf开发详解
  8. 第01课:敏捷教练和 ScrumMaster 基本功四部曲(iPad 版)
  9. w2ui 复选框功能
  10. xen html插件美化桌面,过去的界面都弱爆了!魔兽界面美化插件推荐