1. 实现方法
处理器有一个24位的系统定时器,SysTick。该定时器向下计数。计数到0后,重新从STK_LOAD寄存器中重载计数值,继续向下计数。使用SysTick的优点是,不用占用中断和定时器资源。
2. 相关寄存器
STK_CTRL:
0-bit,计数器使能位;
1-bit,选择时钟源
16-bit,计数到0后,该标志位被置1
STK_LOAD
计数值重载寄存器,当计数值计数到0后,将从该寄存器中重新加载计数值。
STK_VAL
保存当前计数值
#include "delay.h"
static u8 fac_us = 0;
static u16 fac_ms = 0;
void delay_init(u8 sys_clock)
{
SysTick->CTRL &= ~(1<<2); //external clock
fac_us = sys_clock/8; //AHB/8
fac_ms = (u16)fac_us*1000;
}
//n < 2^24/fac_us
//sys_clock = 168MHz, fac_us=21MHz, 2^24/fac_us=798915
void delay_us(u32 n)
{
u32 temp;
SysTick->LOAD = n*fac_us; //connter
SysTick->VAL = 0; //clear current value
SysTick->CTRL = 0x01; //start timer
do
{
temp = SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //16-bit will be set 0 when current value is 0
SysTick->CTRL = 0x00; //stop timer
SysTick->VAL = 0x00; //clear current value
}
//@sys_clock=168MHz, n < 798
void delay_ms(u16 n)
{
u32 temp;
SysTick->LOAD = (u32)n*fac_ms;
SysTick->VAL = 0x00;
SysTick->CTRL = 0x01;
do
{
temp = SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //16-bit will be set 0 when current value is 0
SysTick->CTRL = 0x00; //stop timer
SysTick->VAL = 0x00; //clear current value
}
实现更长的延时(超过798.915ms)。方法是多次调用上面实现的delay_ms。如果需要延时5s。5000ms>798.915ms,所以无法使用delay_ms。按照delay_long_ms的方法,每一个repeat可以延时540ms,repeat=5000/540=9, remain = 5000%540=140。对于用户而言,直接调用
delay_long_ms(5000);
程序中使用540的原因。理论上这个数值越接近798.915越好,但是我们要注意,798915这个值是按照系统时钟168MHz下计算出来的。
2^24*8/clock
而有些时候,系统可以工作在248MHz频率下,超频使用。此时2^24*8/248=541200。考虑到驱动的兼容性,选择540作为单次最大延时时间。
void delay_long_ms(u16 n)
{
u8 repeat = n / 540;
u16 remain = n % 540;
while(repeat)
{
delay_ms(540);
repeat--;
}
if(remain) delay_ms(remain);
}
参考
STM32F3与 F4 系列 Cortex M4 内核编程手册
STM32F4 开发指南(寄存器版)
STM32F4xxx中文参考手册