OpenEdv-开源电子网

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

基于STC89C52简单的RTOS

[复制链接]

10

主题

86

帖子

2

精华

中级会员

Rank: 3Rank: 3

积分
490
金钱
490
注册时间
2012-2-11
在线时间
8 小时
发表于 2013-1-4 22:53:42 | 显示全部楼层 |阅读模式

       这两天没事想学RTOS,但是没有实时操作系统的概念,就想起以前看过的一篇文章,是在51系列单片机上建立一个简单的多任务实时操作系统RTOS,我就开始拿这个当台阶吧,让自己对多任务实时操作系统有个大概的认识,这样才能让自己不会被复杂的RTOS给吓倒。

        我们在写51系列单片机程序时肯定有很多人跟我一样,只是把基础模块一个一个的实现,而不会很深入的去写,或许你能将它们组合,一般都是一个大循环while, 加一些延时Delay,但是你想过没,在你用whileDelay时你很犯了一个很大的错误,因为我们让MCU在处理Delay时白白的浪费了很多时间,因为MCU在等待Delay,也许你会说只是延时几s,或者几ms,但是你要知道我们的MCU是以us为单位工作的,在MCU等待的这段时间它可以处理很多事情了,所以如果在处理这些事情时加入一个实时操作系统,让RTOS帮我们合理分配MCU的时间。如果我们把这些事情当做RTOS的几个任务,并合理设置分配

RTOS的节拍和设置这些任务的执行频度,这就可以大大的提升了系统的速度和性能,这是以后写实用程序的最好开始。好了废话少说,进入主题~

        在进入主题之前先说说我理解的几个概念:

        系统任务:所谓任务,就是需要CPU 周期关照的事件,就是我们需要MCU做的事情。

        实时操作系统:就是当外部产生事件时能及时快速处理,且根据处理结果在规定的时间之内作出相应的控制和响应,并控制所有实时任务协调一致运行的操作系统。

          51系列的多任务实时操作系统有4个文件:            

          MAIN.c         ——   main 函数文件

           OS.c           ——   系统 相关函数文件
           OS.h           ——   
系统 相关配置参数头文件

          OS_TASK.c  ——   用户任务task 函数文件

 

        系统原理:单片机定时器延时中断来产生系统任务调度节拍,设置各个任务的执行频度,

                          来调度各任务。以实现系统多线 实时操作。
                          

                                                        

下面一一列出:

 

一、MAIN.c文件

/********************************
*FileName:  MAIN_C
*Author:   JZHG1992
*Versions:  V1.0
*********************************/

#include "OS.h"

 
/************************************
*   
主函数
*************************************/

void main( void )
{
 uchar i;
 
 OS_Timer0_Init();         // 
系统定时器时钟初始化
 EA = 1;       // 
开总中断
 while(1)
 {
  for ( i=0; i<TASK_MAX; i++ )
  {
   if ( Task_Delay == 0 )
   {
    OS_Task_Run( task );
    break;
   }
  }
 }        
}

 

二、OS.c文件

/********************************
*FileName:  OS_C
*Author:   JZHG1992
*Versions:  V1.0
*********************************/

#include "OS.H"

/************************************
*   
系统任务执行频度参数
*************************************/

uchar Task_Delay[TASK_MAX];

/************************************
*   
系统定时器时钟初始化
*************************************/

void OS_Timer0_Init( void )
{
 uchar i;

 for ( i=0; i<TASK_MAX; i++ )
 {
  Task_Delay = 0;   // 
复位系统任务执行频度参数  
 }
 TMOD = (TMOD&0xf0)|0x01; // 
设置定时器0方式1
 TH0 = 256-(OS_CLOCK/TASK_CLOCK)/12/256; // 
赋初值200Hz
 TL0 = 256-(OS_CLOCK/TASK_CLOCK)/12%256;
 TR0 = 1;  // 
使能定时器0
 ET0 = 1;  // 
使能定时器0中断
}

/************************************
*   
系统任务调度函数
*************************************/

void OS_Task_Run( void (*ptask)() )
{
 (*ptask)();
}

/************************************
*   
系统中断服务函数
*************************************/

void OS_ISR( void ) interrupt 1
{
 uchar i;

    TH0 = 256-(OS_CLOCK/TASK_CLOCK)/12/256; // 赋初值200Hz
 TL0 = 256-(OS_CLOCK/TASK_CLOCK)/12%256;
 for ( i=0; i<TASK_MAX; i++ )
 {
  if ( Task_Delay )Task_Delay --;
 }
}

 

三、OS.h文件

 

