OpenEdv-开源电子网

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

关于delay_us函数的一个小小的却又重大的发现,大部分人应该没注意到吧

[复制链接]

17

主题

342

帖子

0

精华

高级会员

Rank: 4

积分
544
金钱
544
注册时间
2014-4-24
在线时间
20 小时
发表于 2015-1-23 22:15:53 | 显示全部楼层 |阅读模式
今天在做DHT11实验时,许多函数都调用了delay_us函数,原子哥写的源码是:
[mw_shl_code=c,true]//延时nus //nus为要延时的us数. void delay_us(u32 nus) { u32 temp; SysTick->LOAD=nus*fac_us; //时间加载 SysTick->VAL=0x00; //清空计数器 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数 do { temp=SysTick->CTRL; } while(temp&0x01&&!(temp&(1<<16)));//等待时间到达 SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器 SysTick->VAL =0X00; //清空计数器 }[/mw_shl_code]
大家在调用延时函数时都认为它是非常精准的,的确,延时达到ms级时它真的很准。
可是在调用delay_us函数进行几us的延时时,它的误差却非常大!经测试,delay_us(1)所花的时间约为2us,误差达100% !
我写了个函数用USMART进行了测试:
void delayus(u32 n)
{
while(n--) delay_us(1);
}
调用delayus(10000)测出所花时间为19.6ms,而理论值为10ms,多出近1倍的时间!
这是因为delay_us函数中的初始化及数据处理也花了时间,这个时间大概为1us。
delay_us函数的代码量为68字节,不仅仅是延时等待要时间,运行这些代码也要时间。
所以,调用
delay_us(n)时,用的时间为(n+1)us,而不是nus!
这1us的误差看起来好像没什么大不了,可某些对时序(时间)要求非常苛刻的场合说不定能导致实验失败,得不到预期的结果。
原子哥应该也没注意到这点吧?哈哈~
唉,强迫症又犯了。。。。。注定一辈子只能当程序猿。。。。
[mw_shl_code=c,true][/mw_shl_code]
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2015-1-23 22:50:17 | 显示全部楼层
这个我也注意到了,谢谢提醒.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

14

主题

338

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
464
金钱
464
注册时间
2013-6-15
在线时间
15 小时
发表于 2015-1-23 22:53:13 | 显示全部楼层
几微秒的延时软件延时一下就好,就不去倒腾systick了
回复 支持 反对

使用道具 举报

69

主题

475

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1334
金钱
1334
注册时间
2013-12-28
在线时间
197 小时
发表于 2016-1-13 22:11:56 | 显示全部楼层
楼主分析的很透彻    装载初值的时候应该是 nus*fac_us-1
回复 支持 反对

使用道具 举报

7

主题

185

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2729
金钱
2729
注册时间
2015-12-27
在线时间
469 小时
发表于 2016-1-14 09:09:26 | 显示全部楼层
在大多数情况下这样用就可以了吧
回复 支持 反对

使用道具 举报

10

主题

43

帖子

0

精华

初级会员

Rank: 2

积分
157
金钱
157
注册时间
2016-1-21
在线时间
30 小时
发表于 2016-1-21 17:22:26 | 显示全部楼层
我初始化了delay函数后,刚开始运行delay_us()时没问题的,不会卡死。但是等我后面用到串口中断收发数据后就会卡在那个do while()循环内,跳不过去。我后来将延时us小的用__nop();来代替,大一点的us用delay_ms(1);代替就没有这种情况了。所以我想问问原子哥给的那个delay源代码的delay_us()函数是不是有什么BUG?
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
15
金钱
15
注册时间
2016-11-6
在线时间
3 小时
发表于 2016-11-6 15:11:39 | 显示全部楼层
void delay_us(u32 nus)
{               
        u32 temp;                     
        SysTick->LOAD=nus*fac_us-9;                                         //时间加载          
        SysTick->VAL=0x00;                                                //清空计数器
        SysTick->CTRL=0x01 ;        //开始倒数          
        do
        {
                temp=SysTick->CTRL;
        }while((temp&0x01)&&!(temp&(1<<16)));                //等待时间到达   
        SysTick->CTRL=0x00;        //关闭计数器
        SysTick->VAL =0X00;                                               //清空计数器         
}


这里应该写成 nus*fac_us-9  假设时钟是72Mhz

单纯延时1us这个delay_us好像做不到了,要重新写个函数。

void delay_us1()
{               
        u32 temp;                     
        SysTick->LOAD=fac_us;                                         //时间加载          
        SysTick->VAL=0x00;                                                //清空计数器
        SysTick->CTRL=0x01 ;        //开始倒数          
        do
        {
                temp=SysTick->CTRL;
        }while(((temp+1)&0x01)&&!(temp&(1<<16)));                //等待时间到达   
        SysTick->CTRL=0x00;        //关闭计数器
        SysTick->VAL =0X00;                                               //清空计数器
}

这里好像没有实际的意义,只是刚好是1us而已。。。。
原子哥看下~~~
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
15
金钱
15
注册时间
2016-11-6
在线时间
3 小时
发表于 2016-11-6 15:12:37 | 显示全部楼层
回复 支持 反对

使用道具 举报

10

主题

561

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1835
金钱
1835
注册时间
2014-6-27
在线时间
981 小时
发表于 2016-11-6 20:19:33 | 显示全部楼层
我发过2个延时函数,也是用systick来做的,没有不准的情况的啊,原来的写法定时器只能做延时,不能做其他事情了,其实定时器除了延时,还可以做很多事情,而且不影响延时的精度。
回复 支持 反对

使用道具 举报

63

主题

305

帖子

1

精华

高级会员

Rank: 4

积分
853
金钱
853
注册时间
2012-8-3
在线时间
79 小时
发表于 2017-7-21 10:52:06 | 显示全部楼层
mark
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-16 07:29

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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