首页 > 其他分享 >基于32位单片机的裸机开发:使用定时器进行任务调度 V2.0

基于32位单片机的裸机开发:使用定时器进行任务调度 V2.0

时间:2024-10-22 11:45:41浏览次数:3  
标签:index Task 32 list period 裸机 任务 task 任务调度

  在嵌入式系统开发中,合理地管理和调度任务对于提高系统的实时性、可靠性和可维护性非常重要。本文将详细介绍一个基于定时器的任务管理系统的设计与实现,该系统无需使用系统滴答定时器(SysTick)来增加堆栈深度,而是采用基本的定时器来实现任务的分时执行。

V2.0对比V1.0优点

V2.0相比V1.0有几个显著的优点,这些改进使得任务管理系统更加健壮、灵活且易于维护。以下是V2.0的主要优点:

1. 增强的任务状态管理

  • 挂起状态的支持:V2.0增加了挂起状态 (TASK_STATE_SUSPEND),使得任务不仅可以在可执行 (TASK_STATE_RUN) 和等待 (TASK_STATE_STOP) 状态之间切换,还能被临时挂起。这使得系统在处理多任务时更加灵活,可以动态地暂停不需要立即执行的任务。

2. 回调机制的引入

  • 挂起回调函数:当任务被挂起时,可以通过 callback_suspend 回调函数执行一些额外的逻辑,例如保存任务状态或者释放资源等。这提高了系统的可扩展性,允许在不同状态下执行特定的操作。

3. 任务控制API的增加

  • 挂起和恢复任务的功能:提供了 Task_suspend 和 Task_resume 函数,允许应用程序根据需要动态地暂停和恢复任务。这使得在系统需要调整任务执行顺序或者暂时禁用某个任务时变得更加容易。

4. 任务信息查询功能

  • 任务索引和状态查询:通过 Task_get_task_id 和 Task_get_task_state 函数,开发者可以轻松地查询任务的索引号和当前状态。这不仅便于调试,还提高了系统的透明度,使得开发者更容易监控任务的执行情况。

5. 更高的灵活性和可扩展性

  • 动态管理任务:由于增加了挂起状态和支持回调函数,V2.0版本的任务管理系统能够更灵活地应对不同的应用场景。这种灵活性意味着系统可以更好地适应未来的变更和扩展需求。

6. 增强的系统维护性

  • 易于维护和调试:通过提供更多的API来控制和查询任务状态,V2.0版本的任务管理系统使得维护和调试变得更加直观和简便。这减少了因系统复杂性带来的维护难度。

二设计

1. 任务管理器设计

为了更好地管理多个任务,我们定义了一个任务结构体`Task_t`,以及一个任务列表`task_list`,用于存储所有需要执行的任务的信息。(task.c)

// 使用结构体数组,封装所有的任务
typedef struct Task{
	
	uint8_t 		state;		// 任务状态,1可执行,0等待中
	uint16_t 		count;		// 任务计数,倒计数到0,修改任务状态为可执行
	uint16_t   period;    // 任务周期,即多少ms执行一次任务(固定)
	
//	void (* callback)(void); // 任务执行回调
	Task_callback		callback;	// 任务执行回调
	Task_callback		callback_suspend;	// 任务执行回调
	
} Task_t;
// 把所有要执行的任务封装为结构体的列表

Task_t task_list[] = {
	// state,		     count,  	period, 	 callback
	{TASK_STATE_STOP,  0, 			10,  		App_Input_task},
	{TASK_STATE_STOP,  0, 			50, 		App_Balance_task},
	{TASK_STATE_STOP,  0, 			2000,		App_Protocol_task, NULL},
	{TASK_STATE_STOP,  0, 			100, 		App_OLED_task, App_OLED_suspend},
};

 2. Timer 任务执行状态的判定和切换

定时器中断服务程序中,我们将不断地减少每个任务的计数器值。当计数器值减至0时,将任务状态设置为可执行,并重置计数器。(task.c)

// 任务执行状态的判定和切换(在中断里1ms执行一轮)
void Task_switch_handler(void){
	// 1.不断给所有任务的count--
	// 2.判断count值,如果减到0,设置可执行标记
	// 3.把count重置为period
	for(uint8_t i = 0; i < task_cnt; i++){
		
		// 如果任务是挂起状态, 跳过本次循环
		if(task_list[i].state == TASK_STATE_SUSPEND){
			continue;
		}
		
		if(task_list[i].count > 0) task_list[i].count--;
		
		// 倒计数结束
		if(task_list[i].count == 0){
			// 任务状态切换
			task_list[i].state = TASK_STATE_RUN;
			// 重置count计数值
			task_list[i].count = task_list[i].period;
		}
	}
}

          任务的切换是在timer中进行的(timer.c)