/********************************
*FileName:  OS_H
*Author:   JZHG1992
*Versions:  V1.0
*********************************/
/********************************
*
系统原理:单片机定时器延时中断来产
*                 
生系统任务调度节拍,设置
*                
各个任务的执行频度,来调
*                
度各任务。以实现系统多线
*                
操作。
*********************************/
#ifndef _OS_H_
#define _OS_H_
#include<reg52.h>

/************************************
*  
定义变量类型
*************************************/

#define uchar unsigned char  // 宏定义uchar
#define uint unsigned int  // 
宏定义uint

/************************************
*  
配置系统参数
*
这里你可以根据你的需要修改
*************************************/

#define OS_CLOCK  12000000   // 系统晶振频率,单位Hz
#define TASK_CLOCK 200       // 
任务中断节拍,单位Hz
#define TASK_MAX   2         // 
任务数目

/************************************
系统任务外调函数与参数
*************************************/

extern uchar Task_Delay[TASK_MAX];        // 系统任务执行频度参数
extern void OS_Timer0_Init( void );       // 
系统定时器时钟初始化
extern void OS_Task_Run( void(*ptask)()); // 
系统任务调度函数
extern void ( *const task[] )();          // 
获得任务指针

//-------------
#endif


四、OS_TASK.c文件

 

/********************************
*FileName:  TASK_C
*Author:   JZHG1992
*Versions:  V1.0
*********************************/

#include "OS.H"

/************************************
*   
设置系统任务执行频度
*       
根据自己任务分配执行频度
*************************************/

#define TASK_DELAY0 TASK_CLOCK/10   // 任务0的执行频度
#define TASK_DELAY1 TASK_CLOCK/1    // 
任务1的执行频度

/* ........ */

#defien TASK_DELAYn  TASK_CLOCK/1  // 任务n的执行频度

/************************************
*   
任务0函数
*************************************/

void task0( void )
{
 Task_Delay[0] = TASK_DELAY0;  // 
设置任务执行度

 /* 你的任务*/
 /* ..... */
  
}

/************************************
*   
任务1函数
*************************************/

void task1( void )
{
 Task_Delay[1] = TASK_DELAY1;  // 
设置任务执行度

 /* 你的任务*/
 /* ......  */       
  
}
/************************************
*   
任务n( n=TASK_MAX -1 )函数
*************************************/

void taskn( void )
{
 Task_Delay[n] = TASK_DELAYn;  // 
设置任务执行度

 /* 你的任务*/
 /* ......  */       
  
}

/************************************
*   
获得任务指针
*************************************/

void ( *const task[] )() = { task0, task1,..taskn };

 

//--------------------------------------------------------------

 

配置过程:

 

1、设置的只有OS.h文件中的

/************************************
*  
配置系统参数
*
这里你可以根据你的需要修改
*************************************/

#define OS_CLOCK  12000000   // 系统晶振频率,单位Hz
#define TASK_CLOCK 200       // 
任务中断节拍,单位Hz
#define TASK_MAX   2         // 
任务数目

/************************************

 

 

2、设置OS_TASK.c文件中的

 

/************************************
*   
设置系统任务执行频度
*       
根据自己任务分配执行频度
*************************************/

#define TASK_DELAY0 TASK_CLOCK/10   // 任务0的执行频度
#define TASK_DELAY1 TASK_CLOCK/1    // 
任务1的执行频度

/* ........ */

#defien TASK_DELAYn  TASK_CLOCK/1  // 任务n的执行频度

 

3、将我的任务加进来

/************************************
*   
任务0函数
*************************************/

void task0( void )
{
 Task_Delay[0] = TASK_DELAY0;  // 
设置任务执行度

 /* 你的任务*/
 /* ..... */
  
}

/************************************
*   
任务1函数
*************************************/

void task1( void )
{
 Task_Delay[1] = TASK_DELAY1;  // 
设置任务执行度

 /* 你的任务*/
 /* ......  */       
  
}
/************************************
*   
任务n( n=TASK_MAX -1 )函数
*************************************/

void taskn( void )
{
 Task_Delay[n] = TASK_DELAYn;  // 
设置任务执行度

 /* 你的任务*/
 /* ......  */       
  
}

 

4 提取任务的函数指针

 

/************************************
*   
获得任务指针
*************************************/

void ( *const task[] )() = { task0, task1,..taskn };

 

 

 

这个多任务实时操作系统虽然很简单,但是他让我知道了一些多任务实时操作系统的一些概念,让我跟有信心的去迎接更复杂、功能更强大的多任务实时操作系统,也希望对跟我一样很菜的电子人一些启发,也希望有兴趣的朋友可以跟我交流~~

1、52RTOS主文件.zip

22.5 KB, 下载次数: 1268

3、52RTOS数码管实验.zip

28.64 KB, 下载次数: 1102

4、52RTOS数码管时钟.zip

