OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 12620|回复: 39

分享一个状态机实现类操作系统延时风格的算法

[复制链接]

27

主题

711

帖子

0

精华

版主

Rank: 7Rank: 7Rank: 7

积分
12410
金钱
12410
注册时间
2015-11-5
在线时间
2134 小时
发表于 2016-11-22 00:03:00 | 显示全部楼层 |阅读模式
本帖最后由 FreeRTOS 于 2016-11-22 00:05 编辑

今天看到论坛里的一个求助帖子:
http://www.openedv.com/forum.php ... 39&page=1#pid505654
让我想起了之前一直想仿照contiki来解决传统状态机碰到多个延时不好处理的情况,今天恰好有心情说干就干!
相关资料请查阅contiki源码,本测试程序完全仿照contiki的算法实现,不过是简化版的,大神勿喷
关于状态机的基础知识我这里就不作详细讲解了,好了直接上源码:
[mw_shl_code=applescript,true]#define LINE_NUM_GET(num)   num = __LINE__; case __LINE__:
#define PROCESS_BEGIN(s)    switch(s) { case 0:
#define PROCESS_END()       }

/* 任务结构体 */
typedef struct _TaskStruct
{
    void (*TaskHook)(void);     // 要运行的任务函数
    uint32_t Counter;           // 任务全局节拍
    uint16_t LineNum;           // 行号
    uint8_t Run;                // 程序运行标记:0-不运行,1运行
} TaskStruct;

TaskStruct Tasks[3];


#define PROCESS_DELAY(task, n)      do                                              \
                                    {                                               \
                                        task.Counter = GlobalTimerCnt;              \
                                        LINE_NUM_GET(task.LineNum);                 \
                                        if( (GlobalTimerCnt - task.Counter) > n )   \
                                        {                                           \
                                            break;                                  \
                                        }                                           \
                                        return;                                     \
                                    } while(0)[/mw_shl_code]
如果对contiki没了解过的话,看起来会有些吃力,这里我大概说明下。
在每个任务的开头与结尾必须是 PROCESS_BEGIN(s)和PROCESS_END(),至于这两个宏是什么等下再解释
然后就是仿照我们平时使用OS时最常用方式:在while(1)里完成对应的任务
好了,接下来就是最关键的部分PROCESS_DELAY(task, n),这部分代码就是以状态机来实现类操作系统延时!
说太多口水都干了,直接贴几个任务看看使用方法,使用非常简单:
[mw_shl_code=applescript,true]/**********************************************/
/*                                            */
/*                  任务1                     */
/*                                            */
/**********************************************/
void test_process1(void)
{
    PROCESS_BEGIN(Tasks[0].LineNum);
   
    while (1)
    {
        PROCESS_DELAY(Tasks[0], 1000);
        Uart1SendString("rocess1 Delay1 Test!\r\n");
        
        PROCESS_DELAY(Tasks[0], 2000);
        Uart1SendString("rocess1 Delay2 Test!\r\n");
        
        PROCESS_DELAY(Tasks[0], 1500);
        Uart1SendString("rocess1 Delay3 Test!\r\n");
    }
   
    PROCESS_END();
}


/**********************************************/
/*                                            */
/*                  任务2                     */
/*                                            */
/**********************************************/
void test_process2(void)
{
    PROCESS_BEGIN(Tasks[1].LineNum);
   
    while (1)
    {
        PROCESS_DELAY(Tasks[1], 700);
        Uart1SendString("rocess2 Delay1 Test!\r\n");
        
        PROCESS_DELAY(Tasks[1], 1500);
        Uart1SendString("rocess2 Delay2 Test!\r\n");
    }
   
    PROCESS_END();
}


/**********************************************/
/*                                            */
/*                  任务3                     */
/*                                            */
/**********************************************/
void test_process3(void)
{
    PROCESS_BEGIN(Tasks[2].LineNum);
   
    while (1)
    {
        PROCESS_DELAY(Tasks[2], 500);
        Led_Toggle(LED1);
    }
   
    PROCESS_END();
}[/mw_shl_code]
任务1与任务2是串口每隔一段时间打印出测试字符串,任务3是小灯最喜欢的跑灯任务,没有之一!!!