void TIMER6_IRQHandler(void){
  
  if(SET == timer_interrupt_flag_get(TIMER, TIMER_INT_FLAG_UP)){
    // 清除中断标记
    timer_interrupt_flag_clear(TIMER, TIMER_INT_FLAG_UP);
    
	
//		if(period_1ms_num > 0) period_1ms_num--;
//		if(period_10ms_num > 0) period_10ms_num--;
//		if(period_100ms_num > 0) period_100ms_num--;
//		if(period_200ms_num > 0) period_200ms_num--;
//		if(period_500ms_num > 0) period_500ms_num--;
//		if(period_1000ms_num > 0) period_1000ms_num--;
		task_tick++;
		
		Task_switch_handler();
  }
}

3. 在主循环中执行任务

在主循环中,检查每个任务的状态,如果是可执行状态,则执行任务,并将其状态重置为等待状态。(main.c)

// 任务执行句柄(在main函数循环执行execute所有任务)
void Task_exec_handler(void){
	// 将状态为 TASK_STATE_RUN 执行一次,将标记恢复成STOP
	for(uint8_t i = 0; i < task_cnt; i++){
		if(task_list[i].state  == TASK_STATE_RUN){
			// 执行任务
			task_list[i].callback();
			// 任务状态切换
			task_list[i].state = TASK_STATE_STOP;
		}
	}
}

4. 暂停与恢复任务

允许用户暂停或恢复特定的任务。当任务被暂停时,可以执行特定的回调函数;当任务恢复时,它的计数器将被重置,状态将被恢复。(task.c)

// 根据任务索引位置,挂起指定任务(暂停)
void Task_suspend(uint8_t index){
	if(index >= task_cnt) return;
	
	// 设置为挂起状态
	task_list[index].state = TASK_STATE_SUSPEND;
	
	// 执行挂起回调函数(前提是此函数不是NULL)
	if(task_list[index].callback_suspend != NULL){
		task_list[index].callback_suspend();
	}
}

// 根据任务索引位置,恢复指定任务
void Task_resume(uint8_t index){
	if(index >= task_cnt) return;

	// 重置count计数值
	task_list[index].count = task_list[index].period;
	// 恢复状态
	task_list[index].state = TASK_STATE_STOP;
}

 5. 获取任务信息

提供函数来获取任务的状态或索引,以便在应用程序中根据需要控制任务的行为。(task.c)

// 根据任务函数名,查找对应位置
int Task_get_task_id(Task_callback func_name){
	
	for(uint8_t i = 0; i < task_cnt; i++){
		if(task_list[i].callback == func_name){
			return i;
		}
	}
	
	return -1;
}

// 根据任务索引位置,获取任务状态
uint8_t Task_get_task_state(uint8_t index){
	if(index >= task_cnt) return TASK_STATE_STOP;
	
	return task_list[index].state;
}

 示例应用

可以根据任务的状态 (获取任务索引) 执行任务具体的逻辑

下面是一个简单的按键示例,展示了如何根据按键输入来控制任务的暂停与恢复:

