Chinaunix首页 | 论坛 | 博客
  • 博客访问: 191144
  • 博文数量: 34
  • 博客积分: 746
  • 博客等级: 军士长
  • 技术积分: 202
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-09 21:19
文章分类

全部博文(34)

文章存档

2011年(34)

分类: 嵌入式

2011-03-02 22:58:25

原文地址

Author: chenzhufly


Email: chenzhufly@126.com


2010-05-04


    这篇我将来玩玩多线程操作,体会一下其中的乐趣。实际上这也不能严格意义上称为多线程,只不过封装的比较好,感觉和多线程差不多,可以实现多任务而已。不过这还是需要您深入的研究才会明白的。欢迎您深入研究,欢迎您分享您的心得! Let’s  go……………………….


 


一. 为什么需要用多线程


    个人感觉是代码清晰,具有层次感,可读性强,增加任务或删减任务都很方便。JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ


 


二. 为什么选择Protothreads


Protothrcads是由瑞典计算机科学研究所的科学家Adam Dunkels所创的一种新的线程编程方法。特别适用于资源受限的系统,非常适合我们的LPC1343,呵呵,这也是我选择它的原因。


 


欲了解详情,请访问主页:~adam/pt/  同时可下载相关源码!先介绍一下Protothreads吧,然大家有个直观的认识。


 


Protothreads具有的特性:


1.    Very small RAM overhead - only two bytes per protothread and no extra stacks


非常少的RAM资源,每个Protothread仅需要2个字节,没有额外的栈


2.    Highly portable - the protothreads library is 100% pure C and no architecture specific assembly code


很强的移植性 -  protothreads库以C语言实现,无硬件依赖性


3.    Can be used with or without an OS


可以用于有操作系统或无操作系统的场合


4.     Provides blocking wait without full multi-threading or stack-switching


支持阻塞操作且没有栈的切换


 


Protothreads的典型应用:


1.    Memory constrained systems


内存紧张的系统


2.    Event-driven protocol stacks


时间驱动型协议栈,比如著名的uIP使用的就是Protothreads协议栈


3.    Small embedded systems


小的嵌入式系统


4.    Sensor network nodes


传感器网络节点


5.    Portable C applications


具有移植性的c应用


 


接着我们从主页上下载pt-1.4.tar.gz并解压,目录结构如下图所示:



 


从目录中可以看出,主要是5h文件:


lc-addrlabels.h 以字符串方式实现Protothreads系统,占用的ram可能会多些


lc-switch.h 以标准Cswitch结构实现Protothreads系统(默认)


lc.h 选择lc-addrlabels.hlc-switch.h两种实现Protothreads系统


pt.h 在实际应用中一般只包含此文件就行了


pt-sem.h 附加的信号量操作的支持,不需要的话则不必包含他


 


其他三个是例子程序,可以作为系统设计很好的参考!


 


我在这里只不过只是点一个LED而已,所以理所当然的只包含了一个pt.h文件,代码结构如图所示:



 


这个时候如果点编译工程的话,会出错的,如下图所示; 怎么办呢LLLLLL


明明目录底下是有lc.h文件,为什么还说没有包含,气愤啊!!!


 



 


 


研究了半天发现,原来是忘了增加include路径,那么又怎么增加新的include路径呢?看到编译器右下角有个quick setting没?点它,出下以下界面。看到Include Paths没?呵呵,就是在这里设置!然后一切顺利。。。。J



经过简要的修改,编译下载,这个时候你就可以看到LED很欢快的闪起来啦!!


 


到这里还是简要的看看pt.h都实现了啥吧,具体的还是麻烦您自己去看看手册,哈哈!


 


pt.h中的宏定义:


PT_INIT(pt)     初始化任务变量,只在初始化函数中执行一次就行


PT_BEGIN(pt)   启动任务处理,放在函数开始处


PT_END(pt)     结束任务,放在函数的最后


PT_WAIT_UNTIL(pt, condition) 等待某个条件(条件可以为时钟或其它变量,IO等)如果成立,继续;否则直接退出本函数,下一次进入本 函数就直接跳到这个地方判断。


PT_WAIT_WHILE(pt, cond)    和上面一个一样,只是条件取反了


PT_WAIT_THREAD(pt, thread) 等待一个子任务执行完成


PT_SPAWN(pt, child, thread)   新建一个子任务,并等待其执行完退出


PT_RESTART(pt)           重新启动某个任务执行


PT_EXIT(pt)               任务后面的部分不执行,直接退出重新执行


PT_YIELD(pt)               锁死任务


PT_YIELD_UNTIL(pt, cond)   锁死任务并在等待条件成立,恢复执行


 


pt中一共定义四种线程状态,在任务函数退出到上一级函数时返回其状态


PT_WAITING   等待


PT_EXITED    退出


PT_ENDED    结束


PT_YIELDED   锁死


 


废话就不多说,上代码才是王道!


三. 代码示例


这个代码是在pt-1.4中自带的example-small.c文件的基础上做的一些修改,主要是实现2个线程,一个线程做延时,一个线程做点LED操作。


 


#include "LPC13xx.h"                 


#include "gpio.h"


#include "config.h"


#include "pt.h"      //包含的头文件


static int protothread1_flag, protothread2_flag;


int i;


char j=0;


 


static int


protothread1(struct pt *pt) //线程1,完成LED操作,每进一次,IO取反


{


  PT_BEGIN(pt); //开始线程


  while(1) {


    protothread2_flag = 0;


    protothread1_flag = 1;


    j= ~j;


    GPIOSetValue( LED_PORT, LED_BIT, j );


  }


  PT_END(pt); //接触线程


}


 


static int


protothread2(struct pt *pt) //线程2,完成延时操作


{


  PT_BEGIN(pt);


 


  while(1) {


    protothread2_flag = 1;


    PT_WAIT_UNTIL(pt, protothread1_flag != 0); //等待条件


    protothread1_flag = 0;


    for(i=0;i<500000;i++);


  }


  PT_END(pt);


}


 


static struct pt pt1, pt2;


int


main(void)


{


  GPIOInit();


  GPIOSetDir( LED_PORT, LED_BIT, 1 );


  PT_INIT(&pt1);     //初始化线程1


  PT_INIT(&pt2);     //初始化线程2


  while(1) {


    protothread1(&pt1); //调用线程1


    protothread2(&pt2); //调用线程2


  }


}


 


LED是不是又闪起来了?这里你学到了什么了呢?你是不是有更好的应用呢?或者更好的想法呢?欢迎您的参与,欢迎您的分享!

阅读(1440) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~