2021/7/18--stm32需要用到的c語言
2021/7/18
1. ifdef條件編譯
條件編譯命令最常見的形式為:
它的作用是:當識別符號已經被定義過(一般是用#define命令定義),則對程式段1進行編譯,否則編譯程式段2。
2. extern變數宣告
C語言中extern可以置於變數或者函式前,以表示變數或者函式的定義在別的檔案中,提示編譯器遇到此變數和函式時在其他模組中尋找其定義。這裡面要注意,對於extern申明變數可以多次,但定義只有一次。在我們的程式碼中你會看到看到這樣的語句:
extern u16 USART_RX_STA;
這個語句是申明USART_RX_STA變數在其他檔案中已經定義了,在這裡要使用到。所以,你肯定可以找到在某個地方有變數定義的語句:
u16 USART_RX_STA;
下面通過一個例子說明一下使用方法。 在Main.c定義的全域性變數id,id的初始化都是在Main.c裡面進行的。 Main.c檔案
u8 id;//定義只允許一次
main()
{
id=1;
printf("d%",id);//id=1
test();
printf("d%",id);//id=2
}
但是我們希望在main.c的 changeId(void)函式中使用變數id,這個時候我們就需要在main.c裡面去申明變數id是外部定義的了,因為如果不申明,變數id的作用域是到不了main.c檔案中。看下面main.c中的程式碼:
extern u8 id;//申明變數id是在外部定義的,申明可以在很多個檔案中進行
void test(void)
{
id=2;
}
在main.c中申明變數id在外部定義,然後在main.c中就可以使用變數id了。
3.typedef類型別名
typedef用於為現有型別建立一個新的名字,或稱為類型別名,用來簡化變數的定義。typedef在MDK用得最多的就是定義結構體的類型別名和列舉型別了。
struct _GPIO
{
__IO uint32_t MODER;
__IO uint32_t OTYPER;
...
};
struct _GPIO GPIOA;//定義結構體變數GPIOA
但是這樣很繁瑣,MDK中有很多這樣的結構體變數需要定義。這裡可以為結體定義一個別名GPIO_TypeDef,這樣就可以在其他地方通過別名GPIO_TypeDef來定義結構體變量了。方法如下:
typedef struct
{
__IO uint32_t MODER;
__IO uint32_t OTYPER;
…
} GPIO_TypeDef;
Typedef為結構體定義一個別名GPIO_TypeDef,這樣我們可以通過GPIO_TypeDef來定義結構體變數:
GPIO_TypeDef _GPIOA,_GPIOB;
這裡的GPIO_TypeDef就跟struct _GPIO是等同的作用了。
4.結構體
宣告結構體型別:
Struct 結構體名{
成員列表;
}變數名列表;
例如:
Struct U_TYPE {
Int BaudRate
Int WordLength;
}usart1,usart2;
在結構體申明的時候可以定義變數,也可以申明之後定義,方法是:
Struct 結構體名字結構體變數列表;
例如:
struct U_TYPE usart1,usart2;
結構體成員變數的引用方法是:
結構體變數名字.成員名
比如要引用usart1的成員BaudRate,方法是:usart1.BaudRate; 結構體指標變數定義也是一樣的,跟其他變數沒有啥區別。 例如:struct U_TYPE *usart3;//定義結構體指標變數usart1; 結構體指標成員變數引用方法是通過“->”符號實現,比如要訪問usart3結構體指標指向的結構體的成員變數BaudRate,方法是:
Usart3->BaudRate;
在我們微控制器程式開發過程中,經常會遇到要初始化一個外設比如串列埠,它的初始化狀態是由幾個屬性來決定的,比如串列埠號,波特率,極性,以及模式等。對於這種情況,在沒有學習結構體的時候,我們一般的方法是:
void USART_Init(u8 usartx,u32 u32 BaudRate,u8 parity,u8 mode);
這種方式是有效的同時在一定場合是可取的。但是試想,如果有一天,我們希望往這個函式裡面再傳入一個引數,那麼勢必需要修改這個函式的定義,重新加入字長這個入口引數。於是定義被修改為:
void USART_Init (u8 usartx,u32 BaudRate, u8 parity,u8 mode,u8 wordlength );
結構體就是將多個變數組合為一個有機的整體。上面的函式,BaudRate,wordlength, Parity,mode,wordlength這些引數,他們對於串列埠而言,是一個有機整體,都是來設定串列埠引數的,所以可以將他們通過定義一個結構體來組合在一個。MDK中是這樣定義的:
typedef struct
{
uint32_t USART_BaudRate;
uint16_t USART_WordLength;
uint16_t USART_StopBits;
uint16_t USART_Parity;
uint16_t USART_Mode;
uint16_t USART_HardwareFlowControl;
} USART_InitTypeDef;
於是,在初始化串列埠的時候入口引數就可以是USART_InitTypeDef型別的變數或者指標變量了,MDK中是這樣做的:
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
這樣,任何時候,只需要修改結構體成員變數,往結構體中間加入新的成員變數,而不需要修改函式定義就可以達到修改入口引數同樣的目的了。這樣的好處是不用修改任何函式定義就可以達到增加變數的目的。