void Keys_on_keydown(uint8_t index){
	float cur_angle = Servo_get_angle();
	
	switch(index){
		case 0:  
			cur_angle -= 10;
			break;
		case 1: 
			cur_angle += 10;
			break;
		case 2: 
			printf("暂停任务\n");
//			int index = Task_get_task_id(App_Balance_task);
//			Task_suspend(index);
			Task_suspend(3);
			break;
		case 3: 				
			printf("恢复任务\n");
//			Task_resume(Task_get_task_id(App_Balance_task));
			Task_resume(3);
			break;
		default: break;
	}

通过上述方法,我们构建了一个简单但功能齐全的任务管理系统,它可以在没有操作系统支持的情况下有效地管理多个任务的执行。这对于资源受限的嵌入式系统来说尤其有用。

总结

V2.0版本的任务管理系统通过增加任务状态、回调机制、控制API以及信息查询功能,使得系统不仅更加灵活,而且更加易于扩展和维护。这些改进使得V2.0版本成为了一个更为成熟和强大的任务管理解决方案。

希望这篇文章能帮助你在嵌入式开发中更好地理解和实现任务调度机制。

标签:index,Task,32,list,period,裸机,任务,task,任务调度
From: https://blog.csdn.net/m0_74045985/article/details/143130089

相关文章

  • LeetCode题练习与总结:区间和的个数--327
    一、题目描述给你一个整数数组 nums 以及两个整数 lower 和 upper 。求数组中,值位于范围 [lower,upper] (包含 lower 和 upper)之内的 区间和的个数 。区间和 S(i,j) 表示在 nums 中,位置从 i 到 j 的元素之和,包含 i 和 j (i ≤ j)。示例1:输入......
  • LeetCode题练习与总结:奇偶链表--328
    一、题目描述给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。请注意,偶数组和奇数组内部的相对顺序应该与输入时保持一致。你必须在 ......
  • STM32F407 HAL库:双DAC的信号发生器+双ADC采集
    文章目录概要CubeMX配置代码细节1.串口发送:串口重定向:调用HAL库函数:2.串口接收:3.DAC+DMA提前写入的数据:函数生成数据:DAC+DMA程序中调用:4.ADC+DMAADC转换标志位:ADC的使用:5.FFT操作总结概要使用F407内部的DAC由定时器触发并加上DMA操作实现如正弦波、方......
  • 在STM32CubeMX中配置 PWM
    一、基本配置 首先来基本的配置1.将debug 改为  模拟输出2.在RCC中选择内部晶振(有需要也可以选外部晶振)3.开始配置引脚4.配置时钟树(省略)这里我设置72HZ 5.最后的收尾设置(前面一期有讲) 正式开始PWM的配置 1、PWM的设置需要定时器的时钟来控制频率(具......
  • 20222320 2024-2025-1 《网络与系统攻防技术》实验三实验报告
    目录目录目录0.认识工具Veil1.实验目标2.实验内容3.实验过程(1)使用msf编码器,使用msfvenom生成如jar之类的其他文件(2)使用veil加壳工具加壳(3)使用C+shellcode编程(4)通过组合应用各种技术实现恶意代码免杀(5)用另一电脑实测,在杀软开启的情况下,可运行并回连成功4.问题及解决方案5.学习感......
  • HL7协议简介及其在STM32上的解析实现
            近期完成一个医疗相关的项目,其中包括了体征监测设备,该设备使用的通信协议便是HL7V2.4协议,在医疗信息化领域,HL7(HealthLevelSeven)协议扮演着至关重要的角色。它是一种国际标准,用于定义医疗机构间以及医疗设备与信息系统之间的数据交换格式和通信协议。HL7标......
  • Leetcode 328. Odd Even Linked List
    我的解法没有什么需要推理的地方,要注意一开始要让cur走的比odd和even快,否则会导致cur的next被odd和even修改,代码里有注释。ListNode*oddEvenList(ListNode*head){if(!head){returnhead;}ListNode*cur=nullptr,*headofOdd=h......
  • 项目-STM32F765VIT6+W5500 使用单片机串口发送命令实现OTA远程升级单片机程序测试说明
       测试1,单片机通过SPI1和模块通信; 单片机PA8引脚作为复位模组使用;串口1做日志打印(115200); 2,打开例程 3,使用下载器先下载BootLoader,然后再下载用户程序   4,在网站的根目录建几个文件夹  目录要和mcu_project程序里面的目录一致 ......
  • TMtech凯钰T8332AD升降压LED驱动芯片AEC-Q100认证
    T8332AD是TMTechnology,Inc.设计的一款多功能LED驱动IC。它具有广泛的输入电压范围、精确的恒流控制和多种保护机制,非常适合各种大功率LED应用。以下是其主要特点、应用和技术规格的概述。主要特点1.宽输入电压范围:在5V到60V之间高效运行。2.精确的电流控制......
  • 20222323 2024-2025-1 《网络与系统攻防技术》实验三实验报告
    1.实验内容1.1实践目标(1)正确使用msf编码器,veil-evasion,自己利用shellcode编程等免杀工具或技巧正确使用msf编码器,使用msfvenom生成如jar之类的其他文件veil,加壳工具使用C+shellcode编程(2)通过组合应用各种技术实现恶意代码免杀(3)用另一电脑实测,在杀软开启的情况下,可......