STM32F10x,使用systick写一个软件延时
相关寄存器
在core_cm3.h
里定义了滴答时钟的相关时钟
typedef struct
{
__IO uint32_t CTRL; /*!< Offset: 0x00 SysTick Control and Status Register */
__IO uint32_t LOAD; /*!< Offset: 0x04 SysTick Reload Value Register */
__IO uint32_t VAL; /*!< Offset: 0x08 SysTick Current Value Register */
__I uint32_t CALIB; /*!< Offset: 0x0C SysTick Calibration Register */
} SysTick_Type;
/* SysTick Control / Status Register Definitions */
#define SysTick_CTRL_COUNTFLAG_Pos 16 /*!< SysTick CTRL: COUNTFLAG Position */
#define SysTick_CTRL_COUNTFLAG_Msk (1ul << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */
#define SysTick_CTRL_CLKSOURCE_Pos 2 /*!< SysTick CTRL: CLKSOURCE Position */
#define SysTick_CTRL_CLKSOURCE_Msk (1ul << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */
#define SysTick_CTRL_TICKINT_Pos 1 /*!< SysTick CTRL: TICKINT Position */
#define SysTick_CTRL_TICKINT_Msk (1ul << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */
#define SysTick_CTRL_ENABLE_Pos 0 /*!< SysTick CTRL: ENABLE Position */
#define SysTick_CTRL_ENABLE_Msk (1ul << SysTick_CTRL_ENABLE_Pos) /*!< SysTick CTRL: ENABLE Mask */
/* SysTick Reload Register Definitions */
#define SysTick_LOAD_RELOAD_Pos 0 /*!< SysTick LOAD: RELOAD Position */
#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFul << SysTick_LOAD_RELOAD_Pos) /*!< SysTick LOAD: RELOAD Mask */
/* SysTick Current Register Definitions */
#define SysTick_VAL_CURRENT_Pos 0 /*!< SysTick VAL: CURRENT Position */
#define SysTick_VAL_CURRENT_Msk (0xFFFFFFul << SysTick_VAL_CURRENT_Pos) /*!< SysTick VAL: CURRENT Mask */
/* SysTick Calibration Register Definitions */
#define SysTick_CALIB_NOREF_Pos 31 /*!< SysTick CALIB: NOREF Position */
#define SysTick_CALIB_NOREF_Msk (1ul << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */
#define SysTick_CALIB_SKEW_Pos 30 /*!< SysTick CALIB: SKEW Position */
#define SysTick_CALIB_SKEW_Msk (1ul << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */
#define SysTick_CALIB_TENMS_Pos 0 /*!< SysTick CALIB: TENMS Position */
#define SysTick_CALIB_TENMS_Msk (0xFFFFFFul << SysTick_VAL_CURRENT_Pos) /*!< SysTick CALIB: TENMS Mask */
/*@}*/ /* end of group CMSIS_CM3_SysTick */
这些寄存器的说明如下:
在system_stm32f10x.c
里找到如下定义(不用改,只是给你看看你选择的时钟源的频率):
#ifdef SYSCLK_FREQ_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_24MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_24MHz; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_36MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_36MHz; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_48MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_56MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_72MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz; /*!< System Clock Frequency (Core Clock) */
#else /*!< HSI Selected as System Clock source */
uint32_t SystemCoreClock = HSI_VALUE; /*!< System Clock Frequency (Core Clock) */
#endif
两个步骤实现systick
延时
如果前面看不懂也没关系,只需要知道下面这两个步骤就能轻松实现systick延时
- 设置时钟中断时间(即设置
重装载数值寄存器
) - 开启systick时钟,待计时完成后关闭systick即可
调用如下函数(也在core_cm3.h
里):
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 */
}
这个函数的意义如下:
- 判断ticks值,如果大于SysTick_LOAD_RELOAD_Msk,也就是计数值超过
重装载数值寄存器
所能赋值的最大值,那么返回1作为报错信息。 - 如果ticks值在允许范围内,那么把它赋值到
重装载数值寄存器
。 - 配置NVIC
- 计数值清零
- 设定控制及状态寄存器
其实你需要关心的没那么多,只要关心你的ticks的值就行了
可以自定义一个初始化函数
void systick_enable(void)
{
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
}
void systick_disable(void)
{
SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;
}
static __IO u32 TimingDelay;
void SysTick_Init(void)
{
if (SysTick_Config(SystemCoreClock / 1000))//设置每1ms中断进一次systick中断
{
/* Capture error */
while (1);
}
systick_disable();
}
如何计算SysTick_Config()
里的参数呢?
我们的stm32频率
MCU_fre=72MHz
前面的SysTick_Config函数里执行了
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;
所以每次时钟倒数到0时需要的时间是
interrupt_time = ticks / MCU_fre
在本文里,我使用的MCU是72MHz,所以SystemCoreClock=72MHz
你也可以使用这个SystemCoreClock,改用自己需要的值。
那么如果仅仅填入SystemCoreClock,我们的单片机将会每1s进入一次systick中断
如果再把这个值除以1000,那么也就是每(1s/1000=1ms)的时间进入一次中断
在文件stm32f10x_it.c
里有滴答时钟的中断服务函数,这个文件是没有读写保护的,我们可以在这里写入自己需要的函数,也可以不写。
void SysTick_Handler(void)
{
}
当配置好滴答时钟后开启时钟,那么每当时钟计数值向下计数到0时,就进入此中断函数里。
本文里,我直接把LED灯翻转的代码写入了中断函数里:
#include "LED.h"
extern u8 LED_state;
u16 Time=500;
void SysTick_Handler(void)
{
if (Time != 0x00)
{
Time--;
}
else
{
LED_state = 1 - LED_state;
LED_Set(LED_state);
Time=500;//相当于500ms翻转一次LED灯
}
}
如果想用它来做一个软件延时函数就可以这么写:
//mydelay.c里
static __IO u32 TimingDelay;
void Delay_us(__IO u32 nTime)
{
TimingDelay = nTime;
systick_enable();
while(TimingDelay != 0);
systick_disable();
}
void TimingDelay_Decrease(void)
{
if (TimingDelay!= 0x00)
{
TimingDelay--;
}
}
//stm32f10x_it.c里
void SysTick_Handler(void)
{
TimingDelay_Decrease();
}
感谢阅读
代码参考自YSF1-012. SYSTICK-系统滴答定时器
下面附上通过systick中断实现的LED翻转视频。
systick中断实现LED翻转