你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

结构体在STM32串口接收中的妙用

[复制链接]
心升明月 发布时间:2018-5-25 17:37
本帖最后由 心升明月 于 2018-6-6 10:27 编辑 % c: a* p0 X4 [1 A  f

( e& F" I/ L+ M6 T5 U: _2 l
结构体C程序中在STM32单片机串口接收的妙用之一
  结构体是一种数据的归类方式,相比数组或变量更具有整体全面性,例如一个数组只可以放一些按照元素顺序存放的单元变量,即tab={x,x,x,x,x......},i有多大,数组内元素就有多少.那么我们这时候如果我们用这个数组来接收串口接收信息,信息的格式是: 数据头>数据长度>数据区>数据校验>数据尾.
假设数据区为 <身高-体重-性别-年龄-学历>
那么我们用数组接收时,提取数据时就需要计算出数据格式中每个单元所对应的位置,即数组中第i个元素对应的内容.这样显然是很麻烦的,效率很低.这就相当于先织了一个大网,捕捉到一网鱼,还得过下称,才能按照重量分类开来一样.
那么如果我们能提前根据接收的数据的格式来做一个容器,直接把接收的数据复制到这个容器内,岂不是省了好大劲,来,有个好东西,这就是结构体.
我们按照接收数据的格式顺序定义一个结构体如下:
typedef struct
{
         u8    head;            //数据头
        u16    dataLen;      //数据长度值
        u8    height;           //身高
         u8    weight;          //体重
         u8    sex;               //性别
         u8    age;               //年龄
         u8    education;     //学历
         u8    checksum;     //校验和
         u8    endmark;      //结束字节
) I5 B/ I. x- c, W- n: P1 ~
} RecData;
RecData  userData;
结构体已经定义好了,接下来我们就将串口接收的数据复制到这个结构体 userData里面.
定义串口接收的缓冲数组为
U8 serRec[len];
U8  len=100; //按照实际接收范围定义

- M& I9 E4 b( Y4 Z8 G* u" f
我这里使用的是stm32单片机,串口具有空闲中断功能,当检测到串口收到一帧数据后,会进入中断置位,此时我们将进行数据的复制,如下:
memcpy(&userData,&serRec,len ); //内存复制
这就将串口数据完整的复制到userData中了,而且是对号入座的, 错,stm32单片机是32位单片机,结构体中的变量存储时不是按照一字节对齐存储的,即默认每个存储单元分配是4个字节,像u8类型只占一字节这种默认也占了四个字节,显然空了3个字节,那么整个结构体的容量就不是结构体内所有变量的实际类型所占的大小之和.
   我们要做的就是让结构体内的变量可以以一字节为最小单位对齐,即各个变量紧密的连在一起在内存中,这就需要字节对齐的预处理指令:
      另外需要注意的是STM32的数据存储方式是小端模式,即数据的高字节存储在内存地址的高字节,低字节存储在内存地址的低字节,如果串口接收到的数据是低字节在前,则拷贝来的数据就不用进行处理,如果接收的数据是高字节在前则需要对拷贝来的数据进行高低字节反转.  z4 v2 ^' S/ K/ D; [- d8 u, H

, h: ^( `. |1 O9 `: ]
' T0 ~) h- p( l- _

/ N. w+ s) L0 k& D2 ^1 |

1 Y! v# Q/ m1 g什么是大端和小端        + S' A1 V) t& I- h4 q
Big-Endian和Little-Endian的定义如下:
8 Q- r' D4 m& S/ i/ v( n! `% \+ A1) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
2 z* F- ~$ w6 Z1 }4 c2) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。% x% p: x1 P3 [1 c
举一个例子,比如数字0x12 34 56 78在内存中的表示形式为:
3 M5 q& p& N7 G& y& F

1)大端模式:

低地址 -----------------> 高地址- H% V3 m9 s9 m4 k
0x12  |  0x34  |  0x56  |  0x78