下面就是创建任务,主要是对结构体成员LineNum清零(必须)和设置任务回调函数:
[mw_shl_code=applescript,true]/* 任务初始化 */
    memset((void*)Tasks, 0, sizeof(Tasks));
    Tasks[0].TaskHook = test_process1;
    Tasks[1].TaskHook = test_process2;
    Tasks[2].TaskHook = test_process3;[/mw_shl_code]

好了接下来看执行,执行跟状态机一样,就是各个任务对应的函数轮着来,值得注意的是并没有任务在原地死等,所有任务都以查询的方式进入和退出!!!
[mw_shl_code=applescript,true]while(1)
    {
        /* 任务执行,本质还是状态机,但类似操作系统风格 */
        for(i=0; i<3; i++)
        {
            Tasks.TaskHook();
        }
    }[/mw_shl_code]

到这里就完成了以状态机的方式来实现类操作系统风格的延时!可能各位对代码一时摸不着头脑,我大概说下算法的思想。
把宏PROCESS_BEGIN()与PROCESS_END()展开可以发现其实就是一个switch结构,任务里面的延时调用了PROCESS_DELAY()之后
会把行号记录在任务结构成员LineNum,而算法的精髓也是在于这里,每次调用任务的回调函数时switch结构会跳转到记录行号的位置
然后查询任务结构体成员Counter的值是否已达到延时的节拍,如果还没延时完毕就直接return,任务不需要在原地死等。由于所有任务共用一个堆栈,因此任务中不能出现临时变量,如果实在需要使用变量,那么就遵从contiki的建议使用静态变量,
个人不建议使用全局变量,没别的原因,主要是看起来太TM烦!

算法的大概思想就是这样,小灯近段时间烦心事太多了,所以没有来得及检查代码,只是粗略测试了好像没问题,希望各位大神
能帮忙检查下然后把问题报告给我,我会第一时间修改!

小灯采用阿波罗STM32F7开发板做的测试,如果你们手头上的板子不是的话,要么光顾下原子网店,否则就自行修改下吧。
Process_Delay.rar (1.08 MB, 下载次数: 1487)
拿来长岛冰茶换我半晚安睡
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

17

主题

344

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1280
金钱
1280
注册时间
2013-12-14
在线时间
567 小时
发表于 2016-11-22 12:49:25 | 显示全部楼层
FreeRTOS 发表于 2016-11-22 12:07
switch case是否容易出错我没研究过,求科普

简单来说就是内层的switch会屏蔽掉外层的case: __LINE__这个功能。
半导体->模拟电路->数字电路->单片机->汇编->C->操作系统->java
回复 支持 0 反对 1

使用道具 举报

21

主题

109

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
321
金钱
321
注册时间
2015-3-28
在线时间
64 小时
发表于 2016-11-22 08:14:31 | 显示全部楼层
这个跟“小小调度器”的那个差不多……不找这些东西还真不知道有内置宏__LINE__
回复 支持 反对

使用道具 举报

9

主题

538

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3371
金钱
3371
注册时间
2015-1-7
在线时间
794 小时
发表于 2016-11-22 09:17:27 | 显示全部楼层
赞一个!
我也写了一个实现类似的延时,欢迎大神前来指导工作 https://github.com/ianhom/MOE/bl ... Demo/Task_PT_Demo.c  
[mw_shl_code=c,true]
    while(1)
    {
        TASK_PT_DEMO_LED_On(LED_RED);
        PT_DELAY(1000);
        TASK_PT_DEMO_LED_Off(LED_RED);

        TASK_PT_DEMO_LED_On(LED_GREEN);
        PT_DELAY(1000);
        TASK_PT_DEMO_LED_Off(LED_GREEN);

        TASK_PT_DEMO_LED_On(LED_BLUE);
        PT_DELAY(1000);
        TASK_PT_DEMO_LED_Off(LED_BLUE);
}[/mw_shl_code]
机器生汇编,汇编生B,B生C,C生万物.... 经过长期对C语言的研究,目前只有两个方面不懂:这也不懂,那也不懂
https://github.com/ianhom
回复 支持 反对

