打印

更好的软件延时方式

[复制链接]
3067|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
工控秀才|  楼主 | 2009-4-3 12:01 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
如下**:
最近常在网络上看一些朋友在讨论如何做软件延时,有用C的,也有用ASM的.

作为个人而言,我一般不喜欢软件延时的,特别是在单核心的单片机系统中.想想看

即使是1MIPS的MCU执行速率,1ms的时间,系统就可以跑1000条指令呀,可以检测

多少个需要处理的信号.但是由于软件延时处理起来比较方便一点,所以一直还受多数人的追捧.

        首先,我们这里讲的软件延时是指把MCU几乎当下来,什么事情都不处理,只是简单

的在一个延时LOOP中循环,知道需要的时间到后,才跳出循环.从这里,我们就可以看出软件

延时的优缺点了.软件延时的优点是,在不计较中断的影响下,只要指令周期计算得很精准

延时的精度也会很高,而且处理十分方便.它的缺点就是,在延时过程中,会忽略一些输入信号的处理.

造成处理的时实性不是很好.

       为了实现精准的延时,你必须要弄清楚2个问题: 1是你使用的MCU的指令执行速度是多少,即指令周期,2是每一个指令执行需要多少个指令执行周期.比如你使用传统的51,一个NOP

指令需要2个指令周期,当你使用12M的外部晶体是,指令周期刚好是1us,所以这个NOP就需要

2us的时间来执行.

          例如我们在模拟IIC通信时,为了运行可靠,需要在改变IO状态后延时10us左右,再改变时钟信号线.

           这里,我们往往是使用一长串NOP指令,5个,或者更多。所以当一些朋友使用了我们的多核心

IC后,就幽默的说,其实那样的NOP串真的很不环保.因为在我们的系统中,延时10个指令周期,

也可以简单的写成DELAY 9,这是真正的原指令,并非一个虎人的宏指令,因为它绝对只需要你一

条指令占有的空间就可以存储了.

       我不谈别人怎么去实现1ms的延时了,我用我的系统写给你看看,指令周期还是1us,都知道,需要

1000个指令周期啦.

        好办得很:

         delay_1ms:

                           delay 249        ;延时250

                           delay 249

                           delay 249

                           delay 248

                            ret                ;此返回指令需要一个指令周期,所以上面少执行一个,多好配合呀,哈哈.

             如果要延时长一点,那也加几个回圈, 看看我的循环,仔细体会一下吧,先忙其它的去了.

delay_n100ms:
        mov    temp00, a
delay_n100ms_loop:        
        mov    a, 250
        mov    temp01, a  ;250 *800
        delay  249
        delay  249
        delay  249
        delay  47
        dzsn   temp01
        goto   $-5
        ;
        dzsn   temp00
        goto   delay_n100ms_loop
        ret   
;--------------------------------------------------------
delay_n10ms:
        mov    temp00, a
delay_n10ms_loop:        
        mov    a,80        
        mov    temp01, a ;250*
        delay  247
        dzsn   temp01
        goto   $-2
        dzsn   temp00
        goto   delay_n10ms_loop
        ret            

相关链接:http://http://www.gkbk.com/more.asp?name=gongkong&id=83211

相关帖子

沙发
songbangyan| | 2009-4-3 16:56 | 只看该作者

没看出来什么意思!

使用特权

评论回复
板凳
zq1987731| | 2009-4-3 18:35 | 只看该作者

定时器延时才是王道

    这类死机式的软件延时本人觉得拿来教学没什么问题,真正应用的话就是极大程度得浪费MCU的资源!
    试想一下,通过计算指令周期得到的“精确的延时”,拿来何用?难道指望用这东西来做RTC?何况“精确的延时”必有一个大前提,就是延时中不得有任何中断发生,不然谈不上所谓的“精确”!
    在51上,难免因为外设资源缺乏,IIC、SPI甚至单总线等等均要靠IO口模拟,所以不得不加上些NOP,这也是没办法的事,但好多人在诸如按键处理上都要使用“超高精度”的delayms(10);这就显得很没道理了,通过定时器设置时基然后用状态机扫描键盘法,几乎无额外时间损失,况且有“定时器复用”这么个小手法,也谈不上什么定时器资源不够的问题,何乐而不为呢?此外..论“精确”,定时器延时的精度难道会比死机式的差?
    而在外设齐全的ARM上还用软件延时的话,那就很浪费了,因为有硬件支持的总线接口基本上都有中断收发模式,所以连NOP都可省掉,毕竟全扔给硬件自动解决了。

使用特权

评论回复
地板
stm32f100| | 2009-4-3 19:02 | 只看该作者

IAR,GCC直接调用库延时函数

AVRIAR直接__delay_cycles,精确到时钟周期,

AVRGCC:

void 
_delay_loop_1(uint8_t __count) 

        __asm__ volatile ( 
                "1: dec %0" " " 
                "brne 1b" 
                : "=r" (__count) 
                : "0" (__count) 
        ); 


准确延时是3*__count个时钟周期         (0<__count<256) 

void 
_delay_loop_2(uint16_t __count) 

        __asm__ volatile ( 
                "1: sbiw %0,1" " " 
                "brne 1b" 
                : "=w" (__count) 
                : "0" (__count) 
        ); 


准确延时是4*__count+1个时钟周期        (0<__count<256*256-1) 


