结构体的一个简单应用——工程师原创应用笔记

发布时间:2020-08-18 阅读量:1481 来源: 我爱方案网 作者: 我爱方案网

【编者按】工程师很多时候需要使用单片机的串口与外设模块通讯,我们可以怎么设计这个数据结构以方便单片机操作从串口接收或者发送的数据呢?本文介绍两种方法处理这个问题,一种是使用数组来构建满足协议的数据结构,另一种是使用结构体来构建满足协议的数据结构。


假如我们需要使用单片机的串口与外设模块通讯,串口的通讯协议如下图所示,我们可以怎么设计这个数据结构以方便单片机操作从串口接收或者发送的数据呢?


工程师.png   



这里,我介绍两种方法,一种是使用数组来构建满足协议的数据结构,另一种是使用结构体来构建满足协议的数据结构,我们看看哪种方法更适合处理上述问题。


首先看看使用数组来构建数据结构的方法,如下代码所示。


  1. //用于存放6个字节的协议数据

  2. unsigned char arr[6];

  3. unsigned char len;


  4. len = sizeof(arr);

  5. //当串口缓冲区(假设是一个名为ser的数组)来了数据后,我们需要把串口数据复制到arr数组中

  6. memcpy(arr, ser, len);


  7. //拷贝完成后,我们需要校验、检查这些数据

  8. unsigned char sum = 0;

  9. unsigned char *p;


  10. p = arr;

  11. while(--len> 0)

  12. {

  13.   sum += *p++; 

  14. }


  15. //校验

  16. if(sum == arr[5])

  17. {

  18.   //检查收到的数据ID是否是我的目的ID

  19.   if(arr[0] == 0x01 && arr[1] == 0x02 && a[2] == 0x03)

  20.   {

  21.      //检查类型,确认是否是我的目标类型

  22.      if(arr[3] == 0x05)

  23.      {

  24.        //检查事件并做相应的动作.....  

  25.      }

  26.   }   

  27. }


从上述代码可以看出,对于接收到数据保存在arr后,需要指定索引才能准确的引用你需要的字节数据,这样做除了不方便以外,还容易出错。假如此时串口协议变更,比如我们需在ID3与类型之间扩充一个字节,此时你的代码肯定要改动,因为arr数组中arr[3]对于的位置已经不是类型了,arr[5]对应的也不是校验和了。显然,这种方法虽然可以用来处理串口数据,但是扩展性不好,程序引用相应的数据也不方便。那怎么办呢,用结构体就可以很好的解决这些问题,我们先来看代码。


  1. typedef struct

  2. {

  3.   unsigned char id[3];

  4.   unsigned char type;

  5.   unsigned char event;

  6.   unsigned char sum;    

  7. }pro_t;


  8. pro_t pro;

  9. unsigned char len;


  10. len = sizeof(pro_t);

  11. //当串口缓冲区(假设是一个名为ser的数组)来了数据后,我们需要把串口数据复制到pro结构体中

  12. memcpy((unsigned char *)&pro, ser, len);


  13. //拷贝完成后,我们需要校验、检查这些数据

  14. unsigned char sum = 0;

  15. unsigned char *p;


  16. p = (unsigned char *)&pro;

  17. while(--len > 0)

  18. {

  19.   sum += *p++; 

  20. }


  21. //校验

  22. if(sum == pro.sum)

  23. {

  24.   //检查收到的数据ID是否是我的目标ID

  25.   if(pro.id[0] == 0x01 && pro.id[1] == 0x02 && pro.id[2] == 0x03)

  26.   {

  27.      //检查类型,确认是否是我的目标类型

  28.      if(pro.type == 0x05)

  29.      {

  30.        //检查事件并做相应的动作.....  

  31.      }

  32.   }   

  33. }


从上述代码可以看出,程序引用协议数据相比数组结构更为方便而且清晰不易出错,当需要在ID3以及类型之间插入一个字节时,我们只需要更改pro_t类型的数据结构,而不需要变更我们已经写好的程序,如下图所示。


  1. typedef struct

  2. {

  3.   unsigned char id[3];

  4.   unsigned char extend;

  5.   unsigned char type;

  6.   unsigned char event;

  7.   unsigned char sum;    

  8. }pro_t;


综合来看,为了更好的让单片机的程序组织或者引用协议数据,使用结构体要比使用数组更好,不论从清晰,方便以及可扩展上都更具优势。


【编者按】在设计算法时,我们常常需要对算法的效果进行仿真,从而验证这个算法的效果。仿真的好处在于使用尽可能低的成本解决自己面临的问题。在实践中,我们常常使用如MATLAB、Python等工具进行仿真分析,以找出特征,设计算法,验证算法。要熟练的掌握上述的工具并不简单,那有没有什么工具容易掌握并且也能进行类似MATLAB的工作呢?答案是肯定的,那就是我们人人都会使用的excel,本文以传感器的输出信号为例来说明excel在信号分析中的应用。


我把excel在信号分析中的应用主要归纳为三种。第一是分析信号趋势;第二是分析信号特征,选择或者设计相应算法;第三是验证算法的效果。我们首先看看第一种如何分析信号趋势。


有时候我们需要把握传感器的输出信号随外界因素的变化趋势,以直观的知道输出信号是怎么随着外界因素的变化而变化的。那么我们该怎么知道这条曲线呢,此时excel就能排上用场,怎么做呢。


首先,收集信号。使用单片机的A/D对传感器的信号采样,然后利用串口把采样值(这个值如果不做转换的话一般是十六进制的)打印并保存到文件中,这一步可以结合电脑的串口软件完成。


其次,将保存在文件中的信号复制到excel中,然后把十六进制的传感器数据转换为十进制数据。如下所示。


