四、stm32系统滴答定时器与三种延时方式

首先贴出工程
工程上传到了我的github上了,点此进入
我用的LED引脚是PC13,芯片是stm32c8t6。

首先理解systick

我们一般称它为系统滴答定时器,一个24位的系统节拍定时器,它只有基本的计数功能,所有cortex m3核心的单片机都有这样一个定时器,因为它是属于cortex m3内核的,不属于外设一类。

它可以干什么

首先它是一个定时器,肯定是来定时的,学过51的都了解,定时器就是计数来的,计数达到定时要求。它的寄存器非常简单
在这里插入图片描述在这里可以看到它的解释,如果想了解更多,可以看一下《Cortex-M3权威指南》
在这里插入图片描述在这里插入图片描述在这里插入图片描述

所有基于ARM Cortex_M3内核的控制器都带有SysTick定时器,这样就方便了程序在不同的器件之间的移植。而使用RTOS的第一项工作往往就是将其移植到开发人员的硬件平台上,由于SYSTICK的存在无疑降低了移植的难度。
这也是为什么我们使用滴答定时器的原因,因为它属于内核,每个arm单片机都有,简单。

关于滴答定时器中断

32的滴答定时器的中断受到NVIC的管理,所以它的中断是可以设置优先级的
其中断函数是void SysTick_Handler(void)这个我就不说了。中断优先级,在调用SysTick_Config(uint32_t ticks)之后,调用 void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)。这个函数在core_cm3.h头文件中。

关于延时

目前接触的有三种常用的延时方式
第一种是最普通的延时,也就是根据系统运行频率去加减一个数来达到延时效果,这个的特点是实现简单但是不能保证时间的完全正确,这个用来粗略延时场所是最合适的。

第二种通过系统滴答定时器计数,获取寄存器状态来获得延时效果,本质上与第一个延时方法一致,但是更加精确。个人不喜欢这种定时方式,arm的芯片确实用起来可以,一旦换了其它内核的芯片就不好移植了。

第三种通过定时器中断,不限于滴答定时器,但是平常我们都用滴答定时器来做。中断计数,获取计数值来延时。这个的好处就是相对精确,ms以上延迟用着不错,但是涉及中断的嵌套,这个是要注意中断优先级的,将这个中断优先级设置为最高就好,反正计数不过US级别的时间,不会对其它任务有影响。
很明显第二种和第三种不可能兼容
所以我推荐第一种和第三种,第二种是正点原子做的方式吧,我不是很喜欢,毕竟我使用任务调度搞一个timebase,照它这个搞法timebase是没得咯。
第一种延时代码

//毫秒级的延时
void delay_ms(u16 time)
{
	u16 i=0;  
	
	while(time--)
	{
		i=12000;  //自己定义
		while(i--) ;    

		}
}

这个可以自己调嘛,肯定是的。。。。

第二种延时代码

void delay_init()
{
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);	//选择外部时钟  HCLK/8
	fac_us=SystemCoreClock/8000000;	      //为系统时钟的1/8,实际上也就是在计算1usSysTick的VAL减的数目
	fac_ms=(u16)fac_us*1000;		//代表每个ms需要的systick时钟数,即每毫秒SysTick的VAL减的数目   
}
void delay_ms(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&(1<<16)));	//等待时间到达,看CTRL的第16位(COUNTFLAG)是否为1,看STRL的第0位(ENABLE)是否为1   
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;       //关闭计数器
	SysTick->VAL =0X00;       //清空计数器	  	    
} 

第三种延时代码
官方sdk的代码是这样子的

void systick_Init(void){
	SysTick_Config(SystemCoreClock / 1000);
}

void TimingDelay_Decrement(void)
{
  if (TimingDelay != 0x00)
  { 
    TimingDelay--;
  }
}
void Delay(__IO uint32_t nTime)
{ 
  TimingDelay = nTime;

  while(TimingDelay != 0);
}

/**
  * @brief  This function handles SysTick Handler.
  * @param  None
  * @retval None
  */
void SysTick_Handler(void)
{
  TimingDelay_Decrement();
}

但是由于老毛病,我日常需要一个向上计数的timebase,所以我改了改。
下面是我的第三种延迟代码

void systick_Init(void){
	SysTick_Config(SystemCoreClock / 1000);
}
void sysdelay_ms(u16 ms)
{
	u32 end_time = systime_ms+ms;
  while( systime_ms < end_time)
  {
    ;
  }
}

/**
  * @brief  This function handles SysTick Handler.
  * @param  None
  * @retval None
  */
void SysTick_Handler(void)
{
	systime_ms++;
}

OK,收工。。。。

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于STM32F103系列微控制器的滴答定时器,可以使用它来实现毫秒和微秒级的延时。下面是两个简单的函数示例,用于实现延时。 首先,我们需要启用滴答定时器。可以使用下面的代码片段来初始化滴答定时器: ```c void SysTick_Init(void) { SysTick->LOAD = (uint32_t)(SystemCoreClock / 1000) - 1; // 设置滴答定时器的重装载值,实现1ms的中断一次 SysTick->VAL = 0; // 清空当前计数值 SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk; // 开启滴答定时器 } ``` 接下来,我们可以定义一个函数来实现毫秒级延时: ```c void delay_ms(uint32_t ms) { uint32_t start = SysTick->VAL; // 记录当前计数值 uint32_t target = start - (ms * (SystemCoreClock / 1000)); // 计算目标计数值 if (start < target) // 处理计数器溢出的情况 { while (SysTick->VAL > start || SysTick->VAL <= target); } else { while (SysTick->VAL > start && SysTick->VAL <= target); } } ``` 最后,我们可以定义一个函数来实现微秒级延时: ```c void delay_us(uint32_t us) { uint32_t start = SysTick->VAL; // 记录当前计数值 uint32_t target = start - (us * (SystemCoreClock / 1000000)); // 计算目标计数值 if (start < target) // 处理计数器溢出的情况 { while (SysTick->VAL > start || SysTick->VAL <= target); } else { while (SysTick->VAL > start && SysTick->VAL <= target); } } ``` 使用这两个函数,你可以在STM32F103微控制器上实现所需的毫秒和微秒级延时。请注意,这些函数会阻塞程序的执行,直到延时结束。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值