网页资讯视频图片知道文库贴吧地图采购
进入贴吧全吧搜索

 
 
 
日一二三四五六
       
       
       
       
       
       

签到排名:今日本吧第个签到,

本吧因你更精彩,明天继续来努力!

本吧签到人数:0

一键签到
成为超级会员,使用一键签到
一键签到
本月漏签0次!
0
成为超级会员,赠送8张补签卡
如何使用?
点击日历上漏签日期,即可进行补签。
连续签到:天  累计签到:天
0
超级会员单次开通12个月以上,赠送连续签到卡3张
使用连续签到卡
08月10日漏签0天
arduino吧 关注:75,374贴子:230,226
  • 看贴

  • 图片

  • 吧主推荐

  • 视频

  • 游戏

  • 1 2 3 下一页 尾页
  • 69回复贴,共3页
  • ,跳到 页  
<<返回arduino吧
>0< 加载中...

【教程】ProtoThreads在Arduino中的应用#多任务处理#

  • 只看楼主
  • 收藏

  • 回复
  • 逍遥猪葛亮
  • 颇具盛名
    7
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
一楼、背景——
想象一个这样的情况,请不要在意这样奇怪的情景——
一个四位的数码管,由于要“同时”显示,因此每5ms刷新一次。(求别说MAX7219之类的IC……)
同时要处理一个矩阵键盘,设计是每10ms扫描一行,同时还有去抖处理,需要在检测到按键后再延时40ms检查一次。
检测到有效按键,在数码管上显示某个值,比如1234。
同时还能从串口接收数据,如果有数据收到,马上在数码管上显示某个值,比如5678,停留1s,期间按矩阵键盘不会有任何反应。
程序怎么写?晕了没?
比如说,去抖的时候,如果直接用delay(40)的话,那数码管的5ms刷新怎么办?串口收到的数据办?
基于这种超烦的(划掉)多任务处理,为了编程方便,让我们祭出嵌入式操作系统这一个神器!!!
哎!别走!!!妹子等我说完,我不打算讲高深理论哎!!(旁白:反正你也不是这个专业的,也讲不出)
嵌入式操作系统是用来处理这类超烦的(划掉)多任务处理的情况,常见的有uCos、RT-Thread等等,有兴趣的可以去看看。
但是Arduino,编译一个文件出来,如果你有留意的话,体积很大,而arduino本身的内存就不多,再移植一个就Orz了。所以,上面说的,不能用!!!哎!别走啊喂!!!
鉴于大家做些小作品,不需要用到如此高深的操作系统,只要简单地处理一下这些多任务的问题,所以,让我们祭出Adam Dunkels大神的ProtoThreads(附件)!


