一、临界段应用
1.临界段作用
在程序访问资源时,不希望被其他任务或者中断打断,这段要执行的代码,称为临界代码段
1.1不想被打断访问的资源(临界段保护)
读取或者修改变量(全局变量) |
调用公共函数的代码(不可重入函数) |
使用硬件资源(外设) |
对时序有精准要求的操作 |
用户不想被打断的代码 |
1.2 临界段函数原型
函数原型 | #include “FreeRTOS.h” #include “task.h” void taskDISABLE_INTERRUPTS( void ); |
功能概述 | 关闭中断,这里的关中断只是频率低于configMAX_SYSCALL_INTERRUPT_PRIORITY 优先级的中断 |
参数 | None |
返回值 | None |
注意事项 | 采用此接口,不允许嵌套 |
函数原型 | #include “FreeRTOS.h” #include “task.h” void taskENABLE_INTERRUPTS ( void ); |
功能概述 | 开启中断 |
参数 | None |
返回值 | None |
注意事项 | 采用此接口,不允许嵌套 |
函数原型 | #include “FreeRTOS.h” #include “task.h” void taskEXIT_CRITICAL( void ); |
功能概述 | 退出临界段,内部调用taskENABLE_INTERRUPTS,支持嵌套 任务在运行态内调用,退出后可进行任务调度 |
参数 | None |
返回值 | None |
注意事项 | 保证临界段代码执行周期比较快,否则影响调度器进行调度 不能在中断中使用 |
函数原型 | #include “FreeRTOS.h” #include “task.h” UBaseType_t taskENTER_CRITICAL_FROM_ISR( void ); |
功能概述 | 进入临界段(在中断中使用),内部调用taskDISABLE_INTERRUPTS,支持嵌套 |
参数 | None |
返回值 | UBaseType_t :返回上次中断屏蔽寄存器操作值 |
注意事项 | None |
二、实现功能需求
1、分别修改Usart_Task、DelayTask任务
2、配置延时周期为50ms打印一次运行状态,观察现象,是否出现,资源冲突问题
3、通过临界段解决共享资源冲突问题
Cortex-M快速关中断指令
FreeRTOS采用BASEPRI指令 |
名字 | 功能描述 |
PRIMASK | 这是个只有单一比特的寄存器。 在它被置 1 后,就关掉所有可屏蔽的异常,只剩下 NMI 和硬 FAULT 可以响应。它的缺省值是 0,表示没有关中断。 |
FAULTMASK | 这是个只有 1 个位的寄存器。当它置 1 时,只有 NMI 才能响应,所有其它的异常,甚至是硬 FAULT,也通通闭嘴。它的缺省值也是 0,表示没有关异常。 |
BASEPRI | 这个寄存器最多有 9 位( 由表达优先级的位数决定)。它定义了被屏蔽优先级的阈值。当它被设成某个值后,所有优先级号大于等于此值的中断都被关(优先级号越大,优先级越低)。但若被设成 0,则不关闭任何中断, 0 也是缺省值。 |
二、任务堆栈大小确认
函数局部变量 函数形参 函数返回地址 函数内部状态值
所有的寄存器都需要入栈 M4内核浮点寄存器也需要入栈
M4 内核的 8 个通用寄存器和 18 个浮点寄存器是自动入栈的,这个栈是任务栈
使用的局部变量以及可能发生的中断嵌套都是用的系统栈
通过这个文件用户可以知道每个被调用函数的最大栈需求以及各个函数字节的调用关系。(函数指针和中断嵌套不分析)
1、在任务切换时检测任务栈指针是否过界
2、任务创建的时候将任务栈所有数据初始化为 0xa5,任务切换时进行任务栈检测的时候会检测末尾的 16 个字节是否都是 0xa5
调用vTaskList()打印每个任务的详细信息
2.1堆栈检测API
名称 | 功能 |
configCHECK_FOR_STACK_OVERFLOW | 配置宏 0:不启动栈溢出检测 1:启用栈溢出检测方案一 2:启动栈溢出检测方案二 |
void vApplicationStackOverflowHook ( TaskHandle_t*pxTask, signed char *pcTaskName ); 一个是句柄 一个是任务名称 | 栈溢出回调函数 |
函数原型 | #include “FreeRTOS.h” #include “task.h” void vTaskList( char *pcWriteBuffer ); |
功能概述 | 根据传入的缓冲区生成字符串,这个字符串将包含所有任务信息 |
参数 | ①缓冲区地址 |
返回值 | None |
注意事项 | configUSE_TRACE_FACILITY 必须置为1 configUSE_STATS_FORMATTING_FUNCTIONS 必须置为1 |
三.CPU利用率
函数原型 | #include “FreeRTOS.h” #include “task.h” void vTaskGetRunTimeStats( char *pcWriteBuffer ); |
功能概述 | 统计每个任务运行时间,并生成到传入缓冲区内 |
参数 | 缓冲区:根据任务数量建立缓冲区大小 |
返回值 | None |
注意事项 | configGENERATE_RUN_TIME_STATS 必须置为1 configUSE_STATS_FORMATTING_FUNCTIONS必须置为1 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() 初始化高精度定时器 portGET_RUN_TIME_COUNTER_VALUE() 获取高精度定时器计数值 |
3.1业务流程
配置相关宏 ->使能高精度定时器->定时器中断回调函数->FreeRTOS嵌套函数实现->按键触发CPU利用率
3.2
1.使能STM32CUBEMX FreeRTOS中 vTaskGetRunTimeStats
2.开启定时器Time2,可知Time2在APB1上
主要使用函数 vTaskGetRunTimeStats() PDF手册第177页
函 数 vTaskGetRunTimeStats() 是 一 个 很 实 用 的 函 数 , 要 使 用 此 函 数 的 话 宏 configGENERATE_RUN_TIME_STATS 和configUSE_STATS_FORMATTING_FUNCTIONS 必须 都为 1。如果宏 configGENERATE_RUN_TIME_STATS 为 1 的话还需要实现一下几个宏定义:
● portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(),此宏用来初始化一个外设来
提供时间统计功能所需的时基,一般是定时器/计数器。这个时基的分辨率一定要比 FreeRTOS
的系统时钟高,一般这个时基的时钟精度比系统时钟的高 10~20 倍就可以了。
1.● portGET_RUN_TIME_COUNTER_VALUE()或者
2.portALT_GET_RUN_TIME_COUNTER_VALUE(Time),这两个宏实现其中一个就行
了,这两个宏用于提供当前的时基的时间值。
函数原型如下: void vTaskGetRunTimeStats( char *pcWriteBuffer )
参数: pcWriteBuffer: 保存任务时间信息的存储区。存储区要足够大来保存任务时间信息。
3.configGENERATE_RUN_TIME_STATS和configUSE_STATS_FORMATTING_FUNCTIONS在这里配置为1
HAL_TIM_Base_Init(TIM_HandleTypeDef *htim),也就意味着我们要首先初始化好TIM_HandleTypeDef这个结构体