目录
前言
一、主函数内容
二、osKernelInitialize ()内核初始化函数内容
三、IS_IRQ()宏定义中断检测函数内容
四、如果这篇文章能帮助到你,请点个赞鼓励一下吧ξ( ✿>◡❛)~
前言
使用STM32CubeMX添加FreeRTOS进入工程之后,会自动在main函数中生成FreeRTOS的初始化和启动代码。
一、主函数内容
main.c函数代码如下:
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_I2C2_Init();/* USER CODE BEGIN 2 *//* USER CODE END 2 *//* Init scheduler */osKernelInitialize(); //FreeRTOS内核初始化/* Call init function for freertos objects (in cmsis_os2.c) */MX_FREERTOS_Init(); //FreeRTOS初始化/* Start scheduler */osKernelStart(); //FreeRTOS内核启动,任务调度算法/* We should never get here as control is now taken by the scheduler *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}
二、osKernelInitialize ()内核初始化函数内容
main函数中完成时钟和外设初始化之后,开始执行对FreeRTOS的初始化和启动流程,首先从osKernelInitialize ()内核初始化函数开始执行,osKernelInitialize ()函数代码如下所示:
osStatus_t osKernelInitialize (void) {osStatus_t stat;if (IS_IRQ()) //如果当前程序处于中断上下文中{stat = osErrorISR; //stat状态寄存器变量赋异常值}else //如果不在中断中{ if (KernelState == osKernelInactive) //如果内核状态标志位处于未激活状态{#if defined(USE_TRACE_EVENT_RECORDER) //如果开启事件轨迹记录标志位EvrFreeRTOSSetup(0U); //触发FreeRTOS初始化开始事件,0表示初始阶段,用于性能分析#endif//如果定义了使用HEAP_5规则来进行堆栈内存分配#if defined(USE_FreeRTOS_HEAP_5) && (HEAP_5_REGION_SETUP == 1) vPortDefineHeapRegions (configHEAP_5_REGIONS); //初始化堆内存区域#endifKernelState = osKernelReady; //内核状态切换为就绪状态stat = osOK; //函数状态返回值切换为OK} else { //如果内核状态不处于未激活状态stat = osError; //函数状态返回值赋值为osError}}return (stat); //返回值
}
这个FreeRTOS内核初始化函数的主要作用,就是在保障安全的情况下(检查当前程序是否处于中断上下文中),将FreeRTOS与运行状态标志位KernelState由osKernelInactive未激活状态切换为osKernelReady就绪状态。为什么不能在中断中进行处理呢?因为在中断中有可能会发生中断嵌套,如果两个中断都操作了同一寄存器,可能会引起同一变量的竞争,造成异常现象。
三、IS_IRQ()宏定义中断检测函数内容
其中,IS_IRQ()是宏定义的中断检测函数入口,其引用的函数原型是 __get_IPSR(void),这个函数将32位的变量映射到ARM的IPSR寄存器,IPSR寄存器内部存储当前中断号或代码异常标志,若其返回值不为0,表示当前程序正处在中断函数中。
#define IS_IRQ_MODE() (__get_IPSR() != 0U)
#define IS_IRQ() IS_IRQ_MODE()/**\brief Get IPSR Register\details Returns the content of the IPSR Register.\return IPSR Register value*/
__STATIC_INLINE uint32_t __get_IPSR(void) //获取IPSR寄存器的数值
{//register是C语言中的关键字,功能是建议将变量存储在寄存器而非内存中//__asm是汇编语言的关键字,将register映射到ipsr寄存器,这是编译器的扩展语法,强制将变量__regIPSR与ARM的ipsr特殊寄存器绑定register uint32_t __regIPSR __ASM("ipsr"); return(__regIPSR); //返回寄存器的值
}