OpenEdv-开源电子网

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

STM8S003F3上一种基于时间片思想的多任务设计方法

[复制链接]

1

主题

16

帖子

0

精华

初级会员

Rank: 2

积分
188
金钱
188
注册时间
2013-5-3
在线时间
40 小时
发表于 2015-12-11 12:48:32 | 显示全部楼层 |阅读模式
      刚开始接触STM8,就被其极高的性价比所吸引,刚好手头有一些STM8S003F3的板子,于是就以此为基础进行研究。
      之前使用STM32F103时已经挂载了ucosii,正如周立功先生所说的,一旦使用操作系统来编程,那么就很难再接受以前的前后台编程,
所以在还未确切明了STM8究竟有什么功能的时候,我首先想的是这玩意能使用哪种操作系统呢。ucosii肯定不行,对STM8这样的小身板
而言太大了,扛不住。在网上找啊找,找到了atomtheards,号称专为STM8而设计的。根据atom的官方资料,RAM要求低至1KB,S003刚
好达标,于是找了个基于IAR的例程一番修改,编译成功,也能仿真下载,就是无法正常工作,一直提示堆栈指针超出范围,这还是只有
一个LED显示任务的情况,在加了一个简单的串口任务以后,连编译都无法通过。大概分析了一下,还是RAM太小,跑不动,但是添加任
务就得开辟堆栈,开辟堆栈就需要占用RAM,就那么点资源,三两下就玩完了,所以像S003这种小RAM的片子基本跟OS拜拜了。
      但事还没完,OS用不了,那么有没有其他方法来实现呢?想起以前看过的时间片设计方法,就是给每一个任务分配一个时间片(就好
比任务是一辆辆的汽车,有大有小,时间片就是汽油,大车加多点,小车加少点),虽然实时性差点,但资源占用少。不过呢,一个完整
的时间片操作对S003而言还是有点复杂(确切的说是我自己感觉复杂),毕竟在不同的任务跳转时还是需要开辟堆栈进行现场保护的,巧
妇难为无米之炊,RAM太小,要把人逼疯的节奏。RAM太小,不要开辟堆栈不就行了,那跟前后台方式有什么区别?实际上,我这里实现
的方法就是一种前后台的过程,但实现的思想是类似于时间片的多任务方式。
      首先实现的是一个定时函数Delay_Ds(u8 ds_num, u32 t); 
     
      volatile u32 tick;             //系统心跳,每1ms加1,在定时中断中实现                         
      static   u32 fac_us = 0;  //us延时倍乘数

      static   u32 ds_read[DS_NUM_MAX];       //读取当前tick
      static   u32 ds_read_bit[DS_NUM_MAX]; //当前tick已读取标志

      static   u8  ds_sw[DS_NUM_MAX];          //定时开关

      /*****************************************************************************
     功能:定时
     入参:ds_num, 定时编号
               t, 定时时间,单位ms
     返回:REACHED, 定时时间到
               UNREACHED, 定时时间未到
     说明1:当定时函数用于不同的定时任务时,定时编号不能重复
     说明2:u32个ms的一个计数周期约49天,不考虑tick跨越多个计数周期的情况(也不用考虑
                 ,因为一个定时最多也就u32个计数)
     ******************************************************************************/
    Timing_Type   Delay_Ds(u8 ds_num, u32 t)
    {
       if(ds_sw[ds_num] == 1)  return UNREACHED;  //定时器关闭

       CLI();      //不允许中断打断
       if(ds_read_bit[ds_num]==0)              //定时开始,还未读取当前tick值
      {
        ds_read[ds_num]=tick;                     //读取当前tick
        ds_read_bit[ds_num]=1;      //标记为已读
      } 
      SEI();
    
      if(ds_read[ds_num]<tick)      //tick还在一个计数周期内
      {
        if(t<=tick-ds_read[ds_num])        //定时时间到
        {
          ds_read_bit[ds_num]=0;                  //重新计数
          return REACHED;      //返回定时到
        }
        else  return UNREACHED;      //否则返回定时未到
      }
      else if(ds_read[ds_num]>tick)      //tick已经在下一个计数周期内
      {
        if(t<=0xffffffff-ds_read[ds_num]+tick)  
        {
          ds_read_bit[ds_num]=0;                  //定时时间到,重新计数
          return REACHED; 
        }
        else  return UNREACHED;
      }
      else  return UNREACHED;      //
    }                        
    例如,LED以500ms的周期进行闪烁,那么就可以使用Delay_Ds()函数为LED闪烁任务设置一个500ms定时,500ms定时到,则执行一次
