单片机裸机程序——程序架构

2024-08-26 11:28
文章标签 裸机 程序 单片机 架构

本文主要是介绍单片机裸机程序——程序架构,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目 录

  • 程序架构等同于思想体系
  • 一、前后台顺序法
  • 二、时间片轮询法


程序架构等同于思想体系

建一栋楼房,地基要先设计好,而不是马上砌砖,地基和布局都合理,房子就住得舒服,也不会闹心。

写一段程序也一样,程序构架要想好,而不是一边写一边调整构架,想到这个功能就先写这个功能,多个功能放在一起后无法协调,又要改构架,效率非常低。

把构架用图形的形式设计好,再像添砖加瓦一样去编码,实现功能。

一、前后台顺序法

公司都有负责接待来宾的前台,当有人来访或有电话来,前台就会通知其他负责人,正在有序工作的负责人必须马上停止手中工作,接待或接听结束后再回到原来的事情上继续。有人来访或有电话比做前台,正在有序工作比做后台。

前后台顺序执行是入门开发者常用的程序架构,逻辑简单,复杂度低,代码量少,最直观了,从上往下执行,全部任务都在一个循环里执行,不考虑每个函数执行所需要的时间。但遇到延时就要等待,因此会造成其他函数间隔执行时间的不同,尽管能够通过定时器中断的方式,但前提是中断服务函数执行的时间必须短。

顺序执行就是在你前面的执行完了,才到你执行,好比上体育课列队报数一样,必须按顺序来,你前面相邻的同学报完数,你才能报数。

还有就是有中断发生,就优先执行中断要执行的事情,好比体育课,点到谁的名字就优先得去跑两圈。

未加入中断的轮询系统

int main(void) 
{ uint8 keyValue;InitSys();                  // 系统初始化while (1){TaskDisplayClock();//显示系统时钟keyValue = TaskKeySan();//扫描键盘switch (keyValue){case x: TaskDispStatus(); break;...default: break;}}
}

在while(1)死循环中从第一行代码往下执行到最后一行,然后返回到第一行,如此反复执行。

在轮询系统基础上加入中断处理

