搜索
bottom↓
回复: 53

单片机怎么实现实时多任务,不用RTOS,请大家讲讲思路。

[复制链接]

出0入0汤圆

发表于 2007-10-16 09:57:02 | 显示全部楼层 |阅读模式
在51等单片机中,容量小,如果运行某个RTOS的话,觉得资源非常的紧,RTOS占用了一部分,应用程序空间就显得非常小。
如果不用RTOS的话,能够自己编一个适合这些小容量,运行速度相对比较慢的单片机的某种结构。而且又能实时的响应多个任务。
那样的话,相对比用RTOS好。
    不知道大侠们有什么好的思路和程序结构呢?诚心请教。

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2007-10-16 10:40:03 | 显示全部楼层
1 自己做个简单的RTOS,用一个定时器,不支持任务抢断,只支持静态任务数量和静态的任务.应该比较小.
2 任务中加状态机或者标志符号.主程序while(1){处理}

出0入0汤圆

发表于 2007-10-16 11:32:30 | 显示全部楼层
其实usmart基本上就是这种结构。完整的usmartx占用ram最小也有200多字节。移植51还是不行。

楼主可以把usmartx进行裁减,只保留任务调度和定时器部分。

出0入0汤圆

发表于 2007-10-16 11:53:42 | 显示全部楼层
用step方式.其实就是二楼说的方式,状态机.

原理是:函数执行时不是一次就完成所有功能,而是只执行一部分功能.凡有延时等待的需要,就将过程打断,插入step.这方法我用过很多年了,很好用,但要用习惯才行,不然写出的代码有点难懂.

unsigned char retval;
unsigned char step = 0;
void function_1(){
  if(step == 0){
  }
  if(step == 1){
  }
  if(step >=2  && step <= 5){
  }
  if(step == 6){
  }
......
  if(step == 20){
  }
  step++;
  if(step == 20)
    step = 0;
}
...
//function 2和3的定义和function_1差不多.这里就略去了
function_2()
function_3()
...
void main(){

  while(1){
    function_1();
    function_2();
    function_3();
  }

}

出0入0汤圆

发表于 2007-10-16 12:45:19 | 显示全部楼层
不支持任务抢断,那还谈什么实时性?!
有一种方法可以实现,抢断在中断退出之前,即可.
理解的了就试试,理解不了也没有关系-反正是个野路子!

出0入0汤圆

发表于 2007-10-16 13:02:48 | 显示全部楼层
不支持抢占就没有实时性?那么前后台系统呢?有没有抢占?实时性如何?

不支持抢占,只是任务的事实性差了些。任务的实时性差一点,并不意味着整个系统的实时性差,只要保证中断的实时性够高就行。
us级实时性有中断控制,ms级实时性由操作系统控制。
像notos,usmartx就是非抢占式操作系统。

出0入0汤圆

发表于 2007-10-16 13:06:24 | 显示全部楼层
实时是相对的,对于低速的单片机而言,中断就是最好的实时处理办法。不会什么系统,但知道那就是时间分割:1个奶妈喂多个孩子,都要照顾到。感觉定制中断的优先级还是很科学的。紧要的就先做,不要紧的缓下也没什么

出0入0汤圆

发表于 2007-10-16 13:11:49 | 显示全部楼层
to 楼上
用操作系统难道就不能用中断!!

出0入0汤圆

发表于 2007-10-16 13:25:20 | 显示全部楼层
谈实时性会引向极端,5楼比较有心得,确实也是这么一回事情,我只是针对楼主的问题提出了一个方法,这个方法用不用问题不大.
只是采用中断退出前其它任务争夺到CPU控制权的方式,比RTOS来的方便,不需要自己做现场保护,实时性上又能提高一截.
XX外中断退出前,查寻一下任务列表  
XX定时中断退出前,查寻一下任务列表
在这些列表中的任务要比后台任务优先级高,事实上还是在中断中完成一般.
完全野路子,复杂系统我顷向换于单片机和用RTOS.小系统还是用传统得前后台得了.

出0入0汤圆

发表于 2007-10-16 13:25:59 | 显示全部楼层
没说你不能用中断!你就是套10层中断也没什么稀奇的。什么是实时,什么是多任务,这不是等价的。用一个8M的AVR去采集一个1MHZ的波形,同时还要输出50Hz的正弦波,你能在所谓的系统中用中断完成吗?