使用道具 举报

17

主题

344

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1280
金钱
1280
注册时间
2013-12-14
在线时间
567 小时
发表于 2016-11-22 09:20:14 | 显示全部楼层
小小速 发表于 2016-11-22 08:14
这个跟“小小调度器”的那个差不多……不找这些东西还真不知道有内置宏__LINE__

阿mo上的那个小小调度器其实就是仿照CONTIKI的调度机制PT协程来写的,这种方式看起来很巧妙,但是不知道实际用到工程上会发生什么。

看了你另一个帖子的问题,如果延时小于系统的节拍,这个确实没法弄,这个时候估计也只能减小系统节拍,然后把I2C通讯的长任务自己用状态机的思想分割。

我也刚开始研究状态机,非阻塞相关的东西,以后可以多多交流啊。
半导体->模拟电路->数字电路->单片机->汇编->C->操作系统->java
回复 支持 反对

使用道具 举报

17

主题

344

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1280
金钱
1280
注册时间
2013-12-14
在线时间
567 小时
发表于 2016-11-22 09:25:17 | 显示全部楼层
ianhom 发表于 2016-11-22 09:17
赞一个!
我也写了一个实现类似的延时,欢迎大神前来指导工作 https://github.com/ianhom/MOE/blob/master ...

请教一下大神,感觉PT协程是一种很取巧的实现多任务的方式,本质上还是状态机,只不过是用C语言的行号来记录他的状态,我看21ic的simon大神的vsf架构也是采用这种PT协程的方式来实现非阻塞编程的。

有没有更好的,在裸机环境实现非阻塞编程的方法呢,用状态机的话,经常要将一个长任务打散,分成好几个小任务,感觉很混乱,也不好理解,划分时间片也非常累。
半导体->模拟电路->数字电路->单片机->汇编->C->操作系统->java
回复 支持 反对

使用道具 举报

22

主题

751

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1605
金钱
1605
注册时间
2015-6-10
在线时间
222 小时
发表于 2016-11-22 09:34:18 | 显示全部楼层
最早看到是在蝇量级协程的文章

最大的问题就是在里面嵌套Switch case容易出错
回复 支持 反对

使用道具 举报

21

主题

109

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
321
金钱
321
注册时间
2015-3-28
在线时间
64 小时
发表于 2016-11-22 09:47:14 | 显示全部楼层
东北小辉辉 发表于 2016-11-22 09:20
阿mo上的那个小小调度器其实就是仿照CONTIKI的调度机制PT协程来写的,这种方式看起来很巧妙,但是不知道 ...

我才看了一天,是个十足的新人,脑子里还有很多问题
回复 支持 反对

使用道具 举报

20

主题

158

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
334
金钱
334
注册时间
2012-8-21
在线时间
27 小时
发表于 2016-11-22 11:20:48 | 显示全部楼层
对于这个我使用的是用定时器来表述,主要是去维护一个数组
具体如下,
timer_core_create 创建定时器,
void  timer_list_link(p_fun backcall,u32 max,u8 auto_stop,u8 mutual_main_ui);创建一个定时事件,
主要参数如下,
第一个是回调函数,
第二个说明最大的计数周期,
第三个说明该注册的函数是只执行一次还是周期性定时
第四个说明该事件所互斥的事件,
回复 支持 反对

使用道具 举报

20

主题

158

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
334
金钱
334
注册时间
2012-8-21
在线时间
27 小时
发表于 2016-11-22 11:22:49 | 显示全部楼层
原理很简单,就是维护一个定时器,定时事件组,有互斥类型的,也有周期运行的,
更新和维护这个定时器事件组,则可以将
task_timer_list_running
放入主循环或者直接放入TICK中断函数执行,至于具体放在哪里,则要看这个事件组里面,执行时间最长的事件所需要花费的时间,
回复 支持 反对

使用道具 举报

20

主题

