新闻中心

EEPW首页>嵌入式系统>设计应用> 基于单片机的协程多任务

基于单片机的协程多任务

作者: 时间:2016-11-25 来源:网络 收藏
在很多的 单片机项目中,由于操作系统的体积以及使用的背景知识,如果采用的话,可能让项目脱离主要业务方向,这个时候很有必要使用简单的 协程多任务
1协程多任务的特点
每个任务优先级平等
每个任务主动释放CPU控制权
2 UCOS等操作系统的特点
任务存在不同优先级,很方便进行CPU资源的分配。
对于ucos的任务来说,每个任务都认为自己是独占cpu的,可以随便休眠之类,这样对于代码的风格的限制比较小,比较好修改现存的模块。
操作系统一般提供比较多的服务,对于复杂应用比较好。
3 协程多任务的应用场合
协程方式适合简单的多任务,每个任务要确认其符合协程的模型,不能阻塞cpu运行,要主动释放CPU,如果考虑到多人合作,或者引入第三方的代码,进来,那么协程方式恐怕工作量过大(模型改造检查),这时最好使用操作系统。
协程或者操作系统的平台的建立,这些都需要积累,也没有什么高级和低级的区别,只是针对不同的场景和开发人员选择不同而已。
4协程多任务的实现
为了使用方便,并且将来便于系统升级,多任务采用基于接口的方式定义和实现。
4.1 任务的定义
每个任务会管理自己的数据,提供对外接口,每个任务提供以下形式结构
Struct _task1
{
//任务对外接口,函数指针
Void (*start)(Struct _task1*handle);
Void (*run)(Struct _task1*handle);
Void (*stop)(Struct _task1*handle);
//其他对外接口
...
//任务私有数据
} task1;
之所以将对外接口放在任务结构体中,是为了强调这些是任务的对外接口,而且客户只能调用这里面的接口,另外函数指针也很方便的提供了一个接口和实现的分隔层
4.2 任务的实现
任务的实现层面,用户可以根据对系统和业务的理解,做系统演化,而不会影响到外部接口的使用
//任务接口实现函数
Void task1_start(Struct _task1*handle)
{
//设置任务开始标识
}
Void task1_run(Struct _task1*handle)
{
If(handle->status1)
{
//处理
}
Else if(handle->status2)
{
//处理
}
}
Void task1_stop(Struct _task1*handle)
{
//设置任务结束标识
}
//任务初始化函数,构造任务结构体
Void task1_init(Struct _task1*handle)
{
Handle->start = task_start;
Handle->run = task_run;
Handle->stop= task_stop;
}
4.3 调用形式
4.3.1 定义全局任务结构体
Struct _task1
{
//任务对外接口,函数指针
Void (*start)(Struct _task1*handle);
Void (*run)(Struct _task1*handle);
Void (*stop)(Struct _task1*handle);
//其他对外接口
...
//任务私有数据
} task1;
4.3.2 任务初始化
Task1_init(&task1);
4.3.3 开始任务
Task1->start(&task1);
4.3.4 结束任务
Task1->stop(&task1);
4.3.5 任务运行
一般系统在启动后运行的一个无限循环语句中有
While(1)
{
Task1->run(&task1);
Task2->run(&task2)
...其他任务运行
}
5 定时器以及延时的实现方法
协程多任务不会在代码中使用sleep()阻塞CPU的方法做定时器或者休眠,定时器会有一个单独的任务,任务提供新增定时器、删除定时器、查询定时器值等接口来提供软件定时器功能。
6 任务间通讯
原则上通过任务提供的接口来通讯,当然如果通讯工作量过大,不反对使用第三方任务来完成通讯。
7 驱动层模块任务例子
对于 务来说,应用层和驱动层是优先级相同的任务,对于很多的驱动来说,例如UART驱动,其发送和接收很多采用的是查询的方式来进行,下面简单的使用多任务的结构方式来说明驱动的写作
Struct _com{
//任务对外接口,函数指针
Void (*start)(Struct _com*handle);
Void (*run)(Struct _com*handle);
Void (*stop)(Struct _com*handle);
//其他对外接口
Void read(char* ch)
Void write(char* ch)
...
//任务私有数据
//驱动状态,
Char status;
}com1;
//运行代码
Void Com_run(Struct _com * handle)
{
If(read)
{
If(register1)
{
}
Else if(register2)
{
}
}
Else if(write)
{
If(register3)
{
}
Else if(register4)
{
}
}
}
从上面代码可见,驱动模块其实和普通的任务没有区别。


关键词:单片机协程多任

评论


技术专区

关闭