contiki操作系统下基于Protothreads事件驱动编程的注意事项

来源:互联网 发布:手机淘宝怎么找主播 编辑:程序博客网 时间:2024/05/29 18:20

什么是contiki?

Contiki is an open source operating system for the Internet of Things. Contiki connects tiny low-cost, low-power microcontrollers to the Internet.

contiki的主要特点:

  • Open Source Software
  • Full IP Networking( with standard IP protocols such as UDP, TCP, and HTTP, in addition to the new low-power standards like 6lowpan, RPL, and CoAP. )
  • Dynamic Module Loading(he Contiki module loader can load, relocate, and link standard ELF files that can optionally be stripped off their debugging symbols to keep their size down.)
  • Protothreads(Protothreads is a mixture of the event-driven and the multi-threaded programming mechanisms. With protothreads, event-handlers can be made to block, waiting for events to occur.)
详细信息参考:http://www.contiki-os.org/index.html#why

关于Protothreads的作者的论文Protothreads Simplifying Event-Driven Programming of Memory-Constrained Embedded Systems.pdf

http://muneebali.com/pubs/dunkels06protothreads.pdf

protothread中文学习资料:

contiki代码学习之一:浅探protothread进程控制模型【1】

zhuangxiu.ganji.com/ask/2587821.htm
zhuangxiu.ganji.com/ask/2587822.htm
zhuangxiu.ganji.com/ask/2587823.htm
http://zhuangxiu.ganji.com/ask/2587821.htm
http://zhuangxiu.ganji.com/ask/2587822.htm
http://zhuangxiu.ganji.com/ask/2587823.htm

http://contikistudio.smeshlink.com/forum.php?mod=viewthread&tid=274&extra=page%3D1

Contiki学习笔记:实例hello_world剖析 

http://blog.chinaunix.net/uid-9112803-id-2898026.html

Contiki的任务调度机制

http://radiocov.cn/?p=134


Protothreads给嵌入式带来了很大的方面,且与多线程相比非常节省RAM资源,每个Protothread只保存1个字节。缺点就是程序如果想保存上一次调用的状态,需要使用全局变量。还有一个特殊的问题是protothread引入了一些宏:PROCESS_BEGIN()PROCESS_END()等,这些宏使得代码的执行顺序和c语言的通常代码的执行顺序不同。
从我遇到的一个问题说起,原本的问题来自一个协议栈,设计随机数的产生,为了突出重点,只保留问题相关部分(每秒产生一个随机数)。发现随机数每次都不变!代码如下:


#include "contiki.h"
#include <stdio.h> 
#include "lib/random.h"
/*---------------------------------------------------------------------------*/
PROCESS(pt_test_process, "pt test process");
AUTOSTART_PROCESSES(&pt_test_process);




/*---------------------------------------------------------------------------*/
PROCESS_THREAD(pt_test_process, ev, data)
{
  static struct etimer et;
  random_init(0);
  PROCESS_BEGIN();

  while(1){
etimer_set(&et, CLOCK_SECOND);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
printf("random number is:%d\n",random_rand());
etimer_set(&et, CLOCK_SECOND);
  }
  PROCESS_END();
}
编译:make pt_test TARGET=native
执行:./pt_test.native          
输出:
contiki started
Rime started with address 2.1
MAC nullmac RDC nullrdc NETWORK Rime
random number is:17767
random number is:17767
random number is:17767


经检查不是random相关函数的问题,而是random_init(0);的位置没有写对,每秒时间触发后都会执行一次random_init(0);所以random_rand()的结果就不随机了

将 random_init(0);和PROCESS_BEGIN();的位置颠倒一下就好了。


输出结果为:

contiki started
Rime started with address 2.1
MAC nullmac RDC nullrdc NETWORK Rime
random number is:17767
random number is:9158
random number is:39017
random number is:18547
random number is:56401
从这个例子可以看出,该protothread被系统调用并不是直接跳转到PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));那一行,而是从程序入口执行到PROCESS_BEGIN();再跳转到PROCESS_WAIT_EVENT_UNTIL那一行。为了更形象的说明protothread的执行顺序,看下面的代码:
#include "contiki.h"
#include <stdio.h> 
#include "lib/random.h"
/*---------------------------------------------------------------------------*/
PROCESS(pt_test_process, "pt test process");
AUTOSTART_PROCESSES(&pt_test_process);




/*---------------------------------------------------------------------------*/
PROCESS_THREAD(pt_test_process, ev, data)
{
  static struct etimer et;
 
  printf("before BEGIN\n");
  PROCESS_BEGIN();
  printf("after BEGIN\n");
  while(1){
printf("before PROCESS_WAIT_EVENT_UNTIL\n");
etimer_set(&et, CLOCK_SECOND);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
etimer_set(&et, CLOCK_SECOND);
printf("after PROCESS_WAIT_EVENT_UNTIL\n");
  }
  printf("before END\n");
  PROCESS_END();
  printf("after END\n");
}
/*---------------------------------------------------------------------------*/
结果输出如下:
contiki started
Rime started with address 2.1
MAC nullmac RDC nullrdc NETWORK Rime
before BEGIN
after BEGIN
before PROCESS_WAIT_EVENT_UNTIL
before BEGIN
after PROCESS_WAIT_EVENT_UNTIL
before PROCESS_WAIT_EVENT_UNTIL
before BEGIN
after PROCESS_WAIT_EVENT_UNTIL
before PROCESS_WAIT_EVENT_UNTIL
before BEGIN
after PROCESS_WAIT_EVENT_UNTIL
before PROCESS_WAIT_EVENT_UNTIL
^C


after BEGIN部分只执行了一遍,before BEGIN,after PROCESS_WAIT_EVENT_UNTIL,before PROCESS_WAIT_EVENT_UNTIL部分每次时间触发都会执行,请注意上面的顺序。


小结:在protothread编程中,程序初始化的部分(只执行一次的)放在after BEGIN部分,每次事件触发的处理放在after PROCESS_WAIT_EVENT_UNTIL。