单片机无操作系统 多任务 无延时架构

时间:2021-08-04 19:52:00
两年前一直在用前后台的方式编程。后来越来越不爽。觉得有些任务不能及时处理,或者代码会很乱。另外在程序中有很多delay()。在delay的时候CPU基本不做事,很浪费。

于是乎就想到多任务。第一个想到的就是ucos,但是这个东西不太适合用在资源有限的单片机上。很纠结。但是看过ucos之后对它的任务处理方式有一定的认识。然后就想得用它的理念放在单片机上。

在处理delay的时候想到让cpu跳出正在执行的任务去做其它的事情。在没有处理堆栈的时候要怎么做呢?用全局变量来保存任务的关键信息,用switch将任务分成N个小任务,任务之前用一个全局变量来联接。其实就是个状态机的思想。每遇到 一个需要等待的地方就作为一个小任务的结束。在下个小任务去判断是不是应该往下执行。

几个大的任务放在一个大循环里,一次循环下来,每个大的任务只会被执行一小段。有点想系统里面的时间片的概念了。合作式的高度器。

delay的事还没有完,要准确延时的地方要用定时器才可以。有很多个任务,硬件定器只用有限的几个,那怎么搞~?汲取了别人的经验就用了软件定时器,一个任务配一个。

如此一个多任务,无延时(长延时)的架构就出来了。 和高手们的架构有很多的差距,请高手拍砖;

软件定时器:

u16 times[ x];

硬件定时器中断()
{
      for(i = 0; i < x;i++)
     {
           if(0 != times[i] )
           {
               times[i]--;
           }
     }
}

任务分割:

void pro0(void)
{
     static u8 step = 0;  //状态机

    switch(step)
    {
         case 0:
              .........
               times[0] = 200; //延时准备
             step++;                  //状态转换
            break;                    //跳出程序

         case 1:
          if(0 != times[0])     //检测延时是否到
         {
            break;
         }                               //延时到则继续执行
           ......
          step++;                 //状态转换
          break;

             case 2:
             ............
              step = 0;            //状态复位
              break;
    }
}

void pro1(void)
{
       static u8 step = 0;

     if(0 != times[0])     //在程序头检测延时是否到
         {
            return;
         }          
      switch(step)
      {
            case 0:
             
             break;
            ......
        }
}

主函数:

void main(void)
{
           IO初始化;
            其它初始化;
            定时器初始化;
           中断初始化;
           开全局中断;

          while(1)
          {
                   pro0();
                   pro1();
                   .其它任务
            }
}

19 个解决方案

#1


和  Protothreads 类似吧

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

#2


也考虑过这个,发现任务划分不好做,后来简化了一下,改成在delay程序中执行需要及时响应的任务了。ProtoThread没看懂,不过好像lwip中有使用

#3


这样太麻烦了,既然搞任务分割,那为何不用OS?

如果不用OS,其实用不准确的定时器来实现某种任务轮循和中断是很不错的硬办法

:)

#4


在不同的硬件中用不同的架构,还要针对不同的应用

#5


UCOS对硬件的要求不高!

#6


引用 1 楼 zhxianbin 的回复:
和  Protothreads 类似吧

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


眼界不是很宽,所以未有去了解

#7


引用 3 楼 lbing7 的回复:
这样太麻烦了,既然搞任务分割,那为何不用OS?

如果不用OS,其实用不准确的定时器来实现某种任务轮循和中断是很不错的硬办法

:)


加入OS对于Flash只有几K的单片机很吃力的~

#8


引用 4 楼 jennyvenus 的回复:
在不同的硬件中用不同的架构,还要针对不同的应用


这个我认同~如果资源很充足跑系统最好 ,如果资源再少点,前后台方式可能是最好的选择。

#9


这样的设计理念是对的
但有一个重大缺陷,
当step的可能性很多时,这个大型的switch它的时间复杂度其实是1次方的,随问题规模而变慢的。
问题就出在,其实你知道下一步在哪,但这个信息被你损失掉了,而是下一次重新计算该在哪,这一次次的重新计算造成了时间复杂度的上升。一个判断值在switch中的位置如果不走运甚至会影响到时序。

#10