出0入0汤圆

发表于 2007-10-16 13:47:32 | 显示全部楼层
我的意思是说:
任务的实时性并不等同系统的实时性。系统实时性由任务实时性和中断实时性共同作用。非抢占式系统实时性差,只是基于任务实时性差说的。不能只谈到任务实时性差,就把整个系统的实时性完全否决掉。

出0入0汤圆

 楼主| 发表于 2007-10-16 14:14:18 | 显示全部楼层
转21IC的一遍文章 让大家看看,大家觉得这样做能不能实现 实时多任务 的实时响应??

            《一种基于C51的多任务机制及应用》                        
        来源:电子设计应用  作者:厦门大学 王辉堂 颜自勇 陈文芗

本文介绍了一种在MCS51单片机程序中实现多任务机制的简单方法,并给出了源代码和一个应用实例。通过中断进行实时任务切换,具有结构简单清晰、代码量少、不需使用汇编等优点。该方法亦可应用于其他单片机系统。
关键词:多任务系统 单片机 C51  中断 安防系统


引言
    传统的单片机程序一般采用单任务机制,单任务系统具有简单直观、易于控制的优点。然而由于程序只能按顺序依次执行,缺乏灵活性,只能使用中断函数实时地处理一些较短的任务,在较复杂的应用中使用极为不便。嵌入式多任务操作系统的出现解决了这个问题。在多任务系统中,可以同时执行多个并行任务,任务之间可以相互跳转。但是嵌入式操作系统在提供强大功能的同时,也带来了代码量大、结构复杂、对硬件要求较高、开发难度大且成本高等问题。而很多时候只需要实现简单的多任务操作就可以满足实际需要,本文设计的这种简单的多任务机制,在只增加极少量C语言代码的前提下,不需使用汇编,无需对原本的程序进行大改动,就可以实现多任务操作。

     实时操作系统RTOS的核心是中断,利用中断进行任务切换。在大部分RTOS如μC/OS-II中,每个任务都有自己的堆栈,用来保存任务的一些信息,任务之间通过信号量、邮箱、消息队列等传递信息。在很多情况下并不需要这些功能,只需要使单片机在接收到控制信号后,切换到不同的工作状态,也就是只要进行任务切换,不需要保存任务的相关信息。舍弃这些复杂的功能可以使程序结构变得简洁易用。

两种机制在应用实例中的比较
    下面用一个应用实例来说明本设计的思路。要设计一个智能安防系统,它的功能包括:当有人入侵时执行报警工作;用户可以通过键盘板进行功能设置;主板能与管理中心进行通讯,当发生火灾、地震等灾情时,管理中心能通知用户。其结构如图1所示。平时状态下,主板的CPU不断地扫描各个传感器的状态。当检测到传感器的异常信号(有人闯入)时,CPU进入入侵报警状态,执行响警铃、拨打户主电话、通知管理中心等工作。当发生火灾地震时,管理中心发送一个串口代码给主板CPU,使CPU进入灾难报警状态,执行响警铃、语音报警等操作。用户需要进行功能设置时可以通过键盘板使主板CPU进入功能设置状态。因此主板的CPU有4种不同的工作状态。



图1  智能安防系统结构示意图

    如果采用单任务机制, 主板的程序流程如图2所示。在主函数中循环检测传感器状态,如有异常则调用报警函数,灾难报警和功能设置在串口中断中完成。这种单任务结构有两个缺点。首先,在各种非平时状态中,程序需要不停地检测是否收到撤除信号,这个要求在程序代码量大、执行工作较多的情况下很难实现。其次,各状态之间的切换十分困难,用C语言写的程序为求模块化,一般函数数量较多,函数调用的嵌套层数也多,要从一个较深的嵌套立刻跳出到主函数,是非常困难的。一般的解决方法或是使用C51的库函数setjmp()和longjmp()实现长跳转,但是这两个函数在中断函数内部是无能为力的;再或是在C函数中嵌入汇编指令。虽然用汇编指令可以实现程序的长距离跳转,但是这种方法的调试过程十分烦琐,而且程序的可移植性差。对于习惯用C51编程而不想用汇编的设计者,该部分程序是一个难题。


图2  单任务机制程序流程

