FreeRTOS-06任务运行时间信息统计
根据正点原子FreeRTOS视频整理
单片机:STM32F207VC
FreeRTOS源码版本:v10.0.1
* 1. 要使用vTaskGetRunTimeStats()函数,需满足以下条件: * a 宏configGENERATE_RUN_TIME_STATS必须为1 * b 定义宏:portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() 配置一个高精度定时器提供时基 * c 定义宏:portGET_RUN_TIME_COUNTER_VALUE() 读取时基的时间值
1. main.c
1 /* 2 * 1. 要使用vTaskGetRunTimeStats()函数,需满足以下条件: 3 * a 宏configGENERATE_RUN_TIME_STATS必须为1 4 * b 定义宏:portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() 配置一个高精度定时器提供时基 5 * c 定义宏:portGET_RUN_TIME_COUNTER_VALUE() 读取时基的时间值 6 */ 7 #include "main.h" 8 #include "delay.h" 9 #include "sys.h" 10 #include "usart.h" 11 #include <string.h> /*memset()*/ 12 13 #include "stm32f2xx_gpio.h" 14 #include "stm32f2xx_tim.h" 15 16 #include "FreeRTOS.h" 17 #include "task.h" 18 19 #define START_TASK_PRIO 1 /*任务优先级*/ 20 #define START_STK_SIZE 128 /*任务堆栈大小*/ 21 TaskHandle_t StartTask_Handle; /*任务句柄*/ 22 void StartTask(void *pvParameters); /*任务函数*/ 23 24 #define LED_TASK_PRIO 2 25 #define LED_STK_SIZE 128 26 TaskHandle_t LedTask_Handle; 27 void LedTask(void *pvParameters); 28 29 #define RUNTIMESTATS_TASK_PRIO 3 30 #define RUNTIMESTATS_STK_SIZE 128 31 TaskHandle_t RunTimeStats_Handle; 32 void RunTimeStatsTask(void *pvParameters); 33 34 35 char RunTimeInfo[400]; /*保存任务运行时间信息*/ 36 uint8_t ControlCounter = 0; 37 volatile unsigned long long FreeRTOSRunTimeTicks; 38 39 40 /***** 声明 *****/ 41 static void SystemInitial(void); 42 static void GPIO_LED_Configuration(void); 43 static void Timer4_Configuration(void); 44 static void Timer4_NVIC_Configuration(void); 45 46 static void GPIO_LED_Configuration(void) 47 { 48 GPIO_InitTypeDef GPIO_InitStructure; 49 50 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); 51 52 GPIO_InitStructure.GPIO_Pin = LED_POWER | LED_RUN | LED_ALARM; 53 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; 54 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; 55 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 56 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; 57 GPIO_Init(GPIOE, &GPIO_InitStructure); 58 59 LED_Power_On(); 60 GPIO_SetBits(GPIOE, LED_RUN); 61 } 62 63 64 void StartTask(void *pvParameters) 65 { 66 taskENTER_CRITICAL(); /*进入临界区*/ 67 68 xTaskCreate((TaskFunction_t )LedTask, /*任务函数*/ 69 (const char * )"LedTask", /*任务名称*/ 70 (uint16_t )LED_STK_SIZE, /*任务堆栈大小*/ 71 (void * )NULL, /*传递给任务函数的参数*/ 72 (UBaseType_t )LED_TASK_PRIO, /*任务优先级*/ 73 (TaskHandle_t )&LedTask_Handle); /*任务句柄*/ 74 75 xTaskCreate((TaskFunction_t )RunTimeStatsTask, /*任务函数*/ 76 (const char * )"RunTimeStatsTask", /*任务名称*/ 77 (uint16_t )RUNTIMESTATS_STK_SIZE, /*任务堆栈大小*/ 78 (void * )NULL, /*传递给任务函数的参数*/ 79 (UBaseType_t )RUNTIMESTATS_TASK_PRIO, /*任务优先级*/ 80 (TaskHandle_t )&RunTimeStats_Handle); /*任务句柄*/ 81 82 vTaskDelete(StartTask_Handle); /*删除开始任务*/ 83 taskEXIT_CRITICAL(); /*退出临界区*/ 84 } 85 86 void LedTask(void *pvParameters) 87 { 88 while (1) 89 { 90 GPIOE->ODR ^= LED_RUN; 91 vTaskDelay(1000); 92 } 93 } 94 95 void RunTimeStatsTask(void * pvParameters) 96 { 97 while (1) 98 { 99 if (5 == ControlCounter) 100 { 101 ControlCounter = 0; 102 memset(RunTimeInfo, 0, 400); /*信息缓冲区清零*/ 103 vTaskGetRunTimeStats(RunTimeInfo); /*获取任务运行时间信息*/ 104 printf("任务名\t\t运行时间\t运行所占百分比\r\n"); 105 printf("%s\r\n", RunTimeInfo); 106 } 107 vTaskDelay(10); 108 } 109 } 110 111 112 113 static void SystemInitial(void) 114 { 115 /*组4,16级抢占优先级,无响应优先级*/ 116 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); 117 118 DelayInitial(); 119 USART1_Initialization(); 120 GPIO_LED_Configuration(); 121 ConfigureTimeForRunTimeStats(); 122 } 123 124 int main(void) 125 { 126 SystemInitial(); 127 128 /*创建开始任务*/ 129 xTaskCreate((TaskFunction_t )StartTask, /*任务函数*/ 130 (const char * )"StartTask", /*任务名称*/ 131 (uint16_t )START_STK_SIZE, /*任务堆栈大小*/ 132 (void * )NULL, /*传递给任务函数的参数*/ 133 (UBaseType_t )START_TASK_PRIO, /*任务优先级*/ 134 (TaskHandle_t * )&StartTask_Handle); /*任务句柄*/ 135 136 /*开启任务调度*/ 137 vTaskStartScheduler(); 138 } 139 140 ///////////////////定时器4////////////////////////////////////// 141 /***** Timer4 *****/ 142 void ConfigureTimeForRunTimeStats(void) 143 { 144 FreeRTOSRunTimeTicks = 0; 145 Timer4_Configuration(); 146 Timer4_NVIC_Configuration(); 147 } 148 149 /*timer4:APB1 30MHz*/ 150 static void Timer4_Configuration(void) 151 { 152 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 153 154 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); 155 156 /*预分频系数*/ 157 TIM_TimeBaseStructure.TIM_Prescaler = 30-1; 158 /*计数值,每计50个数,产生一次中断. 50*(1/1MHk) = 50us */ 159 TIM_TimeBaseStructure.TIM_Period = 50-1; 160 /*设置计数器模式为向上计数模式*/ 161 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 162 /*设置时钟分频系数,TIM_CKD_DIV1不分频*/ 163 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 164 165 TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStructure); 166 167 /*使能TIM4外设。在使用外设时,不仅要使能其时钟,还要调用此函数使能外设才可以正常使用*/ 168 TIM_Cmd(TIM4, ENABLE); 169 170 /*清除溢出中断标志*/ 171 TIM_ClearFlag(TIM4, TIM_IT_Update); 172 173 /*开启中断*/ 174 TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE); 175 } 176 177 /**/ 178 static void Timer4_NVIC_Configuration(void) 179 { 180 NVIC_InitTypeDef NVIC_InitStructure; 181 182 /*3级抢占优先级,0级响应优先级*/ 183 NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; 184 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; 185 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 186 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 187 188 NVIC_Init(&NVIC_InitStructure); 189 } 190 191 /*中断服务函数*/ 192 uint16_t Timer4Counter = 0; 193 void TIM4_IRQHandler(void) 194 { 195 if (TIM_GetITStatus(TIM4, TIM_IT_Update)==SET) 196 { 197 FreeRTOSRunTimeTicks++; 198 199 Timer4Counter++; 200 if (Timer4Counter>=40000) 201 { 202 Timer4Counter = 0; 203 GPIOE->ODR ^= LED_ALARM; 204 205 ControlCounter++; 206 } 207 } 208 TIM_ClearITPendingBit(TIM4, TIM_IT_Update); 209 } 210 211 /***************************END OF FILE***************************/
2. main.h
1 /**/ 2 #ifndef __MAIN_H__ 3 #define __MAIN_H__ 4 5 #define LED_POWER GPIO_Pin_2 /*PE2*/ 6 #define LED_RUN GPIO_Pin_3 /*PE3*/ 7 #define LED_ALARM GPIO_Pin_4 /*PE4*/ 8 9 #define LED_Power_On() GPIO_ResetBits(GPIOE, LED_POWER) 10 11 extern void ConfigureTimeForRunTimeStats(void); 12 13 14 #endif /*__MAIN_H__*/ 15 16 /***************************END OF FILE***************************/
3. sys.c
1 /**/ 2 #include "sys.h" 3 #include "stdio.h" 4 5 #pragma import(__use_no_semihosting) 6 //标准库需要的支持函数 7 struct __FILE 8 { 9 int handle; 10 11 }; 12 13 FILE __stdout; 14 //定义_sys_exit()以避免使用半主机模式 15 void _sys_exit(int x) 16 { 17 x = x; 18 } 19 /* //重定义fputc函数 20 int fputc(int ch, FILE *f) 21 { 22 while((USART1->SR&0X40)==0) //循环发送,直到发送完毕 23 USART1->DR = (u8) ch; 24 return ch; 25 } */ 26 27 28 /***************************END OF FILE***************************/
4. sys.h
1 /**/ 2 #ifndef __SYS_H__ 3 #define __SYS_H__ 4 5 /*0不支持OS,1支持OS*/ 6 #define SYSTEM_SUPPORT_OS 1 /*定义系统文件夹是否支持OS*/ 7 8 #endif /*__SYS_H__*/ 9 10 /***************************END OF FILE***************************/
5. delay.c
1 /**/ 2 #include "delay.h" 3 #include "sys.h" 4 /*如果需要使用OS,则包括下面的头文件即可*/ 5 #if SYSTEM_SUPPORT_OS 6 #include "FreeRTOS.h" 7 #include "task.h" 8 #endif 9 10 __IO uint32_t TimingDelay; 11 12 ////////////////////////// 13 //static uint8_t fac_us = 0; 14 ////////////////////////// 15 16 /***** 声明 *****/ 17 extern void xPortSysTickHandler(void); 18 19 /*systick中断服务函数,使用FreeRTOS时用到*/ 20 void SysTick_Handler(void) 21 { 22 TimingDelayDecrement(); 23 24 if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED) /*系统已运行*/ 25 { 26 xPortSysTickHandler(); 27 } 28 } 29 30 31 void DelayInitial(void) 32 { 33 /* 34 * SystemCoreClock / 1000 1ms中断一次 35 * SystemCoreClock / 100000 10us中断一次 36 * SystemCoreClock / 1000000 1us中断一次 37 */ 38 if (SysTick_Config(SystemCoreClock / 1000)) 39 { 40 while (1); 41 } 42 /*关闭systick timer定时器*/ 43 /* SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;*/ 44 45 /*使能滴答定时器*/ 46 SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; 47 } 48 49 //void DelayNus(uint32_t nus) 50 //{ 51 // uint32_t ticks; 52 // uint32_t told, tnow, tcnt = 0; 53 // uint32_t reload = SysTick->LOAD; 54 // 55 // fac_us = SystemCoreClock / 1000000; 56 // ticks = nus * fac_us; 57 // told = SysTick->VAL; 58 // 59 // while (1) 60 // { 61 // tnow = SysTick->VAL; 62 // if (tnow != told) 63 // { 64 // if (tnow < told) 65 // { 66 // tcnt += told - tnow; 67 // } 68 // else 69 // { 70 // tcnt += reload - tnow + told; 71 // } 72 // told = tnow; 73 // if (tcnt >= ticks) break; 74 // } 75 // } 76 //} 77 78 ///*不会引起调度*/ 79 //void DelayXms(uint32_t nms) 80 //{ 81 // uint32_t i; 82 // 83 // for (i=0;i<nms;++i) 84 // { 85 // DelayNus(1000); 86 // } 87 //} 88 89 /* 90 * 本函数在中断函数中调用,滴答定时器中断一次调用一次。 91 */ 92 void TimingDelayDecrement(void) 93 { 94 if (TimingDelay != 0x00) 95 { 96 TimingDelay--; 97 } 98 } 99 100 /* 101 * TimingDelay值在TimingDelayDecrement函数中递减 102 */ 103 void DelayNms(uint32_t nTimes) 104 { 105 TimingDelay = nTimes; 106 107 while (TimingDelay!=0); //等待计数停止 108 } 109 110 /***************************END OF FILE***************************/
6. delay.h
1 /**/ 2 #ifndef __DELAY_H__ 3 #define __DELAY_H__ 4 5 #include "stm32f2xx.h" 6 7 #include <stdint.h> 8 9 extern void DelayInitial(void); 10 extern void TimingDelayDecrement(void); 11 extern void DelayNms(uint32_t nTimes); 12 13 ///////////////////////// 14 extern void DelayXms(uint32_t nms); 15 ///////////////////////// 16 17 #endif /*__DELAY_H__*/ 18 /***************************END OF FILE***************************/
7. usart.c
1 /* 2 * USART1: 中断优先级选择第4组, 3级抢占优先级 无响应优先级 3 */ 4 #include "usart.h" 5 #include "stdio.h" /*printf*/ 6 #include "stm32f2xx.h" 7 #include "stm32f2xx_gpio.h" 8 #include "stm32f2xx_rcc.h" 9 #include "stm32f2xx_usart.h" 10 11 12 uint8_t USART1_RxBuffer[USART1_RECEIVE_SIZE]; 13 uint8_t Flag_USART1Receive = 0; 14 uint8_t USART1_ReceiveCount = 0; 15 uint8_t USART1_ReceiveIndex = 0; 16 17 18 void USART1_Initialization(void) 19 { 20 USART1_GPIO_Configuration(); 21 USART1_NVIC_Configuration(); 22 /*USART1使能接收中断*/ 23 // USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); 24 /*USART1使能发送中断*/ 25 /* USART_ITConfig(USART1, USART_IT_TXE, ENABLE); */ 26 } 27 /* 28 */ 29 void USART1_GPIO_Configuration(void) 30 { 31 GPIO_InitTypeDef GPIO_InitStructure; 32 USART_InitTypeDef USART_InitStructure; 33 34 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); 35 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); 36 GPIO_PinAFConfig(GPIOA, 9, GPIO_AF_USART1); /*GPIO连接到串口1上,PA9-TXD*/ 37 GPIO_PinAFConfig(GPIOA, 10, GPIO_AF_USART1); /*GPIO连接到串口1上,PA10-RXD*/ 38 39 /*tx, PA9*/ 40 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 41 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; 42 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 43 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 44 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; 45 GPIO_Init(GPIOA, &GPIO_InitStructure); 46 47 /*rx, PA10*/ 48 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; 49 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; 50 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 51 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; 52 GPIO_Init(GPIOA, &GPIO_InitStructure); 53 54 /*配置波特率9600*/ 55 USART_InitStructure.USART_BaudRate = 115200; 56 /*配置串口的模式。为了配置双线全双工通讯,需要把Rx和Tx模式都开启. Tx发送使能和Rx接收使能*/ 57 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; 58 /*无奇偶校验*/ 59 USART_InitStructure.USART_Parity = USART_Parity_No; 60 /*1停止位*/ 61 USART_InitStructure.USART_StopBits = USART_StopBits_1; 62 /*配置串口传输字长8位*/ 63 USART_InitStructure.USART_WordLength = USART_WordLength_8b; 64 /*不采用硬件流控制*/ 65 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 66 /*向寄存器写入配置参数*/ 67 USART_Init(USART1, &USART_InitStructure); 68 /*使能USART1外设。在使用外设时,不仅要使能其时钟,还要调用此函数使能外设才可以正常使用*/ 69 USART_Cmd(USART1, ENABLE); 70 } 71 72 //void USART1_SendNChar(uint8_t *str, uint8_t n) 73 //{ 74 // /*发送区是否为空*/ 75 // while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); 76 // 77 // while (n--) 78 // { 79 // USART_SendData(USART1, (uint8_t)(*str++)); 80 // /*是否发送完成*/ 81 // while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); 82 // } 83 //} 84 85 /* 86 * 如果一次发送多个字节数据,可能会多次进入此函数 87 * 调用时,应先延时几十毫秒,确保把数据都接收完 88 */ 89 //void USART1_ReceiveIRQ(void) 90 //{ 91 // /*如果寄存器中有数据*/ 92 // while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET) 93 // { 94 // USART1_RxBuffer[USART1_ReceiveIndex++] = USART_ReceiveData(USART1); 95 // USART1_ReceiveCount++; 96 // } 97 // 98 // Flag_USART1Receive = 1; 99 //} 100 101 void USART1_NVIC_Configuration(void) 102 { 103 NVIC_InitTypeDef NVIC_InitStructure; 104 105 /*中断优先级选择第1组*/ 106 // NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); 107 108 /*3级抢占优先级 0级响应优先级*/ 109 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; 110 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; 111 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 112 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 113 NVIC_Init(&NVIC_InitStructure); 114 } 115 116 /*重定义fputc函数 2种方法都可以*/ 117 /* 118 int fputc(int ch,FILE *f) 119 { 120 while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET); 121 USART_SendData(USART1,(uint8_t)ch); 122 while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET); 123 124 return (ch); 125 } 126 */ 127 128 int fputc(int ch, FILE *f) 129 { 130 while((USART1->SR&0X40)==0) /*循环发送,直到发送完毕*/ 131 {} 132 133 USART1->DR = (uint8_t)ch; 134 return ch; 135 } 136 /***************************END OF FILE***************************/
8. usart.h
1 /* 2 * 3 */ 4 #ifndef __USART_H__ 5 #define __USART_H__ 6 7 #include <stdint.h> /* uint8_t */ 8 9 #define USART1_RECEIVE_SIZE 20 10 11 12 void USART1_Initialization(void); 13 void USART1_GPIO_Configuration(void); 14 void USART1_SendNChar(uint8_t *str, uint8_t n); 15 void USART1_ReceiveIRQ(void); 16 void USART1_NVIC_Configuration(void); 17 18 #endif /*__USART_H__*/ 19 20 /***************************END OF FILE***************************/
打印结果:
问题: 1. 在串口助手中,只显示:任务名、运行时间、运行所占百分比这一行,不显示LedTask等信息。 解决:中断服务函数中,忘记这一行:FreeRTOSRunTimeTicks++;