如果各个事件中的子事件都有中断可用的话,规划一个中断驱动的架构是比较合理的。当然,结构会比较支离破碎,可读性差一些。

使用操作系统是以降低效能为代价的。除非资源富余且收益很大,否则不用为好。

#11


ucos 就是用在硬件资源有限的cpu上的。。要是连ucos都不能跑,建议你扔了那个10块钱的cpu。

#12


现在见了这种假OS方式的用法就烦,很少能达到真正需要OS的那种需求。
以后我要么就上UCOS2这样OS,要么用前后台的,这样个假OS的写法,最多也只是个排版上能感觉模块化一点。

#13


感觉想法很好,如果是简单的应用我觉的前后台就够了,但是前后台稍微大一点就容易写的很乱。。。推荐楼主一本书《C嵌入式编程设计模式》,里面讲了几种模式可以用在前后台程序上。我觉得大家可以讲讲自己的程序架构。我做过的前后台差不多都是用一种方法:
while(1)
{
    if(  task_time_flag && other_flag)
    {
    }
.....................................
}
基于时间标志位和触发标志位,用到现在没出过大问题,就是当都满足时偶尔卡一下。大家有没有什么好的架构拿出来看看

#14


可以按实时要求排列任务,从前向后判断。每次只执行一个任务就返回循环再依次判断,这样可以保证优先级,只是不能抢占而已。低优先级任务可以打碎使其尽量短

#15


引用 14 楼 u012586257 的回复:
可以按实时要求排列任务,从前向后判断。每次只执行一个任务就返回循环再依次判断,这样可以保证优先级,只是不能抢占而已。低优先级任务可以打碎使其尽量短

这样做会让cpu 花很多时间在任务查询上。

#16


引用 13 楼 wifity 的回复:
感觉想法很好,如果是简单的应用我觉的前后台就够了,但是前后台稍微大一点就容易写的很乱。。。推荐楼主一本书《C嵌入式编程设计模式》,里面讲了几种模式可以用在前后台程序上。我觉得大家可以讲讲自己的程序架构。我做过的前后台差不多都是用一种方法:
while(1)
{
    if(  task_time_flag && other_flag)
    {
    }
.....................................
}
基于时间标志位和触发标志位,用到现在没出过大问题,就是当都满足时偶尔卡一下。大家有没有什么好的架构拿出来看看


有时候有些系统 不一定要多任务,前后台就很好的呀,哈哈,关键是要用得合适,缩短开发时间。

#17


引用 11 楼 gjq_1988 的回复:
ucos 就是用在硬件资源有限的cpu上的。。要是连ucos都不能跑,建议你扔了那个10块钱的cpu。


哈哈,搞Linux的朋友 会让你扔了你的20块钱的片子。跑系统的同学是没有办法忍受裸跑的,哈哈

#18


引用 15 楼 edanLee 的回复:
Quote: 引用 14 楼 u012586257 的回复:

可以按实时要求排列任务,从前向后判断。每次只执行一个任务就返回循环再依次判断,这样可以保证优先级,只是不能抢占而已。低优先级任务可以打碎使其尽量短

这样做会让cpu 花很多时间在任务查询上。

相对多一些。不过可以保证高优先级任务。
一种方案不会适合所有项目,各种方法提出来,根据自己需要去选择

#19


感觉楼主的局限性比较大 。多查查 。网上有更好的方法。自创可以。但最好从别人那里得到灵感。

#1


和  Protothreads 类似吧

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

#2


也考虑过这个,发现任务划分不好做,后来简化了一下,改成在delay程序中执行需要及时响应的任务了。ProtoThread没看懂,不过好像lwip中有使用

#3


这样太麻烦了,既然搞任务分割,那为何不用OS?

如果不用OS,其实用不准确的定时器来实现某种任务轮循和中断是很不错的硬办法

:)

#4


在不同的硬件中用不同的架构,还要针对不同的应用

#5


UCOS对硬件的要求不高!

#6


引用 1 楼 zhxianbin 的回复:
和  Protothreads 类似吧

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


眼界不是很宽,所以未有去了解

#7


引用 3 楼 lbing7 的回复:
这样太麻烦了,既然搞任务分割,那为何不用OS?

