1. osdelay()是一个会释放cpu的函数释放给其他函数如果高优先级的函数一直都不释放cpu不使用这个函数的话低优先级的任务将不会执行。osDelay(ticks) 是 CMSIS-RTOS2 标准的延时函数它让当前调用线程进入阻塞态Blocked等待 ticks 个系统时钟节拍Tick后自动唤醒osStatus_t osDelay (uint32_t ticks) { osStatus_t stat; if (IS_IRQ()) { stat osErrorISR; // 不允许在中断中调用 } else { stat osOK; if (ticks ! 0U) { vTaskDelay(ticks); // 调用 FreeRTOS 的 vTaskDelay } } return (stat); }要做的任务会一直在ready态但是如果没有用osdelay的就会一直在阻塞态挂起2. 使用printf函数的时候记得重定向并且把mircrolib打开。身printf和半主机模式冲突开启mircrolib库以后解决KeyBinarySem01Handle osSemaphoreNew(1, 0, KeyBinarySem01_attributes); // 第一个参数是max_count 第二个是初始化的计数值3. freesrtos.c里面的一些语法一个任务的基本流程// 类型 变量名 声明void*一个指针变量 osThreadId_t defaultTaskHandle; // 类型修饰符 类型名 变量名 然后初始化 // 这是一个任务属性配置表告诉 RTOS我要创建一个叫 defaultTask 的任务 // 栈大小为 128*4512 字节优先级为 osPriorityLow const osThreadAttr_t defaultTask_attributes { .name defaultTask, .stack_size 128 * 4, .priority (osPriority_t) osPriorityLow, }; // 任务句柄类似于停车票指向 defaultTask 的 TCB // 创建一个新线程把函数、参数、配置表都输入进去 defaultTaskHandle osThreadNew(StartDefaultTask, NULL, defaultTask_attributes); // osThreadNew() 返回的是 FreeRTOS 在堆上分配的任务控制块TCB的指针。 // 它就像一个遥控器拿着它你就能对这个任务做任何操作——挂起、恢复、改优先级、删除。 // 具体的函数内容 void StartDefaultTask(void *argument) { /* USER CODE BEGIN StartDefaultTask */ /* Infinite loop */ for(;;) { HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_4); osDelay(500); } /* USER CODE END StartDefaultTask */ }一个信号量的基本流程osSemaphoreId_t myBinarySem01Handle; const osSemaphoreAttr_t myBinarySem01_attributes { .name myBinarySem01 }; // myBinarySem01Handle osSemaphoreNew(1, 1, myBinarySem01_attributes); // 1第一个参数 max_count这个信号量最多能存几个令牌。1 就是最多 1 个。 // 1第二个参数 initial_count创建时初始就有几个令牌。1 就是一开始就有 1 个可用。 // max_count1 就是二元信号量Binary Semaphore——只有 0 和 1 两种状态相当于一个开关 // 获取信号量句柄超时时间 // 0 拿不到就返回100 等100个tick osSemaphoreAcquire(myBinarySem01Handle, osWaitForever); // 释放信号量 osSemaphoreRelease(myBinarySem01Handle); // 释放信号量的内部逻辑 osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id) { // ① 中断中调用 if (IS_IRQ()) { BaseType_t yield pdFALSE; if (xSemaphoreGiveFromISR(hSemaphore, yield) ! pdTRUE) { return osErrorResource; // 令牌已满max_count 个不能再给 } portYIELD_FROM_ISR(yield); // 如果唤醒了更高优先级任务触发切换 } // ② 任务中调用 else { if (xSemaphoreGive(hSemaphore) ! pdPASS) { return osErrorResource; // 同上令牌满了 } // 如果有人在等待RTOS 内部会唤醒等待队列中的第一个任务 } return osOK; } // xSemaphoreGive 的内部逻辑简化 BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore) { taskENTER_CRITICAL(); if (有任务在等待这个信号量) { // 把等待队列中第一个任务唤醒移到就绪队列 唤醒那个任务 taskEXIT_CRITICAL(); return pdPASS; // ✅ 令牌直接给了等待者 } if (计数 max_count) { 计数; // ✅ 没有等待者令牌存起来 taskEXIT_CRITICAL(); return pdPASS; } // 计数已经到 max_count 了 taskEXIT_CRITICAL(); return pdFAIL; // ❌ 令牌池满了 }4. 二元信号量和互斥锁的区别互斥锁只有acquire的任务才能release但是二元信号量是任何任务都可以release。5. 检查栈空间void task_M(void *argument) { /* USER CODE BEGIN task_M */ /* Infinite loop */ uint32_t stackrest; for(;;) { //printf(Middle Task use cpu, but do nothing\r\n); stackrest osThreadGetStackSpace(taskMHandle); printf(Middle Task stack rest: %d\r\n, stackrest); osDelay(1000); } /* USER CODE END task_M */ }6. 检查CPU使用时间需要在freertosconfig.h里面定义几个宏以后才可以输出这里我没调好先放着7.TICKHOOK函数在freertosconfig里面把IDLE_HOOK打开以后在freertos里面写一个vApplicationTickHook函数这个是在systick里面根据时钟每1ms调用一次的所以tickhook里面不能放阻塞的内容void vApplicationTickHook(void){ static uint16_t timecount 0; timecount 1; if(timecount 500){ timecount 0; HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_4); } }8. IWDG看门狗IWDG 是 STM32 内部的一个硬件定时器由独立的 LSI 低速内部振荡器~32kHz 驱动与系统主时钟完全隔离。即使系统主时钟PLL/HSE挂了它照样跑。核心原理它是一个递减计数器。启动后从 Reload 值往下减减到 0 就产生系统复位。软件必须在计数器归零前调用喂狗刷新把计数器重新填满否则 MCU 就重启。9. 常用的通信接口usart iic SPI10.定时器代码11.钩子函数void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) { /* USER CODE BEGIN vApplicationStackOverflowHook */ /* Run time stack overflow checking is performed if configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook function is called if a stack overflow is detected. */ (void)xTask; (void)pcTaskName; g_overflow_task_handle xTask; g_overflow_task_name pcTaskName; taskDISABLE_INTERRUPTS(); __BKPT(0); for( ;; ); /* USER CODE END vApplicationStackOverflowHook */ }如果栈溢出了程序会卡死在watch窗口里面可以看到是哪个任务栈溢出了。12.消息队列在cubeMX里面设置的时候Quene Size是队列中最多支持多少个数据排队item size是队列中每个数据的大小uint16_t是两个字节uint32_t是4个字节。osMessageQueuePut(BtnQueueHandle, btnCount, 0, 0);第四个参数是超时时间参数0表示队列满了以后直接丢弃数据继续执行后面的代码。oswaitforever是永久等待如果队列满了就一直在这等着不执行后面的任务。osMessageQueueGet(BtnQueueHandle, btnCount, 0, 0);第四个参数是队列为空时的阻塞超时时间0代表队列里时空的话就不取数据了继续往下执行。以上所有内容来在b站油炸鸡、keysking等up的课程只是做笔记自用
【笔记待更新】stm32 freertos 基础知识
发布时间:2026/6/10 15:19:19
1. osdelay()是一个会释放cpu的函数释放给其他函数如果高优先级的函数一直都不释放cpu不使用这个函数的话低优先级的任务将不会执行。osDelay(ticks) 是 CMSIS-RTOS2 标准的延时函数它让当前调用线程进入阻塞态Blocked等待 ticks 个系统时钟节拍Tick后自动唤醒osStatus_t osDelay (uint32_t ticks) { osStatus_t stat; if (IS_IRQ()) { stat osErrorISR; // 不允许在中断中调用 } else { stat osOK; if (ticks ! 0U) { vTaskDelay(ticks); // 调用 FreeRTOS 的 vTaskDelay } } return (stat); }要做的任务会一直在ready态但是如果没有用osdelay的就会一直在阻塞态挂起2. 使用printf函数的时候记得重定向并且把mircrolib打开。身printf和半主机模式冲突开启mircrolib库以后解决KeyBinarySem01Handle osSemaphoreNew(1, 0, KeyBinarySem01_attributes); // 第一个参数是max_count 第二个是初始化的计数值3. freesrtos.c里面的一些语法一个任务的基本流程// 类型 变量名 声明void*一个指针变量 osThreadId_t defaultTaskHandle; // 类型修饰符 类型名 变量名 然后初始化 // 这是一个任务属性配置表告诉 RTOS我要创建一个叫 defaultTask 的任务 // 栈大小为 128*4512 字节优先级为 osPriorityLow const osThreadAttr_t defaultTask_attributes { .name defaultTask, .stack_size 128 * 4, .priority (osPriority_t) osPriorityLow, }; // 任务句柄类似于停车票指向 defaultTask 的 TCB // 创建一个新线程把函数、参数、配置表都输入进去 defaultTaskHandle osThreadNew(StartDefaultTask, NULL, defaultTask_attributes); // osThreadNew() 返回的是 FreeRTOS 在堆上分配的任务控制块TCB的指针。 // 它就像一个遥控器拿着它你就能对这个任务做任何操作——挂起、恢复、改优先级、删除。 // 具体的函数内容 void StartDefaultTask(void *argument) { /* USER CODE BEGIN StartDefaultTask */ /* Infinite loop */ for(;;) { HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_4); osDelay(500); } /* USER CODE END StartDefaultTask */ }一个信号量的基本流程osSemaphoreId_t myBinarySem01Handle; const osSemaphoreAttr_t myBinarySem01_attributes { .name myBinarySem01 }; // myBinarySem01Handle osSemaphoreNew(1, 1, myBinarySem01_attributes); // 1第一个参数 max_count这个信号量最多能存几个令牌。1 就是最多 1 个。 // 1第二个参数 initial_count创建时初始就有几个令牌。1 就是一开始就有 1 个可用。 // max_count1 就是二元信号量Binary Semaphore——只有 0 和 1 两种状态相当于一个开关 // 获取信号量句柄超时时间 // 0 拿不到就返回100 等100个tick osSemaphoreAcquire(myBinarySem01Handle, osWaitForever); // 释放信号量 osSemaphoreRelease(myBinarySem01Handle); // 释放信号量的内部逻辑 osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id) { // ① 中断中调用 if (IS_IRQ()) { BaseType_t yield pdFALSE; if (xSemaphoreGiveFromISR(hSemaphore, yield) ! pdTRUE) { return osErrorResource; // 令牌已满max_count 个不能再给 } portYIELD_FROM_ISR(yield); // 如果唤醒了更高优先级任务触发切换 } // ② 任务中调用 else { if (xSemaphoreGive(hSemaphore) ! pdPASS) { return osErrorResource; // 同上令牌满了 } // 如果有人在等待RTOS 内部会唤醒等待队列中的第一个任务 } return osOK; } // xSemaphoreGive 的内部逻辑简化 BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore) { taskENTER_CRITICAL(); if (有任务在等待这个信号量) { // 把等待队列中第一个任务唤醒移到就绪队列 唤醒那个任务 taskEXIT_CRITICAL(); return pdPASS; // ✅ 令牌直接给了等待者 } if (计数 max_count) { 计数; // ✅ 没有等待者令牌存起来 taskEXIT_CRITICAL(); return pdPASS; } // 计数已经到 max_count 了 taskEXIT_CRITICAL(); return pdFAIL; // ❌ 令牌池满了 }4. 二元信号量和互斥锁的区别互斥锁只有acquire的任务才能release但是二元信号量是任何任务都可以release。5. 检查栈空间void task_M(void *argument) { /* USER CODE BEGIN task_M */ /* Infinite loop */ uint32_t stackrest; for(;;) { //printf(Middle Task use cpu, but do nothing\r\n); stackrest osThreadGetStackSpace(taskMHandle); printf(Middle Task stack rest: %d\r\n, stackrest); osDelay(1000); } /* USER CODE END task_M */ }6. 检查CPU使用时间需要在freertosconfig.h里面定义几个宏以后才可以输出这里我没调好先放着7.TICKHOOK函数在freertosconfig里面把IDLE_HOOK打开以后在freertos里面写一个vApplicationTickHook函数这个是在systick里面根据时钟每1ms调用一次的所以tickhook里面不能放阻塞的内容void vApplicationTickHook(void){ static uint16_t timecount 0; timecount 1; if(timecount 500){ timecount 0; HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_4); } }8. IWDG看门狗IWDG 是 STM32 内部的一个硬件定时器由独立的 LSI 低速内部振荡器~32kHz 驱动与系统主时钟完全隔离。即使系统主时钟PLL/HSE挂了它照样跑。核心原理它是一个递减计数器。启动后从 Reload 值往下减减到 0 就产生系统复位。软件必须在计数器归零前调用喂狗刷新把计数器重新填满否则 MCU 就重启。9. 常用的通信接口usart iic SPI10.定时器代码11.钩子函数void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) { /* USER CODE BEGIN vApplicationStackOverflowHook */ /* Run time stack overflow checking is performed if configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook function is called if a stack overflow is detected. */ (void)xTask; (void)pcTaskName; g_overflow_task_handle xTask; g_overflow_task_name pcTaskName; taskDISABLE_INTERRUPTS(); __BKPT(0); for( ;; ); /* USER CODE END vApplicationStackOverflowHook */ }如果栈溢出了程序会卡死在watch窗口里面可以看到是哪个任务栈溢出了。12.消息队列在cubeMX里面设置的时候Quene Size是队列中最多支持多少个数据排队item size是队列中每个数据的大小uint16_t是两个字节uint32_t是4个字节。osMessageQueuePut(BtnQueueHandle, btnCount, 0, 0);第四个参数是超时时间参数0表示队列满了以后直接丢弃数据继续执行后面的代码。oswaitforever是永久等待如果队列满了就一直在这等着不执行后面的任务。osMessageQueueGet(BtnQueueHandle, btnCount, 0, 0);第四个参数是队列为空时的阻塞超时时间0代表队列里时空的话就不取数据了继续往下执行。以上所有内容来在b站油炸鸡、keysking等up的课程只是做笔记自用