首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

STM32移栽contiki入门之三:从LED灯程序到contiki编程模型

2013-10-08 
STM32移植contiki入门之三:从LED灯程序到contiki编程模型本篇深入前面的led灯程序,分析contiki系统编程,给

STM32移植contiki入门之三:从LED灯程序到contiki编程模型

       本篇深入前面的led灯程序,分析contiki系统编程,给出一般的contiki编程模型。鉴于篇幅原因,不再将LED的代码放在此,如果大家想看,可以参考我的上一篇文章STM32移植contiki入门之二:简单编程点亮LED灯

一、led程序分析

PROCESS(led_on_process, "led on");

AUTOSTART_PROCESSES(&led_on_process); 

PROCESS_THREAD(led_on_process, ev, data)  

{  

    PROCESS_BEGIN(); 

    PROCESS_END(); 

}

process_start(&led_on_process,NULL); 

autostart_start(autostart_processes);

(一)、PROCESS宏

PROCESS宏完成两个功能:

(1) 声明一个函数,该函数是进程的执行体,即进程的thread函数指针所指的函数

(2) 定义一个进程

PROCESS宏源码展开如下(我这里只是部分代码,并没有完全展开):

#define PROCESS(name, strname)   \
  PROCESS_NOLOAD(name, strname);  \
  PROCESS_LOAD(name)

#define PROCESS_NOLOAD(name, strname)   \
  PROCESS_THREAD(name, ev, data);   \
  struct process name = { NULL, strname,  \
                          process_thread_##name }

#define PROCESS_THREAD(name, ev, data)     \
static PT_THREAD(process_thread_##name(struct pt *process_pt, \
           process_event_t ev, \
           process_data_t data))

 

(二)、PROCESS_THREAD宏

PROCESS_THREAD宏的功能是进程name的定义或声明,这取决于宏后面是";"还是"{}"

    PROCESS(led_on_process, "led on"); 展开成两句,其中有一句是也是PROCESS_THREAD(led_on_process, ev, data) ;。这里要注意到分号,是一个函数声明。而这PROCESS_THREAD(led_on_process, ev, data)没有分号,而是紧跟着"{}",是上述声明函数的实现。关于PROCESS_THREAD宏的分析,最后展开如下

contiki的进程之间不是没有联系的,我们之前说过,contiki维护着一个事件链表,当一个事件(进程)需要切换到另一个进程时,就是通过这里来的。(我的理解是这样的)

(三)、AUTOSTART_PROCESSES宏

    AUTOSTART_PROCESSES宏功能是定义一个指针数组,存放Contiki系统运行时需自动启动的进程

宏展开如下:

#define AUTOSTART_PROCESSES(...) \ struct process * const autostart_processes[] = {__VA_ARGS__, NULL}

AUTOSTART_PROCESSES(&led_on_process); 被替换成

struct process * const autostart_processes[] = {&led_on_process, NULL};

    这样就就可以让多个进程自启动了,直接在宏AUTOSTART_PROCESSES()加入需自启动的进程地址,比如有两个进程hello_process和world_process需要自启动,用如下的语句就能启动:

AUTOSTART_PROCESSES(&hello_process,&world_process);

 

 

(四)、PROCESS_BEGIN宏和PROCESS_END宏

PROCESS_BEGIN()进程的主体函数的开始,PROCESS_END()进程的主体函数的结束

 

    原则上,所有代码都得放在PROCESS_BEGIN宏和PROCESS_END宏之间(如果程序全部使用静态局部变量,这样做总是对的。倘若使用局部变量,情况就比较复杂了,当然,不建议这样做),看完下面宏展开,就知道为什么了。

PROCESS_BEGIN宏

PROCESS_BEGIN宏一步步展开如下:

#define PROCESS_BEGIN() PT_BEGIN(process_pt)

process_pt是struct pt*类型,在函数头传递过来的参数(见四),直接理解成lc,用于保存当前被中断的地方,以便下次恢复执行。继续展开:

#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; LC_RESUME((pt)->lc)

#define LC_RESUME(s) switch(s) { case 0:

把参数替换,结果如下:

{

    char PT_YIELD_FLAG = 1; /*将PT_YIELD_FLAG置1,类似于关中断*/

    switch(process_pt->lc) /*程序根据lc的值进行跳转,lc用于保存程序断点*/

   {

        case 0: /*第一次执行从这里开始*/

            ;

    最开始看到这里的时候,我很奇怪,PROCESS_BEGIN宏展开并不是完整的语句,后来才知道,这里有门道,继续向后看吧

PROCESS_END宏

PROCESS_END宏一步步展开如下:

#define PROCESS_END() PT_END(process_pt)

#define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \ PT_INIT(pt); return PT_ENDED; }

#define LC_END(s) }

#define PT_INIT(pt) LC_INIT((pt)->lc)

#define LC_INIT(s) s = 0;

#define PT_ENDED 3

整理下,实际上如下代码:

   }

 PT_YIELD_FLAG = 0;

    (process_pt)->pt = 0;

    return 3;

}

现在我们可以看到,PROCESS_BEGIN中不完整的语句,都被消除了,PROCESS_BEGIN和PROCESS_END这样的设计,真是别具一格,让人耳目一新的感觉。同时我们也应该注意到:PROCESS_BEGIN和PROCESS_END必须是成对出现的,有你有我,互相依靠。呵呵

 综合上面的分析,我们可以手动的展开上一章中LED的代码,得到如下的程序。

static char process_thread_led_on_process(struct pt *process_pt, process_event_t ev, process_data_t data);

struct process led_on_process = { ((void *)0), "led on", process_thread_led_on_process};

struct process * const autostart_processes[] = {&led_on_process, ((void *)0)};

char process_thread_led_on_process(struct pt *process_pt, process_event_t ev, process_data_t data)

{

    {

        char PT_YIELD_FLAG = 1;

        switch((process_pt)->lc)

        {

            case 0:

                ;

     FIO1DIR2 = 0x01 << 18;

     FIO5DIR0 = 0x07 << 2;

     FIO1SET2 = (~0x01) << 18;

     FIO5SET0 = (~0x07) << 2;

        };

     }

     PT_YIELD_FLAG = 0;

     (process_pt)->lc = 0;;

     return 3; 

}

好吧,到这里,估计很多人都糊涂了,我也糊涂了,这些宏到底是怎么展开的?其实非常简单

PROCESS  -> PROCESS_THREAD(声明)  -> PT_THREAD

PROCESS_THREAD   -------->定义

即:PROCESS宏展开为声明,PROCESS_THREAD展开为定义。如果你发现PROCESS宏之后跟的是分号,而PROCESS_THREAD宏之后跟的是{},就可以联想到,这是C语言中的声明和定义了。

 

二、编程模型

通过以上分析,我们可以得出contiki的一个编程模型。

    这实例虽说很简单,但却给出了定义一个进程的模型(还以Hello world为例),实际编程过程中,只需要将usart_puts("Hello, world!\n"); 换成自己需要实现的代码。

//假设进程名称为Hello world

PROCESS(hello_world_process, "Hello world"); //声明进程

AUTOSTART_PROCESSES(&hello_world_process); //将进程放到启动process中

PROCESS_THREAD(hello_world_process, ev, data) //进程定义,真正需要实现的代码放在这里

{

    PROCESS_BEGIN();

    /***填写你的代码***/

    PROCESS_END();

}

 

 

 

热点排行