STM32編程中枚舉和結(jié)構(gòu)體的結(jié)合
01 結(jié)構(gòu)體定義
基本定義:結(jié)構(gòu)體,通俗講就像是打包封裝,把一些有共同特征(比如同屬于某一類事物的屬性,往往是某種業(yè)務(wù)相關(guān)屬性的聚合)的變量封裝在內(nèi)部,通過一定方法訪問修改內(nèi)部變量。
結(jié)構(gòu)體的定義:
第一種:只有結(jié)構(gòu)體定義
- struct stuff{
- char *name; //姓名
- int num; //學(xué)號
- int age; //年齡
- float score; //成績
- };
第二種:附加該結(jié)構(gòu)體類型的“結(jié)構(gòu)體變量”的初始化的結(jié)構(gòu)體定義,如下代碼也就是定義結(jié)構(gòu)體時,直接定義一個變量
- struct stuff{
- char *name; //姓名
- int num; //學(xué)號
- int age; //年齡
- float score; //成績
- }xiaoming;
其實這就相當(dāng)于先定義結(jié)構(gòu)體,再用結(jié)構(gòu)體定義一個結(jié)構(gòu)體變量:
- struct stuff{
- char *name; //姓名
- int num; //學(xué)號
- int age; //年齡
- float score; //成績
- };
- struct stuff xiaoming;
第三種:使用typedef關(guān)鍵字,可以將結(jié)構(gòu)體變量定義時少寫一個struct,比較省事。
- typedef struct stuff{
- char *name; //姓名
- int num; //學(xué)號
- int age; //年齡
- float score; //成績
- }stuff_s;
- stuff_s xiaoming;
使用typedef還可以進一步簡化,將結(jié)構(gòu)體名也省略,這也是常用的方式
- typedef struct{
- char *name; //姓名
- int num; //學(xué)號
- int age; //年齡
- float score; //成績
- }stuff_s;
- stuff_s xiaoming;
STM32的標(biāo)準(zhǔn)外設(shè)庫有大量這樣的應(yīng)用,如下
- typedef struct
- {
- uint32_t GPIO_Pin;
- GPIOMode_TypeDef GPIO_Mode;
- GPIOSpeed_TypeDef GPIO_Speed;
- GPIOOType_TypeDef GPIO_OType;
- GPIOPuPd_TypeDef GPIO_PuPd;
- }GPIO_InitTypeDef;
關(guān)于結(jié)構(gòu)體指針定義問題,有很多的“騷操作”的寫法,我一般按照下面定義指針
- stuff_s *cuerrent_student;
02 結(jié)構(gòu)體初始化
在大部分應(yīng)用中,一般都是定義結(jié)構(gòu)體后,在代碼中進行初始化,如下所示
- typedef struct{
- char *name; //姓名
- int num; //學(xué)號
- int age; //年齡
- float score; //成績
- }stuff_s;
- stuff_s xiaoming;
- void xiaoming_inf_init()
- {
- xiaoming.name = "xiaoming";
- xiaoming.num = 1;
- xiaoming.age = 18.0;
- xiaoming.score = 100;
- }
當(dāng)然也有可以定義時就進行數(shù)據(jù)初始化的
- typedef struct{
- char *name; //姓名
- int num; //學(xué)號
- int age; //年齡
- float score; //成績
- }stuff_s;
- stuff_s xiaoming={"xiaoming",1,18.0,100};
C99和C11為結(jié)構(gòu)提供了指定初始化器(designatedinitializer)。其初始化器使用點運算符和成員名。
關(guān)于C99和C11的知識可以看我之前的文章《C語言的發(fā)展》,在IAR和Keil中記得勾選C99的選項。
例如,只初始化xiaoming結(jié)構(gòu)中的name成員,可以這樣做:
- stuff_s xiaoming=
- {
- .name = "xiaoming"
- };
也可以按照任意順序使用指定初始化器:
- stuff_s xiaoming=
- {
- .age = 18.0,
- .name = "xiaoming"
- };
這樣的賦值方式,在linux方式中很常見,以platform驅(qū)動框架為例:
- static struct platform_driver leds_platform_driver = {
- .driver = {
- .name = "imx6ul-led",
- .of_match_table = leds_of_match,
- },
- .probe = leds_probe,
- .remove = leds_remove,
- };
03 訪問結(jié)構(gòu)體成員
結(jié)構(gòu)體成員的訪問需要借助結(jié)構(gòu)體成員運算符(.),如下
- stuff_s xiaoming,xiaohong;
- void student_inf_init()
- {
- xiaoming.name = "xiaoming";
- xiaoming.num = 1;
- xiaoming.age = 18.0;
- xiaoming.score = 100;
- xiaohong.name = "xiaohong";
- xiaohong.num = xiaoming.num+1;
- }
使用指針時,使用(->)符號訪問結(jié)構(gòu)體成員
- stuff_s xiaoming,xiaohong;
- stuff_s *cuerrent_student;
- void student_inf_init()
- {
- xiaoming.name = "xiaoming";
- xiaoming.num = 1;
- xiaoming.age = 18.0;
- xiaoming.score = 100;
- cuerrent_student = &xiaohong;
- cuerrent_student->name = "xiaohong";
- cuerrent_student->num = xiaoming.num+1;
- }
04 枚舉與結(jié)構(gòu)體的結(jié)合
簡單介紹下枚舉:有些數(shù)據(jù)的取值往往是有限的,只能是非常少量的整數(shù),并且最好為每個值都取一個名字,以方便在后續(xù)代碼中使用,比如一個星期只有七天,一年只有十二個月,一個班每周有六門課程等。
當(dāng)然,你可以用宏定義
- #define Mon 1
- #define Tues 2
- #define Wed 3
- #define Thurs 4
- #define Fri 5
- #define Sat 6
- #define Sun 7
如果用了枚舉則如下
- enum week{
- Mon,
- Tues,
- Wed,
- Thurs,
- Fri,
- Sat,
- Sun
- };
枚舉是一種類型,通過它可以定義枚舉變量:
- enum week a, b, c;
那么枚舉和結(jié)構(gòu)體一起用會產(chǎn)生什么效果呢?假設(shè)我們要協(xié)議一個語音芯片的驅(qū)動,需要表示語音芯片的狀態(tài)
- typedef enum//語音芯片狀態(tài)
- {
- VOICE_INIT_OK = 0x4A, //語音芯片上電初始化成功后,自動回傳命令
- VOICE_RECEIVE_OK = 0x41, //語音芯片收到正確的命令幀
- VOICE_ORDER_ERROR= 0x45, //語音收到錯誤的命令幀
- VOICE_BUSY = 0x4E, //語音忙(正在合成狀態(tài))
- VOICE_FREE = 0x4F //語音空閑
- } VOICE_STATUS;
- typedef struct {
- VOICE_STATUS status ; //!< 語音芯片狀態(tài)
- Ouint32 delayTicks; //!< 播放時間
- Ouint32 playtimes; //!< 播放次數(shù)
- } voicechip_Para_S;
- voicechip_Para_S voicechip_Para;
那么改變語音芯片狀態(tài)時,我們可以按照下面這樣寫
- voicechip_Para.status = VOICE_RECEIVE_OK;
判斷語音芯片狀態(tài)時,我們可以按照下面寫
- if((voicechip_Para.status == VOICE_FREE)
當(dāng)然,你用宏定義是可以的,代碼也很整潔。這里希望你能理解文章最開始的那句話:結(jié)構(gòu)體是某種業(yè)務(wù)相關(guān)屬性的聚合。
05 騷操作
關(guān)于結(jié)構(gòu)體有很多騷操作,如果全部總結(jié)下來,這篇文章就會很臃腫,例如結(jié)構(gòu)體嵌套的騷操作,可以一邊定義結(jié)構(gòu)體B,一邊就使用上:
- struct A{
- struct B{
- int c;
- }b;
- struct B sb;
- }a;
對于這樣的情況,我一般主張能看懂就行,自己寫代碼時就少點這樣的騷操作
- struct B{
- int c;
- }b;
- struct A{
- struct B sb;
- }a;