smset 发表于 2012-5-27 10:43:29

protothread, 就是状态机!

本帖最后由 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

BXAK 发表于 2012-5-30 00:13:14

本帖最后由 BXAK 于 2012-5-30 00:15 编辑

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

hclin 发表于 2012-9-7 16:43:27

very interesting !!!

richards 发表于 2012-9-7 17:46:28

BXAK 发表于 2012-5-30 00:13 static/image/common/back.gif
看了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;
}

475627406 发表于 2012-12-12 12:01:45

楼主有protothread源码没,传一个

cheungman 发表于 2012-12-12 12:11:51

http://dunkels.com/adam/pt/download.html

yzhu 发表于 2012-12-12 12:12:29

源码是开源的,可网上搜。

smset 发表于 2012-12-13 12:07:29

本帖最后由 smset 于 2012-12-13 12:24 编辑

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

/****小小调度器开始**********************************************/
#define MAXTASKS 3
unsigned char currid;
unsigned char timers;
#define _SS   static unsigned char lc=0; switch(lc){   case 0:
#define _EE   ;}; lc=0;
#define WaitX(tickets) {lc=__LINE__; timers=tickets;} return ; case __LINE__:
#define RunTask(TaskName,TaskID) {currid=TaskID; if (timers==0){timers=255; TaskName();}}
#define CallSub(SubTaskName)   WaitX(0); SubTaskName(); if (timers!=255) return;
/*****小小调度器结束*******************************************************/

sbit LED1 = P2^1;
sbit LED2 = P2^2;

void InitT0()
{
      TMOD = 0x21;
      IE |= 0x82;// 12t
      TL0=0Xff;
      TH0=0XDB;//22M---b7;
      TR0 = 1;
}

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

    for (i=0;i<MAXTASKS;i++){
   if ((timers!=0)&&(timers!=255)) {
         timers--;
         }
    }      
}


voidtask1(){
_SS
while(1){
   WaitX(50);
   LED1=!LED1;   
}
_EE
}

voidtask2(){
_SS
while(1){
   WaitX(100);
   LED2=!LED2;   
}
_EE
}


void main()
{
      InitT0();
      while(1){
         RunTask(task1,1);
         RunTask(task2,2);
    }
}

hygs 发表于 2012-12-13 12:34:17

谢谢楼主分享

trey21ic 发表于 2012-12-13 12:39:50

状态机是广泛的,协程是具体的,可以说任何程序都有状态机的思想和用法。

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

jinjin_xia 发表于 2012-12-13 16:24:50

看看,有用   

jz701209李 发表于 2013-4-13 19:41:00

学习学习。。。。。

yoofe 发表于 2013-5-7 16:36:31

protothread 状态机

sgweilong 发表于 2013-9-16 12:31:41

MARK
MARK
MARK

szmini2006 发表于 2013-9-16 17:41:14

学习一下..

wx85105157 发表于 2013-9-18 17:25:54

好像为了做到高响应速度必须在长的任务里面多插入几个点?

crazydtone 发表于 2014-3-27 20:26:05

有点晕...

first393 发表于 2014-7-6 23:20:42

多谢楼主分享!

NEXEN1106 发表于 2014-9-12 13:23:52

学习了,谢谢楼主

cqsgcqsg 发表于 2014-9-30 12:04:53

斯郭依               

lovecxm 发表于 2014-9-30 12:26:48

喜欢楼主的小小调度器

fraser 发表于 2014-10-15 07:14:45

学习了,谢谢楼主

swp 发表于 2014-10-15 08:18:55

了解一下。

AbnerSmith 发表于 2014-10-17 19:49:05

对状态机还是蛮感兴趣的,我也在研究这些。

liupeng08305 发表于 2015-1-15 09:52:47

lc的数据类型用u8可能出问题(如果程序函数太多),最好是用u32

siquche 发表于 2016-2-9 15:12:11

路过,支持一下{:hug:}

wxws 发表于 2016-2-10 12:20:47

看看这篇文章吧:
http://www.kankanews.com/ICkengine/archives/107079.shtml

原理到实现,一步一步

changer15309 发表于 2016-12-14 17:29:44

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

s1j2h3 发表于 2017-1-17 14:50:01

反正我用着感觉不错

yangzhong316 发表于 2017-6-22 16:22:03

学习下。谢谢!

chun_hua82 发表于 2020-8-21 20:30:57

学习学习。。。。。
页: [1]
查看完整版本: protothread, 就是状态机!