优点:
没有硬件相关的任务切换汇编代码。纯C 完成。也就是说。移植起来非常方便,你也可以理解成。不需要移植
极省内存。内存很小的单片机也能用。据说逻辑上更明确。复杂的任务反而省FLASH空间
缺点(也可以说编程需要注意的要点)
任务主体中 不能用SWITCH。子程序里可用。
任务中的变量如果经历了任务切换的部分会重初始化。所以。如果任务一个变量需要任务切换也不变。就需要static修饰.
所有的任务必须非锁死。必须有任务切换的指令。不能有占用CPU的的长延时。因为这个非抢占式,阻塞长延时影响CPU效率和任务切换响应时间。
这是协作式我任务。我就不多解释了
protothreads 架构的多任务。增加了事件消息
本来用于物联网。协议什么的
我把一些用不着的文件都删除了。只保留多任务和事件驱动
代码量很小基本上是个CPU就能用了。
ETIMER定时器需要一个定时启动的中断产生时基。不需要定时器的话也可以不用。
不需要额外的汇编或者C 代码移植
如果需要定时器。就增加一个定时中断。在中断时给ETIME任务发一个事件消息驱动计时就OK了。
具体CONTIKI的多任务机制在网上有笔记。我就不多说了.网上说的很不错。我只是把这个物联网常用的系统中的多任务部分拿出来当RTOS用。。。
#include "sys/process.h"
#include "sys/clock.h"
#include "sys/etimer.h"
主程序
main 循环里开启多任务
PROCESS_NAME(etimer_process);
PROCESS_NAME(precess1);
process_init();
process_start(&etimer_process,NULL);//启动系统进程最先启动etimer
process_start(&precess1,NULL);//启动系统进程最先启动etimer
while(1)
{
while(process_list)
{
do
{
}
while(process_run()>0);
}
}
另外任务的样子
PROCESS(precess1,"precess1");
PROCESS_THREAD(precess1,ev,data)
{
PROCESS_BEGIN();
while(1)
{
PROCESS_YIELD();
}
PROCESS_END();
}
example里有一个基本任务的样子。
/*---------------------------------------------------------------------------*/
PROCESS(hello_world_process, "Hello world process");
AUTOSTART_PROCESSES(&hello_world_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(hello_world_process, ev, data)
{
PROCESS_BEGIN();
printf("Hello, world\n");
PROCESS_END();
}
借用别人的文字解释这种OS的特点
以uc/os-ii为代表的RTOS对于任务阻塞(一般使用等待:信号量、邮箱、消息队列等)是很轻松的,这种基于“上下文切换”(Context Switch)的系统,可以在任务调用的任意函数语句中“挂起自己”
而Contiki进程可以调用protothread实现“函数级阻塞”
①当protothread等待事件时,它先向process调用PT_YIELD()“挂起函数”;process收到protothread的PT_YIELDED返回值时,执行PROCESS_YIELD()“挂起进程”,向ContikiOS让出系统控制权。
②当外部事件(一般为中断)向ContikiOS发消息时,ContikiOS先调度对应的process,process则继续调用protothread,protothread再处理该事件。
③当protothread处理完所有逻辑后,它向process返回PT_ENDED,此时process知道该protothread已经完成工作。
通过这种“函数级阻塞”技术,可以将逻辑复杂的进程分解成多个protothread,采用分而冶之的办法,让程序设计和维护代价大大降低。
Contiki系统调度和阻塞实质是“函数返回”,因此进程设计有3条原则:
① 每个进程响应一个硬件的poll消息;
② 多个硬件之间的时序交给ISR用状态机完成;
③ 进程主体函数尽可能简单,如果复杂将拆分成多个protothread。