( E, Y. \( h7 n" G& z  G* w, w- Z

2)小端模式:

低地址 ------------------> 高地址
0 y7 c& E% F/ {+ s$ e( i0x78  |  0x56  |  0x34  |  0x12$ l! N: Z* |( K6 V& k$ B

可见,大端模式和字符串的存储模式类似。

4 f: c6 u$ f9 t- Y2 f5 R
; V8 m3 j% ]  D# T$ f' N! i; K

& d# y  A+ Q: i- J- @3 i. Z
; [! u/ T4 n% F: W/ a
//keil 下1字节对齐
#pragma pack(push,1)
typedef struct
{
         u8    head;           //数据头
       u16   dataLen;          //数据长度值
        u8    height;          //身高
       u8    weight;          //体重
        u8    sex;            //性别
       u8    age;            //年龄
       u8    education;        //学历
       u8    checksum;         //校验和
       u8    endmark;          //结束字节
9 @% Y! k" L' {3 h& H
} RecData;
; _1 h' O1 U8 [5 Y5 T
#pragma pack(pop)//恢复keil原来的数据对齐方式

- f2 C; Z) }6 ?7 y" P4 Q: {9 G
用这条预处理指令将结构体声明在其中即可,代表结构体中变量会在内存中按照一字节对齐的方式存储.
至此,
userData.head
  userData.dataLen   
userData.height
.........
这些都已对号入座的数据就可以直接使用了.
7 d! J/ A( ~7 w7 g' r

# U+ `& c/ d% n  H4 d- C3 i
3 o+ ^- P* ~- A1 d& V9 b6 ~; l/ t  x. a) Y

1 {2 D9 Z0 }5 K* a" y+ Z
赞 收藏 1 评论7 发布时间:2018-5-25 17:37

举报

7个回答
疯de_恒 回答时间:2018-5-25 17:46:54
要注意大小端问题。
anobodykey 回答时间:2018-5-25 17:57:34
你还得加数据的有效性判断,如果因为某些情况,收到的字节少了一个,或某位出现了错误,你得能够识别并处理
Inc_brza 回答时间:2018-5-25 18:19:20
anobodykey 发表于 2018-5-25 17:571 I1 h6 i4 X# [! T: B$ L9 r
你还得加数据的有效性判断,如果因为某些情况,收到的字节少了一个,或某位出现了错误,你得能够识别并处理 ...

6 h; V: v6 |$ y( i) q# F8 L少收-校验和,结束字符串判断-超时判断
; ]1 J/ Q/ j! j# x/ e+ E* s多收-校验和,结束字符串判断,应该没啥问题。, G. g' C" w# z# |& s! j6 @& W! _
其实这种处理的好处有很多,不过,大小端一定要注意,例如结构中存在U32,U16甚至是bit的处理问题。
wolfgang 回答时间:2018-5-25 18:25:16
modbus就是利用这样的结构体来解析指令的。* A. y* l% x& T" T# e* g" M
可以,继续研究~~,再加上CRC 校验,更加完善。
7 Y0 L# E* V2 {; G
; x' c9 l3 e4 t. R指令接收的容错机制得考虑一下!
STM1024 回答时间:2018-5-25 20:30:42
这个套路其实在C语言编程中很常见,其实就是同样的字节流,不同的理解方式可以得到不同的结果。1 z' C6 s$ _' m" W7 k
除了大小端的问题,有时候还得考虑一下字节对齐的问题
龙白木 回答时间:2018-6-6 09:29:41
最近要处理很多数据,正好试一下把那些数组都改成结构体
心升明月 回答时间:2018-6-6 10:09:37
Inc_brza 发表于 2018-5-25 18:192 c, b# O- n3 _+ a0 k1 A
少收-校验和,结束字符串判断-超时判断2 p; k/ ]( g, U1 J( z; v
多收-校验和,结束字符串判断,应该没啥问题。' a* j; h, @6 s/ ]; j
其实这种处理的好 ...
3 L* z. v: L8 r" c9 l0 }2 T
是的,真正关键的就是注意大小端的处理!
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版