[ 附件影像 RECORD ]
FreeRTOS学习笔记 · 第十四-十六讲:5.2-6.1信号量、互斥量使用示例

FreeRTOS学习笔记 · 第十四-十六讲:5.2-6.1信号量、互斥量使用示例

[ SCAN_URL ]
[ 归档时间 ]:2026-04-07 09:25 [ 课题责任人 ]:文止墨 [ 档案分类 ]:嵌入式, 文章, 编程

二值信号量 demo

C
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc){
  if(hadc->Instance == ADC1){
    //adc_value在/* USER CODE BEGIN Variables */处声明
    adc_value = HAL_ADC_GetValue(hadc);
    //printf("ADC Conversion Completed!\r\n");
    BaseType_t highter_priority_task_woken = pdFALSE;
    if(BinarySem_DataReadyHandle != NULL){// 确保信号量已创建
      // 释放信号量,通知显示任务数据已准备好
      xSemaphoreGiveFromISR(BinarySem_DataReadyHandle, &highter_priority_task_woken);
      portYIELD_FROM_ISR(highter_priority_task_woken);
    }
  }
}
C
void App_Task_showADC(void *argument)
{
  /* USER CODE BEGIN App_Task_showADC */
  /* Infinite loop */
  for(;;)
  {
    // 等待数据准备就绪
    if(xSemaphoreTake(BinarySem_DataReadyHandle, portMAX_DELAY) == pdTRUE){
      // 数据已准备好,继续执行
      // 显示ADC值
      char adc_str[16];
      // 格式化输出,保留4位
      snprintf(adc_str, sizeof(adc_str), "%04lu", adc_value);
      lcd_dma2d_show_eubf_str(0, 64,(char*)"ADC Value:", "ZCOOL QingKe HuangYou", 32, WHITE);
      lcd_dma2d_fill(0, 64, 320, 98, BLACK);
      lcd_dma2d_show_eubf_str(0, 96,(char*)adc_str, "ZCOOL QingKe HuangYou", 32, WHITE);
      lcd_dma2d_update_screen();
      osDelay(1);
    }
    else{
      // 数据未准备好,等待
    }
    osDelay(250);
  }
  /* USER CODE END App_Task_showADC */
}

计数信号量 demo

C
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc){
  // 这里添加RTC唤醒事件处理代码
  //释放计数信号量
  if(CountingSem_TableHandle != NULL){ // 确保信号量已创建
    BaseType_t highter_priority_task_woken = pdFALSE;
    xSemaphoreGiveFromISR(CountingSem_TableHandle, &highter_priority_task_woken);
    portYIELD_FROM_ISR(highter_priority_task_woken);
  }
}
C
void App_Task_CheckIn(void *argument)
{
  /* USER CODE BEGIN App_Task_CheckIn */
  char temp_str[30];
  UBaseType_t last_count = 0xFFFFFFFF; 
  UBaseType_t current_count = 0;

  osDelay(1500); //必须要有这个等待,否则会因为文件系统未挂载导致字体文件无法读取

  sprintf(temp_str, "%lu", uxSemaphoreGetCount(CountingSem_TableHandle));
  
  // 第一行:Y=32 (0~32)
  lcd_dma2d_show_eubf_str(160, 32, (char*)"TOTAL_TABLE:", "ZCOOL QingKe HuangYou", 25, WHITE);
  // 第二行:Y=64 (32~64)
  lcd_dma2d_show_eubf_str(160, 64, temp_str, "ZCOOL QingKe HuangYou", 32, WHITE);
  // 第三行:Y=96 (64~96)
  lcd_dma2d_show_eubf_str(160, 96, (char*)"AVAILABLE:", "ZCOOL QingKe HuangYou", 32, WHITE);
  
  // 第一次推送到屏幕
  lcd_dma2d_update_screen();

  /* Infinite loop */
  for(;;)
  {
    // 按键处理
    if(myGetKeyPressStateByID(KEY_UP)){
      // 清除第五行 (占据 128~160)
      lcd_dma2d_fill(160, 128, 320, 160+1, BLACK); 
      
      if(xSemaphoreTake(CountingSem_TableHandle, 100) == pdTRUE){
        lcd_dma2d_show_eubf_str(160, 160, (char*)"CheckIn OK", "ZCOOL QingKe HuangYou", 25, GREEN);
      } else {
        lcd_dma2d_show_eubf_str(160, 160, (char*)"CheckIn Failed", "ZCOOL QingKe HuangYou", 25, RED);
      }
      lcd_dma2d_update_screen();
    }

    // 按需刷新
    current_count = uxSemaphoreGetCount(CountingSem_TableHandle);
    if(current_count != last_count)
    {
      sprintf(temp_str, "%lu", (unsigned long)current_count);
      
      // 清除第四行 (占据 96~128)
      lcd_dma2d_fill(160, 96, 320, 128+1, BLACK); 
      // 绘制第四行数字
      lcd_dma2d_show_eubf_str(160, 128, temp_str, "ZCOOL QingKe HuangYou", 32, WHITE);
      
      lcd_dma2d_update_screen();
      last_count = current_count;
    }
    
    osDelay(100);
  }
  /* USER CODE END App_Task_CheckIn */
}

有点好笑的是,RTC 唤醒属于拓展功能, 因此,所有相关的函数和回调都会带有 Ex 的后缀,而不是 x。然后我一开始就给拼错了,死活找不到 BUG。

互斥量 demo

不使用互斥量

创建一个二值信号量token,初始可用。

C
void App_Task_High(void *argument)
{
  /* USER CODE BEGIN App_Task_High */
  /* Infinite loop */
  for(;;)
  {
    if(xSemaphoreTake(tokenHandle,portMAX_DELAY) == pdTRUE){
      printf("HIGH TAKE IT!\r\n");
      HAL_Delay(10);
      xSemaphoreGive(tokenHandle);
    }
    osDelay(1);
  }
  /* USER CODE END App_Task_High */
}
C
void App_Task_Middle(void *argument)
{
  /* USER CODE BEGIN App_Task_Middle */
  /* Infinite loop */
  for(;;)
  {
    printf("MIDDLE IS RUNING...\r\n");
    HAL_Delay(10);
    osDelay(500);
  }
  /* USER CODE END App_Task_Middle */
}
C
void App_Task_Low(void *argument)
{
  /* USER CODE BEGIN App_Task_Low */
  /* Infinite loop */
  for(;;)
  {
    if(xSemaphoreTake(tokenHandle,pdMS_TO_TICKS(300)) == pdTRUE){
      // 成功获取到 token,执行临界区代码
      printf("LOW TAKE IT!\r\n");
      HAL_Delay(1000);
      printf("LOW GIVE IT!\r\n");
      HAL_Delay(10);
      xSemaphoreGive(tokenHandle); // 释放 token
    } else {
      // 获取 token 失败,可能被 Task_High 占用
      
    }
    osDelay(20);
  }
  /* USER CODE END App_Task_Low */
}

使用互斥量

把信号量删掉,创建一个同名的互斥量,代码不变。

[ 发起通讯连接 / INITIATE COMM-LINK ]

[SYS]: 您的回传节点(邮箱)将被严格保密。带有 * 的字段为必填项。


> 终止读取并返回主控制台 <