长沙的网站建设公司,上海做网站的哪家好,开公司需要注册多少资金,中国建设银行网址多少文章目录 3 FreeRTOS任务操作3.1 创建task3.2 删除task3.2.1 空闲#xff08;idle#xff09;任务#xff08;守护任务#xff09;3.2.2 钩子#xff08;Hook#xff09;函数 3.3 设置#xff0c;获取#xff0c;task优先级3.3.1 设置任务优先级3.3.2 获取任务优先级 3… 文章目录 3 FreeRTOS任务操作3.1 创建task3.2 删除task3.2.1 空闲idle任务守护任务3.2.2 钩子Hook函数 3.3 设置获取task优先级3.3.1 设置任务优先级3.3.2 获取任务优先级 3.4 任务示例 3 FreeRTOS任务操作
3.1 创建task
任务的创建不代表任务的执行任务创建后还需要使用调度器来让任务执行。即vTaskStartScheduler同时创建任务函数不等于任务处理函数。他只是创建了任务但是没有规定任务要做什么。
有动态创建和静态创建两种创建方式
动态分配只需要我们提供任务的堆栈大小和返回句柄TCB任务块任务堆栈的大小是动态分配的系统会使用malloc等函数分配的内存在堆区基本方式是使用xTaskCreate函数动态分配这也是我们常用的分配方式使用动态分配时会自己自动实现malloc和free功能。静态分配提供任务的堆栈大小和返回句柄的同时还需要提供堆栈空间和任务控制块基本使用方式是使用xTaskCreateStatic函数动态分配。
/* brief 动态分配内存创建任务函数retval pdTRUE创建成功errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY内存不足创建失败 param pvTaskCode是一个函数指针用来指向任务处理函数pcName任务的名字usStackDepth给这个任务分配的栈的深度注意单位是word1表示4个字节而不是1个字节。pvParameters调用任务处理函数时传入的参数uxPriority这个任务的优先级别pxCreatedTask任务句柄之后对这个任务的操作都通过他来操作类似于文件描述符。句柄类型是TaskHandle_t类型。
*/
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,const char * const pcName,const uint16_t usStackDepth,void * const pvParameters,UBaseType_t uxPriority,TaskHandle_t * const pxCreatedTask );/*brief 静态分配内存创建任务函数retval 创建成功的任务句柄param pvTaskCode任务函数pcName任务名称usStackDepth任务栈深度单位为字wordpvParameters任务参数uxPriority任务优先级puxStackBuffer任务栈空间数组创建任务的堆栈首地址pxTaskBuffer任务控制块存储空间
*/
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,const char * const pcName, const uint32_t ulStackDepth,void * const pvParameters,UBaseType_t uxPriority,StackType_t * const puxStackBuffer,StaticTask_t * const pxTaskBuffer );//创建一个任务处理函数即任务创建后被调度器执行的时候做什么事情。函数原型如下
//TaskFunction_t是一个函数指针指向void FunctionName void*这样的函数
typedef void (* TaskFunction_t)( void * );
//所以我们对应的函数应该长这个样子
void TaskFunctionName( void *pvParameters );ps任务控制块地址和任务句柄并不相同我们操控任务是通过任务句柄操作的任务句柄最终指向任务控制块。
根据任务处理函数的原型我们可以知道规定任务处理函数时需要有以下特点
这个函数不能有返回值他的参数void *pvParameters 是通过创建任务函数xTaskCreate的参数传递进来的。可以用同一个任务处理函数创建多个任务也就是说多个任务执行同一个事情。
ps因为每次创建任务的时候都会分配栈空间 这就意味着任务1的局部变量存储在任务1的栈空间中而任务2的局部变量存储在任务2的栈空间中但是有全局变量时我们应该像多线程使用临界资源那样对全局变量进行保护和防止冲突因为全局变量的内存时多个任务公用的。这也就是为什么我们说任务这个概念更类似与线程而不是进程的原因。
3.2 删除task
删除一个任务/释放一个任务的资源。使用vTaskDelete()可以删除使用xTaskCreate()函数创建的任务也可以删除xTaskCreateStatic()函数创建的任务。
/* brief删除一个任务函数retvalNoneparamTaskHandle_t xTaskToDelete任务对应的句柄当这个句柄的值为NULL时代表释放自己的资源。
*/
void vTaskDelete(TaskHandle_t xTaskToDelete)3.2.1 空闲idle任务守护任务
FreeRTOS的调度器决定了任何时刻处理器必须有一个任务运行当所有的任务都处于阻塞或挂起等状态不能运行时空闲任务就会被执行同时我们在创建任务后当然需要删除释放该任务函数所使用的内存这个清理的工作就是由空闲任务来完成的。空闲任务有如下特点
对于自杀的任务内存由空闲任务进行清理。对于被杀的任务由调用了vTaskDelete这个函数的任务内部清理(凶手任务调用这个函数由凶手任务清理)。空闲任务的任务优先级为0它不能阻碍用户的任务运行。空闲任务要么处于就绪Ready态要么处于运行态永远不会阻塞
ps**也正是因为空闲任务的优先级为0最低所以使用vTaskDelete释放自己或其他任务时一定要保证有机会让空闲任务执行否则资源是得不到释放的。**举个例子task1和task2的优先级分别为1和2task2优先级较高所以优先执行若task2自杀后轮到task1执行若task1一直处于运行态不释放CPU的执行权限那么task2的TCB任务块和相应的堆栈资源就一直不会被清理。空闲任务是在调度器vTaskStartScheduler调度时自动创建的第一个任务。
3.2.2 钩子Hook函数
相当于向空闲任务的处理函数中添加了处理程序。使能后当调度器调度内核进入空闲任务时就会调用钩子函数
//一般情况下这个宏为0在FreeRTOSConfig.h文件中
#define configUSE_IDLE_HOOK 0
若要使能钩子函数需要将宏定义为1同时编辑extern void vApplicationIdleHook( void ); 函数这里实现我们在空闲任务中想要额外实现的功能。钩子函数并不会取消原先空闲任务中的释放内存的功能。在钩子函数中万万不可以使用while或者会造成一直阻塞的函数。
3.3 设置获取task优先级
3.3.1 设置任务优先级
/* brief用来设置任务的优先级retvalNoneparamTaskHandle_t xTask对应要设置的任务的句柄UBaseType_t uxNewPriority新的优先级取值范围是0~(configMAX_PRIORITIES-1 )
*/
void vTaskPrioritySet(TaskHandle_t xTask, UBaseType_t uxNewPriority);3.3.2 获取任务优先级
/* brief用来获取任务优先级retval返回优先级paramconst TaskHandle_t xTask获取这个句柄的优先级若为NULL那么获取自己的优先级返回值UBaseType_t是返回的优先级
*/
UBaseType_t uxTaskPriorityGet(const TaskHandle_t xTask)3.4 任务示例
#include main.h
#include usart.h
#include gpio.h#include FreeRTOS.h
#include FreeRTOSConfig.h
#include task.h
#include list.h
#include queue.h
#include freeled.hvoid led_task(void *param);
void usart_task(void *param);//。。。GPIO_INIT()等INIT初始化。。。int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_USART1_UART_Init();//创建两个任务xTaskCreate(led_task, task1, 100, NULL, 1, NULL);xTaskCreate(usart_task, task2, 100, NULL, 1, NULL);vTaskStartScheduler();
}//两个任务处理函数
void led_task(void *param)
{while(1){blink_led(BLUE_LED, 500, 1);blink_led(RED_LED, 500, 1);blink_led(GREEN_LED, 500, 1);}vTaskDelete( NULL );
}void usart_task(void *param)
{while(1){printf(This is task 2\n);vTaskDelay( pdMS_TO_TICKS(1000));}vTaskDelete( NULL );
}//实现led和printf
#define ON 1
#define OFF 0typedef struct gpio_s{GPIO_TypeDef *group;uint16_t pin;
}gpio_t;enum ENUM_LED{RED_LED,GREEN_LED,BLUE_LED,LED_MAX,
};void turn_led(uint32_t which_led, uint32_t led_state);
int blink_led(int which_led, int interval, int num);
gpio_t leds[LED_MAX] {{REDLED_GPIO_Port, REDLED_Pin},{GREENLED_GPIO_Port, GREENLED_Pin},{BLUELED_GPIO_Port, BLUELED_Pin},
};void turn_led(uint32_t which_led, uint32_t led_state)
{GPIO_PinState level;if (which_led LED_MAX){return ;}level (led_state OFF) ? GPIO_PIN_SET : GPIO_PIN_RESET;HAL_GPIO_WritePin(leds[which_led].group, leds[which_led].pin, level);return ;
}int blink_led(int which_led, int interval, int num)
{if (num0 || interval0 || which_ledLED_MAX){return -1;}while( num-- ){turn_led(which_led, ON);vTaskDelay(pdMS_TO_TICKS(interval));turn_led(which_led, OFF);vTaskDelay(pdMS_TO_TICKS(interval));//注意这里替换成freertos的延时};return 0;
}需要注意的是在使用了FreeRTOS后我们应该摒弃使用HAL库中的Delay函数中断函数等避免造成系统的崩溃。