目錄
1. 實(shí)驗(yàn)任務(wù)
2. 使用STM32CubeMX創(chuàng)建基礎(chǔ)工程
2.1 使用STM32CubeMX創(chuàng)建項(xiàng)目
2.2 創(chuàng)建新項(xiàng)目
2.3 時(shí)鐘設(shè)置
2.4 時(shí)鐘配置樹(shù)
2.5 修改時(shí)鐘基準(zhǔn),打開(kāi)串行調(diào)試
2.6 配置串口
2.7 配置狀態(tài)指示燈
2.8 FreeRTOS配置
2.9 配置工程輸出項(xiàng)
3. 代碼編輯
3.1 printf重映射
3.1.1 使用ARMCC 5編譯器時(shí)的printf重映射方法
3.1.2 使用ARM 6編譯器時(shí)的printf重映射方法
3.2 使用FreeRTOS任務(wù)編寫(xiě)代碼
3.3 main函數(shù)中關(guān)于裸機(jī)和多任務(wù)代碼一點(diǎn)說(shuō)明
3.3? 運(yùn)行效果
4 多任務(wù)相關(guān)知識(shí)
4.1 任務(wù)基礎(chǔ)知識(shí)
4.2 任務(wù)狀態(tài)
4.3 任務(wù)優(yōu)先級(jí)
4.4 任務(wù)實(shí)現(xiàn)
1. 實(shí)驗(yàn)任務(wù)
利用STM32CubeMX,創(chuàng)建MDK工程,STM32CubeMX移植FreeRTOS。
開(kāi)發(fā)環(huán)境準(zhǔn)備:
Win11、MDK5、STM32CubeMX、STM32F429IGT6開(kāi)發(fā)板
STM32CubeMX v6.10
2. 使用STM32CubeMX創(chuàng)建基礎(chǔ)工程
2.1 使用STM32CubeMX創(chuàng)建項(xiàng)目
2.2 創(chuàng)建新項(xiàng)目
MCU型號(hào)選擇STM32F429IGT6,開(kāi)始項(xiàng)目。
2.3 時(shí)鐘設(shè)置
選擇使用外部高速時(shí)鐘,時(shí)鐘源為外部晶振(25MHz),配置系統(tǒng)時(shí)鐘,根據(jù)外部晶振頻率,將系統(tǒng)時(shí)鐘配置到180MHz。
2.4 時(shí)鐘配置樹(shù)
2.5 修改時(shí)鐘基準(zhǔn),打開(kāi)串行調(diào)試
- FreeRTOS使用systick系統(tǒng)嘀嗒定時(shí)器當(dāng)作心跳,此處須修改HAL庫(kù)的時(shí)鐘基準(zhǔn)。
- 由于FreeRTOS和HAL庫(kù)不能同時(shí)使用SysTick定時(shí)器,將HAL庫(kù)的定時(shí)器改成TIM4
2.6 配置串口
采用異步通信方式,通訊參數(shù)此處為默認(rèn)值。
2.7 配置狀態(tài)指示燈
2.8 FreeRTOS配置
STM32CubeMX已經(jīng)將FreeRTOS集成到工具中,并且將RTOS的接口封裝為CMSIS-RTOS V1/V2,相較之于V1版本的CMSIS-RTOS API,V2版本的API的兼容性更高,為了將來(lái)的開(kāi)發(fā)和移 植,建議開(kāi)發(fā)者使用V2版本的API。
選擇Middleware-FreeRTOS,Interface中選擇CMSIS_V2。
選擇CMSIS V2接口后,還要進(jìn)一步配置FreeRTOS的參數(shù)和功能。
FreeRTOS的參數(shù)包括時(shí)基頻率、任務(wù)堆棧大小、是否使能互斥鎖等等,需要開(kāi)發(fā)者根據(jù)自己對(duì)FreeRTOS的了解以及項(xiàng)目開(kāi)發(fā)的需求,來(lái)定制參數(shù)。此處使用默認(rèn)參數(shù)不需要修改。
使用STM32CubeMX,可以手工添加任務(wù)、隊(duì)列、信號(hào)量、互斥鎖、定時(shí)器等等。為提高代碼的可移植性和靈活性,建議大家不要嚴(yán)重依賴STM32CubeMX,盡量不使用STM32CubeMX來(lái)添加這些對(duì)象,而是手寫(xiě)代碼來(lái)使用這些對(duì)象。
建立雙任務(wù):
任務(wù)1:LED指示燈閃爍
任務(wù)2:串口打印輸出
提示:留意下串口中斷的問(wèn)題,由于FreeRTOS只允許5以上的中斷級(jí)別,需要中斷的話請(qǐng)?jiān)O(shè)置大于等于5的值。
2.9 配置工程輸出項(xiàng)
3. 代碼編輯
3.1 printf重映射
3.1.1 使用ARMCC 5編譯器時(shí)的printf重映射方法
printf函數(shù)重映射,可以直接使用printf在串口一中打印數(shù)據(jù),定位到usart.c文件中。
/* USER CODE BEGIN 0 */
#include "stdio.h"
/* USER CODE END 0 */
/* USER CODE BEGIN 1 */
int fputc(int ch,FILE *f)
{
??? HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,10);
??? return(ch);
}
/* USER CODE END 1 */
注意:重寫(xiě)printf后運(yùn)行代碼前一定要勾選Use MicroLiB,否則項(xiàng)目燒錄后無(wú)法執(zhí)行。
提示:Keil 5.37以后的版本,不再集成AC5編譯器,安裝與配置方法如下:
Keil MDK5.37以上版本自行添加AC5(ARMCC)編譯器的方法_armcc下載-CSDN博客文章瀏覽閱讀2.4w次,點(diǎn)贊89次,收藏204次。?【對(duì)安裝AC5后,編譯時(shí)提示找不到序列號(hào)的錯(cuò)誤,文中有提示的解決方法】從MDK5.37開(kāi)始,AC5(ARMCC)編譯器不再默認(rèn)安裝,需要獨(dú)立安裝。路徑、字符等安裝問(wèn)題,都可能引起AC5的編譯錯(cuò)誤。下面給出不用爬坑的方法。下面是安裝步驟:下載AC5(ARMCC)編譯器:1. 官方頁(yè)面(可能下載不成功)2.網(wǎng)盤(pán)下載百度網(wǎng)盤(pán):鏈接:https://pan.baidu.com/s/1ND3vKLzqxanWVP304txRtQ ,提取碼:idvc..........................._armcc下載https://blog.csdn.net/qcmyqcmy/article/details/125814461?
3.1.2 使用ARM 6編譯器時(shí)的printf重映射方法
下面兩篇博文提供了同時(shí)使用AC5 和ARM Clang 6編譯器的方法,使用此方法,你可以方便按需選擇合適的編譯器,代碼不再報(bào)錯(cuò)。
方法1:阻塞方式
基礎(chǔ)篇007. 串行通信(一)--阻塞方式發(fā)送接收_串口阻塞-CSDN博客文章瀏覽閱讀1.7k次,點(diǎn)贊2次,收藏10次。在學(xué)習(xí)C語(yǔ)言時(shí)我們經(jīng)常使用C語(yǔ)言標(biāo)準(zhǔn)函數(shù)庫(kù)輸入輸出函數(shù),比如printf、scanf、getchar等。為讓開(kāi)發(fā)板也支持這些函數(shù)需要把USART發(fā)送和接收函數(shù)添加到這些函數(shù)的內(nèi)部函數(shù)內(nèi)。在C語(yǔ)言HAL庫(kù)中,fputc函數(shù)是printf函數(shù)內(nèi)部的一個(gè)函數(shù),功能是將字符ch寫(xiě)入到文件指針f所指向文件的當(dāng)前寫(xiě)指針位置。fgetc函數(shù)與fputc函數(shù)非常相似,實(shí)現(xiàn)字符讀取功能。在使用scanf函數(shù)時(shí)需要注意字符輸入格式。文中引入可使用#if …… #elif …… #endif方式調(diào)試代碼。_串口阻塞https://blog.csdn.net/qcmyqcmy/article/details/130674914
方法二、中斷方式
基礎(chǔ)篇007. 串行通信(二)--中斷方式接收數(shù)據(jù)_串口設(shè)備通信0xffff-CSDN博客文章瀏覽閱讀2.1k次。目錄1. 實(shí)驗(yàn)任務(wù)2. 硬件原理3. 利用STM32CubeMX創(chuàng)建MDK工程3.1 STM32CubeMX工程創(chuàng)建3.2 配置調(diào)試方式3.3 配置時(shí)鐘電路3.4 配置GPIO3.5 配置串口參數(shù)3.6 配置時(shí)鐘3.7 項(xiàng)目配置4. 串行通信實(shí)驗(yàn)4.1 UART串口printf,scanf函數(shù)串口重定向4.2 開(kāi)啟中斷4.3 中斷回調(diào)函數(shù)4.4 main()函數(shù)修改5.調(diào)試與驗(yàn)證6.總結(jié)利用STM32CubeMX,創(chuàng)建MDK工程,使用中斷方式,實(shí)現(xiàn)串口接收數(shù)據(jù),然后在轉(zhuǎn)發(fā)到串口。本實(shí)驗(yàn)是串行通信的第二部分,_串口設(shè)備通信0xffffhttps://blog.csdn.net/qcmyqcmy/article/details/130716056
3.2 使用FreeRTOS任務(wù)編寫(xiě)代碼
在freertos.c中的任務(wù)函數(shù)里面寫(xiě)相應(yīng)的程序
添加頭文件:
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "usart.h"
/* USER CODE END Includes */
MDK截圖如下:?
?添加數(shù)組:
/* USER CODE BEGIN Variables */
uint8_t USART1_BUF[] = "Hello FreeRTOS\r\n";
/* USER CODE END Variables */
MDK截圖如下:??
?添加任務(wù)一啟動(dòng)代碼:
/* USER CODE BEGIN Header_StartTask01 */
/**
* @brief Function implementing the myTask01 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask01 */
void StartTask01(void *argument)
{
/* USER CODE BEGIN StartTask01 */
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
osDelay(1000);
}
/* USER CODE END StartTask01 */
}
MDK截圖如下:??
??添加任務(wù)二啟動(dòng)代碼:
/* USER CODE BEGIN Header_StartTask02 */
/**
* @brief Function implementing the myTask02 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask02 */
void StartTask02(void *argument)
{
/* USER CODE BEGIN StartTask02 */
/* Infinite loop */
for(;;)
{
printf("USART1: %s", USART1_BUF);
osDelay(1000);
}
/* USER CODE END StartTask02 */
}
MDK截圖如下:??
3.3 main函數(shù)中關(guān)于裸機(jī)和多任務(wù)代碼一點(diǎn)說(shuō)明
main.c函數(shù)中,osKernelStart()是任務(wù)調(diào)度函數(shù),通過(guò)它可以進(jìn)入多任務(wù)操作系統(tǒng)。
注釋該語(yǔ)句后,程序就可進(jìn)入后面的while語(yǔ)句了,可作為裸機(jī)程序運(yùn)行。
? /* Start scheduler */
? osKernelStart();
3.3? 運(yùn)行效果
待補(bǔ)充...
4 多任務(wù)相關(guān)知識(shí)
4.1 任務(wù)基礎(chǔ)知識(shí)
單片機(jī)裸機(jī)(未使用系統(tǒng))運(yùn)行時(shí),一般都是在main函數(shù)中用循環(huán)來(lái)處理所有事件,循環(huán)調(diào)用相應(yīng)的函數(shù)完成事件的處理。有時(shí)候也可以通過(guò)中斷完成一些處理。相對(duì)多任務(wù)系統(tǒng)而言,這種就是單任務(wù)系統(tǒng),也稱作前后臺(tái)系統(tǒng),中斷服務(wù)函數(shù)作為前臺(tái)程序,大循環(huán)while(1)作為后臺(tái)程序。
多任務(wù)系統(tǒng)會(huì)把大問(wèn)題劃成很多的小問(wèn)題,逐個(gè)將小問(wèn)題解決掉,大問(wèn)題也就會(huì)隨之解決。這些小問(wèn)題是并發(fā)處理的,并不是說(shuō)同一時(shí)刻一起執(zhí)行很多任務(wù),而是由于每個(gè)任務(wù)執(zhí)行的時(shí)間很短,看起來(lái)像同一時(shí)刻執(zhí)行了很多任務(wù)。通過(guò)FreeRTOS里面的任務(wù)調(diào)度器完成任務(wù)的先后執(zhí)行。在FreeRTOS中是一個(gè)搶占式的實(shí)時(shí)多任務(wù)系統(tǒng),其任務(wù)調(diào)度器也是搶占式的。
高優(yōu)先級(jí)的任務(wù)可以打斷低優(yōu)先級(jí)任務(wù)的運(yùn)行而取得CPU的使用權(quán),這樣就保證了那些緊急任務(wù)的運(yùn)行。高優(yōu)先級(jí)的任務(wù)執(zhí)行完成以后重新把CPU的使用權(quán)歸還給低優(yōu)先級(jí)的任務(wù),這個(gè)就是搶占式多任務(wù)系統(tǒng)的基本原理。
4.2 任務(wù)狀態(tài)
FreeRTOS中的任務(wù)永遠(yuǎn)只有運(yùn)行態(tài)、就緒態(tài)、阻塞態(tài)、掛起態(tài)。任務(wù)狀態(tài)圖切換如下:
(1)運(yùn)行態(tài)
當(dāng)一個(gè)任務(wù)正在運(yùn)行時(shí),那么就說(shuō)這個(gè)任務(wù)處于運(yùn)行態(tài),處于運(yùn)行態(tài)的任務(wù)就是當(dāng)前正在使用處理器的任務(wù)。如果使用的是單核處理器的話那么不管在任何時(shí)刻永遠(yuǎn)都只有一個(gè)任務(wù)處于運(yùn)行態(tài)。
(2)就緒態(tài)
處于就緒態(tài)的任務(wù)是那些已經(jīng)準(zhǔn)備就緒(這些任務(wù)沒(méi)有被阻塞或者掛起),可以運(yùn)行的任務(wù),但是處于就緒態(tài)的任務(wù)還沒(méi)有運(yùn)行,因?yàn)橛幸粋€(gè)同優(yōu)先級(jí)或者更高優(yōu)先級(jí)的任務(wù)正在運(yùn)行!
(3)阻塞態(tài)
如果一個(gè)任務(wù)當(dāng)前正在等待某個(gè)外部事件的話就說(shuō)它處于阻塞態(tài),比如說(shuō)如果某個(gè)任務(wù)調(diào)用了函數(shù)vTaskDelay0的話就會(huì)進(jìn)入阻塞態(tài),直到延時(shí)周期完成。任務(wù)在等待隊(duì)列、信號(hào)量、事件組、通知或互斥信號(hào)量的時(shí)候也會(huì)進(jìn)入阻塞態(tài)。任務(wù)進(jìn)入阻塞態(tài)會(huì)有一個(gè)超時(shí)時(shí)間,當(dāng)超過(guò)這個(gè)超時(shí)時(shí)間任務(wù)就會(huì)退出阻塞態(tài),即使所等待的事件還沒(méi)有來(lái)臨!
(4)掛起態(tài)
像阻塞態(tài)一樣,任務(wù)進(jìn)入掛起態(tài)以后也不能被調(diào)度器調(diào)用進(jìn)入運(yùn)行態(tài),但是進(jìn)入掛起態(tài)的任務(wù)沒(méi)有超時(shí)時(shí)間。任務(wù)進(jìn)入和退出掛起態(tài)通過(guò)調(diào)用函數(shù)vTaskSuspend()和xTaskResume()。
4.3 任務(wù)優(yōu)先級(jí)
每個(gè)任務(wù)都可以分配一個(gè)從0~(configMAX_PRIORITIES-1)的優(yōu)先級(jí),configMAX_PRIORITIES在文件FreeRTOSConfig.h中有定義。如果所使用的硬件平臺(tái)支持類似計(jì)算前導(dǎo)零這樣的指令(可以通過(guò)該指令選擇下一個(gè)要運(yùn)行的任務(wù),Cortex-M處理器是支持該指令的),并且宏configUSE_PORT_OPTIMISED_TASK_SELECTION也設(shè)置為了1,那么宏configMAX_PRIORITIES不能超過(guò)32!也就是優(yōu)先級(jí)不能超過(guò)32級(jí)。其他情況下宏configMAX_PRIORITIES可以為任意值,但是考慮到RAM的消耗,宏configMAX_PRIORITIES最好設(shè)置為一個(gè)滿足應(yīng)用的最小值。
優(yōu)先級(jí)數(shù)字越低表示任務(wù)優(yōu)先級(jí)越低,0的優(yōu)先級(jí)最低,configMAX_PRIORITIES-1的優(yōu)先級(jí)最高??臻e任務(wù)的優(yōu)先級(jí)最低,為0。
FreeRTOS調(diào)度器確保處于就緒態(tài)或運(yùn)行態(tài)的高優(yōu)先級(jí)的任務(wù)獲取處理器使用權(quán),換句話說(shuō)就是處于就緒態(tài)的最高優(yōu)先級(jí)的任務(wù)才會(huì)運(yùn)行。當(dāng)宏configUSE_TIME_SLICING定義為1的時(shí)候多個(gè)任務(wù)可以共用一個(gè)優(yōu)先級(jí),數(shù)量不限。默認(rèn)情況下宏configUSE_TIME_SLICING在文件FreeRTOS.h中已經(jīng)定義為1。此時(shí)處于就緒態(tài)的優(yōu)先級(jí)相同的任務(wù)就會(huì)使用時(shí)間片輪轉(zhuǎn)調(diào)度器獲取運(yùn)行時(shí)間。
4.4 任務(wù)實(shí)現(xiàn)
在使用FreeRTOS的過(guò)程中,需要使用xTaskCreat()或者xTaskCreatStatic()來(lái)創(chuàng)建任務(wù),這兩個(gè)函數(shù)的第一個(gè)參數(shù)為pxTaskCode,就是任務(wù)函數(shù)本體。任務(wù)函數(shù)就是完成本任務(wù)工作的函數(shù)。FreeRTOS官方給出的任務(wù)函數(shù)模板為:
void vATaskFunction(void *pvParameters){????????(1)
??? for(;;){??????????????????????????????????? (2)
?????? --任務(wù)應(yīng)用程序--???????????????????? ?????(3)
?????? vTaskDelay();?????????????????????????? (4)
}
??? VTaskDelete(NULL);????????????????????????? (5)
}
(1)、任務(wù)函數(shù)本質(zhì)也是函數(shù),所以肯定有任務(wù)名什么的,不過(guò)這里要注意:任務(wù)函數(shù)的返回類型一定要為void類型,也就是無(wú)返回值,而且任務(wù)的參數(shù)也是void指針類型的!任務(wù)函數(shù)名可以根據(jù)實(shí)際情況定義。
(2)、任務(wù)的具體執(zhí)行過(guò)程是一個(gè)大循環(huán),for(;;)就代表一個(gè)循環(huán),作用和while(1)一樣,筆者習(xí)慣用while(1)。
(3)、循環(huán)里面就是真正的任務(wù)代碼了,此任務(wù)具體要干的活就在這里實(shí)現(xiàn)!
(4)、FreeRTOS的延時(shí)函數(shù),此處不一定要用延時(shí)函數(shù),其他只要能讓FreeRTOS發(fā)生任務(wù)切換的API函數(shù)都可以,比如請(qǐng)求信號(hào)量、隊(duì)列等,甚至直接調(diào)用任務(wù)調(diào)度器。只不過(guò)最常用的就是FreeRTOS的延時(shí)函數(shù)。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-814022.html
(5)、任務(wù)函數(shù)一般不允許跳出循環(huán),如果一定要跳出循環(huán)的話在跳出循環(huán)以后一定要調(diào)用函數(shù)vTaskDelete(NULL)刪除此任務(wù)!FreeRTOS的任務(wù)函數(shù)和UCOS的任務(wù)函數(shù)模式基本相同的,不止FreeRTOS,其他RTOS的任務(wù)函數(shù)基本也是這種方式的。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-814022.html
到了這里,關(guān)于基于STM32CubeMX創(chuàng)建FreeRTOS—以STM32F429為例的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!