文章目录

  • 1 串口使用的常用场景
  • 2 字节帧处理
  • 总结

1 串口使用的常用场景

使用串口的主要目的是实现数据的交互,数据的交互的方法脱身于常用的场景。这里描述一个比较典型的场景:

MCU作为主控制器通过串口和外部的设备或者人进行交互。对于单片机端的设备往往存在一系列的指令。对于控制一个电机而言,他可以具备如下的行为,停止、转动、速度设置、位置设置等等。进而,对于多个微控制器存在的系统而言,各个控制器间也需要进行一定的信息交互,比如,从机向主机定时的发送心跳包来告知主机我的工作状态良好等。因此,一套遵从统一规则的串口帧协议十分重要,可以较好对命令集合进行处理,同时,可以对常见的问题进行合理的调整。

2 字节帧处理

制定串口协议的方式有很多,这里说一下我处理字节帧的一点经验。
以做过的一个项目为例,具体的帧结构如下图所示:

  • 数据帧头:AA 55
  • ID编号为固定的 0x10
  • CH: 输入 1 – 4 选通指定通道, 5:失能所有通道 6:使能所有通道
  • NULL: 空字节 可填入任意值
  • SUM: SUM = ID + CH + NULL + NULL + NULL + NULL + NULL + NULL + NULL + NULL + NULL + NULL + NULL + NULL + NULL + NULL + NULL + NULL + NULL + NULL

帧定义了帧头、数据、帧尾。这里使用的帧属于定长帧,定长帧的优势在于处理的方式较为简便。缺点也显而易见,对于数据位较少的帧,是一种时间上的浪费(问题不大)。
解帧思路:同时获取到两个帧头,获取ID,通过ID来判断数据的长度,进而获取完整数据,再者检查校验码。校验码正确则消费数据,否则丢弃。

好了,直接上代码(有优化的可以评论留言):