实现多任务机制的程序结构
    本文提供了一种方法,可以在完全不使用汇编指令的前提下实现可移植性强的多任务程序,程序流程如图3所示。


图3  多任务结构程序流程

    实现这个多任务机制的完整源代码如下:
word idata PC_Value, SP_Value;     file://储存中断返回点、SP初值的全局变量
byte idata Ctrl_Code;               file://控制任务切换的全局变量,在中断函数里被赋值
void main()               
{
Initial();          file://初始化函数,与程序结构无关
SP_Value=SP;        file://获取SP的初始值
    PC_Value=Get_Next_PC();             file://获取下一条指令的地址
EA=1;          file://获取PC、SP初值后再开中断保证稳定性
if(Ctrl_Code!=0)
    SP=SP_Value;         file://重置堆栈指针,防止堆栈溢出
    switch( Ctrl_Code)        file://任务入口地址,即中断的返回点
{
  case 1:   goto  TASK1;
  case 2:   goto  TASK2;
  case 3:   goto  TASK3;
  default:  break;
}
TASK1:  for( ; ; )
        {          file://任务1代码        }
TASK2:  for( ; ; )
        {          file://任务2代码        }
TASK3:  for( ; ; )
        {          file://任务2代码        }
}
word Get_Next_PC(void)     file://获取下一条指令的地址
{
  word address;
  address=*((unsigned char *)SP);    file://PC的高字节
  address <<= 8;
  address+=*((unsigned char *)(SP-1));  file://PC的低字节
  return address+4;       file://查看反汇编代码,计算所得
}
void Chuan_Kou_Interrupt(void) interrupt 4 using 0
{
    byte a1,a2;
a1=a1*a2;
*((unsigned char *)(SP-5))=PC_Value>>8;
*((unsigned char *)(SP-6))=PC_Value & 0x00ff;
{
     file://接收串口代码并根据代码修改Ctrl_Code的值
  file://其他操作
}
}

任务调度原理与实现
    程序的整体思路是在主函数main中依次放置几个死循环作为任务框架,即每个任务都是一个死循环,利用中断进行任务切换。以刚才所说的安防系统为例,由于主板、键盘、管理中心之间是通过串口通讯的,因此串口是用来触发任务切换的理想中断源。程序为所有任务设置一个总入口并放在主函数中,串口中断每次返回时必须先经过这个总入口,在总入口处检查任务控制变量(全局变量)的值,任务控制变量已在串口中断中被赋值,其值决定要切换到哪个任务。

  设计中可以把平时状态、入侵报警状态、危机报警状态、功能设置状态分别作为任务1、任务2、任务3、任务4。主板CPU平常工作在平时状态,即任务1;当串口收到管理中心的危机代码,在串口中断函数中令Ctrl_Code = 3,中断返回后会切换到任务3;同样,接收到键盘的功能设置代码后,会切换到任务4;由于入侵检测是由主板CPU自己负责,因此如果检测到有人入侵需要切换到入侵报警状态时,可以借由键盘中转产生串口中断,即向键盘发送一串口数据并要求键盘回送。这样就实现了各个状态的切换。

  实现任务调度需要解决3个关键问题:

  ① 获取任务入口点的程序地址。由于使用C语言不能直接获取和修改程序计数器PC的值,而在调用函数时会将PC值入栈,利用这个特点在任务入口处之前调用Get_Next_PC函数即可从堆栈中获得入口地址。Get_Next_PC中,SP为堆栈指针,得到的PC值要加4才是任务入口地址,因为查看反汇编窗口可知,将函数返回值传给全局变量PC_Value需要两条2字节长的mov指令。

    ② 修改中断返回地址。修改中断返回地址的操作与获取PC值类似,都是通过修改堆栈中的内容实现。但是由于编译器自身的特点,在进入中断时,编译器除了把返回地址入栈外,还会计算自身及它所调用的函数对寄存器ACC、 B、 DPH、 DPL、 PSW、 R0 ~ R7的改变,并将它认为被改变了的寄存器也入栈保护。如果堆栈结构会随中断函数内容改变而变化,就没办法计算中断返回地址堆栈中的位置。解决方法是,在中断函数定义时加上关键字using 0 告诉编译器中断函数及其调用的函数将使用寄存器组0,这样工作寄存器R0~R7将不会被保存。ACC、PSW、DPH、DPL在对PC_Value操作时已经用到,在中断函数开头定义两个变量a1、b1并令它们相乘,使B寄存器也被入栈,这样堆栈的结构就是固定的了。

   ③防止堆栈溢出。由于在调用函数时编译器会将当前地址入栈,返回时再出栈,当任务切换即中断多次发生在函数调用过程中时,堆栈会因为只入不出而最终导致溢出。这是不能容许的。因此,应在主函数开头初始化后立刻将SP值保存,再在每次任务切换后都将SP恢复为初值,这可以有效防止堆栈溢出。

结语
  根据以上的比较与分析可以看出这种实现多任务机制的方法具有如下优点:与采用单任务机制的程序相比,其结构简单清晰,易于控制;利用中断和堆栈实现任务切换时的长跳转,完全不需使用汇编语言,可移植性强;增加的代码量极小,实时性好,节省程序开发时间。

    以上介绍的方法已经通过测试并应用于几个实际项目中,包括智能小区安防系统、汽车CAN总线控制系统等,取得了良好效果。只要根据具体的硬件与编译环境稍作修改,亦可应用于其他的单片机系统中。

参考文献
1. 张培仁. 基于C语言编程MCS-51单片机原理与应用. 北京:清华大学出版社, 2003.1.
2. 胡大可等. 基于单片机8051的嵌入式开发指南. 北京:电子工业出版社, 2003.1




问题:1:当正在执行一个任务,中断到来后,转到另一个任务,这样每转到一个新任务,好像是从新任务的开始的地方开始执行,而不是从原来跳转的地方开始执行,这样好像不对,请大家执导一下吧。

出0入0汤圆

发表于 2007-10-16 14:38:26 | 显示全部楼层
没有保存函数断点数据,不能从断点继续执行。如果采用某种方法强制使程序从断点继续执行,后面的程序执行结果也是错误的。

个人认为这种调度方法其实一点都不好。


采用这种调度方法会更好。

节拍中断:任务等待节拍数减1,如果为0,使任务就绪。

主循环:while(1){如果有任务就绪,执行任务;}//任务是一个普通函数,不是无限循环


建议楼主去看下usmartx的代码,稍加裁减,完全可以在SRAM只有256字节的单片机上运行的很好。

出0入0汤圆

 楼主| 发表于 2007-10-16 15:09:20 | 显示全部楼层
在论坛搜索了一下usmartx,发现全都是【12楼】ATmega32发的贴子,
看来ATmega32用usmartx用的很好啊

出0入0汤圆

发表于 2007-10-16 17:14:20 | 显示全部楼层
希望ATmega32再多介绍一些usmartx的细节

出0入0汤圆

发表于 2007-10-16 17:49:06 | 显示全部楼层
对啊,我也想多了解一下Usmartx

出0入0汤圆

发表于 2007-10-16 17:58:26 | 显示全部楼层
为什么高技术的大侠们心态都这么不平和呢?

出0入0汤圆

发表于 2007-10-16 18:01:35 | 显示全部楼层
平时多受压抑,好不容易逮到能NB一下的机会有点搂不住

出0入0汤圆

发表于 2007-10-16 20:44:29 | 显示全部楼层
上次有人发过一本书说的是51上面的时间触发系统。可以借鉴一下。RTOS也没有说任务必须象中断那样及时,而是说任务必须在规定时间内做完。实时是相对的。

出0入0汤圆

发表于 2010-7-22 21:28:53 | 显示全部楼层
谢谢各位DX学习了

出0入0汤圆

发表于 2011-1-17 14:30:58 | 显示全部楼层
记号 3楼嘅回复 “用step方式.其实就是二楼说的方式,状态机”。

出0入0汤圆

发表于 2011-1-17 16:20:46 | 显示全部楼层
回复【11楼】mmclyy
-----------------------------------------------------------------------

不是多任务吧,像是状态机,不过状态机也不用那么复杂

出0入0汤圆

发表于 2011-1-17 16:36:59 | 显示全部楼层
状态机是单任务的!~

出0入0汤圆

发表于 2011-1-17 18:48:18 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-1-17 20:09:11 | 显示全部楼层
高手如林。受教了。谢谢!

出0入0汤圆

发表于 2011-1-17 20:12:00 | 显示全部楼层
实时多任务,还真没接触过Mark

出0入0汤圆

发表于 2011-2-6 19:06:24 | 显示全部楼层
mark

出0入264汤圆

发表于 2011-2-6 22:44:34 | 显示全部楼层
学习

出0入0汤圆

发表于 2011-2-7 09:45:45 | 显示全部楼层
个人觉得Small RTOS不错!

出0入0汤圆

发表于 2011-2-7 11:26:59 | 显示全部楼层
用protothreads,很好用的。

出0入0汤圆

发表于 2011-10-25 22:10:16 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-10-25 23:09:38 | 显示全部楼层
开个定时中断,在定时中断中刷新标志位就可以了

出0入0汤圆

发表于 2011-10-28 15:52:13 | 显示全部楼层
ATmega32好像是在胡说吧,
不支持任务抢断实时性从何而来?前后台和实时任务是一个概念?
举列说明:WIN7实行性够差了吧,但是当你的软件“死”时,你用ALT+CTRL+DEL,不是可以抢断么?像Vxworks,ucos等都是!
实时任务其实就和ALT+CTRL+DEL一样!说什么这个慢一点,整个不会差,就是强词夺理了!

出0入0汤圆

发表于 2011-10-28 16:36:01 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-10-29 15:02:48 | 显示全部楼层
0000

出0入0汤圆

发表于 2011-11-9 14:30:10 | 显示全部楼层
O_O

出0入0汤圆

发表于 2012-3-30 19:53:24 | 显示全部楼层
我认为不能把问题讲的深入浅出的都难称高手,等我学完后,我会回来的

出0入0汤圆

发表于 2012-3-30 20:29:04 | 显示全部楼层
买过Small RTOS的书,作者陈明计。但没用过。keil的tiny51倒是用过。

出0入0汤圆

发表于 2012-4-3 13:33:24 | 显示全部楼层
值得研究

出0入0汤圆

发表于 2012-4-3 14:06:58 | 显示全部楼层
round robin 喽~ 最实用的

出0入0汤圆

发表于 2012-4-3 14:39:52 | 显示全部楼层
讨论的精彩。

出0入0汤圆

发表于 2012-6-18 16:36:52 | 显示全部楼层
RTOS

出50入0汤圆

发表于 2013-4-4 10:59:34 | 显示全部楼层
rainyss 发表于 2007-10-16 11:53
用step方式.其实就是二楼说的方式,状态机.

原理是:函数执行时不是一次就完成所有功能,而是只执行一部分功 ...

楼主能否再解释一下这种思路的优越性啊,谢谢。

出0入0汤圆

发表于 2013-4-4 11:23:02 来自手机 | 显示全部楼层
qp量子架构…

出0入0汤圆

发表于 2013-4-4 11:38:32 | 显示全部楼层
261854681 发表于 2013-4-4 10:59
楼主能否再解释一下这种思路的优越性啊,谢谢。

stm32F051c6xx上用过这种思路,下面是我写的18b20.h中的主要部分函数,使用过效果还是不错的,优点是将原本一次需要20毫秒左右执行一次的函数分成若干个1毫秒左右的片段去执行,大大降低因为18b20的使用而给主程序体其它部分带来的阻塞效果,提高其它部分的实时性

//CRC校验,查表法
uchar CRC_OK1(uchar *p1,uchar num)
{
    uchar OutData1;
    uchar countbyte1;
                 OutData1=0;
                 num++;
         for(countbyte1=1;countbyte1<num;countbyte1++)
          {
             OutData1=CrcTable[OutData1^*p1];
                  p1++;
          }
        p1-=(num-1);
   return(OutData1);
}

//往DS18B20中写一个字节
static void Write_18B20(unsigned char n)
{
    unsigned char i;
    for(i=0;i<8;i++)
    {
        //P4DIR|=0X20;
        SetDir_PA2_Out();
        DQ0;
   
        _NOP();_NOP();                           //==延时5us===
        _NOP();_NOP();_NOP();
        if((n&0X01)==0X01)
        DQ1;
        else DQ0;
        n=n>>1;
        Cnt_Ruler1=0;
       //delay_us(300);                             //==延时50us 以上===
       delay_10us(7);
        DQ1;
    }
}

//从DS18B20读取一个字节
static unsigned char Read_18B20(void)
{
    unsigned char i;
    unsigned char temp;
    for(i=0;i<8;i++)
    {
        temp=temp>>1;
        //P4DIR|=0X20;
        SetDir_PA2_Out();
        DQ0;
        _NOP();                               //==延时1us===
        DQ1;
        _NOP();_NOP();                           //==延时5us===
        _NOP();_NOP();_NOP();
        //P4DIR&=~0x20;
        SetDir_PA2_IN();
        if(Get_Status_PA2()!=SET)
        {
            temp=temp&0x7F;
        }else
        {
            temp=temp|0x80;
        }
        //delay_us(200);                             //==延时40us===
        delay_10us(5);
        //P4DIR|=0x20;
        SetDir_PA2_Out();
        DQ1;
    }
    return    temp;
}

//18B20总线初始化
static void Init (void)
{
        static uchar Step=0;
          if(((Phase==1)||(Phase==4))&&(Step==0))  Step=1;
          if(Step==1)         {   SetDir_PA2_Out();  DQ0;   Step=2;  PhaseTicket=60; }    //低电平600uS
          if(Step==2)         {   if(PhaseTicket==0)  Step=3;  }       
    if(Step==3)         {   DQ1;    delay_10us(3);   SetDir_PA2_IN(); Step=4;   }    //==延时16~60us==============
    if(Step==4)
      {                              
                            if(Get_Status_PA2()==SET)                        //==0001 1111b=1f  ===========
                            {
                                if(Error<8) Error++;                               //==失败1=====================
                                SetDir_PA2_Out();
                                DQ0;
                            }
                           else
                            {
                                SetDir_PA2_Out();
                                DQ1;
                            }
                           Step=5;    PhaseTicket=48;
       }
     if(Step==5)   {  if(PhaseTicket==0)  {  Step=0; Phase++;  }    }   
}

//18B20跳过内部ROM匹配
static void Skip(void)
{
    Write_18B20(0xcc);
}

//启动18B20温度转换
static void Convert (void)
{
    Write_18B20(0x44);
}

//发送读取18B20寄存器指令
static void ReadDo (void)
{
    Write_18B20(0xbe);
}

//设置DS18B20测温分辨率和转换时间
void SetPar18B20(void)
{
    Init();
    Write_18B20(0xCC); // 跳过读序号列号的操作
    Write_18B20(0x4E); // 设置参数寄存器
    Write_18B20(0x00); // TH
    Write_18B20(0x00); // TL
    Write_18B20(0x3F); // 设置参数寄存器
}

//传感器出错后返回100度,Error=8,传感器测得温度低于零下25度时返回100度,Error=0;
static void ReadTemp (void)
{
    static char temp_low,temp_high;                     //== 温度值 =====
    unsigned int temperature;
    static uchar ReadTStep=0;

    if(ReadTStep==10)
            {
                           if((((temp_high*256)+temp_low)&0x8000)==0x8000)
                            {
                              temperature=~((temp_high*256)+temp_low)+1;
                              BoxTPol=1;
                            }
                           else
                                   {
                             temperature=(temp_high*256+temp_low);
                             BoxTPol=0;
                            }
                       
                           if(Buf18B20A[4]==0xff)  temperature<<=3;      //DS18S20时测得的数据要左移三位
                       
                           if((Buf18B20A[5]!=0xff)||CRC_OK1(Buf18B20A,9))
                                    {   
                                 if(Error<8) Error++; else  {CurT=1600;  BoxTPol=0;     }
                                    }
                                   else
                             {
                                 if(Error>0) Error--;
                                 CurT=temperature;
                                 if(BoxTPol==1)
                                   {
                                             if((LastTPol==0)&&(EverTPol==0))  { if(CurT>50) { CurT=LastT; BoxTPol=0; }   }  //去除突发干扰
                                                     else
                                                             {
                                            if(CurT<=400) {  CurT=0; BoxTPol=0;    }     //-25度-0度时强制读取值为0度
                                              else { CurT=1600;  BoxTPol=0;     }        //低于零下25度时置读取值为100度(强制关闭加热)
                                          }
                                   }
                                 if(CurT<10)  BoxTPol=0;
                                 EverT=LastT;
                                 EverTPol=LastTPol;
                                 LastT=CurT;
                                 LastTPol=BoxTPol;
                             }
                            ReadTStep=0;  Phase++;
                  }
    if(ReadTStep==9) { Buf18B20A[8]=Read_18B20();  ReadTStep=10;   }
    if(ReadTStep==8) { Buf18B20A[7]=Read_18B20();  ReadTStep=9;    }  
    if(ReadTStep==7) { Buf18B20A[6]=Read_18B20();  ReadTStep=8;    }
    if(ReadTStep==6) { Buf18B20A[5]=Read_18B20();  ReadTStep=7;    }
    if(ReadTStep==5) { Buf18B20A[4]=Read_18B20();  ReadTStep=6;    }
    if(ReadTStep==4) { Buf18B20A[3]=Read_18B20();  ReadTStep=5;    }
    if(ReadTStep==3) { Buf18B20A[2]=Read_18B20();  ReadTStep=4;    }               
    if(ReadTStep==1) { Buf18B20A[0]=Read_18B20(); temp_low=Buf18B20A[0];  ReadTStep=2;  }    //== 读低位 =====
    if(ReadTStep==2) { Buf18B20A[1]=Read_18B20(); temp_high=Buf18B20A[1]; ReadTStep=3;  }    //== 读高位 =====
    if((Phase==7)&&(ReadTStep==0))   ReadTStep=1;
}

//=======================================================================================
//============获取DS18B20的温度值========================================================
//=======================================================================================
//===  MCU对DS18B20进行温度转换时,其操作必须满足以下过程:
//===  1- 每一次读写之前都要对DS18B20进行复位.
//===  2- 完成复位后发送一条ROM命令到DS18B20.
//===  3- 最后发送一条RAM命令到DS18B20.
void TConvertStart(void)
{
   if(Phase==3)   { Convert();  Phase=4;     }        //=== 转换(RAM命令)===
   if(Phase==2)   { Skip();     Phase=3;     }        //=== 跳过64位ROM(ROM命令)===
   if(Phase==1)     Init();                           //=== DS1820初始化===
   if(Phase==0)     Phase=1;                          //首次进入
}

uchar  GetBoxTemp(void)
{
   if(Phase==7)   {  ReadTemp();              }        //=== 读取温度值===
   if(Phase==6)   {  ReadDo();  Phase=7;      }        //=== 读暂存器===
   if(Phase==5)   {  Skip();    Phase=6;      }        //=== 跳过64位ROM===
   if(Phase==4)      Init();                           //=== DS1820初始化===
   if(Phase==8)   {  Phase=0; return(Error);  }
}

出50入0汤圆

发表于 2013-4-4 12:21:17 来自手机 | 显示全部楼层
谢谢楼主,恕我菜鸟,已理解.

出0入0汤圆

发表于 2013-4-6 17:33:24 | 显示全部楼层
技术帖看起来很过瘾。似乎都是在C的层次上讨论?其实从汇编的角度来看操作系统,也许更透彻呢。

出0入0汤圆

发表于 2013-4-6 18:20:27 来自手机 | 显示全部楼层
我觉得单片机跑一个时间调度器,效率也很高啊~

出0入0汤圆

发表于 2013-4-6 18:33:32 | 显示全部楼层
avruser 发表于 2007-10-16 18:01
平时多受压抑,好不容易逮到能NB一下的机会有点搂不住

嘿嘿,太逗了...

出0入0汤圆

发表于 2014-2-21 09:59:12 | 显示全部楼层
很有见解

出0入0汤圆

发表于 2014-2-26 16:33:50 | 显示全部楼层
不用OS就要用定时器来处理,实时性可能做不完美

出0入0汤圆

发表于 2014-2-26 16:39:08 | 显示全部楼层
RTOS是可以剪裁的,你把信号量,邮箱等都删除的话,占用不了多少。自己写其实最终也是实现一个多任务的OS内核而已。

出0入0汤圆

发表于 2014-2-26 22:26:45 | 显示全部楼层
rainyss 发表于 2007-10-16 11:53
用step方式.其实就是二楼说的方式,状态机.

原理是:函数执行时不是一次就完成所有功能,而是只执行一部分功 ...

if(step == 20){
   }
//以上这个Step永远没执行
   step++;

出0入0汤圆

发表于 2014-4-6 23:33:18 | 显示全部楼层
看看                     
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-21 03:19

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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