STM32F407ZET6延时函数

本文介绍如何使用STM32的Systick定时器实现精确延时,并提供了毫秒级和微秒级延时函数的具体实现代码。通过配置不同的时钟源,可调整最大延时时间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        利用系统滴答定时器,实现单片机的精确延时。在ARM Cortex-M3和M4内核中有一个Systick定时器,它是一个24位的向下计数定时器,当计数到0时,它就会从Load寄存器中自动重装定时初值,只要不把CTRL寄存器中的ENABLE清0,它就永不停。

        Systick定时器常用来做精确延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。

        精确延时的意义:在很多传感器中,延时需要精确到us,用来做一个启动信号,如果说延时不精确,很难捕捉到启动信号。

相关寄存器

 代码实现:

delay.h

#ifndef _DELAY_H_
#define _DELAY_H_
#include "stm32f4xx.h"

void delay_ms(uint32_t nms);

void delay_us(uint32_t nus);


#endif

delay.c

#include "delay.h"

//延时函数:毫秒级别
void delay_ms(uint32_t nms)
{
	uint32_t tmp;
	while(nms--)
	{
		SysTick->LOAD = 168000000/8/1000;	//计数初值,延时1ms
		SysTick->VAL = 0;					//清空当前值
		SysTick->CTRL |= 0x1;				//开始计数
		do
		{
			tmp = SysTick->CTRL;			//获取CTRL状态
		}while((tmp&0x1) && !(0x1<<16));

		SysTick->VAL = 0;					//清空当前值
		SysTick->CTRL &= 0;					//关闭计数
	}
}

//延时函数:微秒级别
void delay_us(uint32_t nus)
{
	uint32_t tmp;
	while(nus--)
	{
		SysTick->LOAD = 168000000/8/1000000;	//计数初值,延时1us
		SysTick->VAL = 0;					//清空当前值
		SysTick->CTRL |= 0x1;				//开始计数
		do
		{
			tmp = SysTick->CTRL;			//获取CTRL状态
		}while((tmp&0x1) && !(0x1<<16));

		SysTick->VAL = 0;					//清空当前值
		SysTick->CTRL &= 0;					//关闭计数
	}

}


main.c

#include <stm32f4xx.h>  //stm32标准头文件
#include "sys.h"
#include "delay.h"


//初始化led
void init_led(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	//开启GPIOF的时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;			
	//模式选择:输入、输出、复用、模拟
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;		//输出模式
	//类型选择:推挽、开漏
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;		//推挽模式
	//速度选择:低速、中速、快速、高速
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;	//高速模式
	//上下拉选择:无上下拉、上拉、下拉
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;	//无上下拉

	//初始化GPIOF
	GPIO_Init(GPIOF, &GPIO_InitStructure);

    GPIO_SetBits(GPIOF,GPIO_Pin_9);//初始状态设置为高电平,熄灭

}

int main(void)
{

	//设置嘀嗒定时器时钟源
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//用于配置延时函数
	
	init_led();

	while(1)
	{
        GPIO_ResetBits(GPIOF,GPIO_Pin_9);   //将引脚设置为低电平(点亮)
		delay_ms(500);							//延时一会
		
		GPIO_SetBits(GPIOF,GPIO_Pin_9);		//将引脚设置为高电平(熄灭)
		delay_ms(500);
	} 
}

 

 主函数中对于时钟源的配置说明:

/**
  * @brief  Configures the SysTick clock source.
  * @param  SysTick_CLKSource: specifies the SysTick clock source.
  *   This parameter can be one of the following values:
  *     @arg SysTick_CLKSource_HCLK_Div8: AHB clock divided by 8 selected as SysTick clock source.
  *     @arg SysTick_CLKSource_HCLK: AHB clock selected as SysTick clock source.
  * @retval None
  */
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)
{
  /* Check the parameters */
  assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));
  if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
  {
    SysTick->CTRL |= SysTick_CLKSource_HCLK;
  }
  else
  {
    SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;
  }
}

void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);

参数选择:

SysTick _ clk source _ HCLK _ div 8:AHB时钟除以8,选择作为systick时钟源。 

SysTick_CLKSource_HCLK:选择AHB时钟作为SysTick时钟源。

SysTick_CLKSource_HCLK_Div8:AHB时钟/8=168MHz/8=21MHz(推荐)

SysTick_CLKSource_HCLK:AHB时钟=168MHz

最大延时时间分别是多久:

SysTick_CLKSource_HCLK_Div8:(2^24 - 1)/2100000 = 798.915ms

SysTick_CLKSource_HCLK:(2^24 - 1)/168000000 = 99.864375ms

### STM32F407ZET6 延时函数的实现与用法 #### 1. 延时函数头文件定义 在 `delay.h` 文件中,延时功能被封装为两个主要接口:`delay_ms` 和 `delay_us`。这两个函数分别用于实现毫秒级和微秒级的延时操作[^1]。 ```c #ifndef _DELAY_H_ #define _DELAY_H_ #include "stm32f4xx.h" void delay_ms(uint32_t nms); void delay_us(uint32_t nus); #endif ``` #### 2. 延时函数的核心机制 对于基于 HAL 库开发的情况,`HAL_Delay` 函数通常利用系统的滴答计数器 (`SysTick`) 来完成延时任务。具体来说,`HAL_Delay` 的工作原理是通过读取全局变量 `uwTick` 的值,并将其作为初始时间戳。随后进入一个循环等待状态,直到当前的时间戳与初始时间戳之间的差值达到指定的延时参数为止[^2]。 以下是 `HAL_Delay` 的典型实现逻辑: ```c uint32_t tickstart = HAL_GetTick(); // 获取当前系统滴答计数值 while ((HAL_GetTick() - tickstart) < ms) { // 循环等待直至满足延时条件 } ``` 在此过程中,`HAL_GetTick()` 返回的是自 MCU 启动以来经过的毫秒数,因此可以通过简单的减法运算判断是否达到了预期的延时效果。 #### 3. 自定义延时函数的实现方式 如果未使用 HAL 库,则可以手动编写基于 SysTick 或其他定时器资源的延时函数。以下是一个典型的基于 SysTick 的延时函数实现示例: ```c // 初始化 SysTick 定时器 void systick_init(void) { SysTick->LOAD = SystemCoreClock / 1000 - 1; // 配置每毫秒触发一次中断 SysTick->VAL = 0; SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk; } // 毫秒级延时函数 void delay_ms(uint32_t nms) { uint32_t ticks_start, current_ticks; ticks_start = SysTick->VAL; while (nms--) { do { current_ticks = SysTick->VAL; } while (current_ticks != ticks_start); // 等待一毫秒过去 } } ``` 上述代码片段展示了如何配置 SysTick 并以此为基础构建精确的延时功能。需要注意的是,在多任务环境下可能需要额外考虑上下文中断的影响以确保延时精度。 #### 4. 使用注意事项 当调用延时函数时应注意以下几点: - **阻塞性质**:无论是 `HAL_Delay` 还是自定义的延时函数,它们本质上都是阻塞式的,即 CPU 将会停留在该语句上直到延时期间结束。 - **实时性能影响**:长时间运行的延时可能会干扰其他重要事件处理流程,尤其是在硬实时应用场合下应谨慎采用此类方法。 - **频率依赖性**:某些延时算法的有效性和准确性取决于系统核心时钟的速度设置;修改时钟源后需重新校准相关参数。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值