34480016 发表于 2009-2-2 00:42:08

文笔这么好,lz有没有写书的打算

zilog 发表于 2009-2-2 11:18:49

牛哦,MARK

yycool 发表于 2009-2-2 12:07:27

感谢楼主!看来自己是应该进阶下了

lrxgr 发表于 2009-2-2 12:18:47

有个很低级的问题,如果执行第一任务里有一个延时,那么延时还没到达是,切换到第二个任务是,这时第一个任务的延时到达,cpu是不是就错过了一次捕捉延时的机会??

mugangqin 发表于 2009-3-24 09:06:22

楼上的 不能以往的循环延时,这样肯定会错过扑捉的机会
要把任务让出去,给其他任务的执行,通过执行其他的任务的时间差来达到延时的效果,

robinyuan 发表于 2009-3-25 21:06:29

楼主好久没出现了

caiping15 发表于 2009-3-26 17:30:38

能不能用时间片的形式切换任务?

rainyss 发表于 2009-3-27 02:54:12

【215楼】 lrxgr
积分:34
派别:
等级:------
来自:
有个很低级的问题,如果执行第一任务里有一个延时,那么延时还没到达是,切换到第二个任务是,这时第一个任务的延时到达,cpu是不是就错过了一次捕捉延时的机会??

 



这个问题并不低级.这里头有个很重要的概念,就是总任务周期时间:

当任一任务暂时放弃CPU后,在最坏的情况下CPU要多久才能回到该任务.

最简单的计算方法是将每一个任务的最大执行时间加起来,设法让该时间不超过任意一个任务所允许的最大延迟.当然,这种方法太浪费了,但可以保证绝对有效.经验多了以后再去推算动态情况下如何保证每个任务都不会错过执行时机.

liuhengming 发表于 2009-3-28 00:08:23

不顶不行啊

livanfield 发表于 2009-3-28 13:12:23

这块砖太有分量了,真是一砖激起千层浪

hibond 发表于 2009-3-28 15:31:02

caiping15 发表于 2009-3-28 16:24:58

CPU的控制权需要一个任务执行完后再交给下一个任务,这样的操作系统我觉得跟顺序执行没什么区别。

1screw1 发表于 2009-3-29 10:21:26

mark

whjwxp110 发表于 2009-4-6 15:11:36

我的感觉是如果顺序执行的速度够快,不影响实时操作的相应,还是采用顺序执行的方式好些,不过各有优缺点。最适合的才是最好的。楼主给出的是一种思路和代码的实现方式,采用何种架构是你自己的问题。

rainyss 发表于 2009-4-8 03:11:40

楼上精辟.不要用画圈把自已困住才是正道.

wmsky 发表于 2009-4-10 17:48:10

mark

lin135 发表于 2009-4-10 18:53:15

其实要一个单片机做很多任务的话不应该有100uS以上的延时的。最好是没有延时,除非是发送串行为调速率延时5uS以内。
像遥控红外的发射和接收速率很低就不能用延时等待的方式,那样造成有些响应慢,除非你加很多专用的硬件资源。

liuweiele 发表于 2009-4-10 23:47:19

支持

engineer000 发表于 2009-4-14 16:53:57

MARK,MARK!!!

Trubery 发表于 2009-4-15 10:57:45

好贴,MARK 一下呵呵

neohp 发表于 2009-4-17 16:09:12

顶 有汇编的吗? 是不是要了C 才考虑系统这个问题呢

zshx2008 发表于 2009-4-17 17:21:23

好贴,顶呀!

fjf429 发表于 2009-4-19 22:05:01