29.07 KB, 下载次数: 1045

6、按键调时实验.zip

83.84 KB, 下载次数: 1117

2、52RTOS闪烁灯实验.zip

24.43 KB, 下载次数: 1141

5、DS1302实验.zip

36.2 KB, 下载次数: 1085

52仿真图.zip

54.81 KB, 下载次数: 1011

多努力一点点,少遗憾一点点!!!
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2195
金钱
2195
注册时间
2012-2-8
在线时间
34 小时
发表于 2013-1-4 23:09:31 | 显示全部楼层
怎么感觉不是抢占式? 协同式的不能叫实时(RT)吧?
https://github.com/roxma
回复 支持 反对

使用道具 举报

10

主题

86

帖子

2

精华

中级会员

Rank: 3Rank: 3

积分
490
金钱
490
注册时间
2012-2-11
在线时间
8 小时
 楼主| 发表于 2013-1-4 23:18:34 | 显示全部楼层
回复【2楼】Pony279:
怎么感觉不是抢占式? 协同式的不能叫实时(RT)吧?
---------------------------------
哈哈!不好意思!我没接触过RTOS,只是个菜鸟,不知道的还很多,路还很长,希望各位高手以后多教教我啊~~
多努力一点点,少遗憾一点点!!!
回复 支持 反对

使用道具 举报

10

主题

86

帖子

2

精华

中级会员

Rank: 3Rank: 3

积分
490
金钱
490
注册时间
2012-2-11
在线时间
8 小时
 楼主| 发表于 2013-1-4 23:24:42 | 显示全部楼层
对了,找到这篇文章了,大家有需要的可以看看!

从单片机初学者迈向单片机工程师.pdf

4.92 MB, 下载次数: 6361

多努力一点点,少遗憾一点点!!!
回复 支持 反对

使用道具 举报

3

主题

59

帖子

0

精华

初级会员

Rank: 2

积分
104
金钱
104
注册时间
2012-12-25
在线时间
3 小时
发表于 2013-1-13 20:28:16 | 显示全部楼层
回复楼主:你这还是一个大while循环,不涉及上下文切换,算不得任务调度及OS。
如果能够实现两个独立while(1)循环的代码同时运行(宏观同时),就能算任务调度了。

不过,楼主的时间片和C语言用的很好,学习了!
这种代码我很喜欢,void ( *const task[] )() = { task0, task1,..taskn };
回复 支持 反对

使用道具 举报

3

主题

59

帖子

0

精华

初级会员

Rank: 2

积分
104
金钱
104
注册时间
2012-12-25
在线时间
3 小时
发表于 2013-1-13 21:04:13 | 显示全部楼层
      楼主若有兴趣,咋俩可一起讨论讨论这个实现,我只是知道怎么做,但是从来没实践过,所接触的所有os都是会用,
勉强能移植,但从没写过调度器任何代码,也想试试。目前有个大致框架,如下:

void main(void)
{
      调度器初始化;
      添加任务(task1);
      添加任务(task2);
      开始调度,永不返回;
}

void Task1(void)
{
       while(1)
       {
             系统延时1s;
              LED1 亮;
        系统延时1s;
         LED1灭;
       }

}

void Task2(void)
{
       while(1)
       {
             系统延时1s;
              LED2 亮;
        系统延时1s;
         LED2灭;
       }

}

void Task_Idle(void)    //空闲任务,死循环,可统计CPU运行效率
{
   while(1)
   {
   }
}
回复 支持 反对

使用道具 举报

3

主题

59

帖子

0

精华

初级会员

Rank: 2

积分
104
金钱
104
注册时间
2012-12-25
在线时间
3 小时
发表于 2013-1-13 23:15:24 | 显示全部楼层

这个实验预期的结果:这两个任务分别独立闪烁两个LED灯,并能够以某种方式显示CPU效率

另外,目前预想这个调度器的样子:
(1)为降低实现难度以及提高效率,所有任务数量、任务堆栈需要在程序开始时确定
(2)时间片轮询调度,所有就绪任务依次轮询,没有优先级一说。
(3)注意,上面回复里的系统延时1s 不是让CPU傻乎乎的原地踏步1s结束,而是真正释放CPU 1s。
(4)占用资源一个硬件定时器、一些必要的ROM和RAM。
回复 支持 反对

使用道具 举报

3

主题

59

帖子

0

精华

初级会员

Rank: 2

积分
104
金钱
104
注册时间
2012-12-25
在线时间
3 小时
发表于 2013-1-13 23:27:38 | 显示全部楼层

目测实时性能不行,任务响应时间要 n 个滴答,n为任务数量。
回复 支持 反对

使用道具 举报

3

主题

59

帖子

0

精华

初级会员

Rank: 2

