当前位置: 首页 > news >正文

基于 STM32CubeMX 实现 FreeRTOS 可视化移植的多任务 LED 控制实践(基于 STM32F103ZET6)

1. 概述

1.1 实验目的        

        本实验通过使用 STM32CubeMX 工具对 FreeRTOS 进行可视化移植,并基于 STM32F103ZET6 开发板实现多任务 LED 控制,以及通过重定向打印任务运行指标调试信息。旨在掌握嵌入式实时操作系统的移植与任务调度机制。通过本实验,不仅加深了对 STM32 硬件架构与 HAL 库的理解,也提升了在多任务并行与系统资源管理方面的实践能力。该实验为今后在嵌入式系统开发、物联网设备控制及实时系统设计等工作中打下了坚实的基础。

1.2 硬件准备

        本实验所使用的硬件平台为一块 STM32F103ZET6 最小系统开发板,该开发板基于 ARM Cortex-M3 内核,主频 72MHz,性能稳定、资源丰富,适合进行 FreeRTOS 的移植与多任务调度实验。板载集成了两个用户可控的 LED 灯,分别连接至 GPIO 引脚,可用于任务状态的可视化显示与实验验证。

        程序下载与调试使用 J-Link V8 仿真器,其具备高速稳定的调试性能,能够实现对目标芯片的实时在线烧录与断点调试。同时,本实验也支持使用 ST-Link 仿真器 进行程序下载。若更换为 ST-Link,仅需在 Keil MDK 工程中修改 Debug 配置部分,STM32CubeMX 的外设及 FreeRTOS 配置保持完全一致,无需任何改动。

        通过上述硬件环境的搭建,能够为后续的 FreeRTOS 任务创建、调度测试以及多任务 LED 控制实验提供良好的基础和可靠的运行平台。

2 串口调试

2.1 开启配置

在STM32CubeMx中完成如下配置开启

功能CubeMX 选项作用
任务状态统计Use Trace Facility必须 Enable,支持 vTaskList()
任务信息格式化Use Stats Formatting Functions必须 Enable,支持 vTaskList()vTaskGetRunTimeStats()
运行时间统计Generate Run Time StatsEnable,支持 vTaskGetRunTimeStats()

2.2 任务状态信息

调用vTaskList(taskListBuf)获取相关信息,信息解析如下

列名含义
Task Name任务名称,对应在 osThreadNew() 时设置的名字
State当前任务状态:R=Running(运行中),B=Blocked(阻塞/延时等待),X=Suspended(挂起/未运行),其他还有 D=Deleted
Prio任务优先级(数值越大优先级越高)
Stack任务剩余栈空间(单位:字节),0 表示栈已满,需要注意
Num任务编号,由 FreeRTOS 内核分配,用于内部识别

2.3 任务时长及CUP占用

调用vTaskGetRunTimeStats(runTimeStatsBuf)获取相关信息。      

        为了统计 FreeRTOS 任务的运行时间,需要在硬件上准备一个高精度计数器并完成宏定义。通常步骤如下:

步骤1:定时器初始化
在 STM32 中,通过 CubeMX 配置一个独立定时器(如 TIM3)为递增计数模式,用作任务运行时间的计时源。
定时器应具有足够高的计数频率(如 1 MHz),以保证统计精度,同时避免与系统 Tick 或其他定时器冲突。
步骤2:宏定义绑定 FreeRTOS
在用户代码中定义两个宏,使 FreeRTOS 内核能够使用该定时器进行任务运行时间统计:

#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()  HAL_TIM_Base_Start(&htim3)
#define portGET_RUN_TIME_COUNTER_VALUE()          __HAL_TIM_GET_COUNTER(&htim3)

        第一个宏负责启动计时器,第二个宏负责获取当前计数值。
步骤3:任务运行时间统计
FreeRTOS 提供 vTaskGetRunTimeStats() 等函数,可以调用上述计数器来计算各任务的累积运行时间及 CPU 占用率。
通过串口打印结果,可以实时观察各任务的运行状态和 CPU 利用率,从而方便调试和系统性能分析。

2.4 建立监控任务

        在本实验中,为了实时监测 FreeRTOS 系统中各任务的运行状态与调度情况,需要建立一个独立的监控任务(Monitor Task)。
