公司項(xiàng)目原先使用μCOS-II,但是μCOS存在商業(yè)使用付費(fèi)問題,故而我們轉(zhuǎn)向用國產(chǎn)開源免費(fèi)RTOS RT-Thread替代,花了一天半的時(shí)間將原來的μCOS代碼移植到了RT-Thread上面。下面分移植方法和API對應(yīng)表兩部分講下方法。
一、移植方法
軟件環(huán)境:Win7+MDK5.18.0
1.從GitHub下載RT-Thread源碼:https://github.com/RT-Thread/rt-thread;
2.將1步驟下載的源碼打開,目錄如下:
其中bsp目錄下面,可以看到很多開發(fā)板工程目錄,如下圖:
項(xiàng)目主控是stm32f1系列的,選擇stm32f10x這個(gè)目錄下的工程作為基礎(chǔ)版本。
3.基礎(chǔ)工程框架下,將我們原有的工程文件添加進(jìn)來,除去μCOS-II相關(guān)源碼。
原來基于μCOS-II的相關(guān)源碼目錄如下:
os_cfg.h
:μCOS-II系統(tǒng)相關(guān)的一些宏開關(guān)定義(如是否使能事件、mailbox、信號(hào)量及隊(duì)列等)、系統(tǒng)參數(shù)定義(如每秒tick數(shù)、任務(wù)棧大小定義等),對應(yīng)RT-Thread里面的rtconfig.h
。
這個(gè)目錄下面是與處理器相關(guān)的代碼,os_cpu_a.asm
文件通過Thumb2
指令實(shí)現(xiàn)的一些中斷服務(wù)函數(shù)等,例如voidOS_CPU_PendSVHandler(void)
處理上下文切換異常等;對應(yīng)到RT-Thread里面的context_rvds.S
這個(gè)文件。os_cpu_c.c
文件實(shí)現(xiàn)任務(wù)棧初始化和一些鉤子函數(shù)(如空閑任務(wù)和systick等),對應(yīng)到RT-Thread里面的cpuport.c
。
需要說明的是啟動(dòng)文件context_rvds.S
里面定義了兩個(gè)中斷服務(wù)函數(shù)跟stm32f10x_it.c
里面是重復(fù)的,分別是HardFault_Handler
和PendSV_Handler
,移植的時(shí)候需要屏蔽掉stm32f10x_it.c
里面相應(yīng)的部分。
這個(gè)目錄下是與處理器無關(guān)的文件,對應(yīng)RT-Thread根目錄下src里面的內(nèi)容。
在移植的時(shí)候,先將以上與μCOS-II相關(guān)的源碼全部刪除,把我們工程其他源碼放在\bsp\stm32f10x\src
這個(gè)路徑下,keil工程建立在\bsp\stm32f10x
這里。
Keil工程目錄如下:
-
Startup
目錄下是stm32和RT-Thread的啟動(dòng)文件,主要是中斷向量表及中斷服務(wù)函數(shù)定義,堆棧和PC指針的相關(guān)初始化。 -
USER
目錄下是我們的產(chǎn)品業(yè)務(wù)實(shí)現(xiàn)相關(guān)文件,包括main.c
文件。 -
RTT
目錄下是RT-Thread源碼,就是RT-Thread根目錄下src
里面的內(nèi)容。
4.使用RTT的接口修改掉原來的一些系統(tǒng)調(diào)用,具體如下:
-
單純地替換接口是比較容易的(詳見后面API對應(yīng)表),只是在移植的過程中需要了解μCOS-II和RT-Thread在工程涉及的部分存在哪些差異,并按照RT-Thread的方式來更新這些地方。例如
uart
的使用,以及系統(tǒng)的啟動(dòng)過程等。 -
說明一下
uart
驅(qū)動(dòng)的移植,涉及到兩個(gè)驅(qū)動(dòng)文件:usart.c
和serail.c
;在serail.c
中定義了初始化、打開設(shè)備、數(shù)據(jù)收發(fā)等接口,由于接口中都是動(dòng)態(tài)分配緩存的(rtconfig.h
里面可以配置系統(tǒng)是否使用動(dòng)態(tài)分配內(nèi)存,但是關(guān)掉這個(gè)宏之后serail.c
中相關(guān)接口會(huì)報(bào)錯(cuò),因?yàn)楹瘮?shù)定義被屏蔽掉了),所以需要打開RT_USING_HEAP
這個(gè)宏定義。打開這個(gè)宏之后,我們來看看系統(tǒng)啟動(dòng):-
startup_stm32f10x_hd.s
中在
SystemInit()
中初始化時(shí)鐘頻率中斷向量表位置等。 -
components.c
中rtthread_startup()
啟動(dòng)RT-Thread。 -
詳細(xì)看看
rtthread_startup()
里面的工作:rt_hw_board_init()
板子初始化工作;rt_show_version()
顯示版本信息;rt_system_timer_init()
定時(shí)器初始化;rt_system_scheduler_init()
任務(wù)調(diào)度器初始化;rt_application_init()
用戶自定義的任務(wù);rt_system_timer_thread_init()
定時(shí)器線程初始化;rt_thread_idle_init()
空閑任務(wù)初始化;rt_system_scheduler_start()
開始任務(wù)調(diào)度;
-
任務(wù)調(diào)度開始之后,OS就啟動(dòng)好了,之后程序都在OS的管理下運(yùn)行了。
-
接著說uart驅(qū)動(dòng),因?yàn)榇蜷_了
RT_USING_HEAP
,我們需要對系統(tǒng)堆進(jìn)行初始化:rt_system_heap_init((void*)HEAP_BEGIN,(void*)SRAM_END);//其中HEAP_BEGIN為堆起始地址,SRAM_END為結(jié)束地址
根據(jù)自己的MCU進(jìn)行定義:
這樣定義heap
范圍應(yīng)將startup_stm32f10x_hd.s
中heap size
改為0。
-
然后是uart硬件層初始化
rt_hw_usart_init();//注冊設(shè)備(uart1~uart5)
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);//使能RT_CONSOLE_DEVICE_NAME//這個(gè)宏定義的uart口打印。
-
采用輪詢方式發(fā)送,中斷方式接收數(shù)據(jù)
5. 任務(wù)的創(chuàng)建與刪除
RT-Thread的任務(wù)管理分靜態(tài)方法和動(dòng)態(tài)方法,靜態(tài)方法:
只能調(diào)用靜態(tài)方法刪除任務(wù):
動(dòng)態(tài)方法:
只能調(diào)用動(dòng)態(tài)方法刪除任務(wù):
rt_err_t rt_thread_delete(rt_thread_tthread);
其他諸如SPI等驅(qū)動(dòng)及事件、信號(hào)量等處理不再贅述。
二、μCOS-II與RT-Thread API對應(yīng)表:(左側(cè)μCOS-Ⅱ,右側(cè)RT-Thread)
任務(wù)創(chuàng)建與刪除:
OSInit(&err);初始化μC/OS-Ⅱ,對這個(gè)函數(shù)的調(diào)用必須在調(diào)用OSStart()函數(shù)之前。 |
分動(dòng)態(tài)和靜態(tài)方法, 動(dòng)態(tài)方法: rt_thread_create(); rt_thread_delete(); 靜態(tài)方法: rt_thread_init(); rt_thread_detach(); |
OSTaskCreate(); OSTaskDel(); |
|
OSStart();真正開始運(yùn)行多任務(wù)。 |
rt_thread_startup(tid); |
任務(wù)掛起與恢復(fù)
OSTaskSuspend(); |
rt_thread_suspend(tid); |
OSTaskResume (); |
rt_thread_resume (tid); |
操作系統(tǒng)進(jìn)入/退出“臨界區(qū)”的功能代碼:
OS_ENTER_CRITICAL(); |
rt_enter_critical (); |
OS_EXIT_CRITICAL(); |
rt_exit_critical (); |
ENTER ISR
OSIntEnter (); |
rt_interrupt_enter(); |
OSIntExit (); |
rt_interrupt_leave(); |
任務(wù)優(yōu)先級(jí):
μC/OS-Ⅱ和RT-Thread都是值越小優(yōu)先級(jí)越高,但優(yōu)先級(jí)數(shù)不同,μC/OS-Ⅱ支持最多64級(jí),RT-Thread支持最多256級(jí)。
任務(wù)延時(shí):
OSTimeDly();延時(shí)ticks |
rt_thread_delay ();延時(shí)ticks |
OSTimeDlyHMSM ();延時(shí)(時(shí) 分 秒 毫秒) |
事件:
μC/OS-Ⅱ
功能 |
信號(hào)量 |
互斥信號(hào)量 |
事件標(biāo)志組 |
消息郵箱 |
消息隊(duì)列 |
建立事件 |
OSSemCreate(); |
OSMutexCreate(); |
OSFlagCreate(); |
OSMboxCreate(); |
OSQCreate(); |
刪除事件 |
OSSemDel (); |
OSMutexDel (); |
OSFlagDel (); |
OSMboxDel (); |
OSQDel (); |
等待事件 |
OSSemPend(); |
OSMutexPend(); |
OSFlagPend(); |
OSMboxPend(); |
OSQPend(); |
發(fā)送事件 |
OSSemPost(); |
OSMutexPost(); |
OSFlagPost(); |
OSMboxPost(); |
OSQPost(); |
無等待獲得事件 |
OSSemAccept(); |
OSMutexAccept(); |
OSFlagAccept(); |
OSMboxAccept(); |
OSQAccept(); |
查詢事件狀態(tài) |
OSSemQuery(); |
OSMutexQuery(); |
OSFlagQuery(); |
OSMboxQuery(); |
OSQQuery(); |
RT-Thread
功能 |
信號(hào)量 |
互斥信號(hào)量 |
事件標(biāo)志組 |
消息郵箱 |
消息隊(duì)列 |
建立事件 |
靜態(tài)方法: rt_sem_init(); 動(dòng)態(tài)方法: rt_sem_create(); |
靜態(tài)方法: rt_mutex_init (); 動(dòng)態(tài)方法: rt_mutex_create (); |
靜態(tài)方法: rt_event_init (); 動(dòng)態(tài)方法: rt_event_create (); |
靜態(tài)方法: rt_mb_init (); 動(dòng)態(tài)方法: rt_mb_create (); |
靜態(tài)方法: rt_mq_init (); 動(dòng)態(tài)方法: rt_mq_create (); |
刪除事件 |
靜態(tài)方法: rt_sem_detach(); 動(dòng)態(tài)方法: rt_sem_delete(); |
靜態(tài)方法: rt_mutex_detach (); 動(dòng)態(tài)方法: rt_mutex_delete (); |
靜態(tài)方法: rt_event_detach (); 動(dòng)態(tài)方法: rt_event_delete (); |
靜態(tài)方法: rt_mb_detach (); 動(dòng)態(tài)方法: rt_mb_delete (); |
靜態(tài)方法: rt_mq_detach (); 動(dòng)態(tài)方法: rt_mq_delete (); |
等待事件 |
rt_sem_take(); |
rt_mutex_take(); |
rt_event_recv(); |
rt_mb_recv(); |
rt_mq_recv(); |
發(fā)送事件 |
rt_sem_release(); |
rt_mutex_release(); |
rt_event_send(); |
rt_mb_send_wait(); |
rt_mq_send(); rt_mq_urgent(); |
無等待獲得事件 |
rt_sem_trytake(); |
rt_mb_send(); |
|||
查詢事件狀態(tài) |
|||||
其他 |
rt_sem_control(); 執(zhí)行cmd,目前函數(shù)里面只有一個(gè)RT_IPC_CMD_RESET實(shí)現(xiàn) |
rt_mutex_control(); 目前函數(shù)直接返回err: return -RT_ERROR; |
rt_event_control(); 執(zhí)行cmd,目前函數(shù)里面只有一個(gè)RT_IPC_CMD_RESET實(shí)現(xiàn) |
rt_mb_control(); 執(zhí)行cmd,目前函數(shù)里面只有一個(gè)RT_IPC_CMD_RESET實(shí)現(xiàn) |
rt_mq_control(); 執(zhí)行cmd,目前函數(shù)里面只有一個(gè)RT_IPC_CMD_RESET實(shí)現(xiàn) |
整個(gè)移植過程就這樣,最后談下RT-Thread。
接觸RT-Thread之后,個(gè)人還是蠻喜歡的,入門很快,編碼風(fēng)格很好。它是一個(gè)分層的操作系統(tǒng),有豐富的系統(tǒng)組件,例如LwIP輕型TCP/IP協(xié)議棧、文件系統(tǒng)等,使用方便。
開發(fā)過程中對RT-Thread與μCOS最大的不同體驗(yàn)一個(gè)是在RT-Thread中的靜態(tài)和動(dòng)態(tài)方法的區(qū)分,另一個(gè)是內(nèi)存安全性方面。以前項(xiàng)目跑在μCOS上很多double free的問題,μCOS不做任何警告,完全看不出來有什么問題,只是時(shí)間久了,系統(tǒng)復(fù)位;移植到RT-Thread上之后double free系統(tǒng)會(huì)assert,一次性解決了好些bug。
-
嵌入式
+關(guān)注
關(guān)注
5068文章
19021瀏覽量
303317 -
RT-Thread
+關(guān)注
關(guān)注
31文章
1273瀏覽量
39924
原文標(biāo)題:【周四RTOS專欄】一個(gè)美女程序員的μCOS-Ⅱ到RT-Thread移植筆記?
文章出處:【微信號(hào):elecfans,微信公眾號(hào):電子發(fā)燒友網(wǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評(píng)論請先 登錄
相關(guān)推薦
評(píng)論