LED操作,然后让出CPU去执行其它任务。过程如下:
     while(1)
     {
         while(Delay_Ds(led_num, 500) == REACHED) {LED_Task();}
         while(Dealy_Ds(uart_num, 10) == REACHED) {UART_Task();}
         ……
     }
CPU在整个主循环中查询各个任务定时是否到,到则执行一次任务并重新计时,不到则继续查询。
      这样实现的好处显而易见,由于每个任务都是执行完成以后才会让出CPU,所以不会出现被打断的情况,所以不用开辟堆栈来进行现场
保护,在S003上运行起来绰绰有余,甚至更小RAM的单片机都可以运行;相比较传统的前后台编程方式,这种方法的逻辑更简单,不同的
任务可以看作是一个独立的处理过程;实现过程是硬件无关的,所以写好的程序可以在任意平台移植。当然,缺点也同样明显,一个任务
的执行时间不能太长,否则会影响其它任务的处理;未涉及任务的优先级,实时性差等等。
      现已通过这种方法在S003上实现了一个1HZ的LED闪烁任务,一个2HZ的LED闪烁任务和一个每10ms接收一次串口数据并发送回去的串
口任务,当串口助手以100ms发送一帧数据时 ,S003可以很流畅地运行,执行效果与使用OS的多任务处理一样。
      由于本人水平有限,难免有错误以及不足之处,欢迎大家批评指正。我在此也是抛砖引玉,如果各位有更好的方法,还请不吝赐教!

STM8S0_Project_Templates.zip

7.43 MB, 下载次数: 5846

恰如猛虎卧山丘,潜伏爪牙忍受!
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

15

主题

787

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3222
金钱
3222
注册时间
2015-7-26
在线时间
811 小时
发表于 2015-12-11 16:03:22 | 显示全部楼层
我的博客:http://blog.csdn.net/itdo_just
回复 支持 反对

使用道具 举报

0

主题

21

帖子

0

精华

初级会员

Rank: 2

积分
101
金钱
101
注册时间
2014-8-17
在线时间
20 小时
发表于 2016-10-18 09:47:25 | 显示全部楼层
mark一下
回复 支持 反对

使用道具 举报

39

主题

599

帖子

2

精华

金牌会员

Rank: 6Rank: 6

积分
2102
金钱
2102
注册时间
2011-9-3
在线时间
117 小时
发表于 2016-10-26 14:04:47 | 显示全部楼层
资源少可以用这种时间片方法。
回复 支持 反对

使用道具 举报

2

主题

65

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
383
金钱
383
注册时间
2015-4-15
在线时间
73 小时
发表于 2016-11-10 09:40:11 | 显示全部楼层
这种机制还是很常见的,如果一个功能执行过程比较长,可以采用多次循环扫描执行一个功能动作
回复 支持 反对

使用道具 举报

50

主题

1804

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
6632
金钱
6632
注册时间
2016-5-29
在线时间
906 小时
发表于 2016-11-10 15:10:35 | 显示全部楼层
STM8S003 可以实现2到3个任务的抢占式微型OS.可开堆栈.每个任务堆栈的大小设置128BYTE.简单又实用.
回复 支持 反对

使用道具 举报

3

主题

42

帖子

0

精华

高级会员

Rank: 4

积分
713
金钱
713
注册时间
2016-1-25
在线时间
79 小时
发表于 2016-11-21 11:21:24 | 显示全部楼层
多谢楼主分享,学习一下
回复 支持 反对