首先,在 STM32CubeMX 中完成 USART 外设的初始化,并开启 DMA 发送功能和中断功能,以确保系统在多任务环境下能够高效、稳定地进行串口日志输出。同时,通过 重定向 printf() 函数,实现将标准输出流映射到串口,从而便于在终端上查看任务运行信息。

        随后,在 FreeRTOS 配置界面中新建一个名为 monitor_task 的任务,设置适当的任务优先级与堆栈空间。该任务将周期性调用 vTaskList()和 vTaskGetRunTimeStats()等系统函数,获取当前所有任务的状态信息,并通过串口打印输出。
该监控任务的建立,不仅为系统调试与性能分析提供了重要依据,也为后续实现 CPU 占用率统计与任务运行时间监控奠定了基础。

3 STM32CubeMX配置

3.1 系统配置

与之前裸机开发不同,这里时基选择TIM2,选择其他通用定时器也可以。

3.2 配置时钟源

3.3 串口打印设置

3.3.1 设置串口参数

3.3.2 添加串口DMA通道

3.3.3 启动串口中断

3.4 LED引脚设置

通用推挽输出,默认高电平

3.5 freeRTOS设置

3.5.1 关闭NEWLIB

USE_NEWLIB_REENTRANT 选项 只适用于 GCC 编译器(如 STM32CubeIDE、ARM GCC 工具链)
Keil MDK 环境下必须保持 Disable(关闭)

3.5.2 调试信息配置

功能CubeMX 选项作用
任务状态统计Use Trace Facility必须 Enable,支持 vTaskList()
任务信息格式化Use Stats Formatting Functions必须 Enable,支持 vTaskList()vTaskGetRunTimeStats()
运行时间统计Generate Run Time StatsEnable,支持 vTaskGetRunTimeStats()

3.5.3 添加任务

3.5.4 运行时间计数器配置

FreeRTOS 运行时间统计只需要一个 单调递增计数器,通过读取计数器值即可计算各任务的 CPU 占用时间。
原则:统计定时器应独立于系统 Tick,否则计数器更新可能影响内核调度精度。

在当前实现中,使用的定时器为 16 位(最大计数 65535),预分频 7199,因此计数器在运行约 6.5 秒 后就会溢出,导致 CPU 占用率统计出现错误。

为避免溢出,可使用 32 位定时器或调低定时器分频,使溢出周期远大于统计周期,从而保证长期运行的准确性。在 STM32F103ZET6 单片机上,由于所用定时器仅为 16 位,其计数范围最大为 65535,即使调低分频,运行时间统计也只能支持约 6.5 秒 的最大统计周期。因此,在该平台上无法实现长期稳定的 CPU 占用率统计,这已接近硬件定时器的极限。

3.6 project设置

4 keil MDK配置

4.1 下载调试配置

4.2 串口打印配置

5. VSCode

5.1 printf 重定向

printf 重定向到 USART 实现串口日志输出

5.1.1 在usart.c中添加代码

/* USER CODE BEGIN 1 */
int fputc(int ch, FILE * file){ //打印重定�?HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,1000);return ch;
}
/* USER CODE END 1 */

5.1.2 在对应usart.h中添加引用

/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */

5.2 任务日志打印

以下内容均在freertos.c中完成:

5.2.1 添加inclues引用

/* USER CODE BEGIN Includes */
#include "usart.h"
#include "tim.h"
/* USER CODE END Includes */

5.2.2 添加宏定义

/* USER CODE BEGIN 1 */
/* Functions needed when configGENERATE_RUN_TIME_STATS is on */
__weak void configureTimerForRunTimeStats(void)
{HAL_TIM_Base_Start(&htim3);   // 启动 TIM3
}__weak unsigned long getRunTimeCounterValue(void)
{return __HAL_TIM_GET_COUNTER(&htim3);
}
/* USER CODE END 1 */

5.2.3 完善monitor任务

