根據正點原子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++;