前言
本教程是基于STM32F103RBT6基礎(chǔ)工程進(jìn)行移植,同系列的stm32同樣適用,只不過(guò)基礎(chǔ)工程要另外準(zhǔn)備,其中本教程使用到的基礎(chǔ)工程里面有個(gè)SYSTEM的文件夾(如果使用其他工程建議可以把該文件夾復(fù)制過(guò)去使用),里面的函數(shù)是由正點(diǎn)原子團(tuán)隊(duì)提供,這里也是參考原子出品的“STM32F1UCOS開發(fā)手冊(cè)”,想了解更加具體的教程可以自己去網(wǎng)上搜一下。這是stm32學(xué)習(xí)論壇,里面有豐富的學(xué)習(xí)資源。 本教程使用到的文件:工程文件與word; 訪問(wèn)密碼:912b(如果你準(zhǔn)備按照該教程進(jìn)行移植,開始之前請(qǐng)先下載該文件,鏈接失效可以評(píng)論回復(fù),看到后會(huì)處理)注意:請(qǐng)使用MDK5打開工程! 1、準(zhǔn)備工作 (1)stm32F103RBT6基礎(chǔ)工程:這里以跑馬燈為例 (2)UCOSII源碼:官網(wǎng)下載 (3)準(zhǔn)備文件:PORT和CONFIG 2、移植 (1)在基礎(chǔ)工程中建立新文件夾用來(lái)存放源碼:
(2)向三個(gè)文件夾添加UCOSII源碼,首先向CORE文件夾添加(UCOSII源碼):至于為什么不要那兩個(gè)文件,后續(xù)再談,先照著做。 然后向CONFIG文件夾添加文件:將“準(zhǔn)備工作”里面“必需文件”下的CONFIG全部復(fù)制到這里來(lái): 其中includes.h里面定義了一些頭文件,如圖,:

os_cfg.h主要用來(lái)配置和裁剪UCOSII的。 最后是向PORT文件夾添加文件,如上所述,直接將“必需文件”下的PORT直接復(fù)制過(guò)來(lái): 這里的文件是關(guān)鍵,移植需要修改幾乎都在這里,因?yàn)檫@里PORT下的文件已經(jīng)是修改好的,下一步添加到工程時(shí)不用再修改就能在stm32上跑,這里后續(xù)再講,先移植好一個(gè)成功的工程先。
(3)配置工程
a 我們打開基礎(chǔ)工程,將UCOSII添加到工程里面:


 添加成功后:  別忘了添加路徑: b 編譯工程,處理錯(cuò)誤 上面步驟成功之后,現(xiàn)在可以編譯工程了, 提示打不開“app_cfg.h”文件,跟蹤錯(cuò)誤: 再重新編譯一下, 發(fā)現(xiàn)錯(cuò)誤,重復(fù)定義了,我們stm32f10x_it.h里面的注釋掉: 這時(shí)候編譯,發(fā)現(xiàn)工程已經(jīng)沒有錯(cuò)誤了,因?yàn)槲覀兪且昧苏c(diǎn)原子提供的system函數(shù),所以還要按照他們的規(guī)則去修改一下一些文件。 c 修改sys.h頭文件 打開sys.h:  因?yàn)?/font> system 里面的文件適用于裸板也適用移植了操作系統(tǒng)的,所以宏定義要按需更改。 再編譯,提示 ”TRUE” 沒有定義,把 ”TRUE” 改為“ OS_TRUE ”,再編譯: 同理,將stm32f10x.h里面的注釋掉:

