搜索
bottom↓
回复: 30

protothread, 就是状态机!

  [复制链接]

出0入0汤圆

发表于 2012-5-27 10:43:29 | 显示全部楼层 |阅读模式
本帖最后由 smset 于 2012-5-27 10:45 编辑

protothread 是经典的状态机,只要看函数开头的switch(pt-﹥lc)  进行散转,就一清二楚了。
因此说protothread是协程,实际很不准确,  准确地说法是:   protothread 就是状态机!

protothread使用行号代替人为设置的状态,如果使用1个Byte记忆状态,那么一个任务函数内代码行数不能超过255行,所以用了1个word来记忆.因此占用了两个字节.一个任务函数内代码行数不超过65535行(这完全够了).

这就是一个protothread任务消耗2个字节的原因: 就是状态变量的消耗. 只要使用状态机机制,谁能省掉这个呢?

protothread具备状态机的所有特性, 只要能使用状态机的地方,就可以使用protothread. 即可以单独使用,也可以结合其他多任务系统机制使用,也可以和时间调度触发联合使用

而protothread主要好处是: protothread任务函数的代码语法,无需人工设计各个状态, 非常类似于多线程环境下的任务代码,大大降低了代码的复杂度.


附带说下:

很多地方有说到protothread的,总提到protothread是协程,好像有很多问题,
但protothread根本不是协程,而是典型的状态机!

状态机的实时性本身不是问题,问题在于如何使用状态机这种机制
因此,protothread的实时性本身也根本不是问题,问题在于如何使用protothread

出0入0汤圆

发表于 2012-5-30 00:13:14 | 显示全部楼层
本帖最后由 BXAK 于 2012-5-30 00:15 编辑

看了LZ发了不少关于protothread的帖子,
还是一知半解的,要是提供个简单的程序实验就好了,
平时写程序也是用状态机原理,只是没有规范,
想看看按protothread写法会是怎样的,不知LZ是否可提供完整的简单实例(比如控制3个LED分别0.5s、1s、2s闪烁,最好是51的),有现成的完整简单实例直接上传也好

出0入0汤圆

发表于 2012-9-7 16:43:27 | 显示全部楼层
very interesting !!!

出0入0汤圆

发表于 2012-9-7 17:46:28 | 显示全部楼层
BXAK 发表于 2012-5-30 00:13
看了LZ发了不少关于protothread的帖子,
还是一知半解的,要是提供个简单的程序实验就好了,
平时写程序也 ...

传一个例子哦 不过是 VC++的 控制台程序。javascript:;


附件没法上传 就贴个 代码吧

#include <stdio.h>
#include <windows.h>
#include "pt.h"

static struct pt pt_h,pt_m,pt_s;

static int ihour=0,iminute=0,isecond=0;

static int c_s=0,c_m=0;

static int clk=0;


PT_THREAD(hour(struct pt *pt))
{
        PT_BEGIN(pt);
        PT_WAIT_UNTIL(pt,c_m==1);
        c_m=0;
        if(ihour==23)
                ihour=0;
        else
                ihour++;
        PT_END(pt);
}


PT_THREAD(minute(struct pt *pt))
{
        PT_BEGIN(pt);
        PT_WAIT_UNTIL(pt,c_s==1);
        c_s=0;
        if(iminute==59){
                iminute=0;
                c_m = 1;
        }
        else
                iminute++;
        PT_END(pt);
}


PT_THREAD(second(struct pt *pt))
{
        PT_BEGIN(pt);
        PT_WAIT_UNTIL(pt,clk==1);
        clk=0;
        if(isecond==59)
        {
                isecond=0;
                c_s=1;
        }
        else
                isecond++;
        PT_END(pt);
}

int main(void)
{
        printf("%d\n",__LINE__);
        printf("%d\n",__LINE__);
        printf("hello.pt\n");
       
        PT_INIT(&pt_h);
        PT_INIT(&pt_m);
        PT_INIT(&pt_s);
        while(1)
        {
                PT_SCHEDULE(hour(&pt_h));
                PT_SCHEDULE(second(&pt_s));
                PT_SCHEDULE(minute(&pt_m));
               
                Sleep(1000);
                clk=1;
                Sysclr();
               
                printf("Time---%d:%d:%d\n",ihour,iminute,isecond);
        }
        return 0;
}

出0入4汤圆

发表于 2012-12-12 12:01:45 | 显示全部楼层
楼主有protothread源码没,传一个

出0入0汤圆

发表于 2012-12-12 12:11:51 | 显示全部楼层
http://dunkels.com/adam/pt/download.html

出0入0汤圆

发表于 2012-12-12 12:12:29 | 显示全部楼层
源码是开源的,可网上搜。

出0入0汤圆

 楼主| 发表于 2012-12-13 12:07:29 | 显示全部楼层
本帖最后由 smset 于 2012-12-13 12:24 编辑