工程师1.png


最后,选中上图中十进制传感器数据列(E列) -> 插入 -> 折线图,之后就会显示如下图一所示的曲线。有时候为了更好的显示信号的趋势,我们还需要在该曲线上添加一条趋势线(鼠标左键选中曲线 -> 右键出现下拉菜单,选中添加趋势线),以清晰的告诉我们信号的变化趋势是怎么样的,如下图二中的黑线就是蓝线的趋势线。



图1.png


图一


图2.png

图二



通过上述步骤,我们就得出了传感器输出信号随外界因素变化的趋势图,这比我们用口头或者文字描述要直观的多。


说完了excel在分析信号趋势上作用,再来说说excel在信号分析中的第二种作用 --- 分析信号特征,选择或者设计算法。


在使用单片机对信号采样时,为了设计符合要求的算法,信号的特征是我们需要知道的,要获得信号的特征,首先要知道信号的变化规律,那么上述利用excel获取信号曲线图的办法就能排上用场了。比如我在一个充电器的项目中需要采样电流信号,由于电流信号受到了高频干扰,即使充电电流是恒定的,单片机所采样的信号也是剧烈波动的,采样点的特征如下图所示(蓝线是原始采样点形成的信号线,黑线则是这些信号线的趋势线)。采样点大部分靠近趋势线,极少数出现了远离趋势线的采样点。


工程师图3.png


显然,要测量真实的电流,我们需要对采样信号进行过滤。观察信号线(蓝线)的特征,我们可以发现当电流不变时,采样点总是围绕趋势线(黑线)上下波动,而趋势线看上去就是这些波动采样点之间的中间值,因此,为了获得稳定的电流信号,我们完全可以使用数字滤波中常用的一种算法 --- 中值滤波(取一系列采样点数据,然后排序,取这一系列数据的中间值做为代表值)。从实际来看,这种算法是能满足要求的。


由此,我们根据信号特征,选择了一个合适的算法完成对信号的滤波,这就是excel分析信号的第二种应用。


最后,我们来看excel分析信号的第三种应用 --- 对算法的效果进行仿真,这里以一阶低通滤波器为例。


我们知道使用一阶低通滤波器关键在于选择滤波系数,因为滤波系数决定了滤波效果,太小或者太大都不好。选择合适的滤波系数一般只有通过实验才知道,这里我使用excel对算法进行仿真从而选择一个合适的滤波系数,步骤如下。


首先获取并保存采样值(没有经过处理的)然后按顺序导入excel,这一步之前已经讲过,之后设置好滤波系数,最后把一阶低通滤波的公式输入到excel中,如下图所示。


工程师图4.png


上图中的右边有两条曲线,蓝线表示当前采样值,红线为滤波后的输出,滤波效果一目了然。如果我们觉得这种滤波用力过猛,我们可以减少滤波系数,比如把滤波系数改为0.3,效果如下图所示。


工程师图6.png


像上面这样,我们只要调整滤波系数,我们很容易直观的看出滤波效果,最终可以比较轻松的选择一个你觉得合适的滤波系数。这就是excel在分析信号时的第三个作用,验证算法。


excel在信号分析中的3种用途就简单的说完了,上面我并没有详细说excel的操作方法,毕竟这不是我要向你表达的重点,不清楚的话自己可以百度。这里我最想说的其实在我们设计程序时,或许可能通过什么工具或者手段先进行仿真,以最低成本的方式获得最佳的结果。当然,说道仿真,MATLAB或者Python是要比excel更强大的专业软件,但学习成本也比较高,而且也不是所有仿真都必须要用这些工具来分析,还是那句话,只合适的,没有最好,希望能对你有一些启发。


本文作者:会笑的星星是一名设计开发工程师,在平台上的用户名为“ 1585292050XQYe”,有多年的物联网安防产品设计开发经验。





相关资讯
无源晶振YSX321SL应用于高精度HUD平视显示系统YXC3225

在现代汽车行业中,HUD平视显示系统正日益成为驾驶员的得力助手,为驾驶员提供实时导航、车辆信息和警示等功能,使驾驶更加安全和便捷。在HUD平视显示系统中,高精度的晶振是确保系统稳定运行的关键要素。YSX321SL是一款优质的3225无源晶振,拥有多项卓越特性,使其成为HUD平视显示系统的首选。

拥有卓越性能的高精度超薄低功耗心电贴—YSX211SL

随着医疗技术的进步,心电监护设备在日常生活和医疗领域中起到了至关重要的作用。而无源晶振 YSX211SL 作为一种先进的心电贴产品,以其独特的优势在市场上备受瞩目。

可编程晶振选型应该注意事项

对于可编程晶振选型的话,需要根据企业的需求选择。在选择可编程晶振的时候注重晶振外观、晶振的频率、晶振的输出模式、晶振的型号等等,这些都是要注意的,尤其是晶振的频率和晶振输出模式以及晶振的型号都是需要注意的。

性能高的服务器—宽电压有源晶振YSO110TR 25MHZ,多种精度选择支持±10PPM—±30PPM

在现代科技发展中,服务器扮演着越来越重要的角色,为各种应用提供强大的计算和数据存储能力。而高品质的服务器组件是确保服务器稳定运行的关键。YSO110TR宽电压有源晶振,作为服务器的重要组成部分,具备多项优势,成为业界必备的可靠之选。

差分晶振怎么测量

其实对于差分晶振怎么测量方式有很多种,主要还是要看自己选择什么样的方式了,因为选择不同的测量方式步骤和操作方式是不同的。关于差分晶振怎么测量的方式,小扬给大家详细的分享一些吧!