簡介
Arduino IDE 是一個非常方便的工具,可以編寫您的程式碼並上傳到MCU中。但是,它暫時還沒有好用的除錯器功能,這意味著為我們的程式除錯的唯一方法就是使用串行監視器來打印Log訊息。
除錯訊息很方便,但是一旦您完成除錯並且準備部署您的程式的時候,我們還需要手動刪除/註釋掉那些除錯訊息代碼,如果是一個比較大的專案的話,這樣做就太痛苦了,因為太多要刪除了。
因此,這邊給大家介紹一種只需幾行代碼即可打開/關閉除錯訊息的簡單方法,以及如何更高效地找到訊息來源地的方法。
方法
這裡使用的方法就是宏函數 (Macro Function)
1. 開關除錯LOG
先來看看下面的程式碼,
#define __DEBUG__
#ifdef __DEBUG__
#define DEBUG(...) Serial.println(__VA_ARGS__)
#else
#define DEBUG(...)
#endif
由於所有使用Arduino的MCU都支援 Serial.println()
,我們可以將 Serial.println()
重定義為宏函數,這邊我將其命名為 DEBUG()
.
因此每當你想打印出除錯訊息的時候,你要使用 DEBUG()
來代替Serial.println()
,這樣子,你就可以通過 添加/取消注釋 這一行程式碼:#define __DEBUG__
來輕鬆啟用或禁用除錯訊息。
讓我們看一個例子
示例代碼 1
這是一個簡單的程式碼,它會每隔一秒打印出 “Debug msg 1” 和 “Debug msg 2”。
(圖中雖然使用的是printf()函數,但在實際使用中與Serial.print()的效果是一樣的)
注意代碼的第一行并未被注釋掉,因此我們看到的除錯訊息實際上是使用DEBUG()
函數成功打印出來的。
示例代碼 2
注意 這是相同的代碼,除了第一行 被註釋掉了。因此,串行監視器上沒有打印出任何東西。
正如我們所願!
2. 可以定位除錯訊息的高級版 DEBUG()
既然 Serial.println()
可以被重定義為一個宏函數,那麽我們是否可以再加一點邏輯進去好讓它爲我們提供更多有用的除錯訊息呢?
是的! 這裏就要借用GCC工具鏈中一個方便的功能了,我們先來看code:
#ifdef __DEBUG__
// You should only uncomment 1 version at a time!
// Version 1
//#define DEBUG(...) Serial.println(__VA_ARGS__)
// Version 2
#define DEBUG(...) Serial.println(__VA_ARGS__); \
Serial.print(" @ [SRC]: "); \
Serial.println(__FILE__); \
Serial.print(" @ [LINE]: "); \
Serial.println(__LINE__); \
Serial.print(" @ [FUNCTION]: "); \
Serial.println(__func__);
#else
// else DEBUG is diabled
#define DEBUG(...)
#endif
這裏可以看到,我們這裏有了兩個版本的 DEBUG()
, 第一個版本只是最基本的 Serial.println()
重定義, 而第二版本中,我們使用換行符 \
來讓 DEBUG()
可以一次性打印出多行的訊息,其中主要使用了GCC的標準函數庫中已經定義好的 __FILE__, __LINE__, __func__
宏,當我們打印這些宏的時候,程式就會幫我們把當前程式碼位置下的,
- 源文件名
- 行數
- 函數名
全部匯報給我們,輕鬆掌握這條除錯訊息的所有背景訊息,幫助大家更快的定位bug,以及bug出現的位置。 下面就是使用這個高級版DEBUG()
的實際表現:
可以看到,在開啓 並選定好高級版本的DEBUG()
之後(第二行和第九行),我們每一次使用DEBUG()
的時候,它除了打印我們已經寫好了的除錯訊息之外,也把這個 DEBUG()
所處的源文件路徑,行數還有所在的函數名都打印出來了,非常方便!
當然了,如果你覺得訊息太多了,也可以刪掉不想要的訊息,還你乾净的除錯界面,總之就是可以隨心所欲地做出適合你的調整,非常的靈活。
想要源碼的話可以點擊這裏:
結論
雖然這個方法是我們沒有除錯器時的一個臨時的方法,但是如果使用得當的話,也是可以成爲很强大的軟體除錯器的,并且可以通過修改一行程式碼來開啓/關閉以及切換等級,這個在Arduino IDE的環境下還是非常方便的。
希望你喜歡這篇小文,也希望它對你有用~
Happy coding~