目录
一、前后台系统轮询法
二、时间片轮询法
三、多任务操作系统
浅淡嵌入式开发中常见使用的三种软件架构:前后台系统轮询法、时间片轮询、多任务操作系统。
一、前后台系统轮询法
这是大部分初学者常用的一种软件框架设计方法。特点是代码简单,适用于对系统整体实行性和并发性要求不高的简单业务开发。
优点:代码简单直观,逻辑简单明了。适用于逻辑简单,复杂度比较低的软件开发。
缺点:实时性低,由于每一个业务代码或多或少存在延时,即使是1ms,也会对造成其他业务函数执行时间的不同。同事随着程序复杂度提升,代码的实现以及维护难度也会相应提升。
常见伪代码实现形式如下:通常系统初始化后,在while(1){}中实现业务函数。
void main(void)
{
/*硬件初始化*/
/*业务初始化*/
while (1)
{
/* 业务代码1 */
/* 业务代码2 */
/* ... */
}
}
二、时间片轮询法
该方法是一种介于前后台顺序执行法和操作系统之间的一种程序架构设计方案。适用于程序较复杂的嵌入式系统,对实时性有一定的要求,但目前的需求设计需要完全没有必要上操作系统;
该设计方案通常需要使用一个定时器,一般情况定时1ms即可,不建议中断过于频繁,降低系统实时性。同时需要考虑每一个任务函数的执行时长,最低的要求就是任务执行时长不得大于或接近任务执行周期,同时要求主循环或任务函数中不能存在毫秒级别的延时。
参考伪代码实现方式:
typedef struct code
{
unsigned char task_status; //运行状态标志位:0-不运行;1-运行
unsigned char time_count; //任务定时计数
unsigned char teme_initval; //任务定时初始值
void (*task_handler)(void); //任务回调函数
}Task_t;
#define NULL 0
#define TASK_NUM_MAX 3 //任务数量
Task_t M_Task[TASK_NUM_MAX];
int task_num = 0;
/*定时任务添加初始化函数*/
char TimeTask_Init(Task_t* task)
{
/*任务数量超载*/
if(task_num >= TASK_NUM_MAX)
return -1;
M_Task[task_num].teme_initval = task->teme_initval; /*定时周期*/
M_Task[task_num].task_handler = task->task_handler; /*任务回调*/
M_Task[task_num].task_status = 0; /*任务状态*/
M_Task[task_num].time_count = M_Task[task_num].teme_initval;/*任务计时器*/
task_num++;
return 0;
}
/*定时任务执行函数*/
void TimeTask_Pross(void)
{
for (int i = 0; i < TASK_NUM_MAX; i++)
{
if(M_Task[task_num].task_status == 1)
{
/*回调执行*/
if(M_Task[task_num].task_handler != NULL)
{
M_Task[task_num].task_handler();
}
M_Task[task_num].task_status = 0;
}
}
}
/*任务定时器处理函数,中断定时器中调用*/
void TimeTask_Tick(void)
{
for (int i = 0; i < TASK_NUM_MAX; i++)
{
if(M_Task[task_num].time_count > 0)
{
M_Task[task_num].time_count--;
}
if(M_Task[task_num].time_count == 0)
{
M_Task[task_num].task_status = 1; /*任务运行*/
M_Task[task_num].time_count = M_Task[task_num].teme_initval; /*定时器初始化*/
}
}
}
/****************************以下为伪代码部分****************************/
#define TIEM_TASK1 1
#define TIEM_TASK2 5
#define TIEM_TASK3 10
Task_t task1;
Task_t task2;
Task_t task3;
void task1_fun(void)
{
}
void task2_fun(void)
{
}
void task3_fun(void)
{
}
void main(void)
{
/*硬件初始化*/
/*定时任务初始化*/
task1.teme_initval = TIEM_TASK1;
task1.task_handler = task1_fun;
task2.teme_initval = TIEM_TASK2;
task2.task_handler = task2_fun;
task3.teme_initval = TIEM_TASK3;
task3.task_handler = task3_fun;
TimeTask_Init(&task1);
TimeTask_Init(&task2);
TimeTask_Init(&task3);
while (1)
{
TimeTask_Pross();
}
}
/*定时器中断-1ms*/
void Timer_IRQHandler(void)
{
TimeTask_Tick();
}
三、多任务操作系统
操作系统的本身是一个比较复杂的系统,任务的管理和调度实现的底层是相对负责的。但对于大部分的程序并不需要实现它,仅仅是将目前市面存在的实时系统移植作为我们开发的平台。目前市面比较常用的操作系统有ucos、freertos、rt-thread、linux等,但我们在使用操作系统的时候仅仅需要学习他们的调度与线程间的通信方式即可。适用于对实时性要求较高的场合。
优点:实时响应,对于工程师而言可以将大部分精力放在业务开发上。
缺点:需要移植且对单片机硬件资源有一定要求;使用比较复杂。
应用代码,参考相应的操作系统实例代码实现。