158

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
334
金钱
334
注册时间
2012-8-21
在线时间
27 小时
发表于 2016-11-22 11:27:53 | 显示全部楼层
另外对于楼主说的这个方法,有这个缺陷,如果在DELAY之前执行的动作时间过长的话,则会影响整个系统的反应速度,如下面代码
void test_process1(void)
{
    PROCESS_BEGIN(Tasks[0].LineNum);
   
    while (1)
    {
       code1...
       delay(x);
      code2...
      delay(y);
    }
   
    PROCESS_END();
}
如此调度会导致在延时前面的某写代码,和某个动作会反复得到执行的机会,大大降低反应速度
回复 支持 反对

使用道具 举报

27

主题

711

帖子

0

精华

版主

Rank: 7Rank: 7Rank: 7

积分
12410
金钱
12410
注册时间
2015-11-5
在线时间
2134 小时
 楼主| 发表于 2016-11-22 12:05:27 | 显示全部楼层
ianhom 发表于 2016-11-22 09:17
赞一个!
我也写了一个实现类似的延时,欢迎大神前来指导工作 https://github.com/ianhom/MOE/blob/master ...

见笑了,指导不敢,交流下还是可以的
拿来长岛冰茶换我半晚安睡
回复 支持 反对

使用道具 举报

27

主题

711

帖子

0

精华

版主

Rank: 7Rank: 7Rank: 7

积分
12410
金钱
12410
注册时间
2015-11-5
在线时间
2134 小时
 楼主| 发表于 2016-11-22 12:07:23 | 显示全部楼层
止天 发表于 2016-11-22 09:34
最早看到是在蝇量级协程的文章

最大的问题就是在里面嵌套Switch case容易出错

switch case是否容易出错我没研究过,求科普
拿来长岛冰茶换我半晚安睡
回复 支持 反对

使用道具 举报

27

主题

711

帖子

0

精华

版主

Rank: 7Rank: 7Rank: 7

积分
12410
金钱
12410
注册时间
2015-11-5
在线时间
2134 小时
 楼主| 发表于 2016-11-22 12:09:52 | 显示全部楼层
lxj19901115 发表于 2016-11-22 11:27
另外对于楼主说的这个方法,有这个缺陷,如果在DELAY之前执行的动作时间过长的话,则会影响整个系统的反应 ...

如果delay之前的代码耗时过长的话,这个哪怕上OS一样解决不了啊,毕竟耗时的代码就在那里,理论上是不可能降低的,除非你改进这部分代码的耗时
拿来长岛冰茶换我半晚安睡
回复 支持 反对

使用道具 举报

27

主题

711

帖子

0

精华

版主

Rank: 7Rank: 7Rank: 7

积分
12410
金钱
12410
注册时间
2015-11-5
在线时间
2134 小时
 楼主| 发表于 2016-11-22 12:15:19 | 显示全部楼层
lxj19901115 发表于 2016-11-22 11:20
对于这个我使用的是用定时器来表述,主要是去维护一个数组
具体如下,
timer_core_create 创建定时器,

你这个结构很像OS里面的软件定时器,也是可以解决我提出的问题,而且比我的做法安全得多,不过还是很难跳出一大堆状态转换的困境啊
拿来长岛冰茶换我半晚安睡
回复 支持 反对

使用道具 举报

17

主题

344

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1280
金钱
1280
注册时间
2013-12-14
在线时间
567 小时
发表于 2016-11-22 12:45:29 | 显示全部楼层
FreeRTOS 发表于 2016-11-22 12:07
switch case是否容易出错我没研究过,求科普

记得使用PT协程这种方式的时候,任务中是禁止使用switch case的,如果需要用到switch的功能,只能用if else来替代,否则,内层的switch会caseC语言的行号,导致外层的switch失效。
半导体->模拟电路->数字电路->单片机->汇编->C->操作系统->java
回复 支持 反对

使用道具 举报

27

主题

711

帖子

0

精华

版主

Rank: 7Rank: 7Rank: 7

积分
12410
金钱
12410
注册时间
2015-11-5
在线时间
2134 小时
 楼主| 发表于 2016-11-22 13:18:05 | 显示全部楼层
