文章目錄
- 前言
- 一、嵌入式實時作業系統
-
- 1.RTOS
- 2.UC/OS
-
- 2.1 uC/OS作業系統概述
- 2.2 組成部分
- 2.3 任務、時間和記憶體管理
- 2.4 任務排程
- 2.5 任務間的通信和同步
- 二、工程項目建立和實驗過程
-
- 1.用STM32CubeMx建立HAL庫
- 2.擷取uC/OS開源代碼
-
- 2.1 下載下傳開源代碼
- 2.2 移植工作:将uC/OS檔案添加到項目中
- 2.3 導入檔案路徑
- 3.改寫代碼和環境配置
-
- 3.1 添加bsp.c和bsp.h代碼
- 3.2 修改部分檔案相關代碼
- 3.3 初始化管腳
- 3.4 撰寫main函數
- 3.5 環境配置
- 三、實驗結果實作和展示
- 總結
前言
學習嵌入式實時作業系統(RTOS),以uc/OS為例,将其移植到stm32F103上,建構至少3個任務(task):其中兩個task分别以1s和3s周期對LED燈進行點亮-熄滅的控制;另外一個task以2s周期通過序列槽發送“hello uc/OS! 歡迎來到RTOS多任務環境!”。記錄詳細的移植過程。
一、嵌入式實時作業系統
1.RTOS
實時作業系統(Real Time Operating System,簡稱RTOS是指當外界事件或資料産生時,能夠接受并以足夠快的速度予以處理,其處理的結果又能在規定的時間之内來控制生産過程或對處理系統做出快速響應,排程一切可利用的資源完成實時任務,并控制所有實時任務協調一緻運作的作業系統。提供及時響應和高可靠性是其主要特點。
實時作業系統),又稱即時作業系統,它會按照排序運作、管理系統資源,并為開發應用程式提供一緻的基礎。
實時作業系統與一般的作業系統相比,最大的特色就是“實時性”,如果有一個任務需要執行,實時作業系統會馬上(在較短時間内)執行該任務,不會有較長的延時。這種特性保證了各個任務的及時執行。
2.UC/OS
2.1 uC/OS作業系統概述
- uC/OS是Jean J.Labrosse于1992年推出的一種規模很小的微核心,後來在此基礎上經過修改和擴充後在1999年又推出第二版,稱為uC/OS-II。。μC/OS和μC/OS-II 是專門為計算機的嵌入式應用設計的, 絕大部分代碼是用C語言編寫的。CPU硬體相關部分是用彙編語言編寫的、總量約200行的彙編語言部分被壓縮到最低限度,為的是便于移植到任何一種其它的CPU 上。
- UCOSIII是一個可裁剪、可剝奪型的多任務核心,而且沒有任務數限制。UCOSIII提供了實時作業系統所需的所有功能,包括資源管理、同步、任務通信等。
- uC/OS是一個可以 基于ROM運作的、可裁減的、搶占式、實時多任務核心,具有高度可移植性,特别适合于微處理器和控制器,适合很多商業作業系統的實時作業系統(RTOS)
- uC/OS可簡單的視為一個多任務排程器,在這個任務排程器之上完善并添加了和多任務作業系統相關的系統服務,如信号量、郵箱等;其主要特點有公開源代碼,代碼結構清晰、明了,注釋詳盡,組織有條理,可移植性好,可裁剪,可固化。 核心屬于搶占式,最多可以管理60個任務;從1992年開始,由于高度可靠性、魯棒性和安全性,uC/OS已經廣泛使用在從照相機到航空電子産品的各種應用中
- μC/OS實時多任務作業系統被廣泛應用于微處理器、微控制器和數字信号處理器;μC/OS最早出自于1992 年美國嵌入式系統專家Jean J.Labrosse 在《嵌入式系統程式設計》雜志的5 月和6 月刊上刊登的文章連載,并把μC/OS的源碼釋出在該雜志的BBS 上
2.2 組成部分
μC/OS-II可以大緻分成核心、任務處理、時間處理、任務同步與通信,CPU的移植等5個部分。
- 核心部分(OSCore.c)是作業系統的處理核心,包括作業系統初始化、作業系統運作、中斷進出的前導、時鐘節拍、任務排程、事件處理等多部分。能夠維持系統基本工作的部分都在這裡。
- 任務處理部分(OSTask.c) 任務處理部分中的内容都是與任務的操作密切相關的。包括任務的建立、删除、挂起、恢複等等。因為μC/OS-II是以任務為基本機關排程的,是以這部分内容也相當重要。
- 時鐘部分(OSTime.c) μC/OS-II中的最小時鐘機關是timetick(時鐘節拍)。任務延時等操作是在這裡完成的。
- 任務同步和通信部分 為事件處理部分,包括信号量、郵箱、郵箱隊列、事件标志等部分;主要用于任務間的互相聯系和對臨界資源的通路。
-
與CPU的接口部分
是指μC/OS-II針對所使用的CPU的移植部分。由于μC/OS-II是一個通用性的作業系統,是以對于關鍵問題上的實作,還是需要根據具體CPU的具體内容和要求作相應的移植。這部分内容由于牽涉到SP等系統指針,是以通常用彙編語言編寫。主要包括中斷級任務切換的底層實作、任務級任務切換的底層實作、時鐘節拍的産生和處理、中斷的相關處理部分等内容。
2.3 任務、時間和記憶體管理
-
時間管理:uC/OS-II 中最多可以支援64 個任務,分别對應優先級0~63,其中0 為最高優先級。63為最低級,系統保留了4個最高優先級的任務和4個最低優先級的任務,所有使用者可以使用的任務數有56個
uC/OS-II提供了任務管理的各種函數調用,包括建立任務,删除任務,改變任務的優先級,任務挂起和恢複等。
系統初始化時會自動産生兩個任務:一個是空閑任務,它的優先級最低,該任務僅給一個整型變量做累加運算;另一個是系統任務,它的優先級為次低,該任務負責統計目前cpu的使用率。
-
時間管理:uC/OS-II的時間管理是通過定時中斷來實作的,該定時中斷一般為10毫秒或100毫秒發生一次,時間頻率取決于使用者對硬體系統的定時器程式設計來實作。中斷發生的時間間隔是固定不變的,該中斷也成為一個時鐘節拍。
uC/OS-II要求使用者在定時中斷的服務程式中,調用系統提供的與時鐘節拍相關的系統函數,例如中斷級的任務切換函數,系統時間函數。
-
記憶體管理:在ANSI C中是使用malloc和free兩個函數來動态配置設定和釋放記憶體。但在嵌入式實時系統中,多次這樣的操作會導緻記憶體碎片,且由于記憶體管理算法的原因,malloc和free的執行時間也是不确定。
uC/OS-II中把連續的大塊記憶體按分區管理。每個分區中包含整數個大小相同的記憶體塊,但不同分區之間的記憶體塊大小可以不同。使用者需要動态配置設定記憶體時,系統選擇一個适當的分區,按塊來配置設定記憶體。釋放記憶體時将該塊放回它以前所屬的分區,這樣能有效解決碎片問題,同時執行時間也是固定的。
2.4 任務排程
uC/OS-II 采用的是可剝奪型實時多任務核心。可剝奪型的實時核心在任何時候都運作就緒了的最高優先級的任務。
uC/os-II的任務排程是完全基于任務優先級的搶占式排程,也就是最高優先級的任務一旦處于就緒狀态,則立即搶占正在運作的低優先級任務的處理器資源。為了簡化系統設計,uC/OS-II規定所有任務的優先級不同,因為任務的優先級也同時唯一标志了該任務本身。
1) 高優先級的任務因為需要某種臨界資源,主動請求挂起,讓出處理器,此時将排程就緒狀态的低優先級任務獲得執行,這種排程也稱為任務級的上下文切換。
2) 高優先級的任務因為時鐘節拍到來,在時鐘中斷的處理程式中,核心發現高優先級任務獲得了執行條件(如休眠的時鐘到時),則在中斷态直接切換到高優先級任務執行。這種排程也稱為中斷級的上下文切換。
這兩種排程方式在uC/OS-II的執行過程中非常普遍,一般來說前者發生在系統服務中,後者發生在時鐘中斷的服務程式中。
排程工作的内容可以分為兩部分:最高優先級任務的尋找和任務切換。其最高優先級任務的尋找是通過建立就緒任務表來實作的。u C / O S 中的每一個任務都有獨立的堆棧空間,并有一個稱為任務控制塊TCB(Task Control Block)的資料結構,其中第一個成員變量就是儲存的任務堆棧指針。任務排程子產品首先用變量OSTCBHighRdy 記錄目前最進階就緒任務的TCB 位址,然後調用OS_TASK_SW()函數來進行任務切換。
2.5 任務間的通信和同步
對一個多任務的作業系統來說,任務間的通信和同步是必不可少的。uC/OS-II中提供了4種同步對象,分别是信号量,郵箱,消息隊列和事件。所有這些同步對象都有建立,等待,發送,查詢的接口用于實作程序間的通信和同步。
二、工程項目建立和實驗過程
1.用STM32CubeMx建立HAL庫
- 打開STM32CubeMx,選擇ACCESS TO MCU SELECTOR,然後選擇STM32F103C8T6,點選Start Project
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2YfNWawNyZuBnL3AjMmljZidjMhJmNklTYiVTZjRTO0QWOyIGOzQWMmR2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
- 配置RCC
- 配置SYS
- 配置序列槽USART1
-
配置PA3和PC13作為LED燈的端口
在右邊引腳圖将PA3和PC13設定為GPIO_Output
- 最後我們設定好路徑,生成工程即可
2.擷取uC/OS開源代碼
2.1 下載下傳開源代碼
- 進入 Micrium 公司官網下載下傳中心:http://micrium.com/downloadcenter/ 選擇ST系列,點選View all STMicroelectronics,點選 STMicroelectronics STM32F107之後按照提示注冊下載下傳即可。
-
可直接下載下傳此網盤連結内容 連結:https://pan.baidu.com/s/10RqsDRecbmVteWmDv2oUNQ
提取碼:1234
2.2 移植工作:将uC/OS檔案添加到項目中
- 将之前下載下傳的檔案中的如下五個檔案夾複制粘貼到之前建立工程的MDK-ARM下
- 從HAL庫中open project到keil,然後右擊檔案夾,選擇Manage Project items
- 點選小視窗建立6個新的檔案夾
- 點選
,再點選Add file,将檔案類型改為All files,再uC-CPu中找到下列三個檔案并添加;然後點選此檔案夾下的ARM-Cortex-M3,再點選RealView,将第二張圖檔的三個檔案盡數添加進去CPU
- 點選
->Add Files;将檔案夾uC-LIB如下的九個檔案全部添加;然後找到MDK-ARM\uC-LIB\Ports\ARM-Cortex-M3\RealView路徑,添加第二張圖檔的程式LIB
- 點選
和Add files;打開路徑MDK-ARM\uCOS-III\Ports\ARM-Cortex-M3\Generic\RealView,添加如下檔案PORT
- 點選
後點選Add files;選擇路徑MDK-ARM\uCOS-III\Source下的所有.c和.h檔案SOURCE
- 點選
->Add files;MDK-ARM\uC-CONFIG路徑下的如下檔案添加進去CONFIG
- 點選
->Add files;MDK-ARM\uC-BSP路徑下選中以下全部檔案,Add添加BSP
2.3 導入檔案路徑
3.改寫代碼和環境配置
3.1 添加bsp.c和bsp.h代碼
bsp.c代碼
#include "includes.h"
#define DWT_CR *(CPU_REG32 *)0xE0001000
#define DWT_CYCCNT *(CPU_REG32 *)0xE0001004
#define DEM_CR *(CPU_REG32 *)0xE000EDFC
#define DBGMCU_CR *(CPU_REG32 *)0xE0042004
#define DEM_CR_TRCENA (1 << 24)
#define DWT_CR_CYCCNTENA (1 << 0)
CPU_INT32U BSP_CPU_ClkFreq (void)
{
return HAL_RCC_GetHCLKFreq();
}
void BSP_Tick_Init(void)
{
CPU_INT32U cpu_clk_freq;
CPU_INT32U cnts;
cpu_clk_freq = BSP_CPU_ClkFreq();
#if(OS_VERSION>=3000u)
cnts = cpu_clk_freq/(CPU_INT32U)OSCfg_TickRate_Hz;
#else
cnts = cpu_clk_freq/(CPU_INT32U)OS_TICKS_PER_SEC;
#endif
OS_CPU_SysTickInit(cnts);
}
void BSP_Init(void)
{
BSP_Tick_Init();
MX_GPIO_Init();
}
#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
void CPU_TS_TmrInit (void)
{
CPU_INT32U cpu_clk_freq_hz;
DEM_CR |= (CPU_INT32U)DEM_CR_TRCENA; /* Enable Cortex-M3's DWT CYCCNT reg. */
DWT_CYCCNT = (CPU_INT32U)0u;
DWT_CR |= (CPU_INT32U)DWT_CR_CYCCNTENA;
cpu_clk_freq_hz = BSP_CPU_ClkFreq();
CPU_TS_TmrFreqSet(cpu_clk_freq_hz);
}
#endif
#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
CPU_TS_TMR CPU_TS_TmrRd (void)
{
return ((CPU_TS_TMR)DWT_CYCCNT);
}
#endif
#if (CPU_CFG_TS_32_EN == DEF_ENABLED)
CPU_INT64U CPU_TS32_to_uSec (CPU_TS32 ts_cnts)
{
CPU_INT64U ts_us;
CPU_INT64U fclk_freq;
fclk_freq = BSP_CPU_ClkFreq();
ts_us = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);
return (ts_us);
}
#endif
#if (CPU_CFG_TS_64_EN == DEF_ENABLED)
CPU_INT64U CPU_TS64_to_uSec (CPU_TS64 ts_cnts)
{
CPU_INT64U ts_us;
CPU_INT64U fclk_freq;
fclk_freq = BSP_CPU_ClkFreq();
ts_us = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);
return (ts_us);
}
#endif
bsp.h代碼
#ifndef __BSP_H__
#define __BSP_H__
#include "stm32f1xx_hal.h"
void BSP_Init(void);
#endif
3.2 修改部分檔案相關代碼
-
打開啟動檔案startup_stm32f103xb.s,改變75、76行,174、175行和178、179行
PendSV_Handler改為
OS_CPU_PendSVHandler
,
SysTick_Handler改為
。OS_CPU_SysTickHandler
-
打開app_cfg.h檔案
圖1,DEF_ENABLED 改為 DEF_DISABLED
圖2,#define APP_TRACE BSP_Ser_Printf 改為
#define APP_TRACE(void)
-
打開includes.h檔案代碼
1,在#include <bsp.h>下面添加
和#include “gpio.h”
2,将#include <stm32f10x_lib.h> 改為 #include#include “app_cfg.h”
“stm32f1xx_hal.h”
-
打開lib_cfg.h檔案
修改為
(該處宏定義設定堆空間的大小,STM32F103C8T6的RAM隻有20K,是以要改小一點)5u
-
修改usart.c檔案代碼
添加代碼完成printf重定向:
/* USER CODE BEGIN 1 */
int fputc(int ch,FILE *f){
HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xffff);
return ch;
}
/* USER CODE END 1 */
-
修改usart.h檔案代碼
在usart.c中找到調用,右擊選擇Open document,則會直接跳到usart.h
3.3 初始化管腳
在gpio.c檔案中修改代碼:
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
/*Configure GPIO pin : PC13|PA3 */
GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
3.4 撰寫main函數
代碼如下
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
#include "usart.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <includes.h>
#include "stm32f1xx_hal.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* 任務優先級 */
#define START_TASK_PRIO 3
#define LED0_TASK_PRIO 4
#define MSG_TASK_PRIO 5
#define LED1_TASK_PRIO 6
/* 任務堆棧大小 */
#define START_STK_SIZE 96
#define LED0_STK_SIZE 64
#define MSG_STK_SIZE 64
#define LED1_STK_SIZE 64
/* 任務棧 */
CPU_STK START_TASK_STK[START_STK_SIZE];
CPU_STK LED0_TASK_STK[LED0_STK_SIZE];
CPU_STK MSG_TASK_STK[MSG_STK_SIZE];
CPU_STK LED1_TASK_STK[LED1_STK_SIZE];
/* 任務控制塊 */
OS_TCB StartTaskTCB;
OS_TCB Led0TaskTCB;
OS_TCB MsgTaskTCB;
OS_TCB Led1TaskTCB;
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* 任務函數定義 */
void start_task(void *p_arg);
static void AppTaskCreate(void);
static void AppObjCreate(void);
static void led_pc13(void *p_arg);
static void send_msg(void *p_arg);
static void led_pa3(void *p_arg);
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
OS_ERR err;
OSInit(&err);
HAL_Init();
SystemClock_Config();
//MX_GPIO_Init(); 這個在BSP的初始化裡也會初始化
MX_USART1_UART_Init();
/* 建立任務 */
OSTaskCreate((OS_TCB *)&StartTaskTCB, /* Create the start task */
(CPU_CHAR *)"start task",
(OS_TASK_PTR ) start_task,
(void *) 0,
(OS_PRIO ) START_TASK_PRIO,
(CPU_STK *)&START_TASK_STK[0],
(CPU_STK_SIZE) START_STK_SIZE/10,
(CPU_STK_SIZE) START_STK_SIZE,
(OS_MSG_QTY ) 0,
(OS_TICK ) 0,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
/* 啟動多任務系統,控制權交給uC/OS-III */
OSStart(&err); /* Start multitasking (i.e. give control to uC/OS-III). */
}
void start_task(void *p_arg)
{
OS_ERR err;
CPU_SR_ALLOC();
p_arg = p_arg;
/* YangJie add 2021.05.20*/
BSP_Init(); /* Initialize BSP functions */
//CPU_Init();
//Mem_Init(); /* Initialize Memory Management Module */
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err); //統計任務
#endif
#ifdef CPU_CFG_INT_DIS_MEAS_EN //如果使能了測量中斷關閉時間
CPU_IntDisMeasMaxCurReset();
#endif
#if OS_CFG_SCHED_ROUND_ROBIN_EN //當使用時間片輪轉的時候
//使能時間片輪轉排程功能,時間片長度為1個系統時鐘節拍,既1*5=5ms
OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);
#endif
OS_CRITICAL_ENTER(); //進入臨界區
/* 建立LED0任務 */
OSTaskCreate((OS_TCB * )&Led0TaskTCB,
(CPU_CHAR * )"led_pc13",
(OS_TASK_PTR )led_pc13,
(void * )0,
(OS_PRIO )LED0_TASK_PRIO,
(CPU_STK * )&LED0_TASK_STK[0],
(CPU_STK_SIZE)LED0_STK_SIZE/10,
(CPU_STK_SIZE)LED0_STK_SIZE,
(OS_MSG_QTY )0,
(OS_TICK )0,
(void * )0,
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
(OS_ERR * )&err);
/* 建立LED1任務 */
OSTaskCreate((OS_TCB * )&Led1TaskTCB,
(CPU_CHAR * )"led_pa3",
(OS_TASK_PTR )led_pa3,
(void * )0,
(OS_PRIO )LED1_TASK_PRIO,
(CPU_STK * )&LED1_TASK_STK[0],
(CPU_STK_SIZE)LED1_STK_SIZE/10,
(CPU_STK_SIZE)LED1_STK_SIZE,
(OS_MSG_QTY )0,
(OS_TICK )0,
(void * )0,
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
(OS_ERR * )&err);
/* 建立MSG任務 */
OSTaskCreate((OS_TCB * )&MsgTaskTCB,
(CPU_CHAR * )"send_msg",
(OS_TASK_PTR )send_msg,
(void * )0,
(OS_PRIO )MSG_TASK_PRIO,
(CPU_STK * )&MSG_TASK_STK[0],
(CPU_STK_SIZE)MSG_STK_SIZE/10,
(CPU_STK_SIZE)MSG_STK_SIZE,
(OS_MSG_QTY )0,
(OS_TICK )0,
(void * )0,
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
(OS_ERR * )&err);
OS_TaskSuspend((OS_TCB*)&StartTaskTCB,&err); //挂起開始任務
OS_CRITICAL_EXIT(); //進入臨界區
}
/**
* 函數功能: 啟動任務函數體。
* 輸入參數: p_arg 是在建立該任務時傳遞的形參
* 返 回 值: 無
* 說 明:無
*/
static void led_pc13 (void *p_arg)
{
OS_ERR err;
(void)p_arg;
BSP_Init(); /* Initialize BSP functions */
CPU_Init();
Mem_Init(); /* Initialize Memory Management Module */
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err); /* Compute CPU capacity with no task running */
#endif
CPU_IntDisMeasMaxCurReset();
AppTaskCreate(); /* Create Application Tasks */
AppObjCreate(); /* Create Application Objects */
while (DEF_TRUE)
{
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
OSTimeDlyHMSM(0, 0, 1, 0,OS_OPT_TIME_HMSM_STRICT,&err);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
OSTimeDlyHMSM(0, 0, 1, 0,OS_OPT_TIME_HMSM_STRICT,&err);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
static void led_pa3 (void *p_arg)
{
OS_ERR err;
(void)p_arg;
BSP_Init(); /* Initialize BSP functions */
CPU_Init();
Mem_Init(); /* Initialize Memory Management Module */
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err); /* Compute CPU capacity with no task running */
#endif
CPU_IntDisMeasMaxCurReset();
AppTaskCreate(); /* Create Application Tasks */
AppObjCreate(); /* Create Application Objects */
while (DEF_TRUE)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_RESET);
OSTimeDlyHMSM(0, 0, 3, 0,OS_OPT_TIME_HMSM_STRICT,&err);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET);
OSTimeDlyHMSM(0, 0, 3, 0,OS_OPT_TIME_HMSM_STRICT,&err);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
static void send_msg (void *p_arg)
{
OS_ERR err;
(void)p_arg;
BSP_Init(); /* Initialize BSP functions */
CPU_Init();
Mem_Init(); /* Initialize Memory Management Module */
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err); /* Compute CPU capacity with no task running */
#endif
CPU_IntDisMeasMaxCurReset();
AppTaskCreate(); /* Create Application Tasks */
AppObjCreate(); /* Create Application Objects */
while (DEF_TRUE)
{
printf("hello uc/OS!歡迎來到RTOS多任務環境! \r\n");
OSTimeDlyHMSM(0, 0, 2, 0,OS_OPT_TIME_HMSM_STRICT,&err);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/* USER CODE BEGIN 4 */
/**
* 函數功能: 建立應用任務
* 輸入參數: p_arg 是在建立該任務時傳遞的形參
* 返 回 值: 無
* 說 明:無
*/
static void AppTaskCreate (void)
{
}
/**
* 函數功能: uCOSIII核心對象建立
* 輸入參數: 無
* 返 回 值: 無
* 說 明:無
*/
static void AppObjCreate (void)
{
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
3.5 環境配置
點選小魔法棒圖示,進行如下更改
然後編譯,無任何錯誤警告即可
三、實驗結果實作和展示
-
線路連接配接
USB轉TTL
3v3->3v3,GND->GND
RXD->A9,TXD->A10
LED連接配接
LED短腳->A3
LED長腳->3v3
- 軟體燒錄
-
視訊示範
前半部分為LED燈的實作,後半部分為序列槽通信
ucos1
總結
本篇部落格初步了解了嵌入式實時作業系統(RTOS)中的uC/OS,将其移植到stm32F103上,建構至少3個任務(task):其中兩個task分别以1s和3s周期對LED燈進行點亮-熄滅的控制;另外一個task以2s周期通過序列槽發送“hello uc/OS! 歡迎來到RTOS多任務環境!”。
此次用uC/OS開源代碼時,筆者發現移植十分繁雜且折磨,需要非常細心,否則在某一步驟不小心出錯了,将會十分難以更改。此步我是參考學長學姐部落格一步一步跟随着實作的,一定要耐心對比每一步的正确與否。
而且要特别注意keil中文輸入問題,十分容易出錯和格式,導緻亂碼。
此次實驗也讓我收益匪淺,感覺到了uc/OS的奇妙,在STM32最小核心闆上用另一種方式實作LED閃爍和序列槽通信,讓我學習到了更多的知識。
如果發現筆者的錯誤和值得改進的地方,歡迎大家多多交流溝通!
參考:https://baike.baidu.com/item/uC%2FOS-II/5866475
https://blog.csdn.net/qq_46467126/article/details/121441622?spm=1001.2014.3001.5502