如果不用OS,其实用不准确的定时器来实现某种任务轮循和中断是很不错的硬办法

:)


加入OS对于Flash只有几K的单片机很吃力的~

#8


引用 4 楼 jennyvenus 的回复:
在不同的硬件中用不同的架构,还要针对不同的应用


这个我认同~如果资源很充足跑系统最好 ,如果资源再少点,前后台方式可能是最好的选择。

#9


这样的设计理念是对的
但有一个重大缺陷,
当step的可能性很多时,这个大型的switch它的时间复杂度其实是1次方的,随问题规模而变慢的。
问题就出在,其实你知道下一步在哪,但这个信息被你损失掉了,而是下一次重新计算该在哪,这一次次的重新计算造成了时间复杂度的上升。一个判断值在switch中的位置如果不走运甚至会影响到时序。

#10


如果各个事件中的子事件都有中断可用的话,规划一个中断驱动的架构是比较合理的。当然,结构会比较支离破碎,可读性差一些。

使用操作系统是以降低效能为代价的。除非资源富余且收益很大,否则不用为好。

#11


ucos 就是用在硬件资源有限的cpu上的。。要是连ucos都不能跑,建议你扔了那个10块钱的cpu。

#12


现在见了这种假OS方式的用法就烦,很少能达到真正需要OS的那种需求。
以后我要么就上UCOS2这样OS,要么用前后台的,这样个假OS的写法,最多也只是个排版上能感觉模块化一点。

#13


感觉想法很好,如果是简单的应用我觉的前后台就够了,但是前后台稍微大一点就容易写的很乱。。。推荐楼主一本书《C嵌入式编程设计模式》,里面讲了几种模式可以用在前后台程序上。我觉得大家可以讲讲自己的程序架构。我做过的前后台差不多都是用一种方法:
while(1)
{
    if(  task_time_flag && other_flag)
    {
    }
.....................................
}
基于时间标志位和触发标志位,用到现在没出过大问题,就是当都满足时偶尔卡一下。大家有没有什么好的架构拿出来看看

#14


可以按实时要求排列任务,从前向后判断。每次只执行一个任务就返回循环再依次判断,这样可以保证优先级,只是不能抢占而已。低优先级任务可以打碎使其尽量短

#15


引用 14 楼 u012586257 的回复:
可以按实时要求排列任务,从前向后判断。每次只执行一个任务就返回循环再依次判断,这样可以保证优先级,只是不能抢占而已。低优先级任务可以打碎使其尽量短

这样做会让cpu 花很多时间在任务查询上。

#16


引用 13 楼 wifity 的回复:
感觉想法很好,如果是简单的应用我觉的前后台就够了,但是前后台稍微大一点就容易写的很乱。。。推荐楼主一本书《C嵌入式编程设计模式》,里面讲了几种模式可以用在前后台程序上。我觉得大家可以讲讲自己的程序架构。我做过的前后台差不多都是用一种方法:
while(1)
{
    if(  task_time_flag && other_flag)
    {
    }
.....................................
}
基于时间标志位和触发标志位,用到现在没出过大问题,就是当都满足时偶尔卡一下。大家有没有什么好的架构拿出来看看


有时候有些系统 不一定要多任务,前后台就很好的呀,哈哈,关键是要用得合适,缩短开发时间。

#17


引用 11 楼 gjq_1988 的回复:
ucos 就是用在硬件资源有限的cpu上的。。要是连ucos都不能跑,建议你扔了那个10块钱的cpu。


哈哈,搞Linux的朋友 会让你扔了你的20块钱的片子。跑系统的同学是没有办法忍受裸跑的,哈哈

#18


引用 15 楼 edanLee 的回复:
Quote: 引用 14 楼 u012586257 的回复:

可以按实时要求排列任务,从前向后判断。每次只执行一个任务就返回循环再依次判断,这样可以保证优先级,只是不能抢占而已。低优先级任务可以打碎使其尽量短

这样做会让cpu 花很多时间在任务查询上。

相对多一些。不过可以保证高优先级任务。
一种方案不会适合所有项目,各种方法提出来,根据自己需要去选择

#19


感觉楼主的局限性比较大 。多查查 。网上有更好的方法。自创可以。但最好从别人那里得到灵感。

#20