2.7.1 delay文件夹
delay文件夹内包含了delay.c和delay.h两个文件,这两个文件用来实现系统的延时功能,其中包含3个函数:
void delay_init(u8 SYSCLK);
void delay_ms(u16 nms);
void delay_us(u32 Nus);
下面分别介绍这三个函数,在介绍之前,我们先了解一下编程思想:CM3内核的处理器,内部包含了一个SysTick定时器,SysTick是一个24位的倒计数定时器,当计到0时,将从RELOAD寄存器中自动重装载定时初值。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。SysTick在STM32的参考手册里面介绍的很简单,其详细介绍,请参阅《Cortex-M3权威指南》第133页。我们就是利用STM32的内部SysTick来实现延时的,这样不占用中断,也不占用系统定时器。
1)delay_init函数
该函数用来初始化2个重要参数:fac_us以及fac_ms;同时吧SysTick的时钟源选择外部时钟。具体代码如下:
//初始化延迟函数
//SYSTICK的时钟固定为HCLK时钟的1/8
//SYSCLK:系统时钟
void delay_init(u8 SYSCLK)
{
SysTick->CTRL&=0xfffffffb;//bit2清空,选择外部时钟 HCLK/8
fac_us=SYSCLK/8;
fac_ms=(u16)fac_us*1000;
}
SysTick是MDK定义了的一个结构体(在stm32f10x_map.里面),里面包含CTRL、LOAD、VAL、CALIB等4个寄存器,
SysTick->CTRL的各位定义如下图所示:
图2.7.1.1
SysTick->CTRL寄存器各位定义
SysTick-> LOAD的定义如下图所示:
图2.7.1.2
SysTick->LOAD寄存器各位定义
SysTick-> VAL的定义如下图所示:
图2.7.1.3
SysTick->VAL寄存器各位定义
SysTick-> CALIB不常用,在这里我们也用不到,故不介绍了。
SysTick->CTRL&=0xfffffffb;这一句把SysTick的时钟选择外部时钟,这里需要注意的是SysTick的时钟源自HCLK的8分频,假设我们外部晶振为8M,然后倍频到72M,那么SysTick的时钟即为9Mhz。
fac_us,为us延时的基数,也就是延时1us,SysTick->LOAD所应设置的值。fac_ms为ms延时的基数,也就是延时1ms,SysTick->LOAD所应设置的值。fac_us为8位整形数据,fac_ms为16位整形数据。正因为如此,系统时钟如果不是8的倍数,则会导致延时函数不准确,这也是我们推荐外部时钟选择8M的原因。这点大家要特别留意。
2)delay_us函数
该函数用来延时指定的us,其参数nus为要延时的微秒数。具体函数如下:
//延时us
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寄存器的描述,这段代码不难理解。其实就是先把要延时的us数换算成SysTick的时钟数,然后写入LOAD寄存器。然后清空当前寄存器VAL的内容,再开启倒数功能。等到倒数结束,即延时了nus。最后关闭SysTick,清空VAL的值。实现一次延时nus的操作。
3)delay_ms函数
该函数用来延时指定的ms,其参数nms为要延时的微秒数。具体函数如下:
//延时nms
//注意nms的范围
//SysTick->LOAD为24位寄存器,所以,最大延时为:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK单位为Hz,nms单位为ms
//对72M条件下,nms<=1864
void delay_ms(u16 nms)
{
u32
temp;
SysTick->LOAD=(u32)nms*fac_ms;//时间加载(SysTick->LOAD为24bit)
SysTick->VAL
=0x00; //清空计数器
SysTick->CTRL=0x01
; //开始倒数
do
{
temp=SysTick->CTRL;
}
while(temp&0x01&&!(temp&(1<<16)));//等待时间到达
SysTick->CTRL=0x00; //关闭计数器
SysTick->VAL
=0X00; //清空计数器
}
此部分代码和7.2节的delay_us大致一样,但是要注意因为LOAD仅仅是一个24bit的寄存器,延时的ms数不能太长。否则超出了LOAD的范围,高位会被舍去,导致延时不准。最大延迟ms数可以通过公式:nms<=0xffffff*8*1000/SYSCLK计算。SYSCLK单位为Hz,nms的单位为ms。如果时钟为72M,那么nms的最大值为1864ms。超过这个值就会导致延时不准确。 |