裸机单片机适用的软件架构

单片机通常分为三种工作模式,分别是

1、前后台顺序执行法 2、操作系统 3、时间片轮询法

1、前后台顺序执行法

利用单片机的中断进行前后台切换 ,然后进行任务顺序执行,但其实在很多时候都是处于一种浪费资源的使用,因为大部分时候都要去查看事件是否发生,并且其实时性低,由于每个函数或多或少存在毫秒级别的延时,即使是1ms,也会造成其他函数间隔执行时间的不同,虽然可通过定时器中断的方式,但是前提是中断执行函数花的时间必须短。当程序逻辑复杂度提升时,会导致后来维护人员的大脑混乱,很难理清楚该程序的运行状态。

其也就是大轮训进行执行while里面的函数

2、操作系统

嵌入式操作系统EOS(Embedded OperatingSystem)是一种用途广泛的系统软件,过去它主要应用于工业控制和国防系统领域,而对于单片机来说,比较常用的有UCOS、FreeRTOS、RT-Thread Nano和RTX 等多种抢占式操作系统(其他如Linux等操作系统不适用于单片机)

操作系统和"时间片轮询法",在任务执行方面来说,操作系统对每个任务的耗时没有过多的要求,需要通过设置每个任务的优先级,在高优先级的任务就绪时,会抢占低优先级的任务;操作系统相对复杂,因此这里没有详细介绍了。

3、时间片轮询法

时间片轮询法是介于前后台顺序执行法和操作系统之间的一种程序架构设计方案。任务函数无需时刻执行,存在间隔时间(比如按键,一般情况下,都需要软件防抖,初学者的做法通常是延时10ms左右再去判断,但10ms极大浪费了CPU的资源,在这段时间内CPU完全可以处理很多其他事情)。

该设计方案需要使用一个定时器,一般情况下定时1ms即可(定时时间可随意定,但中断过于频繁效率就低,中断太长,实时性差),因此需要考虑到每个任务函数的执行时间,建议不能超过1ms(能通过程序优化缩短执行时间则最好优化,如果不能优化的,则必须保证该任务的执行周期必须远大于任务所执行的耗时时间),同时要求主循环或任务函数中不能存在毫秒级别的延时。

时间片轮询法的实现(指针方式)

首先定义一个结构体,用于存储一个任务的所有信息,如下所示:

cpp 复制代码
typedef struct
{
	uint8_t  u8_runflag;		/*程序是否运行标志    TASK_OFF_RUN:不运行   TASK_ON_RUN:运行*/
	uint16_t u16_timer;			/*计时器*/
	uint16_t u16_itvTime;		/*运行间隔时间,也就是多久运行一次*/
	void (*p_TaskHook)(void);	/*任务*/
}Task_InfoType;

然后创建一个具有绑定关系的任务数组:

cpp 复制代码
static Task_InfoType Task_Info[TASK_MAX] = {
	{TASK_OFF_RUN,TASK_200ms,TASK_200ms,logic_task},//逻辑任务
	{TASK_OFF_RUN,TASK_1000ms,TASK_1000ms,led_task}	//LED任务
};

从上图中可以看出,这里创建了两个任务,一个逻辑任务200ms执行一次,另外一个则是1000ms执行一次的LED任务,根据任务的情况,可以自己添加自己需要的。

有了关系之后,那么就需要让这个小系统跑起来了,下面两个函数分别是函数标志位修改函数和函数执行函数。其实这个小系统也就是一个计时,到时间,则打开标志位,去执行对应的函数,标志位没有打开则跳过。

cpp 复制代码
/*
	任务标志处理函数
	定时器1ms中断处理
*/
void Task_Remarks(void)
{
	for(int i=0;i<TASK_MAX;i++)
    {
		if(Task_Info[i].u16_timer)
		{
			Task_Info[i].u16_timer--;
			if(TASK_TIME_ON == Task_Info[i].u16_timer)
			{//定时器计数到后,打开函数运行标志位
				Task_Info[i].u16_timer = Task_Info[i].u16_itvTime;
				Task_Info[i].u8_runflag = TASK_ON_RUN;
			}
		}
    }
}
cpp 复制代码
/*
	任务函数运行处理
	放入主函数的循环中
*/
void Task_Process(void)
{
	for(int i=0;i<TASK_MAX;i++)
    {
		if(Task_Info[i].u8_runflag == TASK_ON_RUN)
		{
			Task_Info[i].p_TaskHook();
			Task_Info[i].u8_runflag = TASK_OFF_RUN;
		}
    }
}

弄完这些后,只需要去配置一个1ms定时器,将计时函数放入其中,即可

cpp 复制代码
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *hitm)
{
	if(hitm->Instance == TIM7)
	{
		Task_Remarks();
	}
}

到这里,这个小系统就完成了一大半了,在这里还需要添加一个打印函数,但是如何做到控制这个打印函数,只需要改变宏定义就可以实现关闭所以的打印呢,在实际的项目中,都会使用这种方式来进行系统的调试。

宏定义控制printf-CSDN博客

STM32关于UART的接收方式_stm32中huart1-CSDN博客

关于STM32CubeIDE使用printf串口打印_stm32cubeide printf-CSDN博客

这些都是跟调试有关的一些文章,可以查看。

相关推荐
深圳市青牛科技实业有限公司1 小时前
【青牛科技】应用方案|D2587A高压大电流DC-DC
人工智能·科技·单片机·嵌入式硬件·机器人·安防监控
Mr.谢尔比2 小时前
电赛入门之软件stm32keil+cubemx
stm32·单片机·嵌入式硬件·mcu·信息与通信·信号处理
LightningJie2 小时前
STM32中ARR(自动重装寄存器)为什么要减1
stm32·单片机·嵌入式硬件
58沈剑2 小时前
80后聊架构:架构设计中两个重要指标,延时与吞吐量(Latency vs Throughput) | 架构师之路...
架构
西瓜籽@3 小时前
STM32——毕设基于单片机的多功能节能窗控制系统
stm32·单片机·课程设计
想进大厂的小王5 小时前
项目架构介绍以及Spring cloud、redis、mq 等组件的基本认识
redis·分布式·后端·spring cloud·微服务·架构
远翔调光芯片^138287988725 小时前
远翔升压恒流芯片FP7209X与FP7209M什么区别?做以下应用市场摄影补光灯、便携灯、智能家居(调光)市场、太阳能、车灯、洗墙灯、舞台灯必看!
科技·单片机·智能家居·能源
阿伟*rui6 小时前
认识微服务,微服务的拆分,服务治理(nacos注册中心,远程调用)
微服务·架构·firefox
极客小张6 小时前
基于STM32的智能充电桩:集成RTOS、MQTT与SQLite的先进管理系统设计思路
stm32·单片机·嵌入式硬件·mqtt·sqlite·毕业设计·智能充电桩
ZHOU西口6 小时前
微服务实战系列之玩转Docker(十八)
分布式·docker·云原生·架构·数据安全·etcd·rbac