文章目录
- 系统定时器SysTick
-
- 滴答定时器寄存器
- STK_CTRL 控制寄存器
- STK_LOAD 重载寄存器
- STK_VAL 当前值寄存器
- STK_CALRB 校准值寄存器
- 初始化 Systick 定时器
-
- SysTick_Init
-
- SysTick_CLKSourceConfig
- delay_us寄存器
- delay_us库函数
- delay_xms短时
- delay_ms长时
- SysTick_Config
系统定时器SysTick
CM4 内核的处理和 CM3 一样,内部都包含了一个SysTick定时器。两者没有区别。其详细介绍,请参阅
《STM32F3与F4系列Cortex M4内核编程手册》第230页。
-
系统定时器是属于 CM3 内核中的一个外设,内嵌在 NVIC 中。因为所有的 CM3 芯片都带有这个定时器,软件在不同 CM3 器件间的移植工作得以化简。
-
系统定时器是一个 24bit 的向下递减的计数器,计数器每计数一次的时间为 1/SYSCLK,一般我们设置系统时钟 SYSCLK 等于 72M。
- 该定时器的时钟源可以是内部时钟,或者是外部时钟。不过,STCLK 的具体来源则由芯片设计者决定
-
当重装载数值寄存器的值递减到 0 的时候,系统定时器就产生一次中断,以此循环往复。
- SysTick 设定初值并使能后,每经过 1 个系统时钟周期,计数值就减 1。计数到 0 时,SysTick 计数器自动重装初值并继续计数,同时内部的 COUNT FLAG 标志会置位,触发中断 (如果中断使能情况下)。
-
只要不把它在 SysTick 控制及状态寄存器中的使能位清除,就永不停息。
在M4内核编程手册中这样说道:SysTick是一个24位系统定时器,它将重加载值递减到零。再在下一个时钟沿将该值重新装载到STK_LOAD寄存器中,然后根据随后的时钟进行递减。
滴答定时器寄存器
Systick 部分内容属于 NVIC 控制部分,一共有 4 个寄存器,名称和地址分别是:
STK_CTRL 0xE000E010 -- 控制寄存器
//貌似这个才是控制寄存器
STK_LOAD 0xE000E014 -- 重载寄存器
STK_VAL 0xE000E018 -- 当前值寄存器
STK_CALRB 0xE000E01C -- 校准值寄存器
STK_CTRL 控制寄存器
寄存器内有 4 个位具有意义
- 第 0 位:ENABLE,Systick 使能位(0:关闭 Systick 功能;1:开启 Systick 功能)
- 第 1 位:TICKINT,Systick 中断使能位(0:关闭 Systick 中断;1:开启 Systick 中断)
- 第 2 位:CLK SOURCE,Systick 时钟源选择(0:使用 HCLK/8 作为 Systick 时钟;1:使用 HCLK 作为 Systick 时钟)
- 第 16 位:COUNT FLAG,Systick 计数比较标志,当计数到0时,置1;定时器开始重新计数时(CLK_LOAD重新写入数值)自动清零。
STK_LOAD 重载寄存器
Systick 是一个递减的定时器,当定时器递减至0 时,重载寄存器中的值就会被重装载,继续开始递减。STK_LOAD 重载寄存器是个24 位的寄存器最大计数0xFFFFFF。
STK_VAL 当前值寄存器
24 位的寄存器,读取时返回当前倒计数的值,写它则使之清零,同时还会清除在 SysTick 控制及状态寄存器中的 COUNTFLAG 标志。
STK_CALRB 校准值寄存器
SysTick calibration value register
- 位31 NOREF:= 1 没有外部参考时钟(STCLK 不可用),= 0 外部参考时钟可用。
- 位30 SKEW:= 1 校准值不是准确的1ms,= 0校准值是准确的1ms
初始化 Systick 定时器
SysTick_Init
void SysTick_Init(u8 SYSCLK);
SysTick_Init(72);
//SYSTICK的时钟固定为AHB时钟的1/8
//SYSCLK:系统时钟频率
void SysTick_Init(u8 SYSCLK)
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
fac_us=SYSCLK/8;
fac_ms=(u16)fac_us*1000;
}
系统时钟是72/8M,计数一次时间1/9000000秒,换算成us就是1/9us,则计数72/8次也就是9次就是1us。
SysTick_CLKSourceConfig
设置SysTick的时钟源。可选项如下:
#define SysTick_CLKSource_HCLK_Div8 ((uint32_t)0xFFFFFFFB)
#define SysTick_CLKSource_HCLK ((uint32_t)0x00000004)
#define IS_SYSTICK_CLK_SOURCE(SOURCE) (((SOURCE) == SysTick_CLKSource_HCLK) ||
((SOURCE) == SysTick_CLKSource_HCLK_Div8))
HCLK的介绍
delay_us寄存器
void delay_us(u32 nus)
{
u32 temp;
SysTick->LOAD = 9*nus;
SysTick->VAL=0X00;//清空计数器
SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
do
{
temp=SysTick->CTRL;//读取当前倒计数值
}while((temp&0x01)&&(!(temp&(116))));//等待时间到达
//使能且没有计数到0就一直循环
SysTick->CTRL=0x00; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
9*nus :假设外设频率为 9M,也就是经过 8 分频,那么计数 9 次是 1us,乘以 9 的意义就是参数的时间对应的服务器托管网次数,也就是重装载值
- 这里看一下判断条件,第一位是使能,16位是计数到0。
第 16 位:COUNT FLAG,Systick 计数比较标志,当计数到0时,置1;定时器开始重新计数时(CLK_LOAD重新写入数值)自动清零。
delay_us库函数
//延时nus
//注意:nus的值,不要大于798915us(最大值即2^24/fac_us@fac_us=21)
void delay_us(u32 nus)
{
u32 temp;
SysTick->LOAD=nus*fac_us; //时间加载
SysTick->VAL=0x00; //清空计数器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(116))); //等待时间到达
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
delay_xms短时
//延时nms
//SysTick->LOAD为24位寄存器,所以,最大延时为:
//nms
//SYSCLK单位为Hz,nms单位为ms
//对168M条件下,nms
void delay_xms(u16 nms)
{
u32 temp;
SysTick->LOAD=(u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit)
SysTick->VAL =0x00; //清空计数器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(116))); //等待时间到达
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
delay_ms长时
//延时nms
//nms:0~65535
void delay_ms(u16 nms)
{
u8 repeat=nms/540; //这里用540,是考虑到某些客户可能超频使用,
//比如超频到248M的时候,delay_xms最大只能延时541ms左右了
u16 remain=nms%540;
while(repeat)
{
delay_xms(540);
repeat--;
}
if(remain)delay_xms(remain);
}
SysTick_Config
设置重装载值。该函数的内部就是个:SysTick->LOAD = 9*nus;
SysTick_Config 的参数是一个时钟次数,意思就是我要多少个1/fosc 时间后中断一下。
static void BSP_CoreClockInit(void)
{
SysTick_Config(SystemCoreClock / 100); //10ms
//SysTick_Config(720000); //10ms
}
SystemCoreClock / 100 代表的是时钟次数,即放入重装载寄存器中的值,每计时一个数需要 1/72000000s 的时间,那么计SystemCoreClock / 100 (SystemCoreClock 为 72M)个数的时间就是 10ms,通过在中断中设置标志位达到 systick 定时中断的功能。
函数实现
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
SysTick->LOAD = ticks - 1; /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1__NVIC_PRIO_BITS) - 1); /* set Priority for Systick Interrupt */
SysTick->VAL = 0; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0); /* Function successful */
}
在外设的中断优先级设置里,外设的硬件编号都是大于等于零的,内核外设的编号都小于零,相当于一个IP。
- __NVIC_PRIO_BITS=4,因为F4使用了四位。
- 中断处理函数IP:
typedef enum IRQn
{
/****** Cortex-M4 Processor Exceptions Numbers ****************************************************************/
NonMaskableInt_IRQn = -14, /*!
MemoryManagement_IRQn = -12, /*!
BusFault_IRQn = -11, /*!
UsageFault_IRQn = -10, /*!
SVCall_IRQn = -5, /*!
DebugMonitor_IRQn = -4, /*!
PendSV_IRQn = -2, /*!
SysTick_IRQn = -1, /*!
/****** STM32 specific Interrupt Numbers **********************************************************************/
WWDG_IRQn = 0, /*!
PVD_IRQn = 1, /*!
TAMP_STAMP_IRQn = 2, /*!
RTC_WKUP_IRQn = 3, /*!
FLASH_IRQn = 4, /*!
RCC_IRQn = 5, /*!
EXTI0_IRQn = 6, /*!
EXTI1_IRQn = 7, /*!
EXTI2_IRQn = 8, /*!
EXTI3_IRQn = 9, /*!
EXTI4_IRQn = 10, /*!
DMA1_Stream0_IRQn = 11, /*!
DMA1_Stream1_IRQn = 12, /*!
DMA1_Stream2_IRQn = 13, /*!
DMA1_Stream3_IRQn = 14, /*!
DMA1_Stream4_IRQn = 15, /*!
DMA1_Stream5_IRQn = 16, /*!
DMA1_Stream6_IRQn = 17, /*!
ADC_IRQn = 18, /*!
内核外设和普通外设的中断优先级比较,虽然二者不是在同一个寄存器中,但是在比较时,也是把内核外设的优先级寄存器配置按照普通的解读。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
相关推荐: 【ES6】 JavaScript 中的Object.assign
Object.assign() 是 JavaScript 中的一个方法,服务器托管网它用于复制源对象的所有可枚服务器托管网举属性到目标对象。该方法会返回目标对象。 这是其基本用法: let target = Object.assign({}, source);…