/* USER CODE BEGIN Header_monitor_task_handler */
/**
* @brief Function implementing the monitor_task thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_monitor_task_handler */
void monitor_task_handler(void *argument)
{/* USER CODE BEGIN monitor_task_handler */char taskListBuf[128];char runTimeStatsBuf[128];/* Infinite loop: 每秒打印一次系统状态 */for(;;){printf("\r\n========== FreeRTOS Monitor ==========\r\n");// 1️⃣ 打印任务列表(任务名称、状态、优先级、剩余栈空间、任务编号)vTaskList(taskListBuf);printf("Task Name   State  Prio  Stack  Num\r\n%s\r\n", taskListBuf);// 2️⃣ 打印 CPU 占用率和运行时间统计vTaskGetRunTimeStats(runTimeStatsBuf);printf("Task          RunTime      CPU Usage(%%)\r\n%s\r\n", runTimeStatsBuf);// 3️⃣ 打印系统启动时间(毫秒 / 秒)printf("System uptime: %lu ms (%lu s)\r\n", osKernelGetTickCount(), osKernelGetTickCount()/1000);printf("======================================\r\n");osDelay(1000); // 延时 1 秒,循环刷新状态}/* USER CODE END monitor_task_handler */
}

5.3 led任务完善

/* USER CODE BEGIN Header_led0_task_handler */
/*** @brief  Function implementing the led0_task thread.* @param  argument: Not used* @retval None*/
/* USER CODE END Header_led0_task_handler */
void led0_task_handler(void *argument)
{/* USER CODE BEGIN led0_task_handler *//* Infinite loop */for(;;){HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);osDelay(1000);}/* USER CODE END led0_task_handler */
}/* USER CODE BEGIN Header_led1_task_handler */
/**
* @brief Function implementing the led1_task thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_led1_task_handler */
void led1_task_handler(void *argument)
{/* USER CODE BEGIN led1_task_handler *//* Infinite loop */for(;;){HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);osDelay(300);}/* USER CODE END led1_task_handler */
}

6. 注意点

6.1 打印日志

6.2 监控时长

在当前实现中,使用的定时器为 16 位(最大计数 65535),预分频 7199,因此计数器在运行约 6.5 秒 后就会溢出,导致 CPU 占用率统计出现错误。

6.3 监控任务堆栈

任务越多,变量就应该越大,否则打印任务列表有截断,或者无法打印日志

char taskListBuf[128];
char runTimeStatsBuf[128];

这个变量调大后,同步的任务堆栈也要调大,否则程序运行异常,我试了下,最大可以调节到256,之后再大程序就无法正常运行了,可能和STM32F103ZET6的硬件最大SRAM有关。

http://www.dtcms.com/a/488065.html

相关文章:

  • 网站制作自己接单微分销代理
  • it项目网站开发的需求文档北京网站设计培训学校
  • Fragment与Fragment、Activity通信的方式?
  • 中建西部建设网站网站网页设计基本理论
  • wordpress网站有哪些免费的ppt模板下载软件
  • 目标检测全解析
  • 微企点网站建设的教学视频小程序定制开发要多少钱
  • 玩机搞机基本常识-------安卓刷机与 ROOT:从基础概念到工具选择指南 基础玩机 一
  • 查看你电脑上某个端口正在被哪个进程占用
  • 垦利网站建设建筑网建筑规范大全
  • wordpress标题标签10个网站用户体验优化的研究结果
  • 没有网站怎么做推广网站开发文献综述
  • 网站建设速成班培训免费公司网址怎么注册
  • 今日训练 ——线段树与二分法
  • PyQt5事件机制
  • 建盏十大高端客户合肥搜索优化排名
  • DeviceNet 转 CC-Link IE 实现欧姆龙 NJ 与西门子 S7-1500 在汽车焊接质量监控系统的集成应用
  • 建立网站的正确方法网站导航排版布局
  • 免费论坛网站大全广州哪个区封了
  • 【JSP程序设计】作用域通信对象 — pageContext对象
  • wordpress视频 小程序志鸿优化设计电子版
  • 专做运动品牌的网站佛山顺德做网站
  • 黔西南州做网站js网站开发视频
  • 数据结构——字典树Trie(介绍、Java实现)
  • 有什么有趣的网站做网站第一步做什么
  • 知名网站制作公司管理会计
  • ceph 手动编辑 crush 规则
  • 湘潭网站建设湘潭营销型网站建设实训报告
  • 网站的风格有哪些创建一个平台多少钱
  • PG Scrub 全流程核心步骤清单