芯查查logo
  • 物料选型
  • 数据服务
    1. 新品推荐
    2. 查替代料
    3. 丝印反查
    4. 查品牌
    5. PCN/PDN
    6. 查代理
    7. 数据合作
  • 应用方案
  • SaaS产品
      SaaS产品
    1. 供应链波动监测预警
    2. 半导体产业链地图
    3. 智能BOM管家
    4. 解决方案
    5. 汽车电子
    6. 政府机构
    7. 数据API
  • 商城
  • 行业资讯
    1. 资讯
    2. 直播
  • 论坛社区
    1. 论坛
    2. 学习
    3. 测评中心
    4. 活动中心
    5. 积分商城
  • 查一下
正在使用账号登录iCEasy商城
【星允派 NEBULA PI】12:添加时间任务调度器
原创 发布时间:2025/08/25 09:07
版块:
单片机/MCU论坛
简介:使用任务调度的方式,完成基本的LED灯闪烁和串口输出

在C语言里,任务调度指的是对多个任务(也被叫做线程或者进程)的执行顺序进行管理,以此来达成高效利用系统资源的目的。

下面为你详细介绍任务调度的相关概念和实现方法。

一:任务调度的概念思想:

抢占式调度:在这种调度方式下,操作系统能够依据任务优先级,强行暂停当前正在执行的任务,转而执行其他任务。

非抢占式调度:采用这种调度方式时,任务只有在主动放弃 CPU 控制权的情况下,其他任务才有机会执行。

实时调度:实时调度的核心是保证任务能在严格的时间限制内完成,它又可以细分为硬实时调度和软实时调度。

优先级调度:优先级调度会为每个任务分配一个优先级,系统会优先执行优先级较高的任务。

二:任务调度的关键要点

上下文切换:在任务切换时,需要保存当前任务的状态(例如寄存器值),并恢复下一个任务的状态。

临界区保护:对于共享资源,要使用互斥锁、信号量等机制来避免竞态条件。

任务同步:可以通过信号量、事件标志组等方式实现任务间的同步。

堆栈管理:每个任务都有自己独立的堆栈,必须确保堆栈大小足够,防止溢出。

常用的任务调用有Free Rtos,OS,RT-threard等等实时操作系统专为嵌入式系统设计,提供了强大的任务调度功能,

这里和大家分享一个简单任务调度器。创建任务队列。然后按照一定时间间隔来处理任务。

三:定时器6实现基本的任务调度

实现任务调度的编写流程如下所示:

1:使能定时器6时钟。

2:初始化定时器,配置ARR,PSC,中断时间1ms。

3:开启定时器6中断,配置NVIC中断优先级。

4:使能定时器6,定时器开始功能。

5: 编写中断服务函数。

这里定时器的中断频率计算公式如下:Tout(中断触发时间)=(ARR+1)(PSC+1)/定时器的时钟频率。

四:程序编写过程如下所示:

4.1 定时器6初始化

void MX_TIM6_Init(void)
{

  /* USER CODE BEGIN TIM6_Init 0 */

  /* USER CODE END TIM6_Init 0 */

  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM6_Init 1 */

  /* USER CODE END TIM6_Init 1 */
  htim6.Instance = TIM6;
  htim6.Init.Prescaler = 999;
  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim6.Init.Period = 71;
  htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM6_Init 2 */
	 HAL_TIM_Base_Start_IT(&htim6); 
  /* USER CODE END TIM6_Init 2 */

}

4.2 编写任务标记回调函数

void Task_Marks_Handler_Callback(void)
{
	char i;
	for(i=0; i<Tasks_Max; i++)
	{
		if(Task_Comps[i].TIMCount)    /* If the time is not 0 */
		{
			Task_Comps[i].TIMCount--;  /* Time counter decrement */
			if(Task_Comps[i].TIMCount == 0)  /* If time arrives */
			{
				/*Resume the timer value and try again */
				Task_Comps[i].TIMCount = Task_Comps[i].TRITime;  
				Task_Comps[i].Run = 1;    /* The task can be run */
			}
		}
	}
}

4.3 编写任务处理函调函数

void Task_Pro_Handler_Callback(void)
{
	char i;
	for(i=0; i<Tasks_Max; i++)
	{
		if(Task_Comps[i].Run) /* If task can be run */
		{
			Task_Comps[i].Run = 0;    /* Flag clear 0 */
			Task_Comps[i].TaskHook();  /* Run task */
		}
	}
}

4.4 分别在定时器中断回调函数,以及主程序中调用上述函数;

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* USER CODE BEGIN Callback 0 */

  /* USER CODE END Callback 0 */

  /* USER CODE BEGIN Callback 1 */
  if (htim->Instance == TIM6) 
  {
		Time6point++ ;
		Task_Marks_Handler_Callback();
		}
	}
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		Task_Pro_Handler_Callback();
  }

五:添加任务:

static TASK_COMPONENTS Task_Comps[]=
{
	{0, 1000,1000, task_1000ms},		          /* task 1 Period: 1000ms */
  {0, 100,100,   task_100ms},		            /* task 2 Period: 500ms */
  {0, 10,10,   task_10ms},		            /* task 2 Period: 500ms */
};
char Tasks_Max = sizeof(Task_Comps)/sizeof(Task_Comps[0]);

编写LED闪烁和串口输出任务:

//========================================================================
// 函数: void task_1000ms(void)
// 描述: 1000ms 任务.
// 参数: None.
// 返回: None.
// 版本: V1.0, 2025-07-09
//========================================================================
void task_1000ms(void)
{
		HAL_UART_Transmit(&huart1, outputchar1, sizeof(outputchar1), 0xffff); 
}	
//========================================================================
// 函数: void task_100ms(void)
// 描述: 100 任务.
// 参数: None.
// 返回: None.
// 版本: V1.0, 2025-07-09
//========================================================================
void task_100ms(void)
{
   HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_4); 
}

六:测试图片如下所示:


源码地址如下所示:

https://gitee.com/congcong-brother/rymcus-evaluation-code-series.git

申请原创奖励
2025/08/25 09:07
  • 举报
😁😂😃😄😅😆😉😊😋😌😍😏😒😓😔😖😘😚😜😝😞😠😡😢😣😤😥😨😩😪😫😭😰😱😲😳😵😷😸😹😺😻😼😽😾😿🙀🙅🙆🙇🙈🙉🙊🙋🙌🙍🙎🙏✂✅✈✉✊✋✌✏✒✔✖✨✳✴❄❇❌❎❓❔❕❗❤➕➖➗➡➰🚀🚃🚄🚅🚇🚉🚌🚏🚑🚒🚓🚕🚗🚙🚚🚢🚤🚥🚧🚨🚩🚪🚫🚬🚭🚲🚶🚹🚺🚻🚼🚽🚾🛀Ⓜ🅰🅱🅾🅿🆎🆑🆒🆓🆔🆕
@好友

全部评论

加载中
游客登录通知
已选择 0 人
自定义圈子
移动
发布帖子
发布动态
发布问答
发布者
聪聪哥哥
最新帖子
为何说UVISI064BU10G是全能型sCMOS相机个人电子元器件管理系统2.0ESP8266的重要更新V18.6国产唐瑞 DDR4 内存颗TRD4C8G63K2-V26C学而思可多编程掌机改装2
热门版块
查看更多
萤火工场
问型号
每日打卡
电子元器件
飞腾
开源硬件项目
单片机/MCU论坛
问行情
电子DIY
维修技术交流

9

收藏

分享

微信扫码
分享给好友

评论