1.1 前后臺系統(tǒng):
早期嵌入式開發(fā)沒有嵌入式操作系統(tǒng)的概念 ,直接操作裸機,在裸機上寫程序,比如用51單片機基本就沒有操作系統(tǒng)的概念。通常把程序分為兩部分:前臺系統(tǒng)和后臺系統(tǒng)。
簡單的小系統(tǒng)通常是前后臺系統(tǒng),這樣的程序包括一個死循環(huán)和若干個中斷服務程序:應用程序是一個無限循環(huán),循環(huán)中調用API函數(shù)完成所需的操作,這個大循環(huán)就叫做后臺系統(tǒng)。中斷服務程序用于處理系統(tǒng)的異步事件,也就是前臺系統(tǒng)。前臺是中斷級,后臺是任務級。
1.2 RTOS系統(tǒng):
RTOS全稱為:Real Time OS,就是實時操作系統(tǒng),強調的是:實時性。實時操作系統(tǒng)又分為硬實時和軟實時。硬實時要求在規(guī)定的時間內必須完成操作 ,硬實時系統(tǒng)不允許超時,在軟實時里面處理過程超時的后果就沒有那么嚴格。
在實時操作系統(tǒng)中,我們可以把要實現(xiàn)的功能劃分為多個任務,每個任務負責實現(xiàn)其中的一部分,每個任務都是一個很簡單的程序,通常是一個死循環(huán)。
RTOS操作系統(tǒng):FreeRTOS,UCOS,RTX,RT-Thread,DJYOS等。
RTOS操作系統(tǒng)的核心內容在于:實時內核。
可剝奪型內核:
RTOS的內核負責管理所有的任務,內核決定了運行哪個任務,何時停止當前任務切換到其他任務,這個是內核的多任務管理能力。多任務管理給人的感覺就好像芯片有多個CPU,多任務管理實現(xiàn)了CPU資源的最大化利用,多任務管理有助于實現(xiàn)程序的模塊化開發(fā),能夠實現(xiàn)復雜的實時應用。
RTOS中的經(jīng)典代表作:FreeRTOS,而FreeOS的內核是可剝奪型的,所以我們簡單提一下什么是可剝奪型內核,關于FreeRTOS內核的詳細內容我們會在后續(xù)的視頻中專門講解的。
可剝奪內核顧名思義就是可以剝奪其他任務的CPU使用權,它總是運行就緒任務中的優(yōu)先級最高的那個任務。
2.1 FreeRTOS系統(tǒng)簡介:
FreeRTOS是一個可裁剪、可剝奪型的多任務內核,而且沒有任務數(shù)限制。FreeRTOS提供了實時操作系統(tǒng)所需的所有功能,包括資源管理、同步、任務通信等。
FreeRTOS是用C和匯編來寫的,其中絕大部分都是用C語言編寫的,只有極少數(shù)的與處理器密切相關的部分代碼才是用匯編寫的,F(xiàn)reeRTOS結構簡潔,可讀性很強!最主要的是非常適合初次接觸嵌入式實時操作系統(tǒng)學生、嵌入式系統(tǒng)開發(fā)人員和愛好者學習。
為什么學FreeRTOS
1、因為FreeROTS開源。
2、FreeRTOS免費
3、FreeRTOS是很多第三方組件欽定的系統(tǒng)!
2.2 FreeRTOS相關資料查找:
1、FreeRTOS官網(wǎng):http://www.freertos.org/。
2、開源電子網(wǎng):www.openedv.com。
3、其他論壇。
FreeRTOS 移植
2.2.1 向工程中添加相應文件
1、添加FreeRTOS 源碼
在基礎工程中新建一個名為FreeRTOS 的文件夾,如圖2.2.1.1 所示:
創(chuàng)建FreeRTOS 文件夾以后就可以將FreeRTOS 的源碼添加到這個文件夾中,添加完以后如圖2.2.1.2 所示:
在1.3.2 小節(jié)中詳細的講解過portable 文件夾,我們只需要留下keil、MemMang 和RVDS這三個文件夾,其他的都可以刪除掉,完成以后如圖2.2.1.3 所示:
2、向工程分組中添加文件
打開基礎工程,新建分組FreeRTOS_CORE 和FreeRTOS_PORTABLE,然后向這兩個分組中添加文件,如圖2.2.1.4 所示:
分組FreeRTOS_CORE 中的文件在什么地方就不說了,打開FreeRTOS 源碼一目了然。重點來說說FreeRTOS_PORTABLE 分組中的port.c 和heap_4.c 是怎么來的,port.c 是RVDS 文件夾下的ARM_CM3 中的文件,因為STM32F103 是Cortex-M3 內核的,因此要選擇ARM_CM3中的port.c 文件。heap_4.c 是MemMang 文件夾中的,前面說了MemMang 是跟內存管理相關
的,里面有5 個c 文件:heap_1.c、heap_2.c、heap_3.c、heap_4.c 和heap_5.c。這5 個c 文件是五種不同的內存管理方法,就像從北京到上海你可以坐火車、坐飛機,如果心情好的話也可以走路,反正有很多種方法,只要能到上海就行。這里也一樣的,這5 個文件都可以用來作為FreeRTOS 的內存管理文件,只是它們的實現(xiàn)原理不同,各有利弊。這里我們選擇heap_4.c,至于原因,后面會有一章節(jié)專門來講解FreeRTOS 的內存管理,到時候大家就知道原因了。這里就先選擇heap_4.c,畢竟本章的重點是FreeRTOS 的移植。
3、添加相應的頭文件路徑
添加完FreeRTOS 源碼中的C 文件以后還要添加FreeRTOS 源碼的頭文件路徑,頭文件路徑如圖2.2.1.5 所示:
頭文件路徑添加完成以后編譯一下,看看有沒有什么錯誤,結果會發(fā)現(xiàn)提示打不開“FreeRTOSConfig.h”這個文件,如圖2.2.1.6 所示:
這是因為缺少FreeRTOSConfig.h 文件,這個文件在哪里找呢?你可以自己創(chuàng)建,顯然這不是一個明智的做法。我們可以找找FreeRTOS 的官方移植工程中會不會有這個文件,打開FreeRTOS 針對STM32F103 的移植工程文件,文件夾是CORTEX_STM32F103_Keil,打開以后如圖2.2.1.7 所示:
果然!官方的移植工程中有這個文件,我們可以使用這個文件,但是建議大家使用我們例程中的FreeRTOSConf.h 文件,這個文件是FreeRTOS 的系統(tǒng)配置文件,不同的平臺其配置不同,但是我們提供的例程中的這個文件肯定是針對ALIENTEK 開發(fā)板配置正確的。這個文件復制到什么地方大家可以自行決定,這里我為了方便放到了FreeRTOS 源碼中的include 文件夾下。FreeRTOSConfig.h 是何方神圣?看名字就知道,他是FreeRTOS 的配置文件,一般的操作系統(tǒng)都有裁剪、配置功能,而這些裁剪及配置都是通過一個文件來完成的,基本都是通過宏定義來完成對系統(tǒng)的配置和裁剪的,關于FreeRTOS 的配置文件FreeRTOSConfig.h 后面也會有一章節(jié)來詳細的講解。到這里我們再編譯一次,沒有錯誤!如圖2.2.1.8 所示:
如果還有錯誤的話大家自行根據(jù)錯誤類型查找和修改錯誤!
2.2.2 修改SYSTEM 文件
SYSTEM 文件夾里面的文件一開始是針對UCOS 而編寫的,所以如果使用FreeRTOS 的話就需要做相應的修改。本來打算讓SYSTEM 文件夾也支持FreeRTOS,但是這樣的話會導致SYSTEM 里面的文件太過于復雜,這樣非常不利于初學者學習,所以這里就專門針對FreeRTOS修改了SYSTEM 里面的文件。
1、修改sys.h 文件
sys.h 文件修改很簡單,在sys.h 文件里面用宏SYSTEM_SUPPORT_OS 來定義是否使用OS,我們使用了FreeRTOS,所以應該將宏SYSTEM_SUPPORT_OS 改為1。
//0,不支持os
//1,支持os
#define SYSTEM_SUPPORT_OS 1 //定義系統(tǒng)文件夾是否支持OS
2、修改usart.c 文件
usart.c 文件修改也很簡單,usart.c 文件有兩部分要修改,一個是添加FreeRTOS.h 頭文件,默認是添加的UCOS 中的includes.h 頭文件,修改以后如下:
//如果使用os,則包括下面的頭文件即可.
#if SYSTEM_SUPPORT_OS
#include "FreeRTOS.h" //os 使用
#endif
另外一個就是USART1 的中斷服務函數(shù),在使用UCOS 的時候進出中斷的時候需要添加OSIntEnter()和OSIntExit(),使用FreeRTOS 的話就不需要了,所以將這兩行代碼刪除掉,修改以后如下:
void USART1_IRQHandler(void) //串口1 中斷服務程序
{
u8 Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
Res =USART_ReceiveData(USART1); //讀取接收到的數(shù)據(jù)
if((USART_RX_STA&0x8000)==0) //接收未完成
{
if(USART_RX_STA&0x4000) //接收到了0x0d
{
if(Res!=0x0a)USART_RX_STA=0; //接收錯誤,重新開始
else USART_RX_STA|=0x8000; //接收完成了
}
else //還沒收到0X0D
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;
}
}
}
}
}
3、修改delay.c 文件
delay.c 文件修改的就比較大了,因為涉及到FreeRTOS 的系統(tǒng)時鐘,delay.c 文件里面有4個函數(shù),先來看一下函數(shù)SysTick_Handler(),此函數(shù)是滴答定時器的中斷服務函數(shù),代碼如下:
extern void xPortSysTickHandler(void);
//systick 中斷服務函數(shù),使用OS 時用到
void SysTick_Handler(void)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系統(tǒng)已經(jīng)運行
{
xPortSysTickHandler();
}
}
FreeRTOS 的心跳就是由滴答定時器產(chǎn)生的,根據(jù)FreeRTOS 的系統(tǒng)時鐘節(jié)拍設置好滴答定時器的周期,這樣就會周期觸發(fā)滴答定時器中斷了。在滴答定時器中斷服務函數(shù)中調用FreeRTOS 的API 函數(shù)xPortSysTickHandler()。delay_init()是用來初始化滴答定時器和延時函數(shù),代碼如下:
//初始化延遲函數(shù)
//SYSTICK 的時鐘固定為AHB 時鐘,基礎例程里面SYSTICK 時鐘頻率為AHB/8
//這里為了兼容FreeRTOS,所以將SYSTICK 的時鐘頻率改為AHB 的頻率!
//SYSCLK:系統(tǒng)時鐘頻率
void delay_init()
{
u32 reload;
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);//選擇外部時鐘 HCLK
fac_us=SystemCoreClock/1000000; //不論是否使用OS,fac_us 都需要使用
reload=SystemCoreClock/1000000; //每秒鐘的計數(shù)次數(shù) 單位為M
reload*=1000000/configTICK_RATE_HZ; //根據(jù)configTICK_RATE_HZ 設定溢出
//時間reload 為24 位寄存器,最大值:
//16777216,在72M 下,約合0.233s 左右
fac_ms=1000/configTICK_RATE_HZ; //代表OS 可以延時的最少單位
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //開啟SYSTICK 中斷
SysTick->LOAD=reload; //每1/configTICK_RATE_HZ 秒中斷
//一次
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //開啟SYSTICK
}
前面我們說了FreeRTOS 的系統(tǒng)時鐘是由滴答定時器提供的,那么肯定要根據(jù)FreeRTOS 的系統(tǒng)時鐘節(jié)拍來初始化滴答定時器了,delay_init()就是來完成這個功能的。FreeRTOS 的系統(tǒng)時鐘節(jié)拍由宏configTICK_RATE_HZ 來設置,這個值我們可以自由設置,但是一旦設置好以后我們就要根據(jù)這個值來初始化滴答定時器,其實就是設置滴答定時器的中斷周期。在基礎例程中滴答定時器的時鐘頻率設置的是AHB 的1/8,這里為了兼容FreeRTOS 將滴答定時器的時鐘頻率改為了AHB,也就是72MHz!這一點一定要注意!接下來的三個函數(shù)都是延時的,代碼如下:
//延時nus
//nus:要延時的us 數(shù).
//nus:0~204522252(最大值即2^32/fac_us@fac_us=168)
void delay_us(u32 nus)
{
u32 ticks;
u32 told,tnow,tcnt=0;
u32 reload=SysTick->LOAD; //LOAD 的值
ticks=nus*fac_us; //需要的節(jié)拍數(shù)
told=SysTick->VAL; //剛進入時的計數(shù)器值
while(1)
{
tnow=SysTick->VAL;
if(tnow!=told)
{
//這里注意一下SYSTICK 是一個遞減的計數(shù)器就可以了.
if(tnow told=tnow; if(tcnt>=ticks)break; //時間超過/等于要延遲的時間,則退出. } }; } //延時nms,會引起任務調度 //nms:要延時的ms 數(shù) //nms:0~65535 void delay_ms(u32 nms) { if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系統(tǒng)已經(jīng)運行 { if(nms>=fac_ms) //延時的時間大于OS 的最少時間周期 { vTaskDelay(nms/fac_ms); //FreeRTOS 延時 } nms%=fac_ms; //OS 已經(jīng)無法提供這么小的延時了, //采用普通方式延時 } delay_us((u32)(nms*1000)); //普通方式延時 } //延時nms,不會引起任務調度 //nms:要延時的ms 數(shù) void delay_xms(u32 nms) { u32 i; for(i=0;i delay_us()是us 級延時函數(shù),delay_ms 和delay_xms()都是ms 級的延時函數(shù),delay_us()和delay_xms()不會導致任務切換。delay_ms()其實就是對FreeRTOS 中的延時函數(shù)vTaskDelay()的簡單封裝,所以在使用delay_ms()的時候就會導致任務切換。delay.c 修改完成以后編譯一下,會提示如圖2.2.2.1 所示錯誤: 圖2.2.2.1 的錯誤提示表示在port.c、delay.c 和stm32f10x_it.c 中三個重復定義的函數(shù):SysTick_Handler()、SVC_Handler()和PendSV_Handler(),這三個函數(shù)分別為滴答定時器中斷服務函數(shù)、SVC 中斷服務函數(shù)和PendSV 中斷服務函數(shù),將stm32f10x_it.c 中的三個函數(shù)屏蔽掉,如圖2.2.2.2 所示: 再次編譯代碼,應該沒有錯誤了,如果還是錯誤的話自行根據(jù)錯誤類型修改!至此,SYSTEM文件夾就修改完成了。 2.3 移植驗證實驗 2.3.1 實驗程序設計 1、實驗目的 編寫簡單的FreeRTOS 應用代碼,測試FreeRTOS 的移植是否成功。鑒于大家還沒正式學習FreeRTOS,可以直接將本實驗代碼復制粘貼到自己的移植工程中。 2、實驗設計 本實驗設計四個任務:start_task()、led0_task ()、led1_task ()和float_task(),這四個任務的任務功能如下: start_task():用來創(chuàng)建其他三個任務。 led0_task ():控制LED0 的閃爍,提示系統(tǒng)正在運行。 led1_task ():控制LED1 的閃爍。 float_task():簡單的浮點測試任務,用于測試STM32F4 的FPU 是否工作正常。 3、實驗工程 FreeRTOS 實驗2-1 FreeRTOS 移植實驗。 4、實驗程序與分析 ●任務設置 #include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "FreeRTOS.h" #include "task.h" /************************************************ ALIENTEK 戰(zhàn)艦STM32F103 開發(fā)板 FreeRTOS 實驗2-1 FreeRTOS 移植實驗-庫函數(shù)版本 技術支持:www.openedv.com 淘寶店鋪:http://eboard.taobao.com 關注微信公眾平臺微信號:"正點原子",免費獲取STM32 資料。 廣州市星翼電子科技有限公司 作者:正點原子 @ALIENTEK ************************************************/ #define START_TASK_PRIO 1 //任務優(yōu)先級 #define START_STK_SIZE 128 //任務堆棧大小 TaskHandle_t StartTask_Handler; //任務句柄 void start_task(void *pvParameters); //任務函數(shù) #define LED0_TASK_PRIO 2 //任務優(yōu)先級 #define LED0_STK_SIZE 50 //任務堆棧大小 TaskHandle_t LED0Task_Handler; //任務句柄 void led0_task(void *p_arg); //任務函數(shù) #define LED1_TASK_PRIO 3 //任務優(yōu)先級 #define LED1_STK_SIZE 50 //任務堆棧大小 TaskHandle_t LED1Task_Handler; //任務句柄 void led1_task(void *p_arg); //任務函數(shù) ● main()函數(shù) int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統(tǒng)中斷優(yōu)先級分組4 delay_init(); //延時函數(shù)初始化 uart_init(115200); //初始化串口 LED_Init(); //初始化LED //創(chuàng)建開始任務 xTaskCreate((TaskFunction_t )start_task, //任務函數(shù) (const char* )"start_task", //任務名稱 (uint16_t )START_STK_SIZE, //任務堆棧大小 (void* )NULL, //傳遞給任務函數(shù)的參數(shù) (UBaseType_t )START_TASK_PRIO, //任務優(yōu)先級 (TaskHandle_t* )&StartTask_Handler); //任務句柄 vTaskStartScheduler(); //開啟任務調度 } ● 任務函數(shù) //開始任務任務函數(shù) void start_task(void *pvParameters) { taskENTER_CRITICAL(); //進入臨界區(qū) //創(chuàng)建LED0 任務
上一篇:STM32CubeMX+FreeRTOS實驗---使用兩個實例,共用一個task
下一篇:STM32使用FreeRTOS中的鏈表創(chuàng)建節(jié)點與列表項
推薦閱讀最新更新時間:2025-07-07 01:53






設計資源 培訓 開發(fā)板 精華推薦
- LTC3624HMSE-23.3 3.3V 輸出電壓、2A 同步降壓型穩(wěn)壓器的典型應用,具有 1MHz、突發(fā)模式操作
- NCV59801CMLADJTCGEVB:NCP59801 DFNW-8 3x3 ADJ 評估板
- 基于51單片機自動澆花系統(tǒng)設計(包含原理圖、源程序、論文等)畢業(yè)設計
- 用于汽車的 DC 到 DC 單路輸出電源
- 用于儀表的 16 位 1 通道 DAC
- AR0135AT2M00XUEAH3-GEVB:1.2 MP Sunex DSL945D 1/3" iBGA CIS HB 評估板
- LT1767EMS8E-2.5 12V 至 3.3V 降壓轉換器的典型應用電路
- LTM4630AIV 4.5V 至 15Vin、300kHz、1V 和 1.2V、18A 輸出 DC/DC 穩(wěn)壓器的典型應用電路
- LT3462 的典型應用 - 在 ThinSOT 中使用集成肖特基反相 1.2MHz/2.7MHz DC/DC 轉換器
- LT1317BCS8 2V 至 3.3V 轉換器的典型應用電路
- 第二屆集微半導體峰會:行業(yè)嘉年華,不一樣的產(chǎn)業(yè)盛宴!
- 美商務部與中興簽署和解協(xié)議,支付4億美元保證金后生效
- 自動化集成商的強大之路 一位BOSS的十年心得
- 十年磨一劍 R&S射頻信號發(fā)生器SMB100A升級到SMB100B
- 煮酒論英雄 細數(shù)AGV機器人創(chuàng)業(yè)公司五大派系
- 智能門鎖有了屬于自己的標準,才能更好地規(guī)范整個行業(yè)
- 新零售讓智能家居走進千家萬戶指日可待
- 未來5年,智能鎖行業(yè)也可能出現(xiàn)幾家巨無霸企業(yè)
- 物聯(lián)網(wǎng)等技術為根治“城市病”提供了嶄新的“解題思路”
- 韓國1小時“搶跑”5G 率先布局機器人