_delay_loop_1() 最小延时是3个时钟周期,最大延时是256*3个时钟周期 

_delay_loop_2() 最小延时是4+1个时钟周期,最大延时是256*256*4+1个时钟周期 


void 
_delay_us(double __us) 

        uint8_t __ticks; 
        double __tmp = ((F_CPU) / 3e6) * __us; 
        if (__tmp < 1.0) 
                __ticks = 1; 
        else if (__tmp > 255) 
        { 
                _delay_ms(__us / 1000.0); 
                return; 
        } 
        else 
                __ticks = (uint8_t)__tmp; 
        _delay_loop_1(__ticks); 


void 
_delay_ms(double __ms) 

        uint16_t __ticks; 
        double __tmp = ((F_CPU) / 4e3) * __ms; 
        if (__tmp < 1.0) 
                __ticks = 1; 
        else if (__tmp > 65535) 
        { 
                //        __ticks = requested delay in 1/10 ms 
                __ticks = (uint16_t) (__ms * 10.0); 
                while(__ticks) 
                { 
                        // wait 1/10 ms 
                        _delay_loop_2(((F_CPU) / 4e3) / 10); 
                        __ticks --; 
                } 
                return; 
        } 
        else 
                __ticks = (uint16_t)__tmp; 
        _delay_loop_2(__ticks); 


_dealy_us()最小延时 与 _delay_loop_1()相同,是3个时钟周期, 
_delay_us(0)就是最小延时,相当于_delay_loop_1(1), 
在8M时钟下,_delay_us(0.375)也是最小延时(0.375us是3个时钟周期) 
_delay_us(0.7499999)仍然是最小延时,相当于_delay_loop_1(1), 
而_delay_us(0.74999999)则相当于_delay_loop_1(2)了。 


_dealy_ms() 最小延时与 _delay_loop_2()相同,是4+1个时钟周期。 
_delay_ms(0)就是最小延时,相当于_delay_loop_2(1), 
在8M时钟下,_delay_ms(0.0005)也是最小延时(0.0005ms相当于是4个时钟周期) 
_delay_ms(0.0009999999)仍然是最小延时,相当于_delay_loop_2(1), 
而_delay_ms(0.00099999999)则相当于_delay_loop_2(2)了。 


_dealy_us(__us)延时精度范围: 
(0 , 3个时钟周期),误差(0,3)个时钟周期 
(3个时钟周期 , 768us/(F_CPU/1000000)),误差(-2,0)个时钟周期 
(768us/(F_CPU/1000000) , 262.14ms/(F_CPU/1000000)),误差(-2,+1)个时钟周期, 
(262.14ms/(F_CPU/1000000)) , 6553.5ms),误差8M时钟下(约+0.18ms,约+57ms) 


_dealy_ms(__ms)延时精度范围: 
(0 , 4个时钟周期),误差(1,5)个时钟周期 
(4个时钟周期 , 262.14ms/(F_CPU/1000000)),误差(-2,+1)个时钟周期, 
(262.14ms/(F_CPU/1000000)) , 6553.5ms),误差8M时钟下(约+0.18ms,约+57ms) 


_dealy_us(__us)最大延时6553.5ms,即_delay_us(6553500); 
_delay_ms(__ms)最大延时6553.5ms,即_delay_ms(6553.5); 


本人水平有限,如果错漏之处,多谢指正。 

补充:
1.WinAVR延时库函数看起来,又是double,又是if、else,难道不耗时间? 
不耗时间。WinAVR延时库函数,double都可以优化成常量,而整型常量,浮点常量运算,结果仍然仍然是常量。 
编译器只要开优化,不会编译出额外的代码出来。if,else也一样。if判断条件是一个常量,也就是说某个分支一定为真, 
另外的分支一定为假,编译器优化时,不会编译出额外代码。需要注意,如果要调用WinAVR延时库函数,则必须要开优化。 

2.怎么没有计算函数调用,返回时间? 
WinAVR延时库函数全部都是内联函数,没有函数调用和返回开销。当然,这也有一个副作用,每处延时函数都会编译出一段代码, 
占据更多的代码空间。 

3.旧版WinAVR  _delay_us()最大延时768us/(F_CPU/1000000),delay_ms()最大延时是262.14ms/(F_CPU/1000000)。
新版WinAVR_delay_us()和_delay_ms()最大延时都是6553.5ms,不过误差也相对较大,每0.1ms多7个时钟周期,8M时钟下,误差约为+0.88%。

[ 本帖最后由 void_c 于 2009-3-30 23:32 编辑 ]

使用特权

评论回复
5
ayb_ice| | 2009-4-3 21:30 | 只看该作者

直接插入NOP搞定,

长延时用定时器配合状态机

使用特权

评论回复
6
常来21ic| | 2009-4-3 23:10 | 只看该作者

楼主A人

使用特权

评论回复
7
工控秀才|  楼主 | 2009-4-7 11:54 | 只看该作者

AVR 不错,跑得快

不过都有各自的优势,AVR带AD的可以卖1.5RMB以下吗.

使用特权

评论回复
8
ayb_ice| | 2009-4-7 20:46 | 只看该作者

AVR跑的快吗?

比老51是要快点,比C8051F还是要差点

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

38

主题

286

帖子

11

粉丝