STM32F10x,使用systick写一个软件延时

本文详细介绍了如何在STM32F10x微控制器中使用SysTick定时器进行软件延时,并展示了如何配置定时器以实现每1ms或自定义时间间隔的中断,以及将LED灯翻转功能集成到SysTick中断服务函数中。
摘要由CSDN通过智能技术生成

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翻转

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值