上一篇博客簡單說了下如何使用Keil創(chuàng)建STM32F103的工程,并且完成了LED點(diǎn)亮,及讓LED等閃爍的功能,那是諸多同學(xué)學(xué)習(xí)單片機(jī)的起手式。本篇博客繼續(xù)上一篇博客的內(nèi)容,依舊是點(diǎn)亮LED,不同的是,這次點(diǎn)亮LED等,是在RT-Thread操作系統(tǒng)中進(jìn)行的。
創(chuàng)建工程
創(chuàng)建一個(gè)Keil工程,芯片依舊選擇STM32F103C8T6,然后在Manage Run-Time Environment對(duì)話框中選擇需要用的的軟件組件,與上文不同的是,我們需要把RTT一起勾上。如下圖:
上圖中,紅線框中即為RTT操作系統(tǒng)的組件,分別為設(shè)備驅(qū)動(dòng),系統(tǒng)內(nèi)核以及shell。藍(lán)線框中為Keil的RTX操作系統(tǒng)。我們現(xiàn)在要用的是RTT,所以勾選RTT的組件即可,其中Kernel為必選項(xiàng),device drivers依賴kernel,shell又依賴device drivers。
shell也提一下,shell強(qiáng)翻成中文就是命令行外殼,如同linux操作系統(tǒng)一樣,RTT也提供了一套共用戶在命令行操作的操作接口。RTT提供的這套接口叫做finsh,主要用于調(diào)試、查看系統(tǒng)信息。finsh支持兩種模式:1. C語言解釋器模式, 為行文方便稱之為c-style;2. 傳統(tǒng)命令行模式,此模式又稱為msh(module shell)。
在大部分嵌入式系統(tǒng)中,一般開發(fā)調(diào)試都使用硬件調(diào)試器和printf日志打印,在有些情況下,這兩種方式并不是那么好用。比如對(duì)于RT-Thread這個(gè)多線程系統(tǒng),我們想知道某個(gè)時(shí)刻系統(tǒng)中的線程運(yùn)行狀態(tài)、手動(dòng)控制系統(tǒng)狀態(tài)。如果有一個(gè)shell,就可以輸入命令,直接相應(yīng)的函數(shù)執(zhí)行獲得需要的信息,或者控制程序的行為。這無疑會(huì)非常方便。finsh就是基于此而設(shè)計(jì),它運(yùn)行于開發(fā)板,可以使用串口/以太網(wǎng)/USB等與PC機(jī)進(jìn)行通信。
創(chuàng)建工程后,相對(duì)上一篇博客創(chuàng)建的工程,項(xiàng)目中會(huì)多出了RTT,如下圖。至于各個(gè)文件及其作用,后續(xù)使用的時(shí)候再逐步理解。我們當(dāng)前最需要關(guān)注的是board.c和rtthread.h兩個(gè)文件。從圖中可以看出,只有這兩個(gè)文件上沒有標(biāo)注鑰匙,有鑰匙標(biāo)注的是不允許更改,也就是我們能更改就是這兩個(gè)文件。后面再分析這兩個(gè)文件。且走下一步。
編寫點(diǎn)燈程序
創(chuàng)建好工程后,開始編寫點(diǎn)燈程序了,與上篇博客一樣,直接貼上代碼:
#include "rtthread.h"
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
int main(){
GPIO_InitTypeDef gpioInit;
//打開GPIOB的時(shí)鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//LED上拉連接GPIOB 12引腳,所以設(shè)置如下,推挽輸出,Pin12,2MHz輸出速度
gpioInit.GPIO_Mode=GPIO_Mode_Out_PP;
gpioInit.GPIO_Pin=GPIO_Pin_12;
gpioInit.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOB,&gpioInit);
while(1){
//點(diǎn)亮LED
GPIO_ResetBits(GPIOB,GPIO_Pin_12);
//延時(shí)0.5s
rt_thread_delay(RT_TICK_PER_SECOND/2);
//關(guān)閉LED
GPIO_SetBits(GPIOB,GPIO_Pin_12);
//延時(shí)0.5s
rt_thread_delay(RT_TICK_PER_SECOND/2);
}
}
這樣編寫程序后,編譯通過,燒寫后卻發(fā)現(xiàn)LED根本無法按照預(yù)期進(jìn)行工作,這是因?yàn)槲覀冞€缺少工作沒有做。
打開board.c,可以看到它上面有幾句注釋,根據(jù)注釋,修改如下:
#include #include #include "stm32f10x_rcc.h" // rtthread tick configuration // 1. include header files // 2. configure rtos tick and interrupt // 3. add tick interrupt handler // rtthread tick configuration // 1. include some header file as need //#include #ifdef __CC_ARM extern int Image$$RW_IRAM1$$ZI$$Limit; #define HEAP_BEGIN (&Image$$RW_IRAM1$$ZI$$Limit) #elif __ICCARM__ #pragma section="HEAP" #define HEAP_BEGIN (__segment_end("HEAP")) #else extern int __bss_end; #define HEAP_BEGIN (&__bss_end) #endif #define SRAM_SIZE 8 #define SRAM_END (0x20000000 + SRAM_SIZE * 1024) /** * This function will initial STM32 board. */ void rt_hw_board_init() { // rtthread tick configuration // 2. Configure rtos tick and interrupt //SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND); SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND); /* Call components board initial (use INIT_BOARD_EXPORT()) */ #ifdef RT_USING_COMPONENTS_INIT rt_components_board_init(); #endif #if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE) rt_console_set_device(RT_CONSOLE_DEVICE_NAME); #endif #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP) rt_system_heap_init((void*)HEAP_BEGIN, (void*)SRAM_END); #endif } // rtthread tick configuration // 3. add tick interrupt handler // tickvoid SysTick_Handler(void) // { // /* enter interrupt */ // rt_interrupt_enter(); // // rt_tick_increase(); // // /* leave interrupt */ // rt_interrupt_leave(); // } void SysTick_Handler(void) { // /* enter interrupt */ rt_interrupt_enter(); // rt_tick_increase(); // // /* leave interrupt */ rt_interrupt_leave(); } 再次編譯,燒寫程序,LED開始閃爍。 RTT第一次分析 board.c修改后,程序就正常工作了??墒菫槭裁茨兀扛鶕?jù)經(jīng)驗(yàn)來說,C程序不是從main開始的么,board中的程序又是何時(shí)執(zhí)行的呢?在main中我們有死循環(huán),如果是從main開始執(zhí)行的,那么board.c的函數(shù)就絕對(duì)不可能執(zhí)行了。 為什么不是從main開始執(zhí)行的 Ctrl+F搜索rt_hw_board_init函數(shù)。發(fā)現(xiàn)他在components.c中的rtthread_startup調(diào)用,再搜索rtthread_startup結(jié)構(gòu)發(fā)現(xiàn)其調(diào)用如下: #if defined (__CC_ARM) extern int $Super$$main(void); /* re-define main function */ int $Sub$$main(void) { rt_hw_interrupt_disable(); rtthread_startup(); return 0; } #elif defined(__ICCARM__) extern int main(void); /* __low_level_init will auto called by IAR cstartup */ extern void __iar_data_init3( void ); int __low_level_init(void) { // call IAR table copy function. __iar_data_init3(); rt_hw_interrupt_disable(); rtthread_startup(); return 0; } #elif defined(__GNUC__) extern int main(void); /* Add -eentry to arm-none-eabi-gcc argument */ int entry(void) { rt_hw_interrupt_disable(); rtthread_startup(); return 0; } #endif 在上面預(yù)處理指令有三段,分別判斷三個(gè)宏是否被定義——__CC_ARM、__ICCARM__、__GNUC__,這三個(gè)是什么呢?如果全局搜索,會(huì)發(fā)現(xiàn)在core_cm3.h中它們出現(xiàn)很多次了。 ARM 系列目前支持三大主流的工具鏈,即ARM RealView (armcc), IAR EWARM (iccarm), and GNU Compler Collection (gcc),這三個(gè)就是用來指示當(dāng)前使用的是哪個(gè)工具鏈。因?yàn)槲覀兪褂玫木褪荝ealView(Keil)了。 可以看到$Super$$main和$Sub$$main,這又是什么呢? 在某些情況下,無法修改現(xiàn)有符號(hào),例如,由于符號(hào)位于外部庫或 ROM 代碼中。為了解決這個(gè)問題,Keil提供了使用 $Super$$ 和 $Sub$$ 模式來修補(bǔ)現(xiàn)有符號(hào)的方法。 $Super$$標(biāo)識(shí)的是原函數(shù), $Sub$$標(biāo)識(shí)的是新函數(shù)。上面的代碼就是它們用法的最好示例了。 extern int $Super$$main(void); /* re-define main function */ int $Sub$$main(void) { rt_hw_interrupt_disable(); rtthread_startup(); return 0; } 這樣,程序的執(zhí)行就不是從用戶寫的main方法開始了。而是從這個(gè)$Sub$$main(void)開始的了。 main是怎么執(zhí)行的 已經(jīng)知道了程序不是從main開始執(zhí)行的是RTT系統(tǒng)作的怪,那么用戶寫的main方法是何時(shí)執(zhí)行的呢?接著搜索$Super$$main,得到其調(diào)用如下: /* the system main thread */ void main_thread_entry(void *parameter) { extern int main(void); extern int $Super$$main(void); /* RT-Thread components initialization */ rt_components_init(); /* invoke system main function */ #if defined (__CC_ARM) $Super$$main(); /* for ARMCC. */ #elif defined(__ICCARM__) || defined(__GNUC__) main(); #endif } 接著搜索main_thread_entry得帶代碼如下: void rt_application_init(void) { rt_thread_t tid; #ifdef RT_USING_HEAP tid = rt_thread_create("main", main_thread_entry, RT_NULL, RT_MAIN_THREAD_STACK_SIZE, RT_THREAD_PRIORITY_MAX / 3, 20); RT_ASSERT(tid != RT_NULL); #else rt_err_t result; tid = &main_thread; result = rt_thread_init(tid, "main", main_thread_entry, RT_NULL, main_stack, sizeof(main_stack), RT_THREAD_PRIORITY_MAX / 3, 20); RT_ASSERT(result == RT_EOK); #endif rt_thread_startup(tid); } 從名字就可以看得出來,這是在造線程啊,查閱下rtthread的官方文檔果然如此。rt_application_init被rtthread_startup調(diào)用,然后它創(chuàng)建了一個(gè)線程,并在線程中調(diào)用了用戶定義的main函數(shù)。至此就真相大白了。RTT利用工具鏈提供的方式,替換掉了用戶的main,來啟動(dòng)操作系統(tǒng),并創(chuàng)建了一條線程,在線程中調(diào)用了用戶的main方法。 至此,RTT操作系統(tǒng)就已經(jīng)在STM32C8T6核心板上跑起來了。后續(xù)使用RTT操作系統(tǒng)得先看下官方文檔,然后在使用中實(shí)踐,在實(shí)踐中深入理解,以便更快更好的掌握RTT。
上一篇:STM32F103+RTT從零開始(一)——點(diǎn)亮LED
下一篇:STM32使用標(biāo)準(zhǔn)庫,有時(shí)候在SLEEP模式下無法喚醒問題
推薦閱讀
史海拾趣
設(shè)計(jì)資源 培訓(xùn) 開發(fā)板 精華推薦
- 基于單片機(jī)的LED自適應(yīng)調(diào)光系統(tǒng)
- 智能小車主控系統(tǒng)電路設(shè)計(jì)
- Microchip 升級(jí)數(shù)字信號(hào)控制器(DSC)產(chǎn)品線 推出PWM 分辨率和 ADC 速度業(yè)界領(lǐng)先的新器件
- 意法半導(dǎo)體STM32MP23x:突破成本限制的工業(yè)AI應(yīng)用核心
- 意法半導(dǎo)體推出用于匹配遠(yuǎn)距離無線微控制器STM32WL33的集成的匹配濾波芯片
- ESP32開發(fā)板連接TFT顯示屏ST7789跳坑記
- 如何讓ESP32支持analogWrite函數(shù)
- LGVL配合FreeType為可變字體設(shè)置字重-ESP32篇
- 使用樹莓派進(jìn)行 ESP32 Jtag 調(diào)試
- 威世推出適用于下一代電動(dòng)汽車?yán)鋮s系統(tǒng)的緊湊型熱敏電阻
- 通過vmRT-Thread和vSOME/IP支持車載SOA開發(fā)
- “唯算力論”是誤區(qū)!堆滿硬件也不一定靠譜!如何才能邁入自動(dòng)駕駛?
- 賦能工業(yè)視覺:Teledyne Bumblebee X 5GigE 立體視覺相機(jī)
- 這款“逆天”電池充滿電僅需18秒!背后藏著什么黑科技?
- 動(dòng)力電池的2025中場戰(zhàn)事
- 高算力支持下,端側(cè)AI模型能給座艙帶來哪些變化?
- Allotrope Energy開發(fā)超級(jí)電容器 使混合動(dòng)力應(yīng)用的性能提高一倍
- 福特汽車申請(qǐng)新專利 或?qū)⑴鋫淇梢苿?dòng)桌子的控制臺(tái)
- 長城汽車攜手南京藝術(shù)學(xué)院及超高清聯(lián)盟,共推車載音視頻技術(shù)革新
- 趣味電子技術(shù)史話之通信技術(shù)史——科技與人文的結(jié)合,傳奇故事在這里!
- TE 福利月|有獎(jiǎng)?wù){(diào)查、技術(shù)干貨、限時(shí)折扣
- 輕盈點(diǎn)擊間,掌閱無盡風(fēng)采!東芝PCIM在線展會(huì)和你不見不散!
- 看是德科技資料填調(diào)查問卷贏好禮
- 艾睿電子直播:聚焦“TI FPD-Link III 汽車芯片組” ,汽車視頻傳輸理想解決方案
- 有獎(jiǎng)活動(dòng):曬出你的電子心頭好
- 【 有獎(jiǎng)直播】 掌握潮流~TI DLP®技術(shù)在汽車上的創(chuàng)新及全新應(yīng)用
- TE有獎(jiǎng)直播:未來感知 由我先知-傳感器在物聯(lián)網(wǎng)中的最新應(yīng)用
- 是德科技有獎(jiǎng)直播:如何使用UXR系列高端示波器
- 招聘有感.
- 【MSP430 編譯器使用經(jīng)驗(yàn)】+將中斷向量表置于RAM中
- 使用protel dxp 時(shí)出現(xiàn) unkonwn pin
- 針對(duì)低功耗設(shè)備的功耗測試方法
- 進(jìn)不了環(huán)境,求助!?。?/span>
- 對(duì)于大學(xué)堂現(xiàn)有的TI 課程,大家有什么建議和意見呢?
- EEWORLD大學(xué)堂----電機(jī)控制
- 【CN0007】利用AD5380 DAC實(shí)現(xiàn)40通道可編程電壓及溫度漂移性能
- 請(qǐng)DSP大神指明路!關(guān)于6474
- TI能量收集方案:真正高效的納米級(jí)電源解決方案