dev c++怎么调试_「正点原子NANO STM32开发板资料连载」第十八章 USMART 调试组件...
1)實驗平臺:ALIENTEK NANO STM32F411 V1開發板2)摘自《正點原子STM32F4 開發指南(HAL 庫版》關注官方微信號公眾號,獲取更多資料:正點原子
第十八章 USMART 調試組件實驗
本章,我們將向大家介紹一個十分重要的輔助調試工具:USMART 調試組件。該組件由
ALIENTEK 開發提供,功能類似 linux 的 shell(RTT 的 finsh 也屬于此類)。USMART 最主要
的功能就是通過串口調用單片機里面的函數,并執行,對我們調試代碼是很有幫助的。本章分
為如下幾個部分:
18.1 USMART 調試組件簡介
18.2 硬件設計
18.3 軟件設計
18.4 下載驗證18.1 USMART 調試組件簡介
USMART 是由 ALIENTEK 開發的一個靈巧的串口調試互交組件,通過它你可以通過串口
助手調用程序里面的任何函數,并執行。因此,你可以隨意更改函數的輸入參數(支持數字(10/16
進制)、字符串、函數入口地址等作為參數),單個函數最多支持 10 個輸入參數,并支持函數返
回值顯示,目前最新版本為 V3.2。
USMART 的特點如下:
1, 可以調用絕大部分用戶直接編寫的函數。
2, 資源占用極少(最少情況:FLASH:4K;SRAM:72B)。
3, 支持參數類型多(數字(包含 10/16 進制)、字符串、函數指針等)。
4, 支持函數返回值顯示。
5, 支持參數及返回值格式設置。
6, 支持函數執行時間計算(V3.1 版本新特性)。
7, 使用方便。
有了 USMART,你可以輕易的修改函數參數、查看函數運行結果,從而快速解決問題。比
如你調試一個攝像頭模塊,需要修改其中的幾個參數來得到最佳的效果,普通的做法:寫函數
->修改參數->下載->看結果->不滿意->修改參數->下載->看結果->不滿意….不停的循環,直到滿
意為止。這樣做很麻煩不說,單片機也是有壽命的啊,老這樣不停的刷,很折壽的。而利用
USMART,則只需要在串口調試助手里面輸入函數及參數,然后直接串口發送給單片機,就執
行了一次參數調整,不滿意的話,你在串口調試助手修改參數在發送就可以了,直到你滿意為
止。這樣,修改參數十分方便,不需要編譯、不需要下載、不會讓單片機折壽。
USMART 支持的參數類型基本滿足任何調試了,支持的類型有:10 或者 16 進制數字、字
符串指針(如果該參數是用作參數返回的話,可能會有問題!)、函數指針等。因此絕大部分
函數,可以直接被 USMART 調用,對于不能直接調用的,你只需要重寫一個函數,把影響調
用的參數去掉即可,這個重寫后的函數,即可以被 USMART 調用了。
USMART 的實現流程簡單概括就是:第一步,添加需要調用的函數(在 usmart_config.c 里
面的 usmart_nametab 數組里面添加);第二步,初始化串口;第三步,初始化 USMART(通過
usmart_init 函數實現);第四步,輪詢 usmart_scan 函數,處理串口數據。
經過以上簡單介紹,我們對 USMART 有了個大概了解,接下來我們來簡單介紹下
USMART 組件的移植。
USMART 組件總共包含 6 文件如圖 18.1.1 所示:
圖 18.1.1 USMART 組件代碼
其中 redeme.txt 是一個說明文件,不參與編譯。其他五個文件,usmart.c 負責與外部互交等。
usmat_str.c 主要負責命令和參數解析。usmart_config.c 主要由用戶添加需要由 usmart 管理的函
數。
usmart.h 和 usmart_str.h 是兩個頭文件,其中 usmart.h 里面含有幾個用戶配置宏定義,可以
用來配置 usmart 的功能及總參數長度(直接和 SRAM 占用掛鉤)、是否使能定時器掃描、是否使
用讀寫函數等。
USMART 的移植,只需要實現 5 個函數。其中 4 個函數都在 usmart.c 里面,另外一個是串
口接收函數,必須有由用戶自己實現,用于接收串口發送過來的數據。
第一個函數,串口接收函數。該函數,我們是通過 SYSTEM 文件夾默認的串口接收來實現
的,該函數在 5.3.1 節有介紹過,我們這里就不列出來了。SYSTEM 文件夾里面的串口接收函
數,最大可以一次接收 200 字節,用于從串口接收函數名和參數等。大家如果在其他平臺移植,
請參考 SYSTEM 文件夾串口接收的實現方式進行移植。
第二個是 void usmart_init(void)函數,該函數的實現代碼如下:
//初始化串口控制器
//sysclk:系統時鐘(Mhz)
void usmart_init(u8 sysclk)
{
#if USMART_ENTIMX_SCAN==1
Timer4_Init(1000,(u32)sysclk*100-1); //分頻,時鐘為 10K ,100ms 中斷一次
//注意,計數頻率必須為 10Khz,以和 runtime 單位(0.1ms)同步.
#endif
usmart_dev.sptype=1; //十六進制顯示參數
}
該函數有一個參數 sysclk,就是用于定時器初始化。這里需要說明一下,為了讓我們的庫
函數和寄存器實現函數一致,我們這里不直接通過 SystemCoreClock 來獲取系統時鐘,直接通
過在外面設置的方式(當然你也可以去掉 sysclk 這個參數),這樣函數體里面的 Timer4_Init
函 數 就 可 修 改 為 Timer4_Init(1000,(u32) SystemCoreClock/100-1) 。 另 外
USMART_ENTIMX_SCAN 是在 usmart.h 里面定義的一個是否使能定時器中斷掃描的宏定義。
如果為 1,就通過定時器初始化函數 Timer4_Init 初始化定時器 4 中斷,每 100ms 中斷一次,并
在中斷服務程序 TIM4_IRQHandler 里面調用 usmart_scan 函數進行掃描,這里我們就不列出代
碼,因為之前的實驗對這方面講解較多。如果為 0,那么需要用戶需要自行間隔一定時間(100ms
左右為宜)調用一次 usmart_scan 函數,以實現串口數據處理。注意:如果要使用函數執行時間統計功能(runtime 1),則必須設置 USMART_ENTIMX_SCAN 為 1。另外,為了讓統計時間精確到 0.1ms,定時器的計數時鐘頻率必須設置為 10Khz,否則時間就不是 0.1ms 了。
第三和第四個函數僅用于服務 USMART 的函數執行時間統計功能(串口指令:runtime 1),
分別是:usmart_reset_runtime 和 usmart_get_runtime,這兩個函數代碼如下:
//復位 runtime
//需要根據所移植到的 MCU 的定時器參數進行修改
void usmart_reset_runtime(void)
{
__HAL_TIM_CLEAR_FLAG(&TIM4_Handler,TIM_FLAG_UPDATE);//清除中斷標志位
__HAL_TIM_SET_AUTORELOAD(&TIM4_Handler,0XFFFF); //將重裝載值設置到最大
__HAL_TIM_SET_COUNTER(&TIM4_Handler,0); //清空定時器的 CNT
usmart_dev.runtime=0;
}
//獲得 runtime 時間
//返回值:執行時間,單位:0.1ms,最大延時時間為定時器 CNT 值的 2 倍*0.1ms
//需要根據所移植到的 MCU 的定時器參數進行修改
u32 usmart_get_runtime(void)
{
if(__HAL_TIM_GET_FLAG(&TIM4_Handler,TIM_FLAG_UPDATE)==SET)
//在運行期間,產生了定時器溢出
{
usmart_dev.runtime+=0XFFFF;
}
usmart_dev.runtime+=__HAL_TIM_GET_COUNTER(&TIM4_Handler);
return usmart_dev.runtime;
//返回計數值
}
這里我們還是利用定時器 4 來做執行時間計算,usmart_reset_runtime 函數在每次 USMART
調用函數之前執行,清除計數器,然后在函數執行完之后,調用 usmart_get_runtime 獲取整個
函數的運行時間。由于 usmart 調用的函數,都是在中斷里面執行的,所以我們不太方便再用定
時器的中斷功能來實現定時器溢出統計,因此,USMART 的函數執行時間統計功能,最多可以
統計定時器溢出 1 次的時間,對 STM32 來說,定時器是 16 位的,最大計數是 65535,而由于
我們定時器設置的是 0.1ms 一個計時周期(10Khz),所以最長計時時間是:65535*2*0.1ms=13.1
秒。也就是說,如果函數執行時間超過 13.1 秒,那么計時將不準確。
最后一個是 usmart_scan 函數,該函數用于執行 usmart 掃描,該函數需要得到兩個參量,
第一個是從串口接收到的數組(USART_RX_BUF),第二個是串口接收狀態(USART_RX_STA)。
接收狀態包括接收到的數組大小,以及接收是否完成。該函數代碼如下:
//usmart 掃描函數
//通過調用該函數,實現 usmart 的各個控制.該函數需要每隔一定時間被調用一次
//以及時執行從串口發過來的各個函數.
//本函數可以在中斷里面調用,從而實現自動管理.
//如果非 ALIENTEK 用戶,則 USART_RX_STA 和 USART_RX_BUF[]需要用戶自己實現
void usmart_scan(void)
{
u8 sta,len;
if(USART_RX_STA&0x8000)//串口接收完成?
{
len=USART_RX_STA&0x3fff; //得到此次接收到的數據長度
USART_RX_BUF[len]='0'; //在末尾加入結束符.
sta=usmart_dev.cmd_rec(USART_RX_BUF);//得到函數各個信息
if(sta==0)usmart_dev.exe();//執行函數
else
{
len=usmart_sys_cmd_exe(USART_RX_BUF);
if(len!=USMART_FUNCERR)sta=len;
if(sta)
{
switch(sta)
{
case USMART_FUNCERR:
printf("函數錯誤!rn");
break;
case USMART_PARMERR:
printf("參數錯誤!rn");
break;
case USMART_PARMOVER:
printf("參數太多!rn");
break;
case USMART_NOFUNCFIND:
printf("未找到匹配的函數!rn");
break;
}
}
}
USART_RX_STA=0;//狀態寄存器清空
}
}
該函數的執行過程:先判斷串口接收是否完成(USART_RX_STA 的最高位是否為 1),如
果完成,則取得串口接收到的數據長度(USART_RX_STA 的低 14 位),并在末尾增加結束符,
再執行解析,解析完之后清空接收標記(USART_RX_STA 置零)。如果沒執行完成,則直接
跳過,不進行任何處理。完成這幾個函數的移植,你就可以使用 USMART 了。不過,需要注意的是,usmart 同外
部的互交,一般是通過 usmart_dev 結構體實現,所以 usmart_init 和 usmart_scan 的調用分別是
通過:usmart_dev.init 和 usmart_dev.scan 實現的。
下面,我們將在第六章實驗的基礎上,移植 USMART,并通過 USMART 調用控制 LED,
讓大家初步了解 USMART 的使用。18.2 硬件設計
本實驗用到的硬件資源有:
1) 指示燈 DS0 和 DS2
2) 串口
這兩個硬件在前面章節均有介紹,本章不再介紹。18.3 軟件設計
這里我們在上一章的實驗的基礎上通過添加文件的方式講解 USMART 的引入,當然大家
也可以直接打開我們光盤的實例工程。打開上一章的工程,復制 USMART 文件夾(該文件夾
可以在光盤的本章實驗例程里面找到)到本工程文件夾下面,如圖 18.3.1 所示:
圖 18.3.1 復制 USMART 文件夾到工程文件夾下
接著,我們打開工程,并新建 USMART 組,添加 USMART 組件代碼,同時把 USMART
文件夾添加到頭文件包含路徑,在主函數里面加入 include“usmart.h”如圖 18.3.2 所示:
圖 18.3.2 添加 USMART 組件代碼
由于 USMART 默認提供了 STM32 的 TIM4 中斷初始化設置代碼,我們只需要在 usmart.h
里面設置 USMART_ENTIMX_SCAN 為 1,即可完成 TIM4 的設置,通過 TIM4 的中斷服務函
數,調用 usmart_dev.scan()(就是 usmart_scan 函數),實現 usmart 的掃描。此部分代碼我們就
不列出來了,請參考 usmart.c。
此時,我們就可以使用 USMART 了,不過在主程序里面還得執行 usmart 的初始化,另外
還需要針對你自己想要被 USMART 調用的函數在 usmart_config.c 里面進行添加。下面先介紹
如何添加自己想要被 USMART 調用的函數,打開 usmart_config.c,如圖 18.3.3 所示:
圖 18.3.3 添加需要被 USMART 調用的函數
這里的添加函數很簡單,只要把函數所在頭文件添加進來,并把函數名按上圖所示的方式
增加即可,默認我們添加了兩個函數:delay_ms 和 delay_us。另外,read_addr 和 write_addr 屬
于 usmart 自帶的函數,用于讀寫指定地址的數據,通過配置 USMART_USE_WRFUNS,可以
使能或者禁止這兩個函數。
這里我們根據自己的需要按上圖的格式添加其他函數,添加完之后如圖 18.3.4 所示:
圖 19.3.4 添加函數后
上圖中,我們添加了 led.h,添加了 led_set 和 test_fun 兩個函數,這兩個函數在 main.c 里面
實現,代碼如下:
//LED 狀態設置函數
void led_set(u8 sta)
{
LED2=sta;
}
//函數參數調用測試函數
void test_fun(void(*ledset)(u8),u8 sta)
{
ledset(sta);
}
led_set 函數,用于設置 LED2 的狀態,而第二個函數 test_fun 則是測試 USMART 對函數參
數的支持的,test_fun 的第一個參數是函數,在 USMART 里面也是可以被調用的。
在添加完函數之后,我們修改 main 函數,如下:
int main(void)
{
HAL_Init();
//初始化 HAL 庫
Stm32_Clock_Init(96,4,2,4);
//設置時鐘,96Mhz
delay_init(96);
//初始化延時函數
uart_init(115200);
//初始化串口 115200
LED_Init();
//初始化 LED
usmart_dev.init(96);
//初始化 USMART
while(1)
{
LED0=!LED0;
delay_ms(500);
}
}
此代碼顯示簡單的信息后,就是在死循環等待串口數據。至此,整個 usmart 的移植就完成
了。編譯成功后,就可以下載程序到開發板,開始 USMART 的體驗。
這里大家注意,因為 usmart 要使用串口接收字符,為了保證接收效率和準確率,我們把中
斷處理過程直接編寫再中斷服務函數中而沒采用 HAL 庫提供的回調函數,具體代碼參考 usart.c
即可。18.4 下載驗證
將程序下載到 NANO STM32F4 后,可以看到 DS0 不停的閃爍,提示程序已經在運行了。
我們打開串口調試助手 XCOM,選擇正確的串口號?多條發送?勾選發送新行(即發送回
車鍵)選項,然后發送 list 指令,即可打印所有 usmart 可調用函數。如下圖所示:
圖 18.4.1 驅動串口調試助手
上圖中 list、id、?、help、hex、dec 和 runtime 都屬于 usmart 自帶的系統命令。下面我們
簡單介紹下這幾個命令:
上圖中 list、id、help、hex、dec 和 runtime 都屬于 usmart 自帶的系統命令,點擊后方的數
字按鈕,即可發送對應的指令。下面我們簡單介紹下這幾個命令:
list,該命令用于打印所有 usmart 可調用函數。發送該命令后,串口將受到所有能被 usmart
調用得到函數,如圖 19.4.1 所示。
id,該指令用于獲取各個函數的入口地址。比如前面寫的 test_fun 函數,就有一個函數參數,
我們需要先通過 id 指令,獲取 led_set 函數的 id(即入口地址),然后將這個 id 作為函數參數,
傳遞給 test_fun。
help(或者‘ ?’也可以),發送該指令后,串口將打印 usmart 使用的幫助信息。
hex 和 dec,這兩個指令可以帶參數,也可以不帶參數。當不帶參數的時候,hex 和 dec 分
別用于設置串口顯示數據格式為 16 進制/10 進制。當帶參數的時候,hex 和 dec 就執行進制轉
換,比如輸入:hex 1234,串口將打印:HEX:0X4D2,也就是將 1234 轉換為 16 進制打印出來。
又比如輸入:dec 0X1234,串口將打印:DEC:4660,就是將 0X1234 轉換為 10 進制打印出來。
runtime 指令,用于函數執行時間統計功能的開啟和關閉,發送:runtime 1,可以開啟函數
執行時間統計功能;發送:runtime 0,可以關閉函數執行時間統計功能。函數執行時間統計功
能,默認是關閉的。
大家可以親自體驗下這幾個系統指令,不過要注意,所有的指令都是大小寫敏感的,不要
寫錯哦。
接下來,我們將介紹如何調用 list 所打印的這些函數,先來看一個簡單的 delay_ms 的調用,
我們分別輸入 delay_ms(1000)和 delay_ms(0x3E8),如圖 18.4.2 所示:
圖 18.4.2 串口調用 delay_ms 函數
從上圖可以看出,delay_ms(1000)和 delay_ms(0x3E8)的調用結果是一樣的,都是延時
1000ms,因為 usmart 默認設置的是 hex 顯示,所以看到串口打印的參數都是 16 進制格式的,
大家可以通過發送 dec 指令切換為十進制顯示。另外,由于 USMART 對調用函數的參數大小寫
不敏感,所以參數寫成:0X3E8 或者 0x3e8 都是正確的。另外,發送:runtime 1,開啟運行時
間統計功能,從測試結果看,USMART 的函數運行時間統計功能,是相當準確的。
若增加其他函數的調用,也都是一樣的方法,這里我們就不多介紹了,說一下帶有函數參
數的函數的調用。我們將 led_set 函數作為 test_fun 的參數,通過在 test_fun 里面調用 led_set
函數,實現對 DS2(LED2)的控制。前面說過,我們要調用帶有函數參數的函數,就必須先得到
函數參數的入口地址(id),通過輸入 id 指令,我們可以得到 led_set 的函數入口地址是:
0X0800022D(注意:這個地址要以實際串口輸出結果為準),所以,我們在串口輸入:
test_fun(0X0800022D,0),就可以控制 DS2 亮了。如圖 18.4.3 所示:
圖 18.4.3 串口調用 test_fun 函數
在開發板上,我們可以看到,收到串口發送的 test_fun(0X0800022D,0)后,開發板的 DS2
亮了,然后大家可以通過發送test_fun(0X0800022D,1),來關閉DS2。說明我們成功的通過test_fun
函數調用 led_set,實現了對 DS2 的控制。也就驗證了 USMART 對函數參數的支持。
USMART 調試組件的使用,就為大家介紹到這里。USMART 是一個非常不錯的調試組件,
希望大家能學會使用,可以達到事半功倍的效果。
總結
以上是生活随笔為你收集整理的dev c++怎么调试_「正点原子NANO STM32开发板资料连载」第十八章 USMART 调试组件...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linker分析2
- 下一篇: 交换网站 iframe 有意请进