int flag1 = 0,flag2= 0,flag3 = 0;
int main(){hardwareInit();//硬件初始化while(1){if(flag1){doSomething1();//处理事件1flag1=0;//清除标志位}if(flag2){doSomething2();//处理事件2flag2=0;//清除标志位}if(flag3){doSomething3();//处理事件3flag3=0;//清除标志位}}
}
//中断处理程序1
void ISR1(void ){flag1=1//置位标志位//中断处理程序2
void ISR2(void ){flag2=1//置位标志位//中断处理程序3
void ISR3(void ){flag3=1//置位标志位

外部事件的响应(改变一些标志位,确保所用时间非常短)在中断里面完成,事件的处理还是要回到轮询系统中完成。

1、如果中断服务程序执行时间太长,可能导致中断嵌套非常深,容易导致栈溢出,也容易出现异常,比如死机。
2、中断只处理紧急事务!紧急事务要用中断处理!比如串口数据的接收和发送,速度太快,放在循环里处理太慢了。然而对于数据的处理,就不用着急了,可以在中断里接收完成后设置标志位,然后在主循环里根据标志位完成处理,之后手动开启相应中断去发送。

中断在这里称为前台,main()函数中的主循环称为后台。
在这里插入图片描述

二、时间片轮询法

敢言:时间片轮询法是万能的裸机程序构架

时间片法是一种多任务执行法,它通过为每个任务分配一定的执行时间片,使得所有任务都能够按照一定的时间间隔交替执行。任务执行的时间片是固定的,当一个任务的时间片用完后,系统切换到下一个任务执行。这种方式使得多个任务能够并行执行,提高了系统的资源利用率和效率。

时间片法适用于中等复杂度的嵌入式系统,可以满足对实时性要求较高的场景。它需要合理设置任务的优先级和时间片大小,以确保重要任务优先执行,并且每个任务都能在适当的时间内完成。

使用定时器设定不同的时间片,定时到了某个时间节点,就去执行对应时间片里的代码,代码执行时间不能超过时间片时间,时间片时间应该根据所执行任务的耗时来设定。比如,按键扫描,通常都需要软件防抖,顺序法是延时10ms左右再去判断,但10ms极大浪费了CPU的资源,在这段时间内CPU完全可以处理很多其他事情,时间片轮询法就能很好利用CPU资源。

世界万事万物都是基于时间这条线而存在而运作的,谁都摆脱不了与时间的关联。

时间片轮询方式也容易理解,你设定的时间到了,你就执行,没到就继续等待,各个时间片之间没有优先级。

时间片轮询法系统的实现思路(只需要一个任意的定时器)
1、在系统初始化里初始化一个定时器,假设定时中断为1ms(也可以改成10ms,根据实际需求,但需要注意,中断过于频繁效率就低,中断太长,实时性差)。
2、定义多个任务变量及标志位
3、定义任务函数
4、把任务调度添加到主循环中
5、把任务切换逻辑控制添加到中断服务中

1、初始化定时器,以51单片机为例

//定时器初始化,定时1ms中断一次
void Timer1_Init(){AUXR &= 0xBF;		//定时器时钟12T模式TMOD &= 0x0F;		//设置定时器模式TMOD |= 0x10;		//设置定时器模式TL1 = 0x30;		//设置定时初值TH1 = 0xF8;		//设置定时初值TF1 = 0;		//清除TF1标志TR1 = 1;		//定时器1开始计时ET1 = 1;       //使能定时器中断EA = 1;
}
//定时器中断服务函数
void TM1_Isr() interrupt 3
{	TL1 = 0x30;		//设置定时初值TH1 = 0xF8;		//设置定时初值
}

2、定义任务相关

//任务结构
typedef struct _TASK_COMPONENTS
{unsigned int Run; //程序运行标记: 0-不运行,1-运行unsigned int Timer; //计时器unsigned int ItvTime;  //任务运行时间间隔void (*TaskHook)(void); //要运行的任务函数
}TASK_COMPONENTS;//任务定义,TASK_COMPONENTS是_TASK_COMPONENTS的别名static TASK_COMPONENTS TaskComps[]=	 //时间节拍为1ms,由定时器产生
{{0,10,10,TaskRfCheck},	//处理RF数据{0,20,20,TaskUart2Check},  //每次只处理串口2的一个字节数据{0,8,8,TaskRGBdata},//RGB数据处理	 刷新频率不能低于30HZ{0,30,30,TaskPWMout}, //刷新PWM数据{0,1000,1000,TaskTimers}, //计时器
};
//任务清单
typedef enum _TASK_LIST
{TASK_RF_CHECK,TASK_UART2_CHECK,TASK_RGB_DATA,TASK_UART1_PRINTF,TASK_TIMERS,TASKS_MAX,	 //总共可分配的定时任务数目
}TASK_LIST;

3、定义任务函数


void TaskRfCheck() //识别遥控器按键
{
//在此处添加代码
}
void TaskUart2Check() //解析串口2数据
{
//在此处添加代码
}
void TaskRGBdata()	//处理RGBW数据
{	
//在此处添加代码
}
void TaskPWMout()	  //刷新PWM数据
{  	
//在此处添加代码
}
void TaskTimers()  //灯带独立计时器
{
//在此处添加代码
}

4、定义任务调度函数并添加到主循环中

void TaskProcess()
{static unsigned char i=0;  //必须是static类型for(i=0;i<TASKS_MAX;i++)	//逐个任务时间处理{if(TaskComps[i].Run)	//任务可以运行{TaskComps[i].TaskHook();  //调用任务函数TaskComps[i].Run = 0; //标志清0}}		 	
}
void SysInit_all()
{Timer1_Init(); //定时器1初始化,用于多个任务调度WDT_CONTR=0x35;//看门狗设置,超时2秒则复位
}
//主函数
int main()
{SysInit_all();//系统初始化while(1){TaskProcess(); //任务处理WDT_CONTR |= 0x10;   //喂看门狗,防止系统复位	 		}return 1;
}

5、把任务切换逻辑控制添加到中断服务中

void TaskRemarks(void)
{static unsigned char i=0;   //必须是static类型for(i=0;i<TASKS_MAX;i++)	 //逐个任务处理{if(TaskComps[i].Timer) //时间不为0{TaskComps[i].Timer--; //减去一个节拍if(TaskComps[i].Timer<=0)//时间减完了{TaskComps[i].Timer = TaskComps[i].ItvTime;	 //恢复计时器值,重新下一次TaskComps[i].Run = 1; //任务可以运行}}}
}
//每1ms就执行一次TaskRemarks()
void TM1_Isr() interrupt 3
{	TL1 = 0x30;		//设置定时初值TH1 = 0xF8;		//设置定时初值TaskRemarks();	//任务调度
}

时间片轮询法的流程图大致为:
在这里插入图片描述

这篇关于单片机裸机程序——程序架构的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1108433

相关文章

SpringBoot实现微信小程序支付功能

《SpringBoot实现微信小程序支付功能》小程序支付功能已成为众多应用的核心需求之一,本文主要介绍了SpringBoot实现微信小程序支付功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作... 目录一、引言二、准备工作(一)微信支付商户平台配置(二)Spring Boot项目搭建(三)配置文件

Java异常架构Exception(异常)详解

《Java异常架构Exception(异常)详解》:本文主要介绍Java异常架构Exception(异常),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. Exception 类的概述Exception的分类2. 受检异常(Checked Exception)

如何用java对接微信小程序下单后的发货接口

《如何用java对接微信小程序下单后的发货接口》:本文主要介绍在微信小程序后台实现发货通知的步骤,包括获取Access_token、使用RestTemplate调用发货接口、处理AccessTok... 目录配置参数 调用代码获取Access_token调用发货的接口类注意点总结配置参数 首先需要获取Ac

基于Python开发PDF转Doc格式小程序

《基于Python开发PDF转Doc格式小程序》这篇文章主要为大家详细介绍了如何基于Python开发PDF转Doc格式小程序,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用python实现PDF转Doc格式小程序以下是一个使用Python实现PDF转DOC格式的GUI程序,采用T

将java程序打包成可执行文件的实现方式

《将java程序打包成可执行文件的实现方式》本文介绍了将Java程序打包成可执行文件的三种方法:手动打包(将编译后的代码及JRE运行环境一起打包),使用第三方打包工具(如Launch4j)和JDK自带... 目录1.问题提出2.如何将Java程序打包成可执行文件2.1将编译后的代码及jre运行环境一起打包2

在不同系统间迁移Python程序的方法与教程

《在不同系统间迁移Python程序的方法与教程》本文介绍了几种将Windows上编写的Python程序迁移到Linux服务器上的方法,包括使用虚拟环境和依赖冻结、容器化技术(如Docker)、使用An... 目录使用虚拟环境和依赖冻结1. 创建虚拟环境2. 冻结依赖使用容器化技术(如 docker)1. 创

MySQL 缓存机制与架构解析(最新推荐)

《MySQL缓存机制与架构解析(最新推荐)》本文详细介绍了MySQL的缓存机制和整体架构,包括一级缓存(InnoDBBufferPool)和二级缓存(QueryCache),文章还探讨了SQL... 目录一、mysql缓存机制概述二、MySQL整体架构三、SQL查询执行全流程四、MySQL 8.0为何移除查

微服务架构之使用RabbitMQ进行异步处理方式

《微服务架构之使用RabbitMQ进行异步处理方式》本文介绍了RabbitMQ的基本概念、异步调用处理逻辑、RabbitMQ的基本使用方法以及在SpringBoot项目中使用RabbitMQ解决高并发... 目录一.什么是RabbitMQ?二.异步调用处理逻辑:三.RabbitMQ的基本使用1.安装2.架构

mybatis的整体架构

mybatis的整体架构分为三层: 1.基础支持层 该层包括:数据源模块、事务管理模块、缓存模块、Binding模块、反射模块、类型转换模块、日志模块、资源加载模块、解析器模块 2.核心处理层 该层包括:配置解析、参数映射、SQL解析、SQL执行、结果集映射、插件 3.接口层 该层包括:SqlSession 基础支持层 该层保护mybatis的基础模块,它们为核心处理层提供了良好的支撑。

百度/小米/滴滴/京东,中台架构比较

小米中台建设实践 01 小米的三大中台建设:业务+数据+技术 业务中台--从业务说起 在中台建设中,需要规范化的服务接口、一致整合化的数据、容器化的技术组件以及弹性的基础设施。并结合业务情况,判定是否真的需要中台。 小米参考了业界优秀的案例包括移动中台、数据中台、业务中台、技术中台等,再结合其业务发展历程及业务现状,整理了中台架构的核心方法论,一是企业如何共享服务,二是如何为业务提供便利。