OpenEdv-开源电子网

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

请教一下delay函数的问题,我是初学者,看不太明白,请详细解释下,谢谢!!

[复制链接]

1

主题

3

帖子

0

精华

新手入门

积分
27
金钱
27
注册时间
2011-8-28
在线时间
0 小时
发表于 2011-8-28 18:47:44 | 显示全部楼层 |阅读模式
void delay_us(u32 nus)
{  
 u32 temp;      
 SysTick->LOAD=nus*fac_us; //时间加载     
 SysTick->VAL=0x00;        //清空计数器
 SysTick->CTRL=0x01 ;      //开始倒数  
 do
 {
  temp=SysTick->CTRL;
 }
 while(temp&0x01&&!(temp&(1<<16)));//等待时间到达  
 SysTick->CTRL=0x00;       //关闭计数器
 SysTick->VAL =0X00;       //清空计数器 
}
那个等待时间到达的那一句到底是怎样运行的,求解释下,看不懂
能不能详细解释下SysTick是如何工作的吗?也许我的问题很白痴,但是我是刚买了板子的初学者,对ARM还不懂,请详细解释下吧,谢谢各位了
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

0

主题

5

帖子

0

精华

新手上路

积分
29
金钱
29
注册时间
2012-1-5
在线时间
1 小时
发表于 2012-1-10 23:11:12 | 显示全部楼层
已找到答案了,如下:

void delay_init(u8 SYSCLK) 

        SysTick->CTRL&=0xfffffffb;

         fac_us=SYSCLK/8;                        
        fac_ms=(u16)fac_us*1000; 


Systick主要的作用就是拿来计时,其原理和应用简述一下就是这样的:通过配置寄存器 SysTick->CTRL来设定Systick的计时频率并Enable使Systick开始计数,这里的SysTick->CTRL&=0xfffffffb应该很好理解,把第2位设定为0,查找应用手册可以知道这是把Systick的计时频率设定为CPU主频(SYSCLK)的1/8。

假定我们板子默认的晶振频率是8Mhz,默认CPU工作频率(SYSCLK)是9倍频,即72M,那Systick的频率就是72/8=9Mhz。

知道了Systick的频率,下一步就是确定倒时计数器的数值,即SysTick-> LOAD这个寄存器的配置。上面已经知道了,Systick的工作频率F=9Mhz=SYSCLK/8,即每秒钟计数器自减900万次,也就是说,SYSCLK/8次的自减耗时1秒,那么(8/SYSCLK)/1000,000次自减就耗时1微秒了,这也就是fac_us的值了。那么上面函数中的fac_us为什么是SYSCLK/8呢?这里先搞清楚一点,函数中SYSCLK的单位是Mhz,所以SYSCLK的值是72(这个以Mhz为单位应该是STM32基础库里面做过宏定义的),否则也不可能用一个8位整形去表示一个7200万的数值;而我们这里计算的SYSCLK是以Hz为单位的,即72Mhz/1000,000=72,所以这个SYSCLK/8是对的。

你可能还没搞清楚fac_us到底是干嘛的。很简单,fac_us就是要写入SysTick-> LOAD寄存器的值,Systick的工作原理是这个寄存器的值在Systick被Enable之后就开始以设定的工作频率自减,减到0的时候就发出中断,实现定时。所以,写入fac_us到SysTick-> LOAD寄存器,就是要Systick在自减了fac_us次以后发出中断,自减fac_us所耗的时间已经说了,1微秒。

下面的fac_ms应该很好理解了,就是1毫秒的计数次数,刚好是1微妙的1000倍,注意9×1000超出了8位整形的表示范围,所以要用(u16)先把fac_us转成16位变量,以保证计算的正确。

具体的应用函数是用来做延时,如下:

