這一次我們繼續(xù)講調(diào)試方法。調(diào)試是排查程序Bug的有效方法,同時(shí)也對(duì)嵌入式軟件設(shè)計(jì)的可靠性、穩(wěn)定性而言至關(guān)重要。之前講的調(diào)試方法能夠打印出變量值、系統(tǒng)狀態(tài),或用互動(dòng)的方式去調(diào)試程序,都不能動(dòng)態(tài)的在系統(tǒng)運(yùn)行時(shí)由程序判斷變量、參數(shù)是否出錯(cuò)。
而我們今天要講的斷言(assert)函數(shù)則能做到在運(yùn)行時(shí)判斷參數(shù)是否超出預(yù)設(shè)值、狀態(tài)是否出錯(cuò),然后打印出出錯(cuò)數(shù)據(jù)所在的源文件和行號(hào)。
那么,什么是斷言函數(shù)呢?百度百科給的定義是:“斷言(assertion)是一種在程序中的一階邏輯(如:一個(gè)結(jié)果為真或假的邏輯判斷式),目的為了表示與驗(yàn)證軟件開(kāi)發(fā)者預(yù)期的結(jié)果——當(dāng)程序執(zhí)行到斷言的位置時(shí),對(duì)應(yīng)的斷言應(yīng)該為真。若斷言不為真時(shí),程序會(huì)中止執(zhí)行,并給出錯(cuò)誤信息。“
接下來(lái),我們繼續(xù)采用上一次實(shí)時(shí)跟蹤調(diào)試的例子,加入斷言函數(shù)對(duì)運(yùn)行過(guò)程的參數(shù)進(jìn)行判斷,看看斷言函數(shù)如何應(yīng)用,有什么效果。
1. CubeMX設(shè)置
我們可以在CubeMX中打開(kāi)例子工程中的.ioc文件,按下圖進(jìn)行設(shè)置。
除此之外,可以直接在CubeIDE的工程屬性里定義一個(gè)宏USE_FULL_ASSERT,也可以在工程任意頭文件中定義這個(gè)宏,效果是一樣的。其實(shí)采用CubeMX配置之后,就是在工程的stm2f7xx_hal_conf.h頭文件中定義了這個(gè)宏。
2. 修改代碼
當(dāng)定義了宏USE_FULL_ASSERT之后,assert_failed函數(shù)就能參與編譯了,這個(gè)函數(shù)在main.c的最下邊。這個(gè)函數(shù)的代碼如下:
void assert_failed(uint8_t *file, uint32_t line)
{
printf("Wrong parameters value: file %s on line %drn", file, (uint16_t)line);
}
斷言失敗的話則會(huì)執(zhí)行這個(gè)函數(shù),利用printf打印一條消息,這里我們用的是CubeIDE的ITM模塊向外打印,打印的消息里包含斷言失敗語(yǔ)句所在的源文件及行數(shù)。
要注意的是,參數(shù)line本來(lái)是無(wú)符號(hào)長(zhǎng)整形,printf函數(shù)用%d對(duì)應(yīng)長(zhǎng)整形的話會(huì)給警告,所以做了一個(gè)強(qiáng)制類(lèi)型轉(zhuǎn)換,變?yōu)闊o(wú)符號(hào)短整型。我想應(yīng)該不會(huì)有一個(gè)源文件超過(guò)65535行吧,那是要挨打的。
接下來(lái)在main.h里定義一個(gè)宏IS_PARA_COUNTER_OK,當(dāng)然名字可以自己任意取。
#define IS_PARA_COUNTER_OK(para) (para < 5)
這個(gè)宏的其實(shí)是個(gè)表達(dá)式,用以對(duì)para參數(shù)的值進(jìn)行判斷,這里假設(shè)para的值小于5是正常的。為了防止出錯(cuò),表達(dá)式用小括號(hào)括起來(lái)了。
在main函數(shù)while循環(huán)開(kāi)始的地方,我們加上一條語(yǔ)句,用來(lái)對(duì)我們?cè)O(shè)置的一個(gè)用來(lái)計(jì)數(shù)的變量counter進(jìn)行參數(shù)斷言。
assert_param(IS_PARA_COUNTER_OK(counter));
其中,assert_param是在stm2f7xx_hal_conf.h中定義的一個(gè)宏。
#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *) FILE , LINE ))
意思是當(dāng)expr表達(dá)式的值為真的時(shí)候,不執(zhí)行任何操作,為假時(shí),斷言失敗,執(zhí)行assert_failed函數(shù),并向該函數(shù)傳遞斷言失敗語(yǔ)句所在的源文件和行。__FILE__和__LINE__都是C語(yǔ)言定義的宏,分別代表當(dāng)前源文件和所在行。
我們?cè)趍ain函數(shù)中寫(xiě)的斷言語(yǔ)句可以完全展開(kāi)如下:
(((counter < 5)) ? (void)0U : assert_failed((uint8_t *)"D:workspaceSTM32F7example2_ITMCoreSrcmain.c", 101))
是的,這條語(yǔ)句位于main.c的101行。
3. 調(diào)試結(jié)果
代碼修改好后,連接好開(kāi)發(fā)板,構(gòu)建工程,進(jìn)入調(diào)試模式并開(kāi)始運(yùn)行,我們可以在SWV ITM Data Console窗口看到如下信息。
這里要說(shuō)明一下,代碼里counter值是在打印之后加1的,也就是說(shuō)在打印出4之后,其值已經(jīng)變?yōu)?,導(dǎo)致參數(shù)斷言出錯(cuò),打印出預(yù)設(shè)消息。另外我們也可以在assert_failed函數(shù)里加入一個(gè)死循環(huán),斷言失敗后程序就不會(huì)繼續(xù)往下執(zhí)行了。
-
C語(yǔ)言
+關(guān)注
關(guān)注
180文章
7608瀏覽量
137110 -
狀態(tài)機(jī)
+關(guān)注
關(guān)注
2文章
492瀏覽量
27574 -
HAL庫(kù)
+關(guān)注
關(guān)注
1文章
121瀏覽量
6322
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論