huyugv_830913 发表于 2008-5-29 23:52:54

由一个长延时想到了程序结构(ATmega128+ICCAVR)【原理篇】[实战篇将讲述基于GPRS无

/******************************************************************************
函数说明: 任务1,LED闪烁(0.5s亮,0.5S灭)
函数实现: 采用状态机的方法实现
#define    LED_INIT       0
#define    LED_ON         1    //LED任务的定义
#define    LED_OFF      2

-------------------------------------------------------------------------------
时间:2008-05-29
作者:胡玉贵
说明:在数据采集仪的设计过程中用到长延时,可能要延时1~10S的时间。如果编写一个简
      单的延时函数系统的响应将是不能忍受的,所以只能考虑采用其他的办法实现很长的
          延时。
          办法1:采用uCosII这样的操作系统,应为有任务的调度,所以实时性的延时很容易实
                 现。
                       任务函数()
                       {
                             系统的延时函数(延时时间);//任务被挂起,直到延时时间到达
                               执行函数();
                       }
                       方法是很好的,我也研究了一段时间,但是网上能用的CODE(ucosII ON m128
                       ICCAVR)没有。****再加上我的系统实时性不是要求那么高,只要能避免很长
                       时间的延时函数就行。***
                       
       办法2:没有uCOSII那样的实时调度,调度采用主函数中的while(1)实现
                声明的几点:系统的实时性不要求非常高的,因此短的延时函数保留,大于100ms
                        的延时采用状态机实现
                       
                        eg:以LEDTask为例,任务有两个状态,ON和OFF,ON-》OFF的延时为500ms,OFF
                        -》ON的延时同样为500ms。如果采用一般的延时函数MCU基本可以不用干其他
                        事了。***用定时器+状态机很好的解决了这个问题***
                       
                        步骤1:为函数定义一个全局的延时变量G_delaytime;
                        步骤2:初始化定时器,这里以25ms为中断对G_delaytime减一处理,当为0是延时
                             时间到
                        步骤3:分析函数的状态,一般多建一个初始化状态,此状态只运行一次。          
                                                                             
******************************************************************************/
void LEDTask(void)
{
    static unsigned char ledstate;//LEDTask函数的状态变量,控制LED的变化
        switch(ledstate)
        {
          case LED_INIT://led任务初始化状态
                  PORTB&=~BIT(0);
                        G_delaytime=20;//打开延时这里是关键
                        ledstate=LED_ON;//状态的转变
                        break;
                case LED_ON:
                  if(G_delaytime==0)//等待延时的结束,此时延时已经用定时器实现,25ms减一,20个单位=25×20=500ms
                        {
                        PORTB|=BIT(0);
                        G_delaytime=20;
                                ledstate=LED_OFF;
                        }       
                  break;
                case LED_OFF:
                  if(G_delaytime==0)
                        {
                        PORTB&=~BIT(0);
                        G_delaytime=20;
                          ledstate=LED_ON;
                        }       
                  break;       
                default :break;
        }
}


点击此处下载 ourdev_296796.rar(文件大小:125K) (原文件名:Multask.rar)

huyugv_830913 发表于 2008-5-29 23:54:29

//TIMER1 initialize - prescale:8
// WGM: 4) CTC, TOP=OCRnA
// desired value: 25mSec
// actual value: 25.000mSec (0.0%)
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCNT1H = 0x79; //setup
TCNT1L = 0x02;
OCR1AH = 0x86;
OCR1AL = 0xFE;
OCR1BH = 0x86;
OCR1BL = 0xFE;
OCR1CH = 0x86;
OCR1CL = 0xFE;
ICR1H= 0x86;
ICR1L= 0xFE;
TCCR1A = 0x00;
TCCR1B = 0x0A; //start Timer
}

#pragma interrupt_handler timer1_compa_isr:13
void timer1_compa_isr(void)
{
//compare occured TCNT1=OCR1A
unsigned char i;
for(i=0;i<MAX_TASK_NUM;i++)
{
   if(G_delaytime>0)
             G_delaytime--;
}
}

huyugv_830913 发表于 2008-5-29 23:55:54

程序的运行效果:http://cache.amobbs.com/bbs_upload782111/files_10/ourdev_296795.JPG
串口任务+LED (原文件名:p.JPG)

Etual 发表于 2008-5-30 08:39:49

顶一下,建议新手学学,这个东西很有用。

cheungman 发表于 2009-4-22 12:04:16

个人喜欢这样来做

volatile unsigned long tick;

//Timer4中断,25MS
void __T4_ISR _T4Interrupt(void)
{
    tick++;                                       
    IFS1bits.T4IF = 0;
}

void LEDTask(void)
{
    static unsigned char ledstate;//LEDTask函数的状态变量,控制LED的变化
    static unsigned long count;
      switch(ledstate)
      {
            case LED_INIT://led任务初始化状态
                  PORTB&=~BIT(0);
                        count = tick;   //打开延时这里是关键
                        ledstate=LED_ON;//状态的转变
                        break;
                case LED_ON:
                  if((tick - count) >= 20)
                        {
                        PORTB|=BIT(0);
                        count = 0;
                              ledstate=LED_OFF;
                        }         
                  break;
                case LED_OFF:
                  if((tick - count) >= 20)
                        {
                        PORTB&=~BIT(0);
                        count = 0;
                            ledstate=LED_ON;
                        }         
                  break;         
                default :break;
      }
}

wear778899 发表于 2009-4-27 10:55:54

收藏了!

谢谢!

ql-dz.com 发表于 2009-4-27 18:32:26

学学...

xyq4513 发表于 2009-5-9 22:14:49

Mark

Gvinnar 发表于 2009-5-11 20:02:55

类似项目,顶一下

youlingfeng11 发表于 2009-6-11 12:34:56

LZ
你的"实战篇将讲述基于GPRS无线模块的数据透明传输“
都一年半了还没出来啊

END12345678 发表于 2009-6-11 14:20:48

我也来看看,希望早日看到

unnormal 发表于 2011-7-7 06:31:16

以后慢慢学谢谢

ufbycd 发表于 2011-7-7 08:56:57

这其实就是协同式多任务的写法。协同式通常都用状态机。

ScorpioTiger 发表于 2011-7-17 21:22:02

透传好还是非透传好呢?还没弄明白

loveskangaroo 发表于 2011-7-21 14:34:57

mark

Free_Bird 发表于 2012-8-12 22:16:53

挖坟,谢谢楼主

lklhzu 发表于 2013-3-29 13:52:33

也来学习下!

liuanty7 发表于 2013-6-20 11:35:27

学习了。。。

ZYBing 发表于 2013-7-20 21:45:20

mark......

loneress 发表于 2013-7-20 21:47:57

这么长时间的延时,我觉得sleep好一点,省电。

张大佳MCU 发表于 2016-7-13 22:15:58

赞赞赞,下载的看看是不是

张大佳MCU 发表于 2016-7-13 22:16:14

赞赞赞,下载的看看是不是
页: [1]
查看完整版本: 由一个长延时想到了程序结构(ATmega128+ICCAVR)【原理篇】[实战篇将讲述基于GPRS无