状态机——protothreads
来源:互联网 发布:cda 数据分析师考试 编辑:程序博客网 时间:2024/05/20 06:31
状态机——Protothreads
宗旨:技术的学习是有限的,分享的精神是无限的。
一、prothreads的优缺点
优点:
1. 以纯C语言实现,无硬件依靠性;因此不存在移植的困难。
2. 极少的资源需求,每个Protothread仅需要2个额外的字节;
3. 支持阻塞操纵且没有栈的切换。
缺点:
1. 函数中不具备可重入型,不能使用局部变量;
2. 按顺序判断各任务条件是否满足,因此无优先级抢占;
3. 任务中的各条件也是按顺序判断的,因此要求任务中的条件必须是依次出现的 protothread的阻塞机制:在每个条件判断前,先将当前地址保存到某个变量中,再判断条件是否成立,若条件成立,则往下运行;若条件不成立,则返回。
二、注意事项
注意:
(1)任务中使用的变量应为静态变量
(2)线程内不能使用纯 while(1)--即含 PT_WAIT_UNTIL()等宏的 while(1)是可以的。
不能在 switch(){case…}中调用任务 Protothreads API 带有 case 的语句(即只能单向嵌套)。
(3)线程内可以使用:
for(){…}
switch(){case…}-- case 与 case 之间必须是一个完整的语句或者语句段
if(){…}else{…}
含宏的 while(1){…}
(4)ProtothreadS 系统可以仍然还是个大 while(1)循环。但也可设计为根据定时器产生的恒定间隔的中断来触发和管理任务
--时间触发方式的嵌入式系统,此时可更改 pt 结构体为(见《时间触发模式下的 ProtothreadS 设计应用》):
struct pt
{
lc_t lc;
unsigned short count; // 每次中断都减 1
unsigned short load; // 初始计数值
char ready; // 任务就绪标志
}
(5)在 ProtothreadS 系统中延时:
1)如果 ProtothreadS 系统是基于时间触发,则延时可基于该触发--即基于系统时钟。
2)如果 ProtothreadS 系统中无系统时钟,
(6)Protothreads 虽然提供了在各自线程内的条件阻塞机制,但对于在该线程内调用的其它函数,则无法阻塞其运行。所以,
如果要在线程内调用占用时间较多的函数,为保证各个线程的实时性要求,需要将这类函数进一步划分为更小的函数,分步执
行。
(7) Protothread 的精华:当 Protothread 程序运行到 PT_WAIT_UNTIL 时,判断其运行条件是否满足,若不满足,则阻塞。
Protothread 的阻塞其实质就是函数返回。
Protothread 仅能在程序员指定位置阻塞。
三、protothreads各函数简要介绍
函数
说明
PT_INIT(pt)
初始化任务变量,只在初始化函数中执行一次
PT_BEGIN(pt)
启动任务处理,放在函数开始处
PT_END(pt)
结束任务,放在函数的最后
PT_WAIT_UNTIL(pt,condition)
条件成立,执行下面的;否则退出,下次直接跳到此处执行
PT_WAIT_WHILE(pt, condition)
类似PT_WAIT_UNTIL,只是条件取反了
PT_WAIT_THREAD(pt, thread)
等待一个子任务执行完成
PT_SPAWN(pt, child, thread)
新建一个子任务,并等待其执行完退出
PT_RESTART(pt)
重新启动某个任务执行
PT_EXIT(pt)
任务后面的部分不执行,直接退出重新执行
PT_YIELD(pt)
锁死任务
PT_YIELD_UNTIL(pt, condition)
锁死任务等待条件成立重新执行
四、protothreads代码
struct pt { lc_t lc;};#define PT_WAITING 0#define PT_YIELDED 1#define PT_EXITED 2#define PT_ENDED 3#define PT_INIT(pt) LC_INIT((pt)->lc)#define PT_THREAD(name_args) char name_args#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1;LC_RESUME((pt)->lc)#define PT_END(pt) LC_END((pt)->lc);PT_YIELD_FLAG = 0; \ PT_INIT(pt); return PT_ENDED; }#define PT_WAIT_UNTIL(pt, condition) \ do { \ LC_SET((pt)->lc); \ if(!(condition)) { \ returnPT_WAITING; \ } \ } while(0)#define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL((pt), !(cond))#define PT_WAIT_THREAD(pt, thread)PT_WAIT_WHILE((pt), PT_SCHEDULE(thread))#define PT_SPAWN(pt, child, thread) \ do { \ PT_INIT((child)); \ PT_WAIT_THREAD((pt), (thread)); \ } while(0)#define PT_RESTART(pt) \ do { \ PT_INIT(pt); \ returnPT_WAITING; \ } while(0)#define PT_EXIT(pt) \ do { \ PT_INIT(pt); \ returnPT_EXITED; \ } while(0)#define PT_SCHEDULE(f) ((f) < PT_EXITED)#define PT_YIELD(pt) \ do { \ PT_YIELD_FLAG = 0; \ LC_SET((pt)->lc); \ if(PT_YIELD_FLAG == 0) { \ returnPT_YIELDED; \ } \ } while(0)#define PT_YIELD_UNTIL(pt, cond) \ do { \ PT_YIELD_FLAG = 0; \ LC_SET((pt)->lc); \ if((PT_YIELD_FLAG == 0) || !(cond)) { \ returnPT_YIELDED; \ } \ } while(0)
五、举例
//解码
static charcamera_rs485_rx_decode(struct pt *pt, uint8_t c){ PT_BEGIN(pt); PT_WAIT_UNTIL(pt, 0x7E == c); camera_rs485.rx_count = 0; while(1) { PT_YIELD(pt); if (0x7E== c) { if(camera_rs485.rx_count) { camera_rs485_dispatch(camera_rs485.rx_buf,camera_rs485.rx_count); PT_EXIT(pt); } else { continue; } } if(0x1B ==c) { PT_YIELD(pt); if (0x00== c) { c =0x1B; } else if (0x65 == c) { c =0x7E; } else { //c ^=0x20; } } if(camera_rs485.rx_count < CAMERA_RS485_RX_BUF_SIZE) { camera_rs485.rx_buf[camera_rs485.rx_count++] = c; } else { PT_EXIT(pt); } } PT_END(pt);}
// 模块类型识别——定时器static chargps_probe(struct pt *pt, uint32_t ms){ staticuint32_t tmo = 0; static inti; const char*cmd; if (tmo >ms) { tmo -= ms; } else { tmo = 0; } PT_BEGIN(pt); tmo = 3000; PT_WAIT_UNTIL(pt, (0 == tmo)); if(GPS_MODULE_TYPE_UNKNOWN == gps.module_type) { for(i =GPS_MODULE_TYPE_UNKNOWN + 1; i < GPS_MODULE_TYPE_COUNT; ++i) { if(gps_cmds[i].query_version) { debug("gps_probe type: %d cmd: %s", i,gps_cmds[i].query_version); // 发送两次,确保模块接收到正确的命令 cmd =gps_cmds[i].query_version; UartSend(gps_uart, cmd, strlen(cmd)); PT_YIELD(pt); cmd =gps_cmds[i].query_version; UartSend(gps_uart, cmd, strlen(cmd)); // 等待模块输出版本信息 tmo =3000; PT_WAIT_UNTIL(pt, (0 == tmo)); } if(GPS_MODULE_TYPE_UNKNOWN != gps.module_type) { break; } } } // stop PT_WAIT_UNTIL(pt, FALSE); PT_END(pt);}
- 状态机——protothreads
- Unity高级——状态机——Switch状态机
- [Q学习]15 Qt状态机框架——状态机停止
- Unity框架——状态机
- react——state(状态机)
- 按键状态机—实现连发
- Protothreads简介
- 图解Protothreads
- Protothreads 简介
- 往死里写——ECAT_Main()状态机处理
- 【学习小记】UML——状态机图
- uml精粹——10.状态机图
- LabVIEW设计模式系列——状态机
- verilog学习笔记——三段式状态机
- 状态机生成工具——SMC
- [Q学习]13 Qt状态机框架——简单的状态机
- 状态机
- 状态机
- Week 8:Unsupervised Learning 第一部分课后习题解答
- 百度地图定位当前地址
- PHP匿名函数(闭包函数)
- Apache、Nginx与Tomcat的区别
- 编译sakai10.6
- 状态机——protothreads
- Jenkins安装,配置,运行
- 解决IE6,7下display:inline-block;失效问题。
- 打包测试 之 之 iOS Provisioning Profile(Certificate)与Code Signing详解
- MATLAB学习之符号运算
- Shell典型应用之应用系列(主控脚本、日志、进程监控和数据库)
- 【Hadoop基础】hadoop fs 命令
- Caffe提取任意层特征并进行可视化
- shadowsocks多端口配置