东北小辉辉 发表于 2016-11-22 12:49
简单来说就是内层的switch会屏蔽掉外层的case: __LINE__这个功能。

我的代码只提供了一个delay功能,里面不可能再嵌套一个delay的,理论上不会出现你说的两个
case: __LINE__嵌套的情况吧
拿来长岛冰茶换我半晚安睡
回复 支持 反对

使用道具 举报

17

主题

344

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1280
金钱
1280
注册时间
2013-12-14
在线时间
567 小时
发表于 2016-11-22 16:04:12 | 显示全部楼层
FreeRTOS 发表于 2016-11-22 13:18
我的代码只提供了一个delay功能,里面不可能再嵌套一个delay的,理论上不会出现你说的两个
case: __LINE ...

应该是会有影响的,我现在在上班,晚上想一个例子。
半导体->模拟电路->数字电路->单片机->汇编->C->操作系统->java
回复 支持 反对

使用道具 举报

20

主题

158

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
334
金钱
334
注册时间
2012-8-21
在线时间
27 小时
发表于 2016-11-22 16:24:30 | 显示全部楼层
FreeRTOS 发表于 2016-11-22 12:15
你这个结构很像OS里面的软件定时器,也是可以解决我提出的问题,而且比我的做法安全得多,不过还是很难跳 ...

你说的这个,去看看DJYOS,事件驱动完美解决,
回复 支持 反对

使用道具 举报

17

主题

344

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1280
金钱
1280
注册时间
2013-12-14
在线时间
567 小时
发表于 2016-11-22 18:11:56 | 显示全部楼层
本帖最后由 东北小辉辉 于 2016-11-22 18:15 编辑
FreeRTOS 发表于 2016-11-22 13:18
我的代码只提供了一个delay功能,里面不可能再嵌套一个delay的,理论上不会出现你说的两个
case: __LINE ...

刚才说的有点问题,举个例子,就比如test_process1,如果在这个位置使用switch的话,就会出现问题。
void test_process1(void)
{
    PROCESS_BEGIN(Tasks[0].LineNum);
     
    while (1)
    {
        switch(var)                              {
           case 1:
           {
              PROCESS_DELAY(Tasks[0], 1000);
              Uart1SendString("Process1 Delay1 Test!\r\n");
              break;
           }
         
           case 2:
           {
              PROCESS_DELAY(Tasks[0], 2000);
              Uart1SendString("Process1 Delay2 Test!\r\n");
              break;
           }
         
           case 3:
           {
              PROCESS_DELAY(Tasks[0], 1500);
              Uart1SendString("Process1 Delay3 Test!\r\n");
              break;
           }

           default:
        }
    }
     
    PROCESS_END();
}
这个例子可能不恰当,但是可以看到,这样的话,case __LINE__:响应的就不是最外层的switch了,程序就会出问题,这个时候就需要用if else来代替switch。

排版真累,编辑好了怎么变这样了?楼主凑合看一下。
半导体->模拟电路->数字电路->单片机->汇编->C->操作系统->java
回复 支持 反对

使用道具 举报

27

主题

711

帖子

0

精华

版主

Rank: 7Rank: 7Rank: 7

积分
12410
金钱
12410
注册时间
2015-11-5
在线时间
2134 小时
 楼主| 发表于 2016-11-22 21:04:08 | 显示全部楼层
本帖最后由 FreeRTOS 于 2016-11-23 01:10 编辑
东北小辉辉 发表于 2016-11-22 18:11
刚才说的有点问题,举个例子,就比如test_process1,如果在这个位置使用switch的话,就会出现问题。
voi ...

