C語言是單片機(jī)開發(fā)中的必備基礎(chǔ)知識(shí),本文列舉了部分STM32學(xué)習(xí)中比較常見的一些C語言基礎(chǔ)知識(shí),希望能對(duì)大家有所幫助。
01
位操作 下面我們先講解幾種位操作符,然后講解位操作使用技巧。C語言支持以下六種位操作:![6e655cde-6ed4-11ed-8abf-dac502259ad0.png](https://file1.elecfans.com//web2/M00/98/64/wKgaomTnS1-ARRUcAAALS0ELSvk183.png)
![6e7cf6c8-6ed4-11ed-8abf-dac502259ad0.png](https://file1.elecfans.com//web2/M00/98/64/wKgaomTnS1-AfXVyAAAMumgcyZ8797.png)
![6e907644-6ed4-11ed-8abf-dac502259ad0.png](https://file1.elecfans.com//web2/M00/98/64/wKgaomTnS1-Abb3UAAASEivnhTk192.png)
SysTick->CTRL |= 1 << 1;
這個(gè)操作就是將CTRL寄存器的第1位(從0開始算起)設(shè)置為1,為什么要通過左移而不是直接設(shè)置一個(gè)固定的值呢?其實(shí)這是為了提高代碼的可讀性以及可重用性。這行代碼可以很直觀明了的知道,是將第1位設(shè)置為1。如果寫成:
SysTick->CTRL |= 0X0002;
這個(gè)雖然也能實(shí)現(xiàn)同樣的效果,但是可讀性稍差,而且修改也比較麻煩。
1.3 ~按位取反操作使用技巧
按位取反在設(shè)置寄存器的時(shí)候經(jīng)常被使用,常用于清除某一個(gè)/某幾個(gè)位。下面是delay_us函數(shù)的一行代碼:
SysTick->CTRL &= ~(1 << 0) ; /* 關(guān)閉SYSTICK */
該代碼可以解讀為:僅設(shè)置CTRL寄存器的第0位(最低位)為0,其他位的值保持不變。同樣我們也不使用按位取反,將代碼寫成:
SysTick->CTRL &= 0XFFFFFFFE; /* 關(guān)閉SYSTICK */
可見,前者的可讀性及可維護(hù)性都要比后者好很多。
1.4 ^按位異或操作使用技巧
該功能非常適合用于控制某個(gè)位翻轉(zhuǎn),常見的應(yīng)用場(chǎng)景就是控制LED閃爍,如下:
GPIOB->ODR ^= 1 << 5;
執(zhí)行一次該代碼,就會(huì)使PB5的輸出狀態(tài)翻轉(zhuǎn)一次,如果我們的LED接在PB5上,就可以看到LED閃爍了。
02
define宏定義 define是C語言中的預(yù)處理命令,它用于宏定義(定義的是常量),可以提高源代碼的可讀性,為編程提供方便。常見的格式:![6ea22632-6ed4-11ed-8abf-dac502259ad0.png](https://file1.elecfans.com//web2/M00/98/64/wKgaomTnS2CAX9anAAAGwG9tkBo497.png)
![6eb1e658-6ed4-11ed-8abf-dac502259ad0.png](https://file1.elecfans.com//web2/M00/98/64/wKgaomTnS2CAbZFqAAAFWBHgVG0381.png)
03
ifdef條件編譯 單片機(jī)程序開發(fā)過程中,經(jīng)常會(huì)遇到一種情況,當(dāng)滿足某條件時(shí)對(duì)一組語句進(jìn)行編譯,而當(dāng)條件不滿足時(shí)則編譯另一組語句。條件編譯命令最常見的形式為:
#ifdef 標(biāo)識(shí)符 程序段1#else 程序段2#endif
它的作用是:當(dāng)標(biāo)識(shí)符已經(jīng)被定義過(一般是用#define命令定義),則對(duì)程序段1進(jìn)行編譯,否則編譯程序段2。
其中#else部分也可以沒有,即:
#ifdef
程序段1
#endif
條件編譯在HAL庫里面是用得很多,在stm32mp1xx_hal_conf.h這個(gè)頭文件中經(jīng)常會(huì)看到這樣的語句:
#if !defined (HSE_VALUE)
#define HSE_VALUE 24000000U
#endif
如果沒有定義HSE_VALUE這個(gè)宏,則定義HSE_VALUE宏,并且HSE_VALUE的值為24000000U。條件編譯也是C語言的基礎(chǔ)知識(shí)吧。
這里提一下,24000000U中的U表示無符號(hào)整型,常見的,UL表示無符號(hào)長(zhǎng)整型,F(xiàn)表示浮點(diǎn)型。
這里加了U以后,系統(tǒng)編譯時(shí)就不進(jìn)行類型檢查,直接以U的形式把值賦給某個(gè)對(duì)應(yīng)的內(nèi)存,如果超出定義變量的范圍,則截取。
04
extern變量申明 C語言中extern可以置于變量或者函數(shù)前,以表示變量或者函數(shù)的定義在別的文件中,提示編譯器遇到此變量和函數(shù)時(shí)在其他模塊中尋找其定義。 這里面要注意,對(duì)于extern申明變量可以多次,但定義只有一次。在我們的代碼中你會(huì)看到看到這樣的語句:
extern uint16_t g_usart_rx_sta;
這個(gè)語句是申明g_usart_rx_sta變量在其他文件中已經(jīng)定義了,在這里要使用到。
所以,你肯定可以找到在某個(gè)地方有變量定義的語句:
uint16_t g_usart_rx_sta;
extern的使用比較簡(jiǎn)單,但是也會(huì)經(jīng)常用到,需要掌握。
05
typedef類型別名 typedef用于為現(xiàn)有類型創(chuàng)建一個(gè)新的名字,或稱為類型別名,用來簡(jiǎn)化變量的定義。typedef在HAL庫用得最多的就是定義結(jié)構(gòu)體的類型別名和枚舉類型了。
struct _GPIO
{
__IO uint32_t CRL;
__IO uint32_t CRH;
…
};
定義了一個(gè)結(jié)構(gòu)體GPIO,這樣我們定義結(jié)構(gòu)體變量的方式為:
struct _GPIO gpiox; /* 定義結(jié)構(gòu)體變量gpiox */
但這樣很繁瑣,HAL庫中有很多這樣的結(jié)構(gòu)體變量需要定義。
這里我們可以為結(jié)體定義一個(gè)別名GPIO_TypeDef,這樣我們就可以在其他地方通過別名GPIO_TypeDef來定義結(jié)構(gòu)體變量了,方法如下:
typedef struct
{
__IO uint32_t CRL;
__IO uint32_t CRH;
…
} GPIO_TypeDef;
Typedef為結(jié)構(gòu)體定義一個(gè)別名GPIO_TypeDef,這樣我們可以通過GPIO_TypeDef來定義結(jié)構(gòu)體變量:GPIO_TypeDef gpiox;
這里的GPIO_TypeDef就跟struct _GPIO是等同的作用了,但是GPIO_TypeDef使用起來方便很多。審核編輯 :李倩
-
寄存器
+關(guān)注
關(guān)注
31文章
5372瀏覽量
121314 -
C語言
+關(guān)注
關(guān)注
180文章
7616瀏覽量
137887
原文標(biāo)題:那些一看就會(huì)、一放就忘的C語言知識(shí)
文章出處:【微信號(hào):mcu168,微信公眾號(hào):硬件攻城獅】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
新手怎么學(xué)嵌入式?
硬件工程師需要掌握的硬件基礎(chǔ)知識(shí)
![硬件工程師需要掌握的硬件<b class='flag-5'>基礎(chǔ)知識(shí)</b>](https://file1.elecfans.com/web3/M00/00/A8/wKgZPGdNDGyAKTnFAABOlwPj4vY636.png)
一些常見的動(dòng)態(tài)電路
![<b class='flag-5'>一些</b><b class='flag-5'>常見</b>的動(dòng)態(tài)電路](https://file1.elecfans.com/web1/M00/F4/F1/wKgaoWc0ATSAA4smAAARqkK1SoQ655.gif)
編程語言的誤區(qū)與常見問題
分享一些常見的電路
![分享<b class='flag-5'>一些</b><b class='flag-5'>常見</b>的電路](https://file1.elecfans.com/web1/M00/F4/F1/wKgaoWc0ATSAA4smAAARqkK1SoQ655.gif)
評(píng)論