[原创] 一个LED的N种玩法(六)----多线程

chenzhufly   2010-5-5 00:06 楼主

一个LEDN种玩法()—多线程

Author: chenzhufly

Email: chenzhufly@126.com

2010-05-04

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

 

一. 为什么需要用多线程

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

 

二. 为什么选择Protothreads

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

 

欲了解详情,请访问主页:http://www.sics.se/~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并解压,目录结构如下图所示:

  6.1.jpg

从目录中可以看出,主要是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文件,代码结构如图所示:

6.3.jpg  

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

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

 

6.2.jpg

 

 

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

6.4.jpg

经过简要的修改,编译下载,这个时候你就可以看到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是不是又闪起来了?这里你学到了什么了呢?你是不是有更好的应用呢?或者更好的想法呢?欢迎您的参与,欢迎您的分享!J

 

 

一个LED的N种玩法_六_----多线程.pdf (184.66 KB)
(下载次数: 251, 2010-5-5 00:06 上传)

pt-test.rar (165.67 KB)
(下载次数: 182, 2010-5-5 00:06 上传)

更多精彩 稍后继续

回复评论 (18)

点赞  2010-5-5 00:28
顶!!!!!!!!!!!!!!!!!!!!
点赞  2010-5-5 06:39
先顶再看!
点赞  2010-5-5 11:39
很好............
不断地学习,才会有创新! 淘宝小店:手机、qq点卡、游戏点卡自动充值 http://shop63727265.taobao.com/
点赞  2010-5-6 16:46
很可惜,没看懂。
不过感觉LZ很能追赶最新技术嘛
强者为尊,弱者,死无葬身之地
点赞  2010-5-10 09:39

引用: 原帖由 辛昕 于 2010-5-10 09:39 发表 很可惜,没看懂。不过感觉LZ很能追赶最新技术嘛

呵呵 貌似这个多线程应该是05年以前就有了吧

不断地学习,才会有创新! 淘宝小店:手机、qq点卡、游戏点卡自动充值 http://shop63727265.taobao.com/
点赞  2010-5-16 18:14
顶一个!
点赞  2010-6-24 22:03

__LINE__:在那里定义的?

#define LC_SET(s) s = __LINE__; case __LINE__:
点赞  2010-6-25 15:28

楼上的问题,想知道。

如果同一个线程里有多个PT_WAIT_UNTIL
那么pt->lc的值是怎么变化的,只看到
LC_SET(s) s = __LINE__; case __LINE__:

__LINE__; 就不知道怎么回事了
点赞  2010-6-25 19:41

很强大

点赞  2010-10-12 16:11
不关心代码,只关心RVDS 4.0 的使用,一直没掌握!
点赞  2010-10-18 21:14
待有时间再来研究
点赞  2010-10-18 22:22
学习了,谢谢楼主!!
点赞  2010-10-24 09:13

PT_YIELD(pt) 锁死任务

我想知道这个PT_YIELD(pt)               锁死任务
到底是怎么锁死任务的,多长时间后返回它下边继续执行呢?
点赞  2010-12-16 17:18

很好,学习一下^_^

很好,学习一下^_^哦,还有谢谢分享^_^
点赞  2011-5-14 16:45
mark
点赞  2011-6-27 12:31
先顶再看!
点赞  2012-8-30 00:16

回复 楼主chenzhufly 的帖子

点赞  2013-8-24 09:26
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复