原贴链接:http://www.openedv.com/forum.php?mod=viewthread&tid=93
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。超过这个值就会导致延时不准确。
附件:
|