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

【经验分享】STM32编程中枚举和结构体的结合

[复制链接]
STMCU小助手 发布时间:2022-4-15 20:33
01、结构体定义
( m: g1 @/ J& b* o3 ~* j( ?基本定义:结构体,通俗讲就像是打包封装,把一些有共同特征(比如同属于某一类事物的属性,往往是某种业务相关属性的聚合)的变量封装在内部,通过一定方法访问修改内部变量。) o% l4 _& P9 B* H

8 s  j* A0 G( U6 t5 \" B+ X结构体的定义:
$ h8 u. ~" \! L2 Z! c0 F2 S: Z# }8 A
第一种:只有结构体定义2 Z+ g2 @3 P2 E8 e4 K

4 i. H$ |- G) Z8 P. A+ g
  1. struct stuff{    c2 g* d% K5 g* A' }7 s
  2.   char *name;  //姓名& |' |' }& S3 }& `/ o: ?; n
  3.   int num;  //学号
    ' ?$ R) [" l- o0 H& Z! f+ J  Y
  4.   int age;  //年龄1 G( ^( `, @8 U2 J4 j. s! f2 o7 s
  5.   float score;  //成绩$ O) i" c9 N' H
  6. };
复制代码
( M: o- o- W# }. |3 \, Y
第二种:附加该结构体类型的“结构体变量”的初始化的结构体定义,如下代码也就是定义结构体时,直接定义一个变量  / s% E0 [+ _% _+ B" Y# y  i
7 Z6 k9 @+ o8 ^: w* T
  1. struct stuff{  
    & g2 C5 _) t" p0 k+ O+ ^" h
  2.   char *name;  //姓名8 _" k# b: ?1 c2 A$ c3 x  s9 [
  3.   int num;  //学号# n. Y; r$ Q- i, a5 ?0 x5 D& ?3 N- y
  4.   int age;  //年龄" Z" f. u  ^  C" l/ B
  5.   float score;  //成绩8 [7 F) ^: r3 K2 H
  6. }xiaoming;
复制代码

* e2 }6 ]. X# c1 r其实这就相当于先定义结构体,再用结构体定义一个结构体变量:/ X0 l( ?+ c: R& G0 g) {4 ?5 l

! `* z% ~; B5 G. I! P# m
  1. struct stuff{  + ?% q  x' _  \4 r2 |
  2.   char *name;  //姓名
    - z' J5 T" P. w5 o& P
  3.   int num;  //学号
    * y: P3 C! @! U) C& h; h
  4.   int age;  //年龄; U* {7 d7 Q% H1 f
  5.   float score;  //成绩
    ; L" h7 [. l+ S" s
  6. };  
    ; @3 r( J9 L8 J- C
  7. struct stuff xiaoming;  
复制代码

$ o* J. x3 u; i* W第三种:使用typedef关键字,可以将结构体变量定义时少写一个struct,比较省事。
3 @* R; p: O% A& w  T, Y' U7 E+ y  e. Q# J; D: n$ t
  1. typedef struct stuff{  # j5 q( K6 a$ ]: S
  2.   char *name;  //姓名; ?8 E5 I# }' b- i) _0 D  C( t
  3.   int num;  //学号
    7 ?( @  p0 p- Y( K9 X, w) }
  4.   int age;  //年龄3 M- v' |; }5 G+ Y$ D$ j
  5.   float score;  //成绩
    ( |0 n5 [6 E: i$ \
  6. }stuff_s;  ( R5 |' p3 ^- s% v
  7. stuff_s xiaoming;
复制代码

# K! X) X( a$ o: M4 d3 Z$ C8 O使用typedef还可以进一步简化,将结构体名也省略,这也是常用的方式
/ T* ~- p. B* N  ^) R! {8 A0 S4 P7 q4 u3 V0 j
  1. typedef struct{  / _# w6 m- W+ x9 t, n
  2.   char *name;  //姓名
    % a4 j( r3 \- z& P1 f: Z
  3.   int num;  //学号# q( O7 [+ @) C
  4.   int age;  //年龄
    $ T) n3 F, F3 F
  5.   float score;  //成绩
    ! i0 X3 X. C" o' A2 o4 Y; d: F0 s
  6. }stuff_s;  8 H/ Y2 `- [1 g. q
  7. stuff_s xiaoming;
复制代码

+ J1 |5 a0 @# ^+ w8 sSTM32的标准外设库有大量这样的应用,如下
3 i, B9 V8 I/ O" v% b
# h2 ^3 {4 C5 g# ^, m# Z1 {
  1. typedef struct4 g1 i8 H+ q2 I. I$ p
  2. {
    ( }# i7 H" h4 y: p" t, |& r
  3.   uint32_t GPIO_Pin;! |5 f' r! c. `
  4.   GPIOMode_TypeDef GPIO_Mode;& J) T; w# ~2 ^
  5.   GPIOSpeed_TypeDef GPIO_Speed;) k0 Y- G' A$ I$ k1 G
  6.   GPIOOType_TypeDef GPIO_OType;5 b& H4 P* B, V! c9 Q7 a$ V
  7.   GPIOPuPd_TypeDef GPIO_PuPd;: B- W! ]1 q- T$ i/ A: c6 U
  8. }GPIO_InitTypeDef;