ProtoThreads.rar
大小:56.95KB下载:586次转存:85次
文件已失效
  • 逍遥猪葛亮
  • 颇具盛名
    7
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
二、ProtoThreads与嵌入式操作系统简介
ProtoThreads是一个通过宏(#define)写出来的神奇的模拟多线程(理解成多任务先)的库,里面全是头文件,找不到.cpp等程序文件。它的核心利用了C语言switch语句的特性。说是嵌入式系统,但这其实还只算是一个调度器,所以,并不能说是一个完整的操作系统。
操作系统最核心的功能是:在等待某个事件发生的时候,比如说定时一段时间、有无按键、串口上有无数据等等,操作系统帮你将单片机从当前的任务中临时切换到另一个任务运行,直到指定事件发生了再回来接着运行,这样就是变相实现了多任务处理,节省了CPU时间,还极大地减少开发难度(我会说我学过嵌入式系统后就再也不想做流水线式的设计了吗?)。
ProtoThreads在较大程度上实现出操作系统的核心功能,而且,每个新建一个任务,只需额外增加16bit即两个字节的空间(引入我的定时器宏则为6个字节)。除了核心功能外,还增加了信号量、延时这两个功能(仅限于我提供的库),我大概想到消息队列、标志怎么写了,但是没空写(旁白:其实是懒吧?)。
但是!!有缺点!!我说过了,它利用了switch语句的特性,所以,我非常不建议在任务中使用switch这个语句,除非你能保证在你的switch语句内不会切换任务。其次,请慎用内部变量,尤其是循环变量,在切换任务时有一定的可能性发生不可预料的错误,要用,请一定加上static修饰。
讲完,下面讲讲怎么用。


2025-08-10 12:17:50
广告
不感兴趣
开通SVIP免广告
  • 逍遥猪葛亮
  • 颇具盛名
    7
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
三、任务准备工作
首先,每个任务都必须要有一个记录变量,记录任务的状态,便于返回。语句:
static struct pt xxx;
这个xxx你们自己取好了。下面的全部都是xxx。请一定要加上前面的static struct。
好,然后要初始化一个任务。在setup()函数里面用这个语句:
PT_INIT(&xxx);
这样就初始化成功啦~记得要加个&符号。(一定要哦~)


  • 逍遥猪葛亮
  • 颇具盛名
    7
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
五、信号量(Semaphore)
妹子求别走T_T
我不得不解释一个专业术语,因为这二货很有用(信号量:你才二)……
我不上定义了,直接用例子说,不是我发明的例子。
停车场。停车。停车场里面的车位是固定的,假设没有一辆车占多个车位的情况。在这种情况下,剩余车位数就是一个“信号量”了。进一量车,剩余车位数就减一;出一量车,剩余车位数就加一。如果剩余车位数为0,那么想进来的车就只能在外面淋雨了。
对,信号量也是这样用。得到了一个信号量,任务继续运行,得不到,一边呆着去。
具体有什么用呢?比如说,一楼写着的,监控串口的任务读到数据了,要占用数码管。那么我们命令一个信号量为土豪,土豪只有一个。每次矩阵键盘要显示数据,先申请一个土豪,写数据,然后释放土豪,如果申请不到就在墙角不断画圈圈。监控串口的任务一旦申请到土豪就劫持1s,不让矩阵键盘用。这样就可以达到要求啦~
下面是用法:
要用的话,请在#include "pt.h"前面加上一句 #define PT_USE_SEM
首先要创建一个信号量,这个一定是全局变量:
static struct pt_sem 信号量名;
接着请在setup()函数里面给它初始化:
PT_SEM_INIT(&信号量名,数量);
信号量名前面有个&,别忘了。数量就相当于停车场的总车位数。
然后要用啦。任务要停一辆车进去:
PT_SEM_WAIT(pt,&信号量名);
信号量名前面有个&,别忘了。一个语句只能停一辆车,土豪好多车就用多次。
任务要开一辆车出来:
PT_SEM_SIGNAL(pt,&信号量名);
信号量名前面有个&,别忘了。用一次出一辆。
当然,对于一个任务来说,信号量没上限,就是说,你可以在停车场内再开辟新的车位,不断用PT_SEM_SIGNAL()就好了。
其实信号量这货解决的问题中,比较出名的是生产者与消费者问题。简单地说,消费者要买,必须要生产者生产才能买到,没生产出来,消费者只能等。


  • 逍遥猪葛亮
  • 颇具盛名
    7
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
六、例子
大家翻了那么久都累了伐……给个例子呗……
要求:板载LED以4秒一周期的速率闪烁。一旦收到串口发来的信息,不管信息量多少,快闪5次。用ProtoThreads写。
//首先启用定时器库和信号量库,下面会用到
#define PT_USE_TIMER
#define PT_USE_SEM
//引用库
#include "pt.h"
static struct pt thread1,thread2; //创建两个任务
static struct pt_sem sem_LED; //来个LED的信号量,同一时间只能一个任务占用
unsigned char i; //循环变量,写在这里其实不合适
void setup() {
//初始化13口和串口
pinMode(13,OUTPUT);
Serial.begin(115200);
PT_SEM_INIT(&sem_LED,1); //初始化信号量为1,即没人用
//初始化任务记录变量
PT_INIT(&thread1);
PT_INIT(&thread2);
}
//这是LED慢速闪烁的任务
static int thread1_entry(struct pt *pt)
{
PT_BEGIN(pt);
while (1)
{
PT_SEM_WAIT(pt,&sem_LED); //LED有在用吗?
//没有
digitalWrite(13,!digitalRead(13));
PT_TIMER_DELAY(pt,1000);//留一秒
PT_SEM_SIGNAL(pt,&sem_LED);//用完了。
PT_YIELD(pt); //看看别人要用么?
}
PT_END(pt);
}
//这是LED快速闪烁的任务,如果有串口消息,快速闪5次
static int thread2_entry(struct pt *pt)
{
PT_BEGIN(pt);
while (1)
{
PT_WAIT_UNTIL(pt, Serial.available()); //等到有串口消息再继续
PT_SEM_WAIT(pt,&sem_LED);//我要用LED啊!
//抢到使用权了,虐5次
for (i=0;i<5;i++)
{
digitalWrite(13,HIGH);
PT_TIMER_DELAY(pt,200);
digitalWrite(13,LOW);
PT_TIMER_DELAY(pt,200);
}
while (Serial.available())
Serial.read();
//清空串口数据,防止又来
PT_SEM_SIGNAL(pt,&sem_LED); //归还LED使用权了
}
PT_END(pt);
}
void loop() {
//依次调用即可
thread1_entry(&thread1);
thread2_entry(&thread2);
}


  • 逍遥猪葛亮
  • 颇具盛名
    7
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
七、后记
版权问题:ProtoThreads的基本代码是由Adam Dunkels编写了,详情请看Readme.md,我个人只扩展了pt-timer.h这一个库。转载及使用ProtoThreads的基本代码请遵循Adam Dunkels的声明。转载及使用我写的pt-timer.h请署名“逍遥猪葛亮”。
欢迎转载、使用、修改等等,提一提“逍遥猪葛亮”我会很高兴的。
@春泥蛋炒饭 申个精?


  • czj19940201
  • 富有名气
    8
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
顶一下,另外几个PT的教程没怎么看懂,这个过会儿看下


  • quhe2010
  • 默默无闻
    1
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
http://dunkels.com/adam/pt/


2025-08-10 12:11:50
广告
不感兴趣
开通SVIP免广告
  • shuke0220
  • 闻名一方
    11
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
顶,让某人的贴沉下去


  • anaesthesia_vp
  • 声名远扬
    12
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
我已经献出了我的膝盖


  • 小猪会轮滑
  • 赫赫有名
    13
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
大赞


  • ffumzw
  • 颇具名气
    6
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
好东西


  • 598358262
  • 颇具名气
    6
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
mark


  • 598358262
  • 颇具名气
    6
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
附件呢?


2025-08-10 12:05:50
广告
不感兴趣
开通SVIP免广告
  • 598358262
  • 颇具名气
    6
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
看到了 刚刚手机看不到附件,看说明还是很有用的!赞一个!


登录百度账号

扫二维码下载贴吧客户端

下载贴吧APP
看高清直播、视频!
  • 贴吧页面意见反馈
  • 违规贴吧举报反馈通道
  • 贴吧违规信息处理公示
  • 1 2 3 下一页 尾页
  • 69回复贴,共3页
  • ,跳到 页  
<<返回arduino吧
分享到:
©2025 Baidu贴吧协议|隐私政策|吧主制度|意见反馈|网络谣言警示