研究了下,确实是有这个问题,因为PROCESS_BEGIN(Tasks[0].LineNum);其实就是一级switch,目标是跳到PROCESS_DELAY里面的case __LINE__:
如果把PROCESS_DELAY放在二级switch嵌套里面:
[mw_shl_code=applescript,true]while (1)
{
    switch(var)
    {
       case 1:
       {
          PROCESS_DELAY(Tasks[0], 1000);
          Uart1SendString("Process1 Delay1 Test!\r\n");
          break;
       }[/mw_shl_code]
那么问题就出现了,PROCESS_DELAY里面的case __LINE__: 相当于没法与一级switch对应起来,导致跳转失败



拿来长岛冰茶换我半晚安睡
回复 支持 反对

使用道具 举报

27

主题

711

帖子

0

精华

版主

Rank: 7Rank: 7Rank: 7

积分
12410
金钱
12410
注册时间
2015-11-5
在线时间
2134 小时
 楼主| 发表于 2016-11-22 21:06:54 | 显示全部楼层
lxj19901115 发表于 2016-11-22 16:24
你说的这个,去看看DJYOS,事件驱动完美解决,

这个是OS,能否撇开OS来简单阐述下原理
拿来长岛冰茶换我半晚安睡
回复 支持 反对

使用道具 举报

22

主题

147

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3982
金钱
3982
注册时间
2015-4-18
在线时间
403 小时
发表于 2016-11-23 11:24:05 | 显示全部楼层
这个不是用UCOS系统吧。。
回复 支持 反对

使用道具 举报

27

主题

711

帖子

0

精华

版主

Rank: 7Rank: 7Rank: 7

积分
12410
金钱
12410
注册时间
2015-11-5
在线时间
2134 小时
 楼主| 发表于 2016-11-23 17:48:10 | 显示全部楼层
752151619 发表于 2016-11-23 11:24
这个不是用UCOS系统吧。。

不是系统,这是裸机
拿来长岛冰茶换我半晚安睡
回复 支持 反对

使用道具 举报

10

主题

271

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1236
金钱
1236
注册时间
2015-5-14
在线时间
352 小时
发表于 2016-11-30 11:46:49 | 显示全部楼层
大神出品,必是精品,顶顶。。。。。。。。。。
30年众生牛马,60年诸佛龙象!
回复 支持 反对

使用道具 举报

22

主题

147

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3982
金钱
3982
注册时间
2015-4-18
在线时间
403 小时
发表于 2017-4-14 19:15:26 | 显示全部楼层
F103的能用这代码吗。。。
回复 支持 反对

使用道具 举报

62

主题

903

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3565
金钱
3565
注册时间
2016-1-8
在线时间
543 小时
发表于 2017-5-9 15:10:38 | 显示全部楼层
[mw_shl_code=applescript,true]void test_process1(void)
{
    //PROCESS_BEGIN(Tasks[0].LineNum);
  switch(Tasks[0].LineNum)
        { case 0:
                        while (1)
                        {
         //       PROCESS_DELAY(Tasks[0], 1000);
                                do                                             
                                {                                             
                                                Tasks[0].Counter = GlobalTimerCnt;            
                                                LINE_NUM_GET(Tasks[0].LineNum);               
                                                if( (GlobalTimerCnt - Tasks[0].Counter) > 1000 )  
                                                {                                          
                                                                break;                                 
                                                }                                          
                                                return;                                    
                                } while(0);
                                        Uart1SendString("Process1 Delay1 Test!\r\n");
                                       
//                                        PROCESS_DELAY(Tasks[0], 2000);
                                do                                             
                                {                                             
                                                Tasks[0].Counter = GlobalTimerCnt;            
                                                LINE_NUM_GET(Tasks[0].LineNum);               
                                                if( (GlobalTimerCnt - Tasks[0].Counter) > 2000 )  
                                                {                                          
                                                                break;                                 
                                                }                                          
                                                return;                                    
                                } while(0);
                                        Uart1SendString("Process1 Delay2 Test!\r\n");
                                       
//                                        PROCESS_DELAY(Tasks[0], 1500);
                                do                                             
                                {                                             
                                                Tasks[0].Counter = GlobalTimerCnt;            
                                                LINE_NUM_GET(Tasks[0].LineNum);               
                                                if( (GlobalTimerCnt - Tasks[0].Counter) > 1500 )  
                                                {                                          
                                                                break;                                 
                                                }                                          
                                                return;                                    
                                } while(0);
                                        Uart1SendString("Process1 Delay3 Test!\r\n");
                        }
        }
//    PROCESS_END();
}
[/mw_shl_code]


楼主你看以下  我把你的define换成代码中
不太明白case 0 怎么能进入下面的语句
回复 支持 反对

使用道具 举报

62

主题

903

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3565
金钱
3565
注册时间
2016-1-8
在线时间
543 小时
发表于 2017-5-9 15:11:28 | 显示全部楼层
[mw_shl_code=c,true]void test_process1(void)
{
    //PROCESS_BEGIN(Tasks[0].LineNum);
  switch(Tasks[0].LineNum)
        { case 0:
                        while (1)
                        {
         //       PROCESS_DELAY(Tasks[0], 1000);
                                do                                             
                                {                                             
                                                Tasks[0].Counter = GlobalTimerCnt;            
                                                LINE_NUM_GET(Tasks[0].LineNum);               
                                                if( (GlobalTimerCnt - Tasks[0].Counter) > 1000 )  
                                                {                                          
                                                                break;                                 
                                                }                                          
                                                return;                                    
                                } while(0);
                                        Uart1SendString("Process1 Delay1 Test!\r\n");
                                       
//                                        PROCESS_DELAY(Tasks[0], 2000);
                                do                                             
                                {                                             
                                                Tasks[0].Counter = GlobalTimerCnt;            
                                                LINE_NUM_GET(Tasks[0].LineNum);               
                                                if( (GlobalTimerCnt - Tasks[0].Counter) > 2000 )  
                                                {                                          
                                                                break;                                 
                                                }                                          
                                                return;                                    
                                } while(0);
                                        Uart1SendString("Process1 Delay2 Test!\r\n");
                                       
//                                        PROCESS_DELAY(Tasks[0], 1500);
                                do                                             
                                {                                             
                                                Tasks[0].Counter = GlobalTimerCnt;            
                                                LINE_NUM_GET(Tasks[0].LineNum);               
                                                if( (GlobalTimerCnt - Tasks[0].Counter) > 1500 )  
                                                {                                          
                                                                break;                                 
                                                }                                          
                                                return;                                    
                                } while(0);
                                        Uart1SendString("Process1 Delay3 Test!\r\n");
                        }
        }
//    PROCESS_END();
}
[/mw_shl_code]
回复 支持 反对

使用道具 举报

62

主题

903

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3565
金钱
3565
注册时间
2016-1-8
在线时间
543 小时
发表于 2017-5-9 15:14:12 | 显示全部楼层
[mw_shl_code=c,true]#define LINE_NUM_GET(num)   num = __LINE__; case __LINE__:
#define PROCESS_BEGIN(s)    switch(s) { case 0:
#define PROCESS_END()       }[/mw_shl_code]
回复 支持 反对

使用道具 举报

27

主题

711

帖子

0

精华

版主

Rank: 7Rank: 7Rank: 7

积分
12410
金钱
12410
注册时间
2015-11-5
在线时间
2134 小时
 楼主| 发表于 2017-5-9 15:34:48 | 显示全部楼层
Sun_Fly 发表于 2017-5-9 15:10
[mw_shl_code=applescript,true]void test_process1(void)
{
    //PROCESS_BEGIN(Tasks[0].LineNum);

Tasks[0].LineNum初始化的时候是0,所以第一次执行switch(Tasks[0].LineNum)时就绝对是0
也就是说第一次执行时一定会跳到case 0
拿来长岛冰茶换我半晚安睡
回复 支持 反对

使用道具 举报

62

主题

903

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3565
金钱
3565
注册时间
2016-1-8
在线时间
543 小时
发表于 2017-5-9 18:47:17 | 显示全部楼层
仔细看了以下  是你这写错了把
应该是这样

#define LINE_NUM_GET(num)   num = __LINE__;
#define PROCESS_BEGIN(s)    switch(s) { case __LINE__:
#define PROCESS_END()       }
回复 支持 反对

使用道具 举报

27

主题

711

帖子

0

精华

版主

Rank: 7Rank: 7Rank: 7

积分
12410
金钱
12410
注册时间
2015-11-5
在线时间
2134 小时
 楼主| 发表于 2017-5-10 10:56:28 | 显示全部楼层
Sun_Fly 发表于 2017-5-9 18:47
仔细看了以下  是你这写错了把
应该是这样

你这种先入为主的思维会对你的理解造成很大阻碍的
如果像你写的那样,那我的这套代码就没意义了,你自己琢磨下
拿来长岛冰茶换我半晚安睡
回复 支持 反对

使用道具 举报

62

主题

903

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3565
金钱
3565
注册时间
2016-1-8
在线时间
543 小时
发表于 2017-5-10 11:23:33 | 显示全部楼层
#define LINE_NUM_GET(num)   num = __LINE__; case __LINE__:

这个define 的用法我没见过,这是什么意思
回复 支持 反对

使用道具 举报

62

主题

903

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3565
金钱
3565
注册时间
2016-1-8
在线时间
543 小时
发表于 2017-5-10 11:26:08 | 显示全部楼层
你已经固定了case 0 第一次初始化LINE是0,之后呢?你永远是case0  但是LINE是变换的,对应不同的进程
回复 支持 反对

使用道具 举报

27

主题

711

帖子

0

精华

版主

Rank: 7Rank: 7Rank: 7

积分
12410
金钱
12410
注册时间
2015-11-5
在线时间
2134 小时
 楼主| 发表于 2017-5-10 12:38:24 | 显示全部楼层
Sun_Fly 发表于 2017-5-10 11:26
你已经固定了case 0 第一次初始化LINE是0,之后呢?你永远是case0  但是LINE是变换的,对应不同的进程

case 0 只是其中一个状态,OK?
我的源代码是 #define LINE_NUM_GET(num)   num = __LINE__; case __LINE__:
看清楚了,这里有一个 case __LINE__:
这里是跳转到其他状态用的,你还认为可以删掉吗?
拿来长岛冰茶换我半晚安睡
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
3
金钱
3
注册时间
2017-5-19
在线时间
0 小时
发表于 2017-5-19 11:21:29 | 显示全部楼层
楼主,内层的不能用switch case 的问题解决了没
回复 支持 反对

使用道具 举报

27

主题

711

帖子

0

精华

版主

Rank: 7Rank: 7Rank: 7

积分
12410
金钱
12410
注册时间
2015-11-5
在线时间
2134 小时
 楼主| 发表于 2017-5-19 13:58:55 | 显示全部楼层
newmen8240 发表于 2017-5-19 11:21
楼主,内层的不能用switch case 的问题解决了没

1、内层的switch不调用任何与DELAY相关的API
2、内层的switch调用的子函数不能调用任何与DELAY相关的API
目前发现满足上面2个条件就可以,说白了就是我的switch...case会破坏你自己写的switch,这个要尽量避免。
我已经写了一套protothread+链表+tickless的代码,并且已经实现了二值信号量、互斥锁的功能,怕别人侵权所以目前还不敢公布,等申请了专利再发布
拿来长岛冰茶换我半晚安睡
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
3
金钱
3
注册时间
2017-5-19
在线时间
0 小时
发表于 2017-5-19 15:13:52 | 显示全部楼层
明白,大神加油
回复 支持 反对

使用道具 举报

0

主题

47

帖子

0

精华

高级会员

Rank: 4

积分
695
金钱
695
注册时间
2019-1-26
在线时间
67 小时
发表于 2019-8-11 10:11:44 | 显示全部楼层
顶楼主!!!!!!!!!!!!!!!!!!!!!
回复 支持 反对

使用道具 举报

17

主题

170

帖子

0

精华

高级会员

Rank: 4

积分
562
金钱
562
注册时间
2018-7-8
在线时间
118 小时
发表于 2020-7-26 10:51:39 | 显示全部楼层
FreeRTOS 发表于 2017-5-19 13:58
1、内层的switch不调用任何与DELAY相关的API
2、内层的switch调用的子函数不能调用任何与DELAY相关的API ...

期待发布~~~
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-4-30 19:18

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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