17686|24

35

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

SysCtlDelay()函数解析 [复制链接]

   最近经常用到SysCtlDelay()函数,觉得这函数不错,可以做到精确延时。不久前,做NRF905模块的时候,有一处要精确到610us。
      TI的资料中,此函数在Sysctl.c中是这样定义的:
 
     #if defined(ewarm) || defined(DOXYGEN)    //定义在IAR的编译环境中
void
SysCtlDelay(unsigned long ulCount)
{
    __asm("    subs    r0, #1\n"
          "    bne.n   SysCtlDelay\n"
          "    bx      lr");
}
#endif

#if defined(codered) || defined(gcc) || defined(sourcerygxx)  //定义在codered、gcc、sourcerygcc编译环境下
void __attribute__((naked))
SysCtlDelay(unsigned long ulCount)
{
    __asm("    subs    r0, #1\n"
          "    bne     SysCtlDelay\n"
          "    bx      lr");
}
#endif

#if defined(rvmdk) || defined(__ARMCC_VERSION)  //在KEIL MDK的编译环境下
__asm void
SysCtlDelay(unsigned long ulCount)
{
    subs    r0, #1;
    bne     SysCtlDelay;
    bx      lr;
}
#endif
  不管哪种环境下,发现用了三条汇编指令。我用的是KEIL MDK。
  subs  r0,#1;  // 使用了16位的Thumb指令,无条件更新标志位。S后缀的使用要担心,16位的Thunb指令有可能会无条件更新标志位,也有可能不会。所以,但你需要更新标志位时,一定不要忘了加上S后缀。
   bne SysCtlDelay;  //  无条件跳转指令有两条,B和BX,  BNE中的NE即NotEqual,对应于标志位Z==0;
  表示不等的时候无条件转移到SysCtlDelay处对应的地址;
   bx    lr;  //执行这条指令后,把返回地址存储到LR(R14)中;
 
 关于SysCtlDelay()延时函数
   TI LM3S8962 默认的设置为采用主晶振6M,   所以,一个周期的时间是1/6us。
   SysCtlDelay()函数里执行了三条指令。
   1.微妙级的延时:
       SysCtlDelay(2); // 延时1us;
        SysCtlDelay(2*x); 延时x us;x=1000时,延时1ms;
        另一种写法
      #defined TheSysClock 6000000
       SysCtlDelay(1*(TheSysClock/3000000)) //延时 1us
    2.毫秒级的延时:
        SysCtlDelay(SysCtlClockGet( 3000);    //   延时1ms 
        SysCtlDelay(10 (SysCtlClockGet( 3000));    //   延时10ms 
         SysCtlClockGet( )=6000000 ;
    另一种种写法
        // 定义系统时钟 6M
        #define TheSysClock  6000000
       SysCtlDelay(10 * (TheSysClock / 3000)); 延时10ms
      // 定义系统时钟 8M
        #define TheSysClock  8000000
      SysCtlDelay(10 * (TheSysClock / 3000));  延时10ms

 
 
 

最新回复

多谢  详情 回复 发表于 2015-1-17 20:16

赞赏

1

查看全部赞赏

 
点赞 关注(1)

回复
举报

66

帖子

0

TA的资源

一粒金砂(中级)

推荐
 

回复 5楼 huangzhiluo 的帖子

除以3000原因如下
假设主晶振 为  A  MHZ
1、延时函数执行3条指令,耗时三个时钟周期,故执行一次该函数 耗时3* (1/A)  uS 即 3/A us
2、要实现 ms的延时 即 (3/A)*  B  = 1000us
     推算一下可得B = A/3000
3、3000出现了吧
要多少ms 就是多少个B  也就是多少个 A/3000
后面的不用推算了吧

[ 本帖最后由 yytdragon 于 2011-7-29 13:09 编辑 ]
 
 

回复

2万

帖子

74

TA的资源

管理员

沙发
 

回复 楼主 myredback 的帖子

谢谢分享  
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
个人签名

加油!在电子行业默默贡献自己的力量!:)

 
 

回复

545

帖子

0

TA的资源

一粒金砂(高级)

板凳
 
很不错,以后就用这个延时函数了,长知识了
 
 
 

回复

66

帖子

0

TA的资源

一粒金砂(中级)

4
 

终于明白了

以前只是在用,不知道里面的3000是怎么来的,还以为是瞎写的
也没仔细去分析汇编源码
谢LZ
 
 
 

回复

19

帖子

0

TA的资源

一粒金砂(初级)

5
 

最后延迟用6m和8m的晶振延迟都除以3000吗?

最后延迟用6m和8m的晶振延迟都除以3000吗?谢谢啦,8m的不是除以4000?本人菜鸟
 
 
 

回复

35

帖子

0

TA的资源

一粒金砂(中级)

6
 

回复 5楼 huangzhiluo 的帖子

很感谢你的提问。
无论是多大的晶振,都是除以3000。
其实这样写有一个很大的好处——就是"延迟时间与具体的时钟频率配置无关,方便移植。
我给你具体分析下吧:
第一:时钟周期与延时长短的关系.
        当振荡源为6MHz时,6个时钟周期耗时1us,    6000个时钟周期耗时1ms。
        当振荡源为8MHz时,8个时钟周期耗时1us     8000个时钟周期耗时1ms。
第二:SysCtlDelay()函数里执行了三条指令,例:SysCtlDelay(20);    //  延时60个时钟周期
    那么,这个60是怎么来的呢! 呵呵,当然是20*3=60;
    也就是说,这个3是关键。
第三:都除以3000就好解释啦;
    // 定义系统时钟 8M
        #define TheSysClock  8000000
    SysCtlDelay(  10*(TheSysClock / 3000)   );  延时10ms

       在这个语句里,10*(TheSysClock / 3000) 相当于SysCtlDelay(20);中的20。
    那么,总的时钟周期=3*[ 10*(TheSysClock / 3000)  ] =10* (TheSysClock / 1000)
                                                                                                      =10* 8个时钟周期
                                                                                                      =10*1us
 
 
 

回复

545

帖子

0

TA的资源

一粒金砂(高级)

7
 

这个延时函数很好啊,不错

 
 
 

回复

102

帖子

0

TA的资源

一粒金砂(高级)

9
 
不错啊!懂了
 
 
 

回复

144

帖子

0

TA的资源

一粒金砂(中级)

10
 
受中断影响,不能精确延时吧?
 
 
 

回复

13

帖子

0

TA的资源

一粒金砂(中级)

11
 

8楼 推的不错 赞一个

 
 
 

回复

130

帖子

0

TA的资源

一粒金砂(中级)

12
 
厉害,长见识了。
 
 
 

回复

419

帖子

0

TA的资源

一粒金砂(高级)

13
 
 bx    lr;  //执行这条指令后,把返回地址存储到LR(R14)中
这条指令的意思是把LR寄存器的值给到PC,也就是函数返回的意思啊!
 
 
 

回复

1万

帖子

16

TA的资源

版主

14
 

搞明白了,顶一下

 
个人签名http://shop34182318.taobao.com/
https://shop436095304.taobao.com/?spm=a230r.7195193.1997079397.37.69fe60dfT705yr
 
 

回复

1

帖子

0

TA的资源

一粒金砂(初级)

15
 
最后一条是返回指令,那么每个循环岂不是只执行了两条语句?
 
 
 

回复

9

帖子

0

TA的资源

一粒金砂(中级)

16
 
两条指令,但是因为有转跳指令,要清流水线,所以我觉得循环应该是4个周期。
但是实际上是6个周期,难道还有数据写入延时?
只有直接调用ROM_SysCtlDelay()循环才是3个周期。
 
 
 

回复

9

帖子

0

TA的资源

一粒金砂(中级)

17
 

我的理解

ARM Cortex-M3内核的预取部件具有分支预测功能,可以预取分支目标地址的指令,使分支延迟减少到一个时钟周期。
循环是两条指令,再加一个分支预测的开销,所以循环是3个周期。
 
 
 

回复

2

帖子

0

TA的资源

一粒金砂(初级)

18
 
貌似不对  看我的proteus8仿真     

Seg 595 OK.zip

80.52 KB, 下载次数: 6

 
 
 

回复

337

帖子

0

TA的资源

纯净的硅(初级)

19
 
支持
 
 
 

回复

164

帖子

0

TA的资源

一粒金砂(中级)

20
 
个人认为不是精确延时,有较大误差

点评

我用的时候也感觉好像不准,您能说一下为什么吗?  详情 回复 发表于 2014-8-6 23:08
 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表