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

C语言的结构体和共用体在单片机中的妙用

[复制链接]
gaosmile 发布时间:2020-9-7 15:30
C语言的结构体和共用体,往往在单片机应用开发中被忽视。如果能够用起来,不仅能够极大的提高单片机的运行效率,还可能解决一些看起来无法解决的问题。
: H2 Y$ O3 A) B! d# C- u' a
现在,给大家举一个例子:单片机串口需要接收并处理大量数据的情况。
# O% R( p6 M$ W# h  ~& G9 n8 F
示例:单片机甲要与某个设备乙通信,它们采用串口连接,设备乙会给单片机甲发送串口数据,数据一共有46个字节,其中前8个字节表示命令,后8个字节表示设备信息,中间30个字节表示有效数据。* B) G( Q' [5 m) o/ {3 W' g
普通的程序代码,会进行如下变量定义:
  1. 4 ~8 A% I" H  S9 o
  2. unsigned char rec_buf[46]; // 定义接收缓存  x5 X- R+ w3 |& f9 ~6 h  i2 M
  3. unsigned char command[8]; // 定义命令变量6 D+ I$ G; D5 {% u" I) I8 a7 U( R
  4. unsigned char valid_data[30]; // 定义有效数据变量- [! d  l9 _6 [3 ~
  5. unsigned char device_info[8]; // 定义器件信息变量
复制代码

' [  P9 p6 @' W: N" x
在串口中断函数中,使用rec_buf接收串口数据。此处省略接收代码,自行脑补。  `- e1 z4 a* H5 r* u* i/ d6 R) G
接收完毕后,再使用如下代码把对应的变量取出来。
+ c& k/ Z! u( L" d6 C
  1. % I  M/ i" R8 ?' O+ f
  2. //取出命令
    2 Q* u* p: V; q  r
  3. for(i=0;i<8;i++)
    * I2 Q  m7 ^4 x8 g+ A6 ]2 D- i$ K
  4. {" S" ^3 ]  \# w
  5.   command[i]=rec_buf[i];
    2 d- \% ^- p  g( {) o
  6. }
    $ i; h! `+ b* c' g$ O5 t- d: M
  7. //取出有效数据
    / h- l6 e$ d8 o  t# i6 q
  8. for(i=8;i<38;i++)
    : p6 i; H  z0 Y6 I6 u
  9. {, s0 M/ |- n5 n
  10.   valid_data[i-8]=rec_buf[i];9 D/ p  G; _8 \
  11. }
    5 g4 M% s+ u  D. e! Y
  12. //取出器件信息
    * s7 l. M% q- e( a( H; x
  13. for(i=38;i<46;i++)
    0 f/ @  q- q; g% v5 u6 G
  14. {
    - v( l$ h3 O1 V
  15.   device_info[i-38]=rec_buf[i];4 w: @+ u+ Q* z3 d2 z3 t
  16. }
复制代码

4 `7 ?8 M$ c; q$ p
取出来之后,就可以在程序中使用了,比如,判断接收到的是什么命令,如下代码所示:
6 O5 c" z; R# f7 E+ h

  1. 8 D, u5 x) @! ], a) W7 i& E
  2. if(command[0]==0x88) // 如果是修改参数命令
    , _: S' W. M" ~! S' u" N! F
  3. {
    7 }& Y; V0 ?0 W: x3 ?
  4.   if(command[1]==0x33)// 如果修改的是IP地址参数
      [. Y  _3 b& ~* A9 N% Q
  5.   {
    " }( k. _; a( ^: P6 u
  6.     // 就怎么怎么样...# K/ M( R. [. V/ k2 F
  7.   }
    2 K/ b4 S4 j0 y7 r' d8 h
  8.   ...% U! m$ K0 j  \# G) H/ g
  9. }
复制代码

  p5 b4 I+ v* E  |  z$ c5 _
好!上面是普通的用法,接下来,我们使用结构体和共用体!
  ^* a, z/ L0 Q7 J% ?  d% P) k1 o" B
  1. 6 ^; f6 o# L* J8 z5 o- q
  2. union! L# L+ |. |% p; e
  3. {
    + g; W  P/ v' z0 J$ E( F4 w1 H
  4.   rec_buf[46];" }& g& t+ h! B
  5.   struct
    ; c& o! ~: S: a0 E& m
  6.   {) f, g- I8 V$ ?' j
  7.     unsigned char command[8];
    3 t  s) Z7 o  q- R3 W' T( e
  8.     unsigned char valid_data[30];
    % ]) s1 e% Y0 e' q. a3 w
  9.     unsigned char device_info[8];  X; G  [/ }# B2 A* ~: {; C
  10.   }ComInfo;' Q1 d$ p2 d% t) A. T6 p
  11. }D_buf;
复制代码
% u, D  B1 z. ?3 f3 i* I5 Y; h
上面代码中,我们使用了共用体和结构体的方法定义了串口接收缓存和串口命令、有效数据和器件信息变量。
4 t. @( ?% X8 X' J
当我们在串口中断中接收完数据后。就可以直接使用这些变量了。例如:
* b; A9 }0 r9 ]$ _% N  z, x
  1. + S6 g: e, b6 A8 f. q# X: o
  2. if(D_buf.ComInfo.command[0]==0x88) // 如果是修改参数命令
    . ~! r' v2 }5 |, {: ^4 Q) o
  3. {: k5 G+ K2 U& N
  4.   if(D_buf.ComInfo.command[1]==0x33)// 如果修改的是IP地址参数
    4 V- k: ~) n: g2 [
  5.   {% `4 `$ E# ~( L1 b  e4 d' h( W
  6.     // 就怎么怎么样...6 c3 c2 h3 o4 P3 o* c; z' c
  7.   }( L0 d3 G# j; \4 N
  8.   ...; R. ]) Y1 u1 }3 A* |$ _
  9. }
复制代码

! p) m- L; v; J$ X8 W6 s
下面,我解释一下代码。4 G6 V) y0 W7 U
共用体的特点:内部的变量使用同一个首地址。在我们定义的共用体里面,有两个变量,一个是rec_buf,一个是ComInfo,所以,它俩的内存首地址是相同的。% W$ k) X! s, U, K9 e# r0 r
结构体的特点:内部的变量地址自增。在我们定义的结构体ComInfo中,command变量、valid_data变量、device_info变量使用同一片内存空间,地址连续。
9 x9 d! i. ]3 ?* p1 B
基于以上共用体和结构体的特点,当我们接收完rec_buf以后,其实,数据就已经在结构体中的这3个变量中了,直接用就可以,省去了前面示例中“取出来”的环节。
' Z9 f; |. i6 j
3 A9 b9 d2 ?: V" \4 o
赞 收藏 1 评论1 发布时间:2020-9-7 15:30

举报

1个回答
louzhulz 回答时间:2020-9-11 14:07:45
很好,又学到一招。牛
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版