再編譯,這時(shí)候發(fā)現(xiàn)已經(jīng)沒有錯(cuò)誤了: 如果還有錯(cuò)誤,請(qǐng)根據(jù)錯(cuò)誤提示自行解決。 如此,UCOSII就已經(jīng)移植完成了,下面寫個(gè)個(gè)測(cè)試程序看看能不能成功即可。 d 測(cè)試是否移植成功, 程序:(將下面代碼直接復(fù)制到main函數(shù)里面,原先的都刪掉,編譯,下載驗(yàn)證,如果LED0和LED1以不同的頻率閃爍說(shuō)明移植成功) #include"led.h" #include"delay.h" #include"sys.h" #include"usart.h" #include"includes.h" //開始任務(wù) #defineSTART_TASK_PRIO 10 #defineSTART_STK_SIZE 128 OS_STKSTART_TASK_STK[START_STK_SIZE]; void start_task(void*pdata); //LED0任務(wù) #defineLED0_TASK_PRIO 7 #defineLED0_STK_SIZE 64 OS_STKLED0_TASK_STK[LED0_STK_SIZE]; void led0_task(void*pdata); //LED1任務(wù) #defineLED1_TASK_PRIO 6 #defineLED1_STK_SIZE 64 OS_STKLED1_TASK_STK[LED1_STK_SIZE]; void led1_task(void*pdata); intmain(void) { delay_init(); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); uart_init(115200); LED_Init(); OSInit(); //UCOSII初始化 OSTaskCreate(start_task,(void*)0,(OS_STK*)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO);//創(chuàng)建開始任務(wù) OSStart(); //系統(tǒng)啟動(dòng) } void start_task(void*pdata) { OS_CPU_SRcpu_sr=0; pdata=pdata; OSStatInit(); OS_ENTER_CRITICAL(); //臨界 OSTaskCreate(led0_task,(void*)0,(OS_STK*)&LED0_TASK_STK[LED0_STK_SIZE-1],LED0_TASK_PRIO);//創(chuàng)建LED0任務(wù) OSTaskCreate(led1_task,(void*)0,(OS_STK*)&LED1_TASK_STK[LED1_STK_SIZE-1],LED1_TASK_PRIO);//創(chuàng)建LED1任務(wù) OSTaskSuspend(START_TASK_PRIO);//開始任務(wù)掛起 OS_EXIT_CRITICAL(); } //LED0任務(wù) void led0_task(void*pdata) { while(1) { GPIO_ResetBits(GPIOA,GPIO_Pin_8); delay_ms(80); GPIO_SetBits(GPIOA,GPIO_Pin_8); delay_ms(80); } } //LED1任務(wù) void led1_task(void*pdata) { while(1) { GPIO_ResetBits(GPIOD,GPIO_Pin_2); delay_ms(300); GPIO_SetBits(GPIOD,GPIO_Pin_2); delay_ms(300); } }
3 移植過(guò)程講解 (1)如果參考上面的步驟你已經(jīng)完成了系統(tǒng)的移植的話,接下來(lái)講解一下移植過(guò)程中主要需要修改的文件,首先是os_cpu_a.asm,前面已經(jīng)說(shuō)過(guò)這些需要修改的文件都是官方提供的代碼,我們只需要根據(jù)自身的硬件體系結(jié)構(gòu)進(jìn)行修改即可: os_cpu_a.asm主要是一些匯編代碼,我們?cè)诠こ讨写蜷_,主要關(guān)注的是這幾個(gè)函數(shù): EXPORT的意思這些函數(shù)在本文件定義供其他文件調(diào)用。
a OSStartHighRdy函數(shù)
OSStartHighRdy是由OSStart()函數(shù)調(diào)用的,這是第一個(gè)任務(wù),用來(lái)開啟多任務(wù),多任務(wù)開啟失敗的話調(diào)用OSStartHang函數(shù)。需要移植的原因是這里的寄存器都要根據(jù)STM32的結(jié)構(gòu)來(lái)進(jìn)行修改,這里已經(jīng)是修改好了的。
bOSCtxSw函數(shù)和OSIntCtxSw函數(shù)
兩個(gè)函數(shù)都是用來(lái)做任務(wù)切換,區(qū)別在于OSCtxSw是任務(wù)級(jí),OSIntCtxSw是中斷級(jí)切換。OSCtxSw函數(shù)在 OSSched函數(shù)中負(fù)責(zé)保存當(dāng)前任務(wù)對(duì)應(yīng)的處理器寄存器到堆棧中,并將任務(wù)中需要恢復(fù)的處理器寄存器從堆棧中恢復(fù)出來(lái)。OSIntCtxSw函數(shù)主要保存當(dāng)前任務(wù)堆棧指針,并將新任務(wù)對(duì)應(yīng)的處理器寄存器從堆棧中恢復(fù)出來(lái)。
 這里也是已經(jīng)移植好了的。其他的都可以暫時(shí)先不用理會(huì)。
(2)移植os_cpu.h
os_cpu.h主要定義了一些數(shù)據(jù)類型,μCOS-II為了保證可移植性,程序中沒有直接使用 int,unsignedint 等定義,而是自己定義了一套數(shù)據(jù)類型,如 INT16U 表示 16 位無(wú)符號(hào)整型,對(duì)于 STM32 這樣的 32 位內(nèi)核,INT16U 是unsigned short型,如果是16位的處理器,則是unsignedint型。如圖示:
這里尤其注意OS_STK類型,這里是32位的。
接下來(lái)是定義棧的增長(zhǎng)方向,CM3棧是由高地址向低地址增長(zhǎng)的,
定義 OS_TASK_SW 宏。OS_TASK_SW 宏是 uC/OS-II 從低優(yōu)先級(jí)任務(wù)切換到高優(yōu)先級(jí)任務(wù)時(shí)的調(diào)用,可以采用下面兩種方式定義:如果處理器支持軟中斷,可以使用軟中斷將中斷向量指向OSCtxSw 函數(shù);
不同的硬件的位數(shù)不一樣,棧的增長(zhǎng)方向也不一樣,自然都要修改。
(3)移植os_cpu_c.c文件
os_cpu_c.c 主要定義了系統(tǒng)需要的鉤子函數(shù),其中必須需要移植的是OSTaskStkInit函數(shù),這個(gè)函數(shù)在任務(wù)創(chuàng)建時(shí)被調(diào)用,它負(fù)責(zé)初始化任務(wù)的堆棧結(jié)構(gòu),其他的鉤子函數(shù)可以暫時(shí)不用理會(huì),有興趣的可以自行了解。
堆棧初始化函數(shù)OSTaskStkInit是由任務(wù)創(chuàng)建函數(shù)OSTaskCreate()和OSTaskCreateExt()這兩個(gè)函數(shù)調(diào)用,用于在創(chuàng)建任務(wù)的時(shí)候初始堆棧,從上面的代碼中可以看出就是在任務(wù)堆棧中保存寄存器的值。
這里要注意一下入棧順序,要根據(jù)CM3的體系,其中CM3硬件會(huì)自動(dòng)將FPSCR、XPSR、PC、LR、R12、R0-R3入棧,入棧順序遵照Stackframe,剩下的R4-R11需要手動(dòng)入棧。
移植UCOSII到stm32三個(gè)文件改動(dòng)基本不大,主要是OS_CPU_A.ASM需要改動(dòng),其他的都是默認(rèn)和CM3的體系相近,不用做出大的改動(dòng)即可移植成功。
至此,UCOSII移植就已經(jīng)全部完成了。
本教程主要是為了對(duì)系統(tǒng)移植的過(guò)程有個(gè)大概了解,其中的細(xì)節(jié)沒有進(jìn)行分析,因技術(shù)水平有限,有錯(cuò)漏之處歡迎指出或有更好的學(xué)習(xí)建議也希望可以回復(fù)交流,共同學(xué)習(xí)、進(jìn)步。
謝謝!
|