复制代码

% h8 _! e+ c# b关于结构体指针定义问题,有很多的“骚操作”的写法,我一般按照下面定义指针) d& P. g+ j6 m' o

* s- t+ F. j, Z2 f
  1. stuff_s *cuerrent_student;
复制代码
% W* S; l: {+ _1 l
02、结构体初始化/ g" ~$ [, y  v% U: [. K& ?
在大部分应用中,一般都是定义结构体后,在代码中进行初始化,如下所示6 J; G* m0 [; N( w( w

" l9 R/ b# z, G: k  F7 X+ K
  1. typedef struct{  
    $ X2 ]. \' c: g2 v" f8 a
  2.   char *name;  //姓名. j- p' m8 M" T" f
  3.   int num;  //学号
    4 Y3 B( N  X  e: q9 I  B
  4.   int age;  //年龄
    # A9 Q# K3 |% H: D+ _6 \& n" u
  5.   float score;  //成绩
    7 E* r$ O: o0 R& w
  6. }stuff_s;
    4 x' F: r" K! d, Z& Z
  7. stuff_s xiaoming;
    , b8 E- u) J: o. ]
  8. void xiaoming_inf_init()
    / z+ a% l) @+ Q2 x  h; q/ h
  9. {
    ! y& n$ E3 K/ b0 K. {: k6 }6 [7 K2 U
  10.   xiaoming.name = "xiaoming";
    ) Z+ h8 I7 t8 u* [+ n
  11.   xiaoming.num = 1;9 {* b! m! u: M; `" P! s
  12.   xiaoming.age = 18.0;6 S& {+ z4 {7 ?6 J6 Q5 M" x  _  N" ^
  13.   xiaoming.score = 100;* z$ R8 T  A- O
  14. }
复制代码
1 B  ?6 K7 y; e3 @: w1 U
当然也有可以定义时就进行数据初始化的& W* E2 [# u) P2 G& B% D! u9 V; Q
  f+ N6 c. p% {( y
  1. typedef struct{  
    8 s% B: V. p' k
  2.   char *name;  //姓名
    - u" u9 K$ v  _0 g$ P
  3.   int num;  //学号
    # ?# g% Y6 w/ [. l* D" p3 e8 P
  4.   int age;  //年龄
    + b  ?% O+ A! o/ c
  5.   float score;  //成绩 4 i2 `" v0 b9 x9 t
  6. }stuff_s;( {' I0 a  n- u1 R7 e
  7. stuff_s xiaoming={"xiaoming",1,18.0,100};
复制代码

4 \3 {: u+ w8 t& u6 _. J- ^; mC99和C11为结构提供了指定初始化器(designatedinitializer)。其初始化器使用点运算符和成员名。; g  g( z& M7 q6 [4 k
# y9 m! ^7 \- T$ t2 I
关于C99和C11的知识可以看我之前的文章《C语言的发展》,在IAR和Keil中记得勾选C99的选项。
2 s) y8 ^6 H* U( @$ z1 h; q2 G! j; L5 d
例如,只初始化xiaoming结构中的name成员,可以这样做:
* T7 @; l) u3 I* L
  Q0 M6 J0 I2 X8 Q( j3 c+ r4 P
  1. stuff_s xiaoming=
    - ]4 [4 ], t8 O
  2. {- k9 p, \, f" ^) b3 ?
  3.   .name = "xiaoming"
    4 }) O- N" x6 C
  4. };
复制代码

& k1 ?- x0 }& u6 X也可以按照任意顺序使用指定初始化器:
& T" p% }" P2 w% h
% Z8 C# x& o& H3 \6 c" y8 ?$ U/ m
  1. stuff_s xiaoming=
    8 @+ R# b2 t4 `- T/ H2 H( t
  2. {' d# y' G  t  z3 O
  3.   .age = 18.0,
    7 d! U% M* b! r  I/ l
  4.   .name = "xiaoming"
    ( L2 t8 q# @4 T4 M% y
  5. };
复制代码

' s+ j* L  F% H. }& T# v这样的赋值方式,在linux方式中很常见,以platform驱动框架为例:
* Z% ]6 ]& i. d, }
* F2 @$ \% ~9 P% _4 V" g% |+ p; [
  1. static struct platform_driver leds_platform_driver = {6 o0 c% ^  u+ q+ ^! h
  2.   .driver = {
    / L! s, C' g* q
  3.     .name = "imx6ul-led",, ?) z: I' K' L0 C
  4.     .of_match_table = leds_of_match,8 q( M' ~% ~1 l9 x
  5.   },
    8 n8 Z- v# l* {8 d! s, e( b
  6.   .probe = leds_probe,& d6 r3 l  m0 J/ z- a* ~" K" e* X
  7.   .remove = leds_remove,( G3 f) b1 ^  s) J: [
  8. };
复制代码

; G. i0 H8 O) D9 e03、访问结构体成员
. m" x- P1 {7 a- ?4 u8 B
结构体成员的访问需要借助结构体成员运算符(.),如下
: a& X1 m# Q2 U3 p! M, d) ~$ s1 X# |! ~1 B
  1. stuff_s xiaoming,xiaohong;
    , p7 C: Y0 a9 k9 f
  2. void student_inf_init()( B( H+ G9 c# R( p1 T+ [$ l, `
  3. {
    % g4 w( [1 z3 W) x' l  n
  4.   xiaoming.name = "xiaoming";
    6 a9 E- B# H# k" b
  5.   xiaoming.num = 1;1 v+ j5 ]7 N7 P1 C- `" Q4 D6 U
  6.   xiaoming.age = 18.0;: H' C  i6 ]3 b: i, j4 i# ?
  7.   xiaoming.score = 100;- H8 t5 }% W1 g  P
  8. 9 A5 c, F4 W. Z+ g' U

  9. ; s; Q6 Y1 c$ D. L- O5 w' t* P
  10.   xiaohong.name = "xiaohong";9 `( V7 ?2 `: ]$ s$ w
  11.   xiaohong.num = xiaoming.num+1;) p; _& Q+ u, l* s# L- E6 x
  12. }
复制代码
, ]$ y% B4 J2 b
使用指针时,使用(->)符号访问结构体成员. g; H0 P2 T4 h! h4 j

: g- m  N& p7 J/ }+ X
  1. stuff_s xiaoming,xiaohong;
    + d8 D5 V7 e1 e+ T: G6 f+ Z
  2. stuff_s *cuerrent_student;
    6 s( q  ~! v' n" d( @
  3. void student_inf_init(); O7 t. B8 J# G( O& N8 j  l$ ?7 ?
  4. {! _) N% S* w, O& L
  5.   xiaoming.name = "xiaoming";( n) Z7 d# e' e5 L2 F
  6.   xiaoming.num = 1;
    3 ^9 _+ b- i  }. s& h8 ^
  7.   xiaoming.age = 18.0;! f+ B1 [; M8 b( o
  8.   xiaoming.score = 100;
      l' Z6 G4 Q* t( z5 `" T
  9.   cuerrent_student = &xiaohong;
    ! ]4 }! `. m8 D: y2 D& |

  10. # A" p8 |& \2 K0 _: M. M

  11. ) U5 e) ]5 b# y0 ]: R  B4 d) s' W
  12.   cuerrent_student->name = "xiaohong";
    ! W5 g& u+ j+ ~  ]: ]: `& s
  13.   cuerrent_student->num = xiaoming.num+1;! k9 P7 M# i* ~- o
  14. }
复制代码
) ~* V" v/ O' ^/ d" c; C
04、枚举与结构体的结合  g/ C: ]) w- u5 [4 u
简单介绍下枚举:有些数据的取值往往是有限的,只能是非常少量的整数,并且最好为每个值都取一个名字,以方便在后续代码中使用,比如一个星期只有七天,一年只有十二个月,一个班每周有六门课程等。" N2 v) R7 ^' q% S" Q- U

% ^, ?& l# R/ m0 j7 N当然,你可以用宏定义4 ^" z- |$ }$ `8 Q' Z5 x
3 ~1 M% w: @# f! F% E& J
  1. #define Mon 1
    1 b; r. |+ p" `7 C/ U
  2. #define Tues 2! p+ z1 {: \( ^2 ?  w
  3. #define Wed 3( e2 ]5 N9 O" S$ {5 Q5 S4 E
  4. #define Thurs 4
    6 m/ @! l3 i" \. F
  5. #define Fri 5% C9 v$ b& r3 `- e( b
  6. #define Sat 6
    ! @) W7 v0 H; u2 W  Q7 ?9 c/ A
  7. #define Sun 7
