2.5多任务示例编程2
1.CUBEMX配置
2.代码
void StartADC(void const * argument)
{/* USER CODE BEGIN StartADC */TickType_t pxPreviousWakeTime=xTaskGetTickCount();/* Infinite loop */for(;;){HAL_ADC_Start(&hadc1);if(HAL_ADC_PollForConversion(&hadc1,100)==HAL_OK){uint32_t value=HAL_ADC_GetValue(&hadc1);OLED_ShowNum(18,1,value,4,OLED_6X8);OLED_Update();}vTaskDelayUntil(&pxPreviousWakeTime,pdMS_TO_TICKS(500));}/* USER CODE END StartADC */
}/* USER CODE BEGIN Header_StartInfo */
/**
* @brief Function implementing the Task_Info thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartInfo */
void StartInfo(void const * argument)
{/* USER CODE BEGIN StartInfo */TaskHandle_t taskHandle=Task_ADCHandle;TaskStatus_t Taskinfo;BaseType_t getFreeStackSpace=pdTRUE;eTaskState taskState=eInvalid;vTaskGetInfo(taskHandle,&Taskinfo, getFreeStackSpace, taskState)PRIVILEGED_FUNCTION;//获取任务信息的函数/*该函数输入参数有四个,TaskHandle_t xTask为所要查询任务的任务句柄;TaskStatus_t *pxTaskStatus为任务状态结构体,用于存放任务的状态,该结构体需要用户自定义;BaseType_t xGetFreeStackSpace为是否计算任务剩余最小堆栈大小,传入参数pdTRUE表示计算,但需要耗费一些时间;eTaskState eState为是否获取任务状态,输入参数eInvalid时表示获取任务状态,但同样也会消耗一些时间,否则用户指定任务状态,不会消耗时间。*/taskENTER_CRITICAL();//开启临界代码段,不允许任务调度CRITICAL主要的,关键的
// uint8_t temp_str[100];
// sprintf(temp_str,"Task Name=%s",Taskinfo.pcTaskName);
// OLED_ShowString(1,9,"*(temp_str)",OLED_6X8);//1 OLED_Printf(1, 9,OLED_6X8,"Task Name=%s",Taskinfo.pcTaskName);
// OLED_Printf(1, 18,OLED_6X8,"Task Number=%d",Taskinfo.xTaskNumber);//获取任务编号
// OLED_Printf(1, 27,OLED_6X8,"Task State=%d",Taskinfo.eCurrentState);
// OLED_Printf(1, 36,OLED_6X8,"Task Priority=%d",Taskinfo.uxCurrentPriority);
// OLED_Printf(1, 45,OLED_6X8,"High Mark=%d(word)",Taskinfo.usStackHighWaterMark);
// OLED_Update();
//2 taskHandle=xTaskGetIdleTaskHandle();
// OLED_Printf(1, 9,OLED_6X8,"Idle Task =%d",uxTaskGetStackHighWaterMark(taskHandle));
// OLED_Printf(1, 18,OLED_6X8,"Task ADCr=%d",uxTaskGetStackHighWaterMark(Task_ADCHandle));
// OLED_Printf(1, 27,OLED_6X8,"Task Info=%d",uxTaskGetStackHighWaterMark(Task_InfoHandle));
// OLED_Update();
// OLED_Clear();OLED_Printf(1, 9,OLED_6X8,"uxTaskGet=%d",uxTaskGetNumberOfTasks());//3获取任务的总数OLED_Update();taskEXIT_CRITICAL();
// OLED_ShowString(9,9,"taskIofo.pcTaskName",OLED_6X8);
// OLED_Update();/* Infinite loop */for(;;){for(uint8_t i=0;i<10;i++){
// OLED_Clear();HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);vTaskDelay(pdMS_TO_TICKS(100));}break;}
// OLED_Clear();OLED_Printf(1, 18,OLED_6X8,"Task_Info is deleted");HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);OLED_Update();vTaskDelete(NULL);/* USER CODE END StartInfo */
}/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
//void vApplicationIdleHook(void)
//{
// OLED_Clear();
//}/* USER CODE END Application */
#define configUSE_TRACE_FACILITY 1 //vTaskGetInfo
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTaskGetIdleTaskHandle 1 //xTaskGetIdleTaskHandle()
使用静态创建函数创建 FreeRTOS 任务时,需要记住一点:必须实现 vApplicationGetIdleTaskMemory 函数来完成空闲任务的内存分配。这是因为在使用静态内存分配时,FreeRTOS 会自动创建一个空闲任务,该任务会在系统空闲时进行调度。
空闲任务可以执行某些不需要 CPU 时间的操作,比如暂时挂起 CPU、等待时钟中断、等待消息等,以便释放 CPU 资源给其它任务使用。
空闲任务需要分配堆栈和任务控制块,而这些内存区域需要手动向 FreeRTOS 系统申请。
在这种情况下,我们需要实现 vApplicationGetIdleTaskMemory 函数,该函数会在空闲任务创建之前被调用。
在该函数中,我们需要声明一个静态的变量作为空闲任务控制块的内存池,
并将该内存池的首地址和大小等信息传递给空闲任务创建函数,以完成空闲任务的内存分配。
任务使用的堆栈将随着任务的执行和中断的处理而增长和收缩。
uxTaskGetStackHighWaterMark()返回自任务开始执行以来任务可用的最小剩余堆栈空间量,
即任务堆栈达到最大(最深)值时未使用的堆栈量。这就是所谓的烟囱“高水位线”。
注意:返回值更新的前提是有新的最小值出现,否则即便初始化新的临时变量,可能也不会刷新这个 HiqhWaterMark 的值(因为 stacksize 减小了,但是没有到刷新最小值的地步)。
注意:Task 本身的 handle、状态管理不消耗这个 stack size(内部用的是malloc),
但是printf()这个函数是消耗 stack size 的。