void delay_us(u32 nus) 
{               
        u32 temp;                           
        SysTick->LOAD=nus*fac_us; //时间加载                      
        SysTick->VAL=0x00;                //清空计数器 
        SysTick->CTRL=0x01 ;            //Enable Systick,开始倒数      
        do 
        { 
                temp=SysTick->CTRL; 
        } 
        while(temp&0x01&&!(temp&(1<<16)));//等待时间到达       
        SysTick->CTRL=0x00;              //Disable Systick

        SysTick->VAL =0X00;              //清空计数器         


具体的寄存器配置只要看手册就知道了,这里只需要理解一句:

do 
        { 
                temp=SysTick->CTRL; 
        } 
        while(temp&0x01&&!(temp&(1<<16)));//等待时间到达    

核心就是while(temp&0x01&&!(temp&(1<<16)));//等待时间到达    

temp已经是Systick控制寄存器的值了,temp&0x01就是把该寄存器的值读出并且把除第一位之外位都清零(当然要通过temp变量来传递值而不是直接修改寄存器),第一位就是Systick的Enable配置信息,写入1就是Enable,写入0就是Disable,读这一位是判断Systick是否仍然处于Enable状态(可能被其他中断禁用掉),temp&(1<<16)就是读取第16位的值,这一位如果为0就表示计数器的值不是0(即还在计数),如果是1就表示计数器已经自减到0了。

       那么这段就很好理解了,即判断,如果Systick还在Enable的状态,并且计数器还没数到0,就不停的循环把当前的SysTick->CTRL寄存器值写入变量temp,继续下一次判断。当Systick被Disable或者计数器数到0了,就停止循环。因为只是做延时,也不需要跳到任何中断服务那边去处理什么,只要这个循环的耗时过程完成就可以了。

回复 支持 2 反对 0

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2011-8-28 23:20:23 | 显示全部楼层
systick就是个时钟频率为系统时钟频率1/8的计数器.
这个延时,就是通过systick的计数来实现的.
比如systick的频率一般为9Mhz,那么计数器计数到9000就是1ms了,计数到9就是1us.
那么你要延时多少ms/us,只要设置计数器的初值即可.
注意这个计数器是倒数的,比如你设置初值为9000,那么当他计数到0的时候,就是1ms的时间.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 1 反对 0

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-1-11 00:27:37 | 显示全部楼层
呵呵
回复 支持 0 反对 1

使用道具 举报

0

主题

5

帖子

0

精华

新手上路

积分
29
金钱
29
注册时间
2012-1-5
在线时间
1 小时
发表于 2012-1-10 23:03:38 | 显示全部楼层
原子哥:

      while(temp&0x01&&!(temp&(1<<16))); 这一句不太理解,能不能分析一下?不要见笑,初学请帮忙,多谢了!
回复 支持 反对

使用道具 举报

1

主题

4

帖子

0

精华

新手入门

积分
28
金钱
28
注册时间
2014-6-1
在线时间
1 小时
发表于 2014-7-7 15:41:17 | 显示全部楼层
帮助很大~不过(8/SYSCLK)/1000,000次  这句话写错了,应该是 (SYSCLK/8)/1000,000次 
大家好~
回复 支持 反对

使用道具 举报

1

主题

12

帖子

0

精华

新手上路

积分
39
金钱
39
注册时间
2014-7-20
在线时间
2 小时
发表于 2014-8-3 21:21:29 | 显示全部楼层
学习了,分析很到位啊~
IT菜鸟逆袭记~~~~
回复 支持 反对

使用道具 举报

0

主题

5

帖子

0

精华

新手上路

积分
28
金钱
28
注册时间
2014-12-2
在线时间
1 小时
发表于 2015-1-9 15:16:26 | 显示全部楼层
回复【4楼】gmolzc:
---------------------------------麻烦问下,&&!是什么意思?怎么运行的
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
15
金钱
15
注册时间
2016-2-16
在线时间
2 小时
发表于 2016-2-16 16:07:19 | 显示全部楼层
蚂蚁乱舞 发表于 2015-1-9 15:16
回复【4楼】gmolzc:
---------------------------------麻烦问下,&&!是什么意思?怎么运行的

先运行!,如果A为真,则!A为假,如果A为假,则!A为真,然后再执行&&,&&表示与运算,而当左边所给表达式或变量为0时,不再计算右侧,整个表达式为零;x&&y:x和y均为true,取值是true,否则取值是false。
回复 支持 反对

使用道具 举报

13

主题

69

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
428
金钱
428
注册时间
2015-4-24
在线时间
72 小时
发表于 2016-4-6 17:48:13 | 显示全部楼层
讲解的很详细
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-19 01:44

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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