使用道具 举报

1

主题

6

帖子

0

精华

初级会员

Rank: 2

积分
52
金钱
52
注册时间
2019-12-31
在线时间
9 小时
发表于 2019-12-31 10:38:57 | 显示全部楼层
非常不错啊~~~~~~~
回复 支持 反对

使用道具 举报

10

主题

277

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2072
金钱
2072
注册时间
2016-8-15
在线时间
413 小时
发表于 2020-1-2 11:19:27 | 显示全部楼层
mark一下
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手上路

积分
23
金钱
23
注册时间
2017-9-6
在线时间
4 小时
发表于 2020-5-17 07:24:18 | 显示全部楼层
下载需要先回复?
回复 支持 反对

使用道具 举报

0

主题

8

帖子

0

精华

初级会员

Rank: 2

积分
121
金钱
121
注册时间
2019-6-30
在线时间
50 小时
发表于 2020-8-30 17:11:39 | 显示全部楼层
支持支持
回复 支持 反对

使用道具 举报

1

主题

3

帖子

0

精华

新手入门

积分
7
金钱
7
注册时间
2020-8-25
在线时间
1 小时
发表于 2020-9-24 13:32:42 | 显示全部楼层
下载不了
回复 支持 反对

使用道具 举报

0

主题

42

帖子

0

精华

高级会员

Rank: 4

积分
615
金钱
615
注册时间
2020-11-21
在线时间
121 小时
发表于 2021-8-23 14:23:39 | 显示全部楼层
谢谢分享
回复 支持 反对

使用道具 举报

0

主题

5

帖子

0

精华

新手上路

积分
27
金钱
27
注册时间
2020-12-1
在线时间
5 小时
发表于 2021-9-3 11:03:29 | 显示全部楼层
谢谢分享 正在找这种
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2022-1-10
在线时间
13 小时
发表于 2022-2-25 16:49:16 | 显示全部楼层
谢谢分享
回复 支持 反对

使用道具 举报

39

主题

128

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2258
金钱
2258
注册时间
2015-5-6
在线时间
245 小时
发表于 2022-2-28 22:14:40 | 显示全部楼层
附件下载不了了啊
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
6
金钱
6
注册时间
2022-3-8
在线时间
2 小时
发表于 2022-3-8 16:01:20 | 显示全部楼层
谢谢分享,时间片方法确实是高效的
回复 支持 反对

使用道具 举报

0

主题

12

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
345
金钱
345
注册时间
2020-8-31
在线时间
26 小时
发表于 2022-9-5 09:39:33 | 显示全部楼层
怎么下载
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手上路

积分
27
金钱
27
注册时间
2017-4-7
在线时间
7 小时
发表于 2022-9-19 18:43:08 | 显示全部楼层
Timing_Type   Delay_Ds(u8 ds_num, u32 t)
    {
       if(ds_sw[ds_num] == 1)  return UNREACHED;  //定时器关闭

       CLI();      //不允许中断打断
       if(ds_read_bit[ds_num]==0)              //定时开始,还未读取当前tick值
      {
        ds_read[ds_num]=tick;                     //读取当前tick
        ds_read_bit[ds_num]=1;      //标记为已读
      }
      SEI();
   
      if(ds_read[ds_num]<tick)      //tick还在一个计数周期内
      {
        if(t<=tick-ds_read[ds_num])        //定时时间到
        {
          ds_read_bit[ds_num]=0;                  //重新计数
          return REACHED;      //返回定时到
        }
        else  return UNREACHED;      //否则返回定时未到
      }
      else if(ds_read[ds_num]>tick)      //tick已经在下一个计数周期内
      {
        if(t<=0xffffffff-ds_read[ds_num]+tick)  
        {
          ds_read_bit[ds_num]=0;                  //定时时间到,重新计数
          return REACHED;
        }
        else  return UNREACHED;
      }
      else  return UNREACHED;      //
    }                        
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2024-5-15 07:50

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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