我已经基于这种原理,写了一个非常节省资源的调度器,已经无需pt源码了,参看另一个帖子:
http://www.amobbs.com/thread-5508723-6-1.html

  1. /**********************************************************/
  2. #include "STC89C51.h"

  3. /****小小调度器开始**********************************************/
  4. #define MAXTASKS 3
  5. unsigned char currid;
  6. unsigned char timers[MAXTASKS];
  7. #define _SS   static unsigned char lc=0; switch(lc){   case 0:
  8. #define _EE   ;}; lc=0;
  9. #define WaitX(tickets) {lc=__LINE__; timers[currid]=tickets;} return ; case __LINE__:
  10. #define RunTask(TaskName,TaskID) {currid=TaskID; if (timers[TaskID]==0){timers[TaskID]=255; TaskName();}}
  11. #define CallSub(SubTaskName)   WaitX(0); SubTaskName(); if (timers[currid]!=255) return;
  12. /*****小小调度器结束*******************************************************/

  13. sbit LED1 = P2^1;
  14. sbit LED2 = P2^2;

  15. void InitT0()
  16. {
  17.         TMOD = 0x21;
  18.         IE |= 0x82;  // 12t
  19.         TL0=0Xff;
  20.         TH0=0XDB;//22M---b7;
  21.         TR0 = 1;
  22. }

  23. void INTT0(void) interrupt 1 using 1
  24. {
  25.     unsigned char i;
  26.         TL0=0Xff;    //10ms 重装
  27.         TH0=0XDB;//b7;

  28.     for (i=0;i<MAXTASKS;i++){
  29.      if ((timers[i]!=0)&&(timers[i]!=255)) {
  30.            timers[i]--;
  31.          }
  32.     }        
  33. }


  34. void  task1(){
  35. _SS
  36.   while(1){
  37.    WaitX(50);
  38.    LED1=!LED1;   
  39.   }
  40. _EE
  41. }

  42. void  task2(){
  43. _SS
  44.   while(1){
  45.    WaitX(100);
  46.    LED2=!LED2;   
  47.   }
  48. _EE
  49. }


  50. void main()
  51. {
  52.         InitT0();
  53.         while(1){
  54.            RunTask(task1,1);
  55.            RunTask(task2,2);
  56.     }
  57. }
复制代码

出0入0汤圆

发表于 2012-12-13 12:34:17 | 显示全部楼层
谢谢楼主分享

出0入0汤圆

发表于 2012-12-13 12:39:50 | 显示全部楼层
状态机是广泛的,协程是具体的,可以说任何程序都有状态机的思想和用法。

PT主要是模拟操作系统的编程方式

出0入0汤圆

发表于 2012-12-13 16:24:50 | 显示全部楼层
看看,有用   

出0入0汤圆

发表于 2013-4-13 19:41:00 | 显示全部楼层
学习学习。。。。。

出0入0汤圆

发表于 2013-5-7 16:36:31 | 显示全部楼层
protothread 状态机

出0入0汤圆

发表于 2013-9-16 12:31:41 | 显示全部楼层
MARK
MARK
MARK

出0入0汤圆

发表于 2013-9-16 17:41:14 | 显示全部楼层
学习一下..

出0入0汤圆

发表于 2013-9-18 17:25:54 | 显示全部楼层
好像为了做到高响应速度必须在长的任务里面多插入几个点?

出0入0汤圆

发表于 2014-3-27 20:26:05 | 显示全部楼层
有点晕...

出0入0汤圆

发表于 2014-7-6 23:20:42 | 显示全部楼层
多谢楼主分享!

出0入0汤圆

发表于 2014-9-12 13:23:52 | 显示全部楼层
学习了,谢谢楼主

出0入0汤圆

发表于 2014-9-30 12:04:53 | 显示全部楼层
斯郭依               

出0入0汤圆

发表于 2014-9-30 12:26:48 | 显示全部楼层
喜欢楼主的小小调度器

出0入0汤圆

发表于 2014-10-15 07:14:45 | 显示全部楼层
学习了,谢谢楼主

出0入0汤圆

发表于 2014-10-15 08:18:55 | 显示全部楼层
了解一下。

出0入0汤圆

发表于 2014-10-17 19:49:05 来自手机 | 显示全部楼层
对状态机还是蛮感兴趣的,我也在研究这些。

出0入0汤圆

发表于 2015-1-15 09:52:47 | 显示全部楼层
lc的数据类型用u8可能出问题(如果程序函数太多),最好是用u32

出0入0汤圆

发表于 2016-2-9 15:12:11 | 显示全部楼层
路过,支持一下

出0入228汤圆

发表于 2016-2-10 12:20:47 | 显示全部楼层
看看这篇文章吧:
http://www.kankanews.com/ICkengine/archives/107079.shtml

原理到实现,一步一步

出0入0汤圆

发表于 2016-12-14 17:29:44 | 显示全部楼层
探讨一个问题:
关于楼主位: “protothread使用行号代替人为设置的状态,如果使用1个Byte记忆状态,那么一个任务函数内代码行数不能超过255行,” 这句话
楼主的理解可能有问题,行号对应的是每一个任务 case __LINE__ 这行 ,也就是 WaitX 对应的行号,而不是任务里函数内代码的行号,1byte 表示最多255个任务,而不是“一个任务函数内代码行数不能超过255行”,其实任务函数内代码函数行数并不受限制,因为任务函数内的代码是在 case __LINE__: 运行,其实是switch的一个分支

出0入0汤圆

发表于 2017-1-17 14:50:01 | 显示全部楼层
反正我用着感觉不错

出0入0汤圆

发表于 2017-6-22 16:22:03 | 显示全部楼层
学习下。谢谢!

出0入0汤圆

发表于 2020-8-21 20:30:57 | 显示全部楼层
学习学习。。。。。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-19 08:09

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表