/*

简单的多任务操作系统

其实只有个任务调度切换,把说它是OS有点牵强,但它对于一些简单的开发应用来说,简单也许就是最好的.尽情的扩展它吧.别忘了把你的成果分享给大家.

这是一个最简单的OS,一切以运行效率为重,经测试,切换一次任务仅20个机器周期,也就是在标准51(工作于12M晶振)上20uS.
而为速度作出的牺牲是,为了给每个任务都分配一个私有堆栈,而占用了较多的内存.作为补偿,多任务更容易安排程序逻辑,从而可以节省一些用于控制的变量.
任务槽越多,占用内存越多,但任务也越好安排,以实际需求合理安排任务数目.一般来说,4个已足够.况且可以拿一个槽出来作为活动槽,换入换入一些临时任务.

task_load(函数名,任务槽号)
装载任务

os_start(任务槽号)
启动任务表.参数必须指向一个装载了的任务,否则系统会崩溃.

task_switch()
切换到其它任务



.编写任务函数注意事项:
KEIL C编译器是假定用户使用单任务环境,所以在变量的使用上都未对多任务进行处理,编写任务时应注意变量覆盖和代码重入问题.

1.覆盖:编译器为了节省内存,会给两个没用调用关系的函数分配同一内存地址作为变量空间.这在单任务下是很合理的,但对于多任务来说,两个进程会互相干扰对方.
解决的方法是:凡作用域内会跨越task_switch()的变量,都使用static前辍,保证其地址空间分配时的唯一性.

2.重入:重入并不是多任务下独有的问题,在单任务时,函数递归同样会导致重入,即,一个函数的不同实例(或者叫作"复本")之间的变量覆盖问题.
解决的方法是:使用reentrant函数后辍(例如:void function1() reentrant{...}).当然,根本的办法还是避免重入,因为重入会带来巨大的目标代码量,并极大降低运行效率.

3.额外提醒一句,在本例中,任务函数必须为一个死循环.退出函数会导致系统崩溃.




.任务函数如果是用汇编写成或内嵌汇编,切换任务时应该注意什么问题?

由于KEIL C编译器在处理函数调用时的约定规则为"子函数有可能修改任务寄存器",因此编译器在调用前已释放所有寄存器,子函数无需考虑保护任何寄存器.
这对于写惯汇编的人来说有点不习惯: 汇编习惯于在子程序中保护寄存器.
请注意一条原则:凡是需要跨越task_switch()的寄存器,全部需要保护(例如入栈).根本解决办法还是,不要让寄存器跨越任务切换函数task_switch()
事实上这里要补充一下,正如前所说,由于编译器存在变量地址覆盖优化,因此凡是非静态变量都不得跨越task_switch().


任务函数的书写:
void 函数名(void){//任务函数必须定义为无参数型
while(1){//任务函数不得返回,必须为死循环
      //....这里写任务处理代码
         
      task_switch();//每执行一段时间任务,就释放CPU一下,让别的任务有机会运行.
}
}


任务装载:
task_load(函数名,任务槽号)

装载函数的动作可发生在任意时候,但通常是在main()中.要注意的是,在本例中由于没考虑任务换出,
所以在执行os_start()前必须将所有任务槽装满.之后可以随意更换任务槽中的任务.



启动任务调度器:
os_start(任务槽号)

调用该宏后,将从参数指定的任务槽开始执行任务调度.本例为每切换一次任务需额外开销20个机器周期,用于迁移堆栈.
*/
#include"iom8v.h"
#include"fun.h"
//#include"def.h"
//#include"var.h"
char led;
char d8={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
unsigned char seg;
char b;

#define MAX_TASKS 2
#define MAX_TASK_DEP 35
/*============================以下为任务管理器代码============================*/
//任务槽个数.在本例中并未考虑任务换入换出,所以实际运行的任务有多少个,就定义多少个任务槽,不可多定义或少定义
//任务的栈指针
#define MAX_TASKS 2
#define MAX_TASK_DEP 35
unsigned int task_sp;
      //最大栈深.最低不得少于2个,保守值为12.                                                                        

                                                //预估方法:以2为基数,每增加一层函数调用,加2字节.如果其间可能发生中断,则还要再加上中断需要的栈深.
                                                //减小栈深的方法:1.尽量少嵌套子程序 2.调子程序前关中断.
unsigned char task_stack;//任务堆栈.

unsigned char task_id;//当前活动任务号
//任务切换函数(任务调度器)
void task_switch(){
      asm("push r0");
      asm("push r1");
      asm("push r2");
      asm("push r3");
      asm("push r4");
      asm("push r5");
      asm("push r6");
      asm("push r7");
      asm("push r8");
      asm("push r9");
      asm("push r10");
      asm("push r11");
      asm("push r12");
      asm("push r13");
      asm("push r14");
      asm("push r15");
      asm("push r16");
      asm("push r17");
      asm("push r18");
      asm("push r19");
      asm("push r20");
      asm("push r21");
      asm("push r22");
      asm("push r23");
      asm("push r24");
      asm("push r25");
      asm("push r26");
      asm("push r27");
      asm("push r28");
      asm("push r29");
      asm("push r30");
      asm("push r31");
      asm("in r16,0x3f");
      asm("push r16");
      task_sp = SP;
      task_id++;
      if(task_id == MAX_TASKS)task_id = 0;
      SP = task_sp;
      asm("pop r16");
      asm("out 0x3f,r16");
      asm("pop r31");
      asm("pop r30");
      asm("pop r29");
      asm("pop r28");
      asm("pop r27");
      asm("pop r26");
      asm("pop r25");
      asm("pop r24");
      asm("pop r23");
      asm("pop r22");
      asm("pop r21");
      asm("pop r20");
      asm("pop r19");
      asm("pop r18");
      asm("pop r17");
      asm("pop r16");
      asm("pop r15");
      asm("pop r14");
      asm("pop r13");
      asm("pop r12");
      asm("pop r11");
      asm("pop r10");
      asm("pop r9");
      asm("pop r8");
      asm("pop r7");
      asm("pop r6");
      asm("pop r5");
      asm("pop r4");
      asm("pop r3");
      asm("pop r2");
      asm("pop r1");
      asm("pop r0");
      asm("ret");
      //return;
}
void delay(long c)
{
          long i;
          for(i=0;i<c;i++)
         {
          asm("nop");
          asm("nop");
          asm("nop");
          asm("nop");
          asm("nop");
          asm("nop");
          asm("nop");         
         }
}
//任务装入函数.将指定的函数(参数1)装入指定(参数2)的任务槽中.如果该槽中原来就有任务,则原任务丢失,但系统本身不会发生错误.
void task_load(void(*task)(),unsigned char tid)
{
         
      task_sp = (unsigned int)(task_stack-1);
      task_stack = (unsigned char)(((unsigned int)task)&0xFF);
      task_stack = (unsigned char)(((unsigned int)task)>>8);
}

//从指定的任务开始运行任务调度.调用该宏后,将永不返回.
//#define os_start(tid) {task_id = tid,SP = task_sp;return;}
void os_start(unsigned char tid)
{
          task_id = tid;
         SP = task_sp+MAX_TASK_DEP - 2;
         return;
}
/*============================以下为测试代码============================*/
void task1(void)
{
          for(;;)
         {
                  PORTC=0x10;
                delay(20000);
                task_switch();
         }
}


void task2(void)
{
          for(;;)
         {
                  PORTC=0x20;
                delay(30000);
                task_switch();
         }
}



void main(){
      //在这个示例里并没有考虑任务的换入换出,所以任务槽必须全部用完,否则系统会崩溃.
      //这里装载了三个任务,因此在定义MAX_TASKS时也必须定义为3
         DDRD=0Xff;
            DDRC=0x07;

      task_load(task1, 0);//将task1函数装入0号槽
      task_load(task2, 1);//将task2函数装入1号槽


      os_start(0);//启动任务调度,并从0号槽开始运行.参数改为1,则首先运行1号槽.
                              //调用该宏后,程序流将永不再返回main(),也就是说,该语句行之后的所有语句都不被执行到.
}
编译器是ICC ,MCU是mega8;这个系统有点问题,就是 在使用task_load(task1, 0)将task1函数装入0号槽时,task1 的值并不是任务1的入口地址,经调试(unsigned int)task1的值是40(0x28);各位大侠,帮帮忙,看看问题出在哪了?小弟不胜感激!!!!!!!!!!!!

rainyss 发表于 2009-4-22 01:00:10

AVR上已经有很多现成的轻量系统,没必要自已做.
你把我专为51写的系统拿到AVR上用是不行的,不是改一点代码就可以的,而是连设计理念都不能在AVR上成立.
当然,你的尝试是对的,不过写一个操作系统需要对该CPU和编译器都十分了解,你需要先练练功底,可以找一两个小OS来研究一下.坛里有一篇阿莫转载的AVR OS DIY的文章,但我找不着了.

hnrain 发表于 2009-4-24 08:46:17

顶个。 。。呵呵。。!!!

rainyss 发表于 2009-4-24 23:41:49

http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=574348&bbs_page_no=1&search_mode=4&search_text=rainyss&bbs_id=9999

找着了.234楼想做AVR的OS,可以去那里看.

hc235280 发表于 2009-4-25 17:41:27

顶,占位学习

tdmi 发表于 2009-4-25 18:26:48

好贴

mikeseaver 发表于 2009-4-26 23:24:17

不怎么看得懂!你说用延时时就调用任务转换器?
那我不用延时程序,用其他程序作为延时不就行了吗?

rainyss 发表于 2009-4-28 00:20:26

那样的话所有的任务都慢下来了.

bygood 发表于 2009-5-10 19:37:07

收藏备用。谢谢

hc235280 发表于 2009-5-10 21:33:22

好贴留名

snow-wind-001 发表于 2009-5-11 11:01:53

留名,以备后用

hejunbok 发表于 2009-5-11 11:10:58

好贴啊
慢慢学习

wear778899 发表于 2009-5-11 17:33:37

我没标记过?

xk061809 发表于 2009-5-11 21:21:26

mark

32446975 发表于 2009-5-18 08:55:01

好贴,顶!

xyz2008 发表于 2009-5-20 16:52:18

mark

lionliu 发表于 2009-5-20 20:21:47

m

womenhome 发表于 2009-5-21 17:26:32

好贴

ksniper 发表于 2009-5-22 10:45:36

太强悍了标记慢慢看

iiset 发表于 2009-5-24 03:03:43

mark

stoneke 发表于 2009-5-24 10:22:53

巨强,收了学习!!

nestlake 发表于 2009-5-27 09:17:26

收藏了

czxf 发表于 2009-5-27 10:44:37

mark

MANANDFEMAN 发表于 2009-5-27 15:22:25

认真看下

DeKaron 发表于 2009-5-27 16:25:22

顶到飞高。。

kinoko 发表于 2009-5-28 08:46:08

怎样收藏

jiekjx 发表于 2009-5-30 21:14:53

强大,非常好,对我以后做的操作系统很有帮助

sukexi 发表于 2009-5-30 21:29:50

感谢楼主,留个标记日后必回!

253283342 发表于 2009-6-2 00:15:33

谢谢,学习中!!

wolf11_1234 发表于 2009-6-2 10:44:08

又把它顶出来,只是现在我添加讨论,不知道作者能不能回应。

LZ的思路我大体看明白,单对任务切换这一块,阐述一些我的看法。

你所讲的任务切换迅速,是建立在一个基础上的:为每个任务保存一个独立的堆栈空间。
这个类同于ucos,ucos对每个任务指定独立大小的堆栈空间。
而51的堆栈处理空间只有内部的RAM区,
这样,ucos移植到51,任务切换的最大的瓶颈就是将每个任务的堆栈从片内搬到片外,又从片外搬到片内。

你的所有任务堆栈都分配在片内RAM上。而且每个堆栈空间独立。
如果任务多了,比如16个任务(RTX51 Tiny支持的最大数量),你的堆栈消耗,在51上是不能满足的。

每个任务的堆栈空间都有两部分,一部分是用掉的,程序调用的压栈,变量的压栈,都是有效数据。
一部分是空白部分,用于新的程序压栈,新的变量压栈。提供为以后的应用。

Tiny的所有任务的堆栈空白部分是共享的。用掉部分是独立的。所以它的内部ram消耗程度是很小的。
由此带来的在任务切换时候的数据搬运,占用了一些系统时间。但这个时间是值得的。

所以,LZ推荐你的思路时候,提出的与Tiny的对比并不是很合适。

homecom 发表于 2009-6-2 11:36:27

很难超越RTX TINY。

v8se 发表于 2009-6-5 09:05:12

对于128byte的51,运行OS确实太勉强了。不光RAM少,连ROM也是个问题。在这种资源下,MCU都不可能做太多事情的。

    在我自己做的几个案子中,最低选择就是有256byte的RAM,就足以把自己的51微内核放进去,而且也具备额uCos的基本特点。
虽然51的堆栈处理空间只有内部RAM,但是可以处理到256byte。恰好就是多这128byte,就可以保存寄存器和任务状态。
   
    至于速度问题,现在的51都可以到1T的速度,用个24M的晶振难道还不够快吗?自己曾经这样同时驱动一个8位的数码管(而且还是
用595扫描驱动)和一个192*64的点阵液晶屏显示DS1302的时间(还用的外部内存映射的方式),任务的切换速度达到800Hz(为了动态扫描),MCU的空闲时间依然很富裕。
    自从用上了OS之后,就如以前看到一个网友这样说过。“当你使用过OS之后,就再也不想用以前的顺序执行方式了”

mamin506 发表于 2009-6-6 21:23:51

标记,慢慢消化

mamin506 发表于 2009-6-6 22:48:58

看完了,学了很多东西,谢谢LZ

rainyss 发表于 2009-6-7 23:38:33

to 【263楼】 wolf11_1234
积分:59
派别:
等级:------
来自:



以空间换时间.

canjany 发表于 2009-6-8 14:54:40

基本功不行,看了两层楼,看的头晕。

qd118 发表于 2009-6-14 13:03:17

mark

suntaogoodboy 发表于 2009-6-16 08:51:45

学学

ppdd 发表于 2009-6-17 08:49:15

学习,不过得先看看,还没弄明白.谢谢!

stefgq 发表于 2009-6-17 22:29:42

mark

song1km 发表于 2009-7-2 16:42:41

标个个个记

sinbord 发表于 2009-7-2 17:07:52

好文,谢谢分享!

hecb999 发表于 2009-7-4 21:09:29

强贴留名

sange 发表于 2009-7-11 15:39:37

学习ing。。。。。。。。。。。

mvsqr2 发表于 2009-7-12 12:25:54

都一年了,这个贴都不沉~~牛!!

onebobo126com 发表于 2009-7-12 17:55:15

太强了

csclz 发表于 2009-7-12 18:20:28

学习学习再学习

he306 发表于 2009-7-21 17:51:13

寄存器为什么不入堆栈呀?
不会丢失数据吗?

liudeee 发表于 2009-7-27 00:19:34

MARK下明天继续看

stefgq 发表于 2009-7-27 00:30:37

MARK

ggyyll8683 发表于 2009-7-27 09:08:26

maRK好贴!!

rainyss 发表于 2009-7-28 00:15:29

【281楼】 he306
积分:1
派别:
等级:------
来自:
寄存器为什么不入堆栈呀?
不会丢失数据吗?


这就是技巧了。放弃寄存器入栈可以极大地提高任何切换的速度以及节省大量的堆栈空间,代价是使用局部变量时不作用域内不得跨越任务。

erobot 发表于 2009-8-6 08:48:55

太好了,晚上回去研究。

dingdangCat 发表于 2009-8-12 23:29:34

顶顶

bygood 发表于 2009-8-15 09:58:37

这就是我所期望的好帖,正在研究51的操作系统。

weilan2200 发表于 2009-8-17 16:35:30

顶一下!

yyfish 发表于 2009-8-19 16:55:19

厉害!

wxhland 发表于 2009-8-19 20:55:56

mark

ZY_Hong 发表于 2009-8-19 21:31:51

看着有点晕,得慢慢消化才行!!

iamapighhh 发表于 2009-8-19 22:23:09

现在还看不懂,先记号下来。

ajin505 发表于 2009-8-19 23:07:14

MARK一下 高深的东西不敢触碰

lukelu1986 发表于 2009-8-23 17:08:50

标记一下,以后肯定用的上 ,谢谢!

vp110 发表于 2009-8-23 22:47:42

看了 一些没有完全看懂
   
楼主的思想太厉害了
   保存了
后面漫漫看

alleazy 发表于 2009-8-23 22:53:28

标记,呵呵

hesai0 发表于 2009-8-25 22:41:28

shamork 发表于 2009-8-26 08:46:47

mark

dgdzov 发表于 2009-8-26 11:01:20

好贴

jchqxl 发表于 2009-8-26 11:15:32

拜读,谢谢。

jianbo513 发表于 2009-8-27 23:24:16

mark

csqfine 发表于 2009-8-28 00:36:13

有空要慢慢研究才行

snowyghost 发表于 2009-8-28 21:03:34

记号。

yanghuagui 发表于 2009-8-30 11:22:59

先mark

ls81250 发表于 2009-9-2 17:16:11

记号,要慢慢研究

iamhope 发表于 2009-9-2 22:24:21

good

a69161 发表于 2009-9-8 18:32:55

记号一下

kavihuang 发表于 2009-9-8 22:25:02

记号了!

lingaoxun 发表于 2009-9-8 23:26:38

记号,虽然现在看不懂改天来慢慢消化

szxy06dq 发表于 2009-9-9 09:07:22

感觉分时复用好
页: 1 2 [3] 4 5 6 7 8 9 10 11 12
查看完整版本: 给51 DIY超轻量级多任务操作系统