积分
104
金钱
104
注册时间
2012-12-25
在线时间
3 小时
发表于 2013-1-13 23:31:46 | 显示全部楼层

仔细想了下,这设计缺点很多,但在小应用中应该能够最大程度上淡化这些缺点。

     首先最大的硬伤是非硬实时,因为不支持高优先级抢占,但是小型应用中任务肯定不会多,
2-3个就完全足够。据经验,一般也就只有像USB Host、TCP/IP等这样的应用才真正需要一个独立任务
(否则状态机会写得很复杂)。另外,可以把系统滴答时钟间隔做的很短,这样实时性可以做到较好,
这样也要求调度器要设计的简洁(运行时间快而不是代码简洁),不能占用CPU过多时间,而由于所有
任务及任务堆栈是静态的,且数量是确定的,这样调度算法可以得到最大程度上的优化。
     其次,任务间通信只能采用全局变量方式,也只能通过关中断的方式处理临界区代码,从而会延长中断
响应时间。然而,好的代码会回避这个问题,可以使程序性能不受影响,反而效率上一般会比信号量机制要高。
但是若处理不当,结果基本都是系统死掉。好在小型应用里代码结构不会太复杂,处理相对容易,稍作注意
一般应该不会出错。
回复 支持 反对

使用道具 举报

3

主题

59

帖子

0

精华

初级会员

Rank: 2

积分
104
金钱
104
注册时间
2012-12-25
在线时间
3 小时
发表于 2013-1-13 23:38:10 | 显示全部楼层

不管了,先实现再说。
回复 支持 反对

使用道具 举报

10

主题

86

帖子

2

精华

中级会员

Rank: 3Rank: 3

积分
490
金钱
490
注册时间
2012-2-11
在线时间
8 小时
 楼主| 发表于 2013-3-15 10:54:27 | 显示全部楼层
回复【10楼】celticzy:
---------------------------------
朋友!你真是高人啊,说实话我只会写一些外围电路的驱动以及控制程序,从没接触过什么系统调度,也没做过什么工程,只是做了很多DIY玩,
向你学习啊》~《
多努力一点点,少遗憾一点点!!!
回复 支持 反对

使用道具 举报

2

主题

255

帖子

0

精华

高级会员

Rank: 4

积分
821
金钱
821
注册时间
2013-6-5
在线时间
141 小时
发表于 2013-6-7 05:34:49 | 显示全部楼层
这个可不是os,连协调式的都不是
一个多任务oS至少要做到
void Task1(void) 

       while(1) 
       { 
             系统延时1s;//这里要把运行的权限交回调度核心,分配给下一个就绪的任务 
              LED1 亮; 
        系统延时1s; 
         LED1灭; 
       } 

}
回复 支持 反对

使用道具 举报

10

主题

86

帖子

2

精华

中级会员

Rank: 3Rank: 3

积分
490
金钱
490
注册时间
2012-2-11
在线时间
8 小时
 楼主| 发表于 2013-6-7 08:45:25 | 显示全部楼层
回复【12楼】zhxzhx:
---------------------------------
呵呵!以前没学过,这只是一个分时概念而已。。。
多努力一点点,少遗憾一点点!!!
回复 支持 反对

使用道具 举报

头像被屏蔽

6168

主题

7036

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
19705
金钱
19705
注册时间
2012-12-27
在线时间
25 小时
发表于 2013-6-8 09:42:41 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

4

主题

22

帖子

0

精华

初级会员

Rank: 2

积分
68
金钱
68
注册时间
2013-7-26
在线时间
2 小时
发表于 2013-9-19 13:02:52 | 显示全部楼层
哇塞,楼主自己写的RTOS?,望成之
回复 支持 反对

使用道具 举报

9

主题

93

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
426
金钱
426
注册时间
2011-7-11
在线时间
49 小时
发表于 2015-11-25 14:10:06 | 显示全部楼层
回复【10楼】celticzy:
---------------------------------
大神的OS怎么样了,怎么没看到进展了?
回复 支持 反对

使用道具 举报

6

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
148
金钱
148
注册时间
2015-12-20
在线时间
24 小时
发表于 2015-12-20 16:23:14 | 显示全部楼层
额,不是stm32的
回复 支持 反对

使用道具 举报

8

主题

569

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2363
金钱
2363
注册时间
2015-5-8
在线时间
320 小时
发表于 2016-6-15 00:38:46 | 显示全部楼层
谢谢分享,正在搞这个
回复 支持 反对

使用道具 举报

2

主题

171

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3792
金钱
3792
注册时间
2016-6-26
在线时间
276 小时
发表于 2016-6-27 06:50:34 | 显示全部楼层
非常不错,谢谢分享。
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2024-11-23 17:14

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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