0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

详解单片机三种应用程序的架构

Q4MP_gh_c472c21 来源:CSDN技术社区 作者:大橙子疯 2022-03-29 11:36 次阅读

摘要:对于单片机程序来说,大家都不陌生,但是真正使用架构,考虑架构的恐怕并不多,随着程序开发的不断增多,架构是非常必要的。

应用程序的架构大致有三种:

1、简单的前后台顺序执行程序,这类写法是大多数人使用的方法,不需用思考程序的具体架构,直接通过执行顺序编写应用程序即可。

2、时间片轮询法,此方法是介于顺序执行与操作系统之间的一种方法。

3、操作系统,此法应该是应用程序编写的最高境界。

一、程序框架设计

1、前后台顺序执行法

这是初学者们常用的程序框架设计方案,不用考虑太多东西,代码简单,或者对系统的整体实时性和并发性要求不高;初始化后通过while(1){}for(;;){}`循环不断调用自己编写完成的函数,也基本不考虑每个函数执行所需要的时间,大部分情况下函数中或多或少都存在毫秒级别的延时等待。

  • 优点:对于初学者来说,这是最容易也是最直观的程序架构,逻辑简单明了,适用于逻辑简单,复杂度比较低的软件开发。

  • 缺点:实时性低,由于每个函数或多或少存在毫秒级别的延时,即使是1ms,也会造成其他函数间隔执行时间的不同,虽然可通过定时器中断的方式,但是前提是中断执行函数花的时间必须短。当程序逻辑复杂度提升时,会导致后来维护人员的大脑混乱,很难理清楚该程序的运行状态。

以下是在校期间做的寝室防盗系统的部分代码(当时也存在部分BUG,没有解决。现在再看,其实很多问题,而且比较严重,比如中断服务函数内竟然有3000ms延时,这太可怕了,还有串口发送等等;由于实时性要求不算太高,因此主函数中的毫秒级别延时对系统运行没有多大影响,当然除BUG外;若是后期需要维护,那就是一个大工程,还不如推翻重写):

intmain(void)
{
u8temperature;
u8humidity;
inta;
delay_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
I2c_init();
uart2_Init(9600);
uart_init(9600);//串口初始化为115200
TIM3_Int_Init(4999,7199);
ds1302_init();
while(DHT11_Init())//DHT11初始化
{
led2=0;
}
a1602_init();
Ds1302Init();
EXTIX_Init();
GPIOX_Init();
lcd12864_INIT();
LcdInit();
beep_init();
RED_Init();
led1=1;
beep=0;
while(1)
{
for(a=0;a<11;a++)
{
num[a+3]=At24c02Read(a+2)-208;
delay_us(10);
}
for(a=0;a<6;a++)
{
shuru[a]=At24c02Read(a+13)-208;
delay_us(10);
}
delay_ms(10);
RED_Scan();
Ds1302ReadTime();//读取ds1302的日期时间
shi=At24c02Read(0);//读取闹钟保存的数据
delay_ms(10);
fen=At24c02Read(1);//读取闹钟保存的数据
usart2_scan();//蓝牙数据扫描
usart2_bian();//蓝牙处理数据
usart2_gai();
nao_scan();
k++;
if(k<20)
{
if(k==1)
LcdWriteCom(0x01);//清屏
LcdDisplay();//显示日期时间
}
if(RED==0)
RED_Scan();
if(k>=20&&k<30)
{
if(k==20)
LcdWriteCom(0x01);//清屏
Lcddisplay();//显示温湿度
LcdWriteCom(0x80+6);
DHT11_Read_Data(&temperature,&humidity);//读取温湿度值
Temp=temperature;Humi=humidity;
LcdWriteData('0'+temperature/10);
LcdWriteData('0'+temperature%10);
LcdWriteCom(0x80+0X40+6);
LcdWriteData('0'+humidity/10);
LcdWriteData('0'+humidity%10);
}
if(k==30)
k=0;
lcd12864();//显示防盗闹钟状态
}
}

//定时器3中断服务程序
voidTIM3_IRQHandler(void)//TIM3中断
{
inti;
if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET)//检查TIM3更新中断发生与否
{
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);//清除TIMx更新中断标志
if(key1==1&&FEN-fen==0&&SHI-shi==0)//时间一到闹钟响起
{
f=1;
}
if(key1==0||FEN-fen!=0||SHI-shi!=0)
else
{
f=0;
}
if(USART_RX_BUF[0]=='R'&&USART_RX_BUF[1]=='I'&&USART_RX_BUF[2]=='N'&&USART_RX_BUF[3]=='G')
{
key0=1;
for(i=0;i<17;i++)
{
USART_SendData(USART1,num[i]);//向串口1发送数据
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
USART_RX_STA=0;
}
delay_ms(3000);
for(i=0;i<3;i++)
{
USART_SendData(USART1,num1[i]);//向串口1发送数据
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
USART_RX_STA=0;
}
}
}
}

二、时间片论法

介于前后台顺序执行法操作系统之间的一种程序架构设计方案。该设计方案需能帮助嵌入式软件开发者更上一层楼,在嵌入式软件开发过程中,若遇到以下几点,那么该设计方案可以说是最优选择,适用于程序较复杂的嵌入式系统

  • 目前的需求设计需要完全没有必要上操作系统。
  • 任务函数无需时刻执行,存在间隔时间(比如按键,一般情况下,都需要软件防抖,初学者的做法通常是延时10ms左右再去判断,但10ms极大浪费了CPU的资源,在这段时间内CPU完全可以处理很多其他事情)
  • 实时性有一定的要求。

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

如何确定每个函数的任务周期呢?根据任务的耗时和效果决定、如按键扫描任务周期为 10ms(为了提高响应),指示灯控制任务周期为 100ms(通常情况下最高100ms的闪烁频率正好,特殊需求除外),LCD/OLED 显示周期为 100ms(通过这种通过SPI/IIC接口的方式耗时大约在 1~10ms,甚至更长,所以任务周期必须远大于耗时,同时为了满足人眼所能接受的刷屏效果,也不能太长,100ms 的任务周期比较合适)等。

以下介绍两种不同的实现方案,分别针对无函数指针概念的朋友和想进一步学习的朋友。

1、无函数指针的设计方式

/**
*@brief主函数.
*@paramNone.
*@returnNone.
*/

intmain(void)
{
System_Init();

while(1)
{
if(TIM_1msFlag)//1ms
{
CAN_CommTask();//CAN发送/接收通信任务

TIM_1msFlag=0;
}
if(TIM_10msFlag)//10ms
{
KEY_ScanTask();//按键扫描处理任务

TIM_10msFlag=0;
}
if(TIM_20msFlag)//20ms
{
LOGIC_HandleTask();//逻辑处理任务

TIM_20msFlag=0;
}
if(TIM_100msFlag)//100ms
{
LED_CtrlTask();//指示灯控制任务

TIM_100msFlag=0;
}
if(TIM_500msFlag)//500ms
{
TIM_500msFlag=0;
}
if(TIM_1secFlag)//1s
{
WDog_Task();//喂狗任务
TIM_1secFlag=0;
}
}
}

/**
*@brief定时器3中断服务函数.
*@paramNone.
*@returnNone.
*/
voidTIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET)//溢出中断
{
sg_1msTic++;
sg_1msTic%1==0?TIM_1msFlag=1:0;
sg_1msTic%10==0?TIM_10msFlag=1:0;
sg_1msTic%20==0?TIM_20msFlag=1:0;
sg_1msTic%100==0?TIM_100msFlag=1:0;
sg_1msTic%500==0?TIM_500msFlag=1:0;
sg_1msTic%1000==0?(TIM_1secFlag=1,sg_1msTic=0):0;
}
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);//清除中断标志位
}

2、含函数指针的设计方式

/**
*@brief任务函数相关信息结构体定义.
*/
typedefstruct{
uint8m_runFlag;/*!< 程序运行标记:0-不运行,1运行 */
uint16m_timer;/*!< 计时器 */
uint16m_itvTime;/*!< 任务运行间隔时间 */
void(*m_pTaskHook)(void);/*!< 要运行的任务函数 */
}TASK_InfoType;

#defineTASKS_MAX5//定义任务数目

/**任务函数相关信息*/
staticTASK_InfoTypesg_tTaskInfo[TASKS_MAX]={
{0,1,1,CAN_CommTask},//CAN通信任务
{0,10,10,KEY_ScanTask},//按键扫描任务
{0,20,20,LOGIC_HandleTask},//逻辑处理任务
{0,100,100,LED_CtrlTask},//指示灯控制任务
{0,1000,1000,WDog_Task},//喂狗任务
};


/**
*@brief任务函数运行标志处理.
*@note该函数由1ms定时器中断调用
*@paramNone.
*@returnNone.
*/
voidTASK_Remarks(void)
{
uint8i;
for(i=0;i< TASKS_MAX; i++)
    {
        if(sg_tTaskInfo[i].m_timer)
{
sg_tTaskInfo[i].m_timer--;
if(0==sg_tTaskInfo[i].m_timer)
{
sg_tTaskInfo[i].m_timer=sg_tTaskInfo[i].m_itvTime;
sg_tTaskInfo[i].m_runFlag=1;
}
}
}
}

/**
*@brief任务函数运行处理.
*@note该函数由主循环调用
*@paramNone.
*@returnNone.
*/
voidTASK_Process(void)
{
uint8i;
for(i=0;i< TASKS_MAX; i++)
    {
        if(sg_tTaskInfo[i].m_runFlag)
{
sg_tTaskInfo[i].m_pTaskHook();//运行任务
sg_tTaskInfo[i].m_runFlag=0;//标志清0
}
}
}

/**
*@brief主函数.
*@paramNone.
*@returnNone.
*/
intmain(void)
{
System_Init();
while(1)
{
TASK_Process();
}
}

/**
*@brief定时器3中断服务函数.
*@paramNone.
*@returnNone.
*/
voidTIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET)//溢出中断
{
TASK_Remarks();
}
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);//清除中断标志位
}

三、操作系统

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

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

关于如何选择合适的操作系统(uCOSFreeRTOSRTThreadRTXRTOS的对比之特点:

  • uCOS:网上资料丰富,非常适合学习,但是在产品上使用则需要收费。
  • FreeRTOS:使用免费,因此很多产品都在用。
  • RT-Thread:国产物联网操作系统,有着十分丰富的组件,也免费,资料:RT-Thread文档中心
  • RTX:为ARM和Cortex-M设备设计的免版税,确定性的实时操作系统。

借网上一张对比图:

详解单片机三种应用程序的架构

四、总结

从上述的对比中可以看出,时间片轮询法的优势还是比较大的,它既有前后台顺序执行法的优点,也有操作系统的优点。结构清晰,简单,非常容易理解,所以这种是比较常用的单片机设计框架。

原文标题:嵌入式软件开发常用的3种架构

文章出处:【微信公众号:嵌入式ARM】欢迎添加关注!文章转载请注明出处。
审核编辑:汤梓红


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    5999

    文章

    43966

    浏览量

    620719
  • 嵌入式
    +关注

    关注

    4981

    文章

    18271

    浏览量

    288265
  • 应用程序
    +关注

    关注

    37

    文章

    3133

    浏览量

    56364
  • 架构
    +关注

    关注

    1

    文章

    483

    浏览量

    25200

原文标题:嵌入式软件开发常用的3种架构

文章出处:【微信号:gh_c472c2199c88,微信公众号:嵌入式微处理器】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    单片机程序架构详解

    本帖最后由 eehome 于 2013-1-5 09:44 编辑 单片机程序架构详解
    发表于 08-17 15:55

    嵌入式软件开发中的程序架构

    单片机软件开发的初期大多数开发者采用的都是简单的前后台顺序执行架构。在嵌入式软件开发中,程序架构主要分为三种,本篇文章将对这
    发表于 02-02 06:58

    单片机应用程序架构的经验

    单片机应用程序架构的经验总结前后台顺序执行法
    发表于 02-04 06:00

    单片机大致应用程序架构三种

    转载----在工作中经过摸索实验,总结出单片机大致应用程序架构三种:1. 简单的前后台顺序执行程序,这类写法是大多数人使用的方法,不需用
    发表于 07-21 08:50

    谈谈怎样架构你的单片机程序

    参考:《谈谈怎样架构你的单片机程序》。本人经过摸索实验,并总结,大致应用程序架构三种:1.
    发表于 07-21 07:01

    单片机MCU应用程序架构的相关资料分享

    单片机MCU应用程序架构在网上看到一篇文章,感觉写的不错,而且日常涉及到的很多程序也是文章中提到的时间片轮询法来做的。转载过来,做个记录。原文链接:http://bbs.eeworld
    发表于 11-04 07:39

    怎样架构你的单片机程序

    的并不都,而且这类书籍基本没有。本人经过摸索实验并总结,大致应用程序架构三种:简单的前后台顺序执行程序,这类写法是大多数人使用的方法,不需用思考
    发表于 12-07 09:25

    单片机大致应用程序架构总结

    转载----微信公众号在工作中经过摸索实验,总结出单片机大致应用程序架构三种:简单的前后台顺序执行程序,这类写法是大多数人使用的方法,不
    发表于 12-07 11:18

    单片机应用程序架构有哪几种呢

    参考:《谈谈怎样架构你的单片机程序》。 本人经过摸索实验,并总结,大致应用程序架构三种:1.
    发表于 12-09 07:48

    三种较为常见单片机的驱动方式以及程序

    三种较为常见单片机的驱动方式以及程序
    发表于 12-21 07:49

    干货:一文搞懂单片机应用程序架构

    对于单片机程序来说,大家都不陌生,但是真正使用架构,考虑架构的恐怕并不多,随着程序开发的不断增多,本人觉得
    的头像 发表于 10-30 17:05 397次阅读

    浅析单片机三种应用程序架构

    在工作中经过摸索实验,总结出单片机大致应用程序架构三种: 1. 简单的前后台顺序执行程序,这类写法是大多
    的头像 发表于 04-07 09:44 4161次阅读

    单片机MCU应用程序架构

    单片机MCU应用程序架构在网上看到一篇文章,感觉写的不错,而且日常涉及到的很多程序也是文章中提到的时间片轮询法来做的。转载过来,做个记录。原文链接:http://bbs.eeworld
    发表于 10-29 11:21 12次下载
    <b class='flag-5'>单片机</b>MCU<b class='flag-5'>应用程序</b><b class='flag-5'>架构</b>

    一文搞懂单片机应用程序架构

    对于单片机程序来说,大家都不陌生,但是真正使用架构,考虑架构的恐怕并不多,随着程序开发的不断增多,本人觉得
    发表于 11-24 19:36 12次下载
    一文搞懂<b class='flag-5'>单片机</b><b class='flag-5'>应用程序</b><b class='flag-5'>架构</b>

    实用:牛人总结的单片机三种应用程序架构

    单片机大致应用程序架构有简单的前后台顺序执行程序、时间片轮询法、操作系统三种
    发表于 02-08 16:39 11次下载
    实用:牛人总结的<b class='flag-5'>单片机</b><b class='flag-5'>三种</b><b class='flag-5'>应用程序</b><b class='flag-5'>架构</b>!