#define FRAME_HEAD1         0xAA
#define FRAME_HEAD2         0x55
#define FRAME_DATA_LEN      20/*
***********************************************************************************************
*   函 数 名: CheckSum
*   功能说明: 校验和判断
*   形    参:无
*   返 回 值: true :校验正确  false:校验失败
***********************************************************************************************
*/
static uint8_t CheckSum(uint8_t *pValueBuff, uint8_t u8BuffLen, uint8_t u8CheckNum)
{uint8_t u8Sum = 0;if (u8BuffLen > FRAME_DATA_LEN){return FALSE;}for (uint8_t i = 0; i < u8BuffLen; i++){u8Sum += *pValueBuff;pValueBuff++;}return u8CheckNum == u8Sum ? TRUE : FALSE;
}/*
***********************************************************************************************
*   函 数 名: DealCmd
*   功能说明: 命令处理函数
*   形    参:数据帧
*   返 回 值: 无
***********************************************************************************************
*/
void DealCmd(uint8_t *pFrame)
{switch (*pFrame){case EM_CYCLIC_ID:{DealCvFrame(pFrame);}break;  case EM_PULSE_ID:{      DealDpvFrame(pFrame);}break;case EM_TEST_ID:{      DealTestFrame(pFrame);}break; default:{print(PERROR, " 无效ID\n ");}break;}
}/*
***********************************************************************************************
*   函 数 名: GetConfigCmd
*   功能说明: 数据帧处理
*   形    参:无
*   返 回 值: 无
***********************************************************************************************
*/
void GetConfigCmd(void)
{uint8_t u8Temp = 0;static uint8_t u8index = 0;static uint8_t u8HeadFlag = 0;static uint8_t u8BuffTemp[FRAME_DATA_LEN + 1] = {0};while (comGetChar(CONNECT_COM, &u8Temp)){if (FRAME_HEAD1 == u8Temp  &&  FALSE == u8HeadFlag){u8HeadFlag = 1;}if (FRAME_HEAD2 == u8Temp  &&  1 == u8HeadFlag){u8HeadFlag = 2;continue;}if (2 == u8HeadFlag){u8BuffTemp[u8index++] = u8Temp;if (u8index > FRAME_DATA_LEN){if (CheckSum(u8BuffTemp, FRAME_DATA_LEN, u8BuffTemp[FRAME_DATA_LEN])){DealCmd(u8BuffTemp);    //消费数据    }u8HeadFlag = FALSE;u8index = 0;u8BuffTemp[0] = EM_MAX_ID;}}}
}

这个实际上不是重点,下面来看看如何提取数据。
我们知道我们很大概率需要传送的数据有,(有无符号)整形,浮点型(往往更具精度乘一定倍数处理成整形)。那如何将这两种类型较好的处理呢。
这里我们用到了C种的结构体,我们知道结构体存在字节对齐的问题,但我们的数据是单字节对齐的,不存在空位的,因此需要使用如下命令告知编译器不适用默认的字节对齐规则,而是单字节对齐。
第二个问题是对于ARM而言,数据的存储方式是小端模式,但是我们的串口数据在接收后存在FIFO种是大端的模式,因此我们需要进行转换。

解决第一个问题:
#pragma pack(1) 中 1 代表单字节对齐。

#pragma pack(1)
typedef struct CV_DATA_FRAME
{uint8_t  Id;int16_t  InitE;int16_t  HighE;int16_t  LowE;uint8_t  InitPN;uint16_t ScanRate;uint32_t SweepSeg;uint8_t  SampleInt;uint32_t QuietTime;
}stCvFrame;
#pragma pack()

解决第二个问题:

#define REVERSE_16(X)        ((X & 0x00FFU) << 8 | (X & 0xFF00U) >> 8)#define REVERSE_32(X)      ((X & 0x000000FFU) << 24 | (X & 0x0000FF00U) << 8 | (X & 0x00FF0000U) >> 8 | (X & 0xFF000000U) >> 24)

OK, 到此为止一切解决。现在看一下提取数据:

/*
***********************************************************************************************
*   函 数 名: DealCvFrame
*   功能说明: 命令处理函数
*   形    参:数据帧
*   返 回 值: 无
***********************************************************************************************
*/
void DealCvFrame(uint8_t *pFrame)
{stCvFrame *p_stCvDataFrame;stCvFrame stCvDataTemp;p_stCvDataFrame = (stCvFrame *)pFrame;{stCvDataTemp.InitE        = REVERSE_16(p_stCvDataFrame->InitE);stCvDataTemp.HighE        = REVERSE_16(p_stCvDataFrame->HighE);stCvDataTemp.LowE         = REVERSE_16(p_stCvDataFrame->LowE);stCvDataTemp.InitPN       = p_stCvDataFrame->InitPN;stCvDataTemp.ScanRate     = REVERSE_16(p_stCvDataFrame->ScanRate);stCvDataTemp.SweepSeg     = REVERSE_32(p_stCvDataFrame->SweepSeg);stCvDataTemp.SampleInt    = p_stCvDataFrame->SampleInt;    }{stCvDataTemp.QuietTime = REVERSE_32(p_stCvDataFrame->QuietTime);stCvDataTemp.Id = p_stCvDataFrame->Id;}
}

总结

具体的实现都写在了正文中,同时如果你有好的建议欢迎留言交流,共同学习。

[STM32] 串口数据帧处理(第一弹)相关推荐

  1. STM32串口第一个字节丢失问题的分析过程

    STM32串口发送必须先检测状态,否则第一个字节无法发出,发送完毕,必须检测发送状态是否完成,否则,发送不成功,使用stm32f10x调试串口通讯时,发现一个出错的现象,硬件复位重启之后,发送测试数据 ...

  2. stm32串口传输数据第一个数据被吞_stm32串口发送数据复位 第一个数据丢失

    http://blog.csdn.net/kevinhg/article/details/40991655 STM32串口发送必须先检测状态,否则第一个字节无法发出,发送完毕,必须检测发送状态是否完成 ...

  3. stm32串口传输数据第一个数据被吞_STM32串口第一个字节丢失问题的分析过程

    STM32串口发送必须先检测状态,否则第一个字节无法发出,发送完毕,必须检测发送状态是否完成,否则,发送不成功,使用stm32f10x调试串口通讯时,发现一个出错的现象,硬件复位重启之后,发送测试数据 ...

  4. STM32串口第一字节消失或者误码的原因和解决方案

    现象:stm32复位之后串口打印的第一个字节误码或者消失. 误码原因:误码多是由于端口初始化有问题.使用ST官方v3.5的标准库时,对串口输出端口进行了重复初始化. 如下代码: /* PA[15:0] ...

  5. proteus如何添加stm32_新手入门轻松掌握 STM32 串口应用

    stm32 USART串口在我们的实际开发中是经常会用到的一个一项技术,所以对于stm32串口的学习还是要细致些的,所以今天我们就来看一下stm32 USART串口的应用,先通过一些文字和简单的代码来 ...

  6. STM32串口通信详解以及通信异常或者卡死常见问题分析

    STM32串口通信详解以及通信异常或者卡死常见问题分析 目录 STM32串口通信详解以及通信异常或者卡死常见问题分析 一.常见的异常问题 二.STM32的串口简介 1.串口的通讯方式 ①按数据传输方向 ...

  7. STM32 —— 串口通讯

    STM32 -- 串口通讯 什么是串口通讯 串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式,其通讯协议可分层 ...

  8. dma接收双缓存 stm32_容易被大多数人忽视的STM32串口DMA问题

    讨论三个问题: 1.什么叫串口DMA 请求: 2.串口简要复习: 3.串口DMA发送流程. 第一 什么叫串口DMA 请求(战舰STM32开发板) 说这个问题之前先简单回顾DMA的基本特性.先导出原子哥 ...

  9. STM32串口接收数据

    参考串口接收中断处理函数: //------------------------------------------------------------------ //函数名:void USART1 ...

最新文章

  1. 自画菜单中如何触发MeasureItem事件的问题及解决办法
  2. php一个英文几个字符,PHP指定截取字符串中的中英文或数字字符的实例分享
  3. sap系统操作流程财务软件_金蝶财务软件的操作流程汇总
  4. 淘宝top平台调用接口响应时间优化
  5. 使用halcon将一个圆上的点拟合成圆形并且求出圆心
  6. 如何在Linux上使用netstat命令查证DDOS***
  7. 如何成为合格的数据分析师
  8. mindoc mysql_MinDoc文档管理系统搭建
  9. BOSS直聘下载自己的简历要钱!而且是PDF格式 - 解决方法
  10. 计算机科学技术对教育的影响,计算机科学技术在计算机教育中的应用分析(原稿)...
  11. 艾尔塔7号/Elta7
  12. (Emitted value instead of an instance of Error)
  13. 支持苹果18W-60W PD快充协议芯片JD6606S
  14. JavaWeb学习(第一天)-1-HTML部分
  15. 为什么要学Markdown?有什么用?
  16. 11.18C语言练习题
  17. 市场调研-全球与中国FPGA和CPLD开发套件市场现状及未来发展趋势
  18. 虚拟服务器安装ibm mq,IBM MQ 客户端查看服务端消息的工具 WMQTool
  19. 【转】Blogcn(中国博客网)宣布终止免费服务
  20. 维修普源DS1102E示波器 24位脉冲编码器

热门文章

  1. 亚马逊登陆显示服务器出错,亚马逊登录不上去为什么?是因为被封号了吗?
  2. imagenet 数据整理
  3. 朗读评价语言集锦_转载‖语文课堂评价语集锦
  4. 如何从Mac轻松清理其他存储文件?
  5. 2017年下一个百亿美金级创业机会的6个特征
  6. 三角形有限元matlab,3结点三角形单元有限元程序MATLAB语言
  7. jQuery怎么把html转义,JS及JQuery对Html内容编码,Html转义
  8. Typora收费后我换了个Markdown编辑器(Marktext)
  9. RR和RC的MVCC实现
  10. couple和double的区别_Double Trouble Couple