十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

FreeRTOS-线程与ISR 01

FreeRTOS-线程与ISR 01 API函数前缀返回值v返回值类型void无返回值x 返回值类型BaseType_t函数返回表示成功/失败pdPASS/pdFAIL或真/假 pdTRUE/pdFALSE的布尔/状态值返回值类型EventBits_t,函数返回等待到的事件标志位返回值类型TaskHandle_t ,函数返回一个任务句柄队列句柄信号量句柄队列集句柄事件标志组句柄ux:返回值类型UBaseType_t函数返回一个无符号整数常用来表示计数、大小或优先级数值ul:返回值类型uint32_te返回值类型eTaskStatepv函数返回void *任务概念动态创建任务任务的任务控制块以及任务栈空间所需的内存均由FreeRTOS从其管理的堆中分配任务控制块内容任务栈顶指针任务状态任务优先级任务名字事件列表项任务通知值任务通知状态[注意]任务优先级越大任务越优先方便FreeRTOS抢占式调度将中断优先级位都分配给“抢占优先级”不保留“子优先级” 空闲任务优先级最低软件定时器任务优先级最高任务内存释放在自身任务中调用xTaskDelete函数并传入NULL这个任务的内存释放就在空闲任务中 在task1中调用xTaskDelete函数并传入task2句柄那么task2任务内存的释放就在task1任务中任务的创建与删除任务创建完成后会进入就绪列表立马进入就绪态 任务调度器会从就绪态列表中找到优先级最高的去执行 被删除的任务会从就绪态列表阻塞态列表挂起态列表事件等待列表中移除任务状态枚举typedef enum { eRunning 0, /* 运行态 */ eReady, /* 就绪态 */ eBlocked, /* 阻塞态 */ eSuspended, /* 挂起态 */ eDeleted, /* 任务被删除 */ eInvalid /* 无效 */ } eTaskState;任务状态信息结构体typedef struct xTASK_STATUS { TaskHandle_t xHandle; /* 任务句柄 */ const char* pcTaskName; /* 任务名 */ UBaseType_t xTaskNumber; /* 任务编号 */ eTaskState eCurrentState; /* 任务状态 */ UBaseType_t uxCurrentPriority; /* 任务当前优先级 */ UBaseType_t uxBasePriority; /* 任务基础优先级 */ configRUN_TIME_COUNTER_TYPE ulRunTimeCounter; /* 任务运行时间 */ StackType_t* pxStackBase; /* 任务栈基地址 */ configSTACK_DEPTH_TYPE usStackHighWaterMark; /* 任务栈历史剩余最小值(栈水位) */ } TaskStatus_t;任务函数启用任务调度函数函数vTaskStartScheduler无参无返回值调用时机任务创建完成后 [注意]任务切换中作用创建IdleTask和prvTimerTask任务阻塞函数函数xTaskDelay入参传入需阻塞tick数无返回值相对延时vTaskDelay 定义每次延时都是从执行函数vTaskDelay开始直到延时指定的时间结束 ​ 绝对延时vTaskDelayUntil 定义操控整个任务运行周期任务自身运行时间 xTaskDelayUntil延时部分时间 高优先级任务抢占运行时间 ​ 入参上一次任务唤醒的时间与延时的时间 返回值无 调用示例 TickType_t xLastWakeTime; xLastWakeTime xTaskGetTickCount(); vTaskDelayUntil(xLastWakeTime, 500);任务创建函数函数xTaskCreate入参任务函数指针创建任务名任务栈大小传递给任务函数的参数任务优先级任务句柄返回值函数执行状态pdPASS表示任务创建成功[注意]任务栈大小以字为单位任务句柄就是任务控制块任务删除函数函数xTaskDelete入参任务句柄无返回值[注意]任务内调用xTaskDelete并传入参数NULL时表示删除任务自身任务的挂起函数函数vTaskSuspend入参任务句柄无返回值[注意]任务内调用vTaskSuspend并传入参数NULL时表示挂起任务自身任务恢复函数任务中恢复 函数vTaskResume 入参任务句柄 无返回值中断中恢复 函数xTaskResumeFromISR 入参任务句柄 返回值pdTRUE表示任务恢复后需要进行一次任务切换 / pdFALSE表示任务恢复后不需要进行一次任务切换[注意]中断中调用这个函数需要判断其返回值FromISR函数只能在FreeRTOS所管理的函数中调用//函数返回值pdTRUE任务切换操作 BaseType_t xYieldRequired; xYieldRequired xTaskResumeFromISR(task1_handler); ​ if(task1_handler pdTRUE) { port_YIELD_FROM_ISR(xYieldRequired); }常用任务API函数(调试)需求获取任务的优先级 函数uxTaskPriority 入参任务句柄 返回值UBaseType_t需求设置任务优先级 函数vTaskPrioritySet 入参任务句柄与预设优先级数 返回值无需求获取系统中任务数量 函数uxTaskGetNumberOfTask 入参无 返回值UBaseType_t [注意]系统中已有的任务空闲任务与软件定时器任务需求获取当前任务的句柄 函数xTaskGetCurretTaskHandle 入参无 返回值当前正在运行任务的句柄需求通过任务名映射出任务句柄 函数xTaskGetHandle 入参任务名 返回值任务句柄需求获取任务栈历史最小值 函数uxTaskGetStackHighWaterMark 入参任务句柄 返回值UBaseType_t [注意]获取到历史最小剩余堆栈可进行DEBUG,判断任务爆栈问题需求查询任务运行状态 函数eTaskGetState 入参任务句柄 返回值eTaskState需求获取任务信息 函数vTaskList 入参字符数组缓冲区指针 返回值无返回值获取任务信息函数使用示例 char buffer[100] {0}; vTaskList(buffer); printf(%s, buffer);[注意]入参的缓冲区用于接收任务缓存信息函数使用效果打印出系统所有任务的名字任务状态任务优先级任务历史剩余最小堆栈任务编号需求获取任务运行时间 函数vTaskGetRunTimeStats 入参字符数组缓冲区指针 返回值无返回值获取任务运行时间函数调用示例 //实现#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() ConfigureTimeForRunTimeStats() void ConfigureTimeForRunTimeStats(void) { //配置时基定时器 配置中断 } ​ //实现#define portGET_RUN_TIME_COUNTER_VALUE() FreeRTOSRunTimeTicks FreeRTOSRunTimeTicks定时器中断中 ​ char buf[100] {0}; vTaskGetRunTimeStats(buf); printf(%s, buf);[注意]实现ConfigureTimeForRunTimeStats:初始化时基定时器精度是系统时钟节拍的10~100倍 1ms - 0.1ms 0.01ms(10us)portGET_RUN_TIME_COUNTER_VALUE()获取时基定时器的计数值任务的挂起与恢复 调度器的挂起与恢复打断程序运行点中断 任务切换任务调度器的挂起与恢复定义挂起任务调度器但中断正常响应作用防止任务之间资源争夺但中断可以正常响应函数vTaskSuspendAll无参无返回值vTaskResumeAll无参无返回值//任务调度器挂起与恢复示例 vTaskSuspendAll(); { //内容 } vTaskResumeAll();临界区临界段代码保护定义临界段代码也叫临界区是指那些必须完整运行不能被打断的代码段适用场景严格按时序初始化的外设I2C SPI临界区函数特点成对使用支持嵌套嵌套计数器 调用一次taskENTER_CRITICAL函数uxCriticalNesting自增一次 调用一次taskEXTI_CRITICAL函数uxCriticalNesting自减一次 [注意]uxCriticalNesting不为0中断就一直被关闭尽量保持临界区耗时短临界区函数-任务级函数taskENTER_CRITICAL和taskEXTI_CRITICAL无参无返回值作用关闭freertos所管理的中断关闭了PendSV中断也就关闭了任务切换关闭了任务切换也就防止了任务与任务之间的资源争夺 [注意]作用的本质就是开关中断//任务级临界区调用示例 taskENTER_CRITICAL(); { //临界区 } taskEXTI_CRITICAL();临界区函数-中断级函数taskENTER_CRITICAL_FROM_ISR和taskEXTI_CRITICAL_FROM_ISR//中断级临界区调用示例 uint32_t save_status; save_status taskENTER_CRITICAL_FROM_ISR(); { //临界区 } taskEXTI_CRITICAL_FROM_ISR(save_status);任务切换任务切换流程开启调度器int main(void) { Hardware_Init(); xTaskCreate(Task1, ...); xTaskCreate(Task2, ...); vTaskStartScheduler(); while(1); }调用vTaskStartScheduler();cpu不会再回到main(),之后执行的只有TaskISR中断{定义cpu打断正常运行的程序转而去处理紧急的程序中断优先级配置寄存器ARM Cortex-M,使用8位宽的寄存器来配置中断的优先级这个寄存器就是中断优先级配置寄存器 - 中断优先级0~255 STM32只用到了中断配置寄存器的高4位 - 中断优先级0~15中断优先级排序中断优先级越小越优先中断优先级分类抢占优先级与子优先级抢占优先级更高抢占优先级的中断发生时会夺取低抢占优先级的cpu使用权 子优先级俩个抢占优先级相同的中断同时发生高子优先级的中断获取cpu使用权不同时发生排队获取cpu使用权中断优先级分组设置NVIC_Priority_Group_0主语抢占优先级分配中断优先级配置寄存器0个位可设范围无子优先级分配中断优先级配置寄存器4个位可设范围0~15NVIC_Priority_Group_4主语抢占优先级分配中断优先级配置寄存器4个位可设范围0~15子优先级分配中断优先级配置寄存器4个位可设范围无中断服务函数使用FreeRTOS的API函数的注意点中断服务函数使用FreeRTOS的API函数必须带FromISR后缀 低于这个宏configMAX_SYSCALL_INTERRUPT_PRIORITY配置的中断优先级的中断服务函数不可调用FreeRTOS中断中API函数中断相关寄存器中断优先级配置寄存器SHPR1 SHPR2 SHPR3 中断屏蔽寄存器PRIMASK FAULTMASK BASEPRIPendSV与Systick中断优先级的配置设为最低优先级15 目的保证进行任务切换时不会抢夺其他中断cpu的使用权开关中断API函数#define configMAX_SYSCALL_INTERRUPT_PRIORITY 5 - FreeRTOS仅可管理优先级为5~15的中断 portDISABLE_INTERRUPTS() portENABLE_INTERRUPTS()}
返回列表