复制代码

& [, `! _" [$ q/ W* p. N* o5 Y如果用了枚举则如下
+ J) {( x& Z; J( {7 L: [/ u
5 I' q; {2 ^# l5 u1 _) @
  1. enum week{
    2 j6 Y- V, ^- K. `: p
  2.   Mon,
    # g: s1 \. y  \$ b) `& u) |
  3.   Tues,
    ; p7 x/ M6 ?4 _6 a% |. m$ l( m
  4.   Wed,% Q" L$ H& U# W7 u1 \, _
  5.   Thurs,
    ' @; x) X: K1 K% M& X# \. x* W- _1 N3 L
  6.   Fri," n" K7 }  S! h; N
  7.   Sat,
    " A7 s5 t. s4 D- D* ~5 d
  8.   Sun
    8 w* u" b+ ]5 V0 T
  9. };
复制代码
" ~5 P2 D4 S1 f4 \7 [% N
枚举是一种类型,通过它可以定义枚举变量:0 w2 s% s" N. M" l% Q$ L
; P, J4 S/ Z5 O, J5 \
  1. enum week a, b, c;
复制代码
* A9 p% j: n/ l! E( h: Y8 K
那么枚举和结构体一起用会产生什么效果呢?假设我们要协议一个语音芯片的驱动,需要表示语音芯片的状态
0 s5 L& Q4 u. K) {, P+ C; p, K9 H& c; {) ^, p
  1. typedef enum//语音芯片状态9 s4 C0 |: E+ u
  2. {' L! `; r0 N9 S1 {( ?% ]
  3.     VOICE_INIT_OK =            0x4A,  //语音芯片上电初始化成功后,自动回传命令
    - X* t/ P- p5 B: A) \6 z+ X( l
  4.     VOICE_RECEIVE_OK =           0x41,  //语音芯片收到正确的命令帧
    3 x8 r. v' R( A* Q4 ^7 @
  5.     VOICE_ORDER_ERROR=         0x45,  //语音收到错误的命令帧
    ' X) O8 M1 T9 e7 m" n* }
  6.     VOICE_BUSY     =            0x4E,  //语音忙(正在合成状态)
    5 F& y! ~9 p6 r( @
  7.     VOICE_FREE     =           0x4F  //语音空闲+ P9 x) F& P  c, \
  8. } VOICE_STATUS;9 y' A( w! q7 `+ L' n- f6 G
  9. typedef struct {' c: ]. Y) s! M5 I* `
  10.     VOICE_STATUS status ;                 //!< 语音芯片状态
    4 K6 @. P8 i" U
  11.     Ouint32  delayTicks;                   //!< 播放时间6 O# l5 ~# w, x  E! B# J) B2 v/ _- U
  12.     Ouint32  playtimes;                    //!< 播放次数- r$ T/ R* B9 H. p8 b' i
  13. } voicechip_Para_S;
    / J) U, `! j2 x0 z' t
  14. voicechip_Para_S voicechip_Para;
复制代码
  ^) B# r6 q  d
那么改变语音芯片状态时,我们可以按照下面这样写
4 ?; w. P8 {6 Q+ d8 C# G8 d  R0 E8 b9 o" P3 U7 z( G$ s
  1. voicechip_Para.status = VOICE_RECEIVE_OK;
复制代码
4 w, J$ B, K1 t- `& L' z* n* g
判断语音芯片状态时,我们可以按照下面写0 Y0 d9 m6 F) U' }  v. n8 M
+ a6 R' y, o' h$ T" s6 j
  1. if((voicechip_Para.status == VOICE_FREE)
复制代码
; c$ K& A- X9 p5 U* S
当然,你用宏定义是可以的,代码也很整洁。这里希望你能理解文章最开始的那句话:结构体是某种业务相关属性的聚合。
7 C) i5 w7 d/ R8 d& g% a
* D! q- o% `# D' ?# Z05、骚操作
) I8 ]0 Q. f8 F& C: O! p- o关于结构体有很多骚操作,如果全部总结下来,这篇文章就会很臃肿,例如结构体嵌套的骚操作,可以一边定义结构体B,一边就使用上:
. F8 i0 M3 I) h* S  \8 w7 V# F) f% M& j' U/ g0 |0 Q
  1. struct A{  
    / h( v6 U2 x5 J0 A- r$ c
  2.     struct B{  
    8 ]) L( e, q$ H9 D/ E& U. E
  3. int c;  
    . E% ^& a  m$ z' k# A1 Q
  4.     }b;  
    / z/ H1 p0 A7 d# f, ]0 c2 w7 M
  5.     struct B sb;  
    ! X+ P2 g% p/ p# [1 ^
  6. }a;
复制代码

  h% m: x. t0 p. J  ~对于这样的情况,我一般主张能看懂就行,自己写代码时就少点这样的骚操作
: m9 B. @" [, |4 I1 Z6 g. Z" Q
+ p# O  b3 |6 C
  1. struct B{  ; g. d, T% ?& }7 a9 D# g2 }2 e' ]* ]
  2.      int c;  
    6 B! I" E; [1 s, t( H# C
  3. }b;
    0 A/ O: I- B& F: Z7 ?7 ?
  4. struct A{  1 P/ h- k4 z& Q, l6 R3 V
  5.      struct B sb;  
      B% T0 M5 I: w9 @0 h$ V4 F* e" ]
  6. }a;) X; P9 E/ F4 g: `! {
复制代码
1 x. ~+ I' Y+ P2 n! M0 L/ l

/ Y/ U$ G8 ]1 n, O
收藏 评论0 发布时间:2022-4-15 20:33

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版