使用STM32CubeMX自动配置的工程,对其提供的FreeRTOS系统的CPU使用率进行监测,并通过串口打印。
(1)软件环境:STM32CubeMX-4.22.0,IAR-7.5,串口调试工具
(2)硬件环境:原子战舰V3开发板
(1)STM32CubeMX软件主要配置:
管脚和其他外设的配置直接省略了,具体的可查看源码文件里的ioc文件。下面贴出主要的系统方面配置图:
首先是Configuration界面,从图中可以看出测试工程使用的东西并不多;
点击中间层的FREERTOS进入系统配置界面,主要注意下图中红色标注的部分;
下图对一些系统的函数进行使能和失能操作,由于测试工程里有用到vTaskDelayUntil函数,所以对其使能。
(2)IAR软件配置:
首先从stm32官网下载的固件包里找到如下文件:
细心的人会发现这个是在F7的固件包里找的,当然F1的固件包里也可以找到,所以此方式也适用于其他支持FreeRTOS的stm32芯片。
将两个文件复制到测试工程文件夹内,对应地址如下图(地址在后面添加头文件时有用,可实际根据自身情况拖放):
在工程里添加cpu_utils.c文件
在工程配置选项里添加cpu_utils.h文件路径,这里我用的是相对路径,如果换别的电脑上时使用只需要重新ReBuild一下工程就好了。
在cpu_utils.h里添加使用到的两个头文件:
最后在FreeRTOSConfig.h文件的用户代码区添加如下两段代码。这一步很重要,如果没有,那么监测到的使用率一直为100%。
以下是测试主要代码,具体内容可查看源码。
/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "cmsis_os.h"
/* USER CODE BEGIN Includes */
#include "gpio.h"
#include "string.h"
#include "usart.h"
#include "cpu_utils.h"
/* USER CODE END Includes */
/* Variables -----------------------------------------------------------------*/
osThreadId defaultTaskHandle;
/* USER CODE BEGIN Variables */
#define START_TASK_PRIO 1
#define START_STK_SIZE 64
TaskHandle_t xHandleTaskStart;
void StartTask(void const * argument);
#define LED1_TASK_PRIO 5
#define LED1_STK_SIZE 128
TaskHandle_t xHandleTaskLED1;
void TaskLED1(void const * argument);
#define LED2_TASK_PRIO 6
#define LED2_STK_SIZE 128
TaskHandle_t xHandleTaskLED2;
void TaskLED2(void const * argument);
void MX_FREERTOS_Init(void) {
//系统自建的任务,不去动它,屏蔽了也没关系。
osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
//创建开始任务
xTaskCreate((TaskFunction_t )StartTask,
(const char * )"Start Task",
(uint16_t )START_STK_SIZE,
(void * )NULL,
(UBaseType_t )START_TASK_PRIO,
(TaskHandle_t * )&xHandleTaskStart);
/* USER CODE END RTOS_QUEUES */
}
//开始任务,用于创建两个新的测试任务
void StartTask(void const * argument)
{
taskENTER_CRITICAL();
xTaskCreate((TaskFunction_t )TaskLED1,
(const char * )"LED1 Task",
(uint16_t )LED1_STK_SIZE,
(void * )str1,
(UBaseType_t )LED1_TASK_PRIO,
(TaskHandle_t * )&xHandleTaskLED1);
xTaskCreate((TaskFunction_t )TaskLED2,
(const char * )"LED2 Task",
(uint16_t )LED2_STK_SIZE,
(void * )str2,
(UBaseType_t )LED2_TASK_PRIO,
(TaskHandle_t * )&xHandleTaskLED2);
vTaskDelete(xHandleTaskStart);
taskEXIT_CRITICAL();
}
//LED1任务
void TaskLED1(void const * argument)
{
char str1[] = "TASK LED1 is Running!\r\n";
portTickType xLastWakeTime;
static uint16_t usage = 0;
uint32_t num = 0;
char buffer[100];
//延时时间单元初始值记录
xLastWakeTime = xTaskGetTickCount();
while(1)
{
//串口1发送提示字符串
HAL_UART_Transmit(&huart1,(uint8_t *)str1,strlen(str1),0xFFFF);
while(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_TC)!=SET);
//获取CPU使用率并串口打印
usage = osGetCPUUsage();
num = sprintf(buffer,"1---CPU 使用率为:%d%%\r\n",usage);
HAL_UART_Transmit(&huart1,(uint8_t *)buffer,num,0xFFFF);
while(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_TC)!=SET);
//LED闪烁
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
vTaskDelayUntil(&xLastWakeTime,(1000/portTICK_RATE_MS));
}
}
//LED2任务
void TaskLED2(void const * argument)
{
char str2[] = "TASK LED2 is Running!\r\n";
portTickType xLastWakeTime;
static uint16_t usage = 0;
uint32_t num = 0;
char buffer[100];
//延时时间单元初始值记录
xLastWakeTime = xTaskGetTickCount();
while(1)
{
//串口1发送提示字符串
HAL_UART_Transmit(&huart1,(uint8_t *)str2,strlen(str2),0xFFFF);
while(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_TC)!=SET);
//获取CPU使用率并串口打印
usage = osGetCPUUsage();
num = sprintf(buffer,"2---CPU 使用率为:%d%%\r\n",usage);
HAL_UART_Transmit(&huart1,(uint8_t *)buffer,num,0xFFFF);
while(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_TC)!=SET);
//LED闪烁
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_RESET);
vTaskDelayUntil(&xLastWakeTime,(300/portTICK_RATE_MS));
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_SET);
vTaskDelayUntil(&xLastWakeTime,(1200/portTICK_RATE_MS));
}
}
/* USER CODE END Application */
在嵌入式系统中,如果当前没有任何计划的任务运行,则系统会自动切换到空闲任务当中去。当一个系统中空闲任务占用一段时间的比值越大,对应硬件CPU对于工程所留的计算余量也就越大,则这个系统的CPU使用率越低。
实际算法可简化为以下公式:
系统使用率 = 1 - 空闲任务占用时间/总测算时间
下图中箭头指向的位置是CPU使用率计算的算法核心,它是在Tick中断发生1000次时进行一次计算处理。也就是总测算时间为1000个心跳时钟。其中计算部分对原公式右边乘上了100倍,实际计算出来的osCPU_Usage为百分数。
以下两个函数是在FreeRTOSConfig.h宏定义中提到的函数,红色数字标注的是要重点关注的地方。这两个函数就是用来测算进入空闲函数的时间。
以上两个函数通过宏定义的方式,实际调用在系统任务切换函数里。也就是在这两个位置进行处理,进而得到需要的空闲任务占用时间。
在IAR的Live Watch窗口监测的系统使用率的值、系统心跳时基和空闲任务总占用时间。
下面是串口的输出,看出系统在刚开始时使用率有一段波动,后面趋于平稳,一直处于1%。
链接:https://pan.baidu.com/s/1qYmD2VU