目录
前言
STM32第十一节(中级篇):SysTick(第一节)——功能框图讲解和系统配置
SysTick功能框图讲解
CTRL控制及状态寄存器
重装载数值寄存器
当前数值寄存器
SysTick定时时间计算
SysTick库函数分析
SysTick中断优先级
编写程序
微秒级,毫秒级延时函数
初始化SysTick
main函数
小结
从这节课开始我们学习有关SysTick系统定时器,主要讲解功能框图以及定时实验讲解。
SysTick:系统定时器,24位,只能递减,存在于内核,嵌套在NVIC中,所有的Cortex-M内核的单片机都具有这个定时器。
counter在时钟的驱动下,从reload初值开始往下递减计数到0,产生中断和置位COUNTFLAG标志。然后又从reload值开始重新递减计数,如此循环。那么这样的话,我们在计数结束后使能中断,那么就会执行中断服务程序,置位COUNTFLAG。
最常用的三个寄存器如上表所示,接下来介绍一下他们分别的功能。
CTRL控制及状态寄存器只有四位有效,第16位为COUNTFLAG,就是说在计数完成后,该位会置为1,那么我们就需要使用软件进行清零,就需要我们读取这个位,就会清零。第2位为CLKSOURCE位,若配置为1,即为AHB时钟,72MHz;若改为0,则为9MHz。 第1位为TICKINT位,我们可以通过该位是否置1去判断我们的程序是否进入中断。 第0位也不多说就是使能位。
该寄存器决定了reload的值,帮我写作文一个这样的话再不就是到倒数计数置0时将被重装载的值。(24位有效)
该寄存器可以读取时返回当前倒计数的值。
t=reload*(1/clk)
CIk=72M 时, t=(72)*(1/ 72 M) = 1US
Clk=72M时 , t=(72000)*(1/72 M) = 1MS
时间单位换算:
1s= 1000ms=1000 000us=1000000 000ns
/**
* @brief Initialize and start the SysTick counter and its interrupt.
*
* @param ticks number of ticks between two interrupts
* @return 1 = failed, 0 = successful
*
* Initialise the system tick timer and its interrupt and start the
* system tick timer / counter in free running mode to generate
* periodical interrupts.
*/
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */
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 */
}
#endif
我们在core.cm3.c文件中大概1700行的代码中找到上述代码,我们可以看到,我们传入的值为 int 类型的 ticks 参数,首先判断ticks 的值是否大于2^24,若大于该值,程序返回1,若小于该值,程序开始中断前的配置。接下来初始化reload 寄存器的值,将该值写入到LOAD中,然后就是配置中断优先级。
我们这里用到了NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);函数来配置中断优先级,配置为15,默认为最低的优先级。
STM32里面无论是内核还是外设都是使用4个二进制位来表示中断优先级。
中断优先级的分组对内核和外设同样适用。当比较的时候,只需要把内核外设的中断优先级的四个位按照外设的中断优先级来分组来解析即可,即人为的分出抢占优先级和子优先级。
我们现在先编写两个函数,使得实现微妙和毫秒级延时。我们先宏定义SystemCoreClock为72000000,然后进入一个for循环,计次减一,直到减到0,每次循环都判断SysTick->CTRL是否为1。那么我们就&一下1左移16位的值。若整体非1,即跳出循环。然后就是关闭SysTick定时器
SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk;函数。另一个与上面相同编程。
// couter 减1的时间 等于 1/systick_clk
// 当counter 从 reload 的值减小到0的时候,为一个循环,如果开启了中断则执行中断服务程序,
// 同时 CTRL 的 countflag 位会置1
// 这一个循环的时间为 reload * (1/systick_clk)
void SysTick_Delay_Us( __IO uint32_t us)
{
uint32_t i;
SysTick_Config(SystemCoreClock/1000000);
for(i=0;iCTRL)&(1<<16)) );
}
// 关闭SysTick定时器
SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;
}
void SysTick_Delay_Ms( __IO uint32_t ms)
{
uint32_t i;
SysTick_Config(SystemCoreClock/1000);
for(i=0;iCTRL)&(1<<16)) );
}
// 关闭SysTick定时器
SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk;
}
/**
* @brief 启动系统滴答定时器 SysTick
* @param 无
* @retval 无
*/
void SysTick_Init(void)
{
/* SystemFrequency / 1000 1ms中断一次
* SystemFrequency / 100000 10us中断一次
* SystemFrequency / 1000000 1us中断一次
*/
// if (SysTick_Config(SystemFrequency / 100000)) // ST3.0.0库版本
if (SysTick_Config(SystemCoreClock / 100000)) // ST3.5.0库版本
{
/* Capture error */
while (1);
}
}
#include "stm32f10x.h"
#include "bsp_SysTick.h"
#include "bsp_led.h"
/*
* t : 定时时间
* Ticks : 多少个时钟周期产生一次中断
* f : 时钟频率 72000000
* t = Ticks * 1/f = (72000000/100000) * (1/72000000) = 10us
*/
/**
* @brief 主函数
* @param 无
* @retval 无
*/
int main(void)
{
/* LED 端口初始化 */
LED_GPIO_Config();
/* 配置SysTick 为10us中断一次 */
SysTick_Init();
// for(;;)
// {
// LED1( ON );
// Delay_us(100000); // 100000 * 10us = 1000ms
// //Delay_ms(100);
// LED1( OFF );
//
// LED2( ON );
// Delay_us(100000); // 100000 * 10us = 1000ms
// //Delay_ms(100);
// LED2( OFF );
//
// LED3( ON );
// Delay_us(100000); // 100000 * 10us = 1000ms
// //Delay_ms(100);
// LED3( OFF );
// }
for(;;)
{
LED1( ON );
SysTick_Delay_Ms( 1000 );
LED1( OFF );
LED2( ON );
SysTick_Delay_Ms( 1000 );
LED2( OFF );
LED3( ON );
SysTick_Delay_Ms( 1000 );
LED3( OFF );
}
}
我们这节就到这里啦,代码部分实现了LED三个灯的流水亮灭。我们下节开始就要学习关于串口的内容了。