利用Systick实现精准延时

点击查看代码
/**
   ******************************************************************************
   * @file    main.c 
   * @author  
   * @version 
   * @date    2024/06/28
   * @brief   实现利用EXTI边沿检测器来检测PA0按键的变化,当用户按下按键时则触发
						  中断,提高程序的实时响应能力
							
							注意:PA0引脚必须和EXTI0建立映射关系,需要对外设进行初始化和配置!
   ******************************************************************************
**/

#include "stm32f4xx.h"  //必须包含



//前台程序就是中断服务程序,该程序是不需要手动调用的,当中断触发之后CPU会自动跳转过来执行该函数
void EXTI0_IRQHandler(void)
{
	
	//判断边沿检测器0的中断是否触发
  if(EXTI_GetITStatus(EXTI_Line0) != RESET)
  {	
		//执行前台程序,比如按下按键就会触发中断,中断执行蜂鸣器的鸣叫
    GPIO_ResetBits(GPIOF,GPIO_Pin_9);//控制PF9引脚输出低电平,则LED会亮
   
    //清除边沿检测器0的中断状态,目的是为了下次可以顺利触发中断
    EXTI_ClearITPendingBit(EXTI_Line0);
  }
}


//LED的初始化
void  LED_Config()
{
	//1.定义GPIO外设的结构体变量
	GPIO_InitTypeDef  GPIO_InitStructure;
	
	//2.打开GPIOF端口的时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
	
	//3.配置PF9引脚为输出模式
	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;
	
	//4.对GPIOF端口进行初始化
	GPIO_Init(GPIOF, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOF,GPIO_Pin_9);//LED不亮
}

//BEEP的初始化
void  BEEP_Config()
{
	//1.定义GPIO外设的结构体变量
	GPIO_InitTypeDef  GPIO_InitStructure;
	
	//2.打开GPIOF端口的时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
	
	//3.配置PF9引脚为输出模式
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_8;
	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;
	
	//4.对GPIOF端口进行初始化
	GPIO_Init(GPIOF, &GPIO_InitStructure);
	
	GPIO_ResetBits(GPIOF,GPIO_Pin_8);//BEEP默认不响
}

void KEY_Config()
{
	//1.定义外设的初始化结构体变量
	EXTI_InitTypeDef   EXTI_InitStructure;
  GPIO_InitTypeDef   GPIO_InitStructure;
  NVIC_InitTypeDef   NVIC_InitStructure;
	
	//2.打开GPIOA+SYSCFG的时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,  ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

	//3.配置PA0引脚为输入模式,如果打算检测PA0引脚的边沿,必须配置为输入模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//4.把EXTI0外部中断线和PA0引脚建立映射关系
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
	
	//5.配置EXTI0外部中断线的参数
	EXTI_InitStructure.EXTI_Line = EXTI_Line0;							//边沿检测器编号,编号需要和引脚编号一致
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;			//中断模式,当检测到指定边沿可以触发中断
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //检测边沿,下降沿是用户按下按键才会生成
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;								//边沿检测器的状态,ENABLE是启用  DISABLE是禁用
	EXTI_Init(&EXTI_InitStructure);

	//6.配置NVIC外设的参数+初始化NVIC
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;				//中断通道,每个边沿检测器都有独立的通道
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//中断的抢占优先级  范围 0 ~ 15
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;       //中断的子优先级    范围 0 ~ 15
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;					 //中断通道的状态  ENABLE是启用  DISABLE是禁用
	NVIC_Init(&NVIC_InitStructure);
}

//延时微秒 注意:Systick是24bit的递减计数器  约等于798915us,所以参数不可以超过这个值
void delay_us(u32 nus)
{
	SysTick->CTRL = 0; 						 // 向控制状态寄存器中写入0,目的关闭系统嘀嗒定时器
	SysTick->LOAD = (nus * 21) - 1;// 指的是计数次数,定时时间 = 计数次数 * 计数周期
	SysTick->VAL  = 0; 						 // 清除当前数值寄存器的值
	SysTick->CTRL = 1; 						 // 开启了定时器,并且定时器的时钟源选择了21MHZ--> 计数周期 = 1/21us
	while ((SysTick->CTRL & 0x00010000)==0);//等待延时时间到达
	SysTick->CTRL = 0; 						 // 向控制状态寄存器中写入0,目的关闭系统嘀嗒定时器

}

//延时毫秒 注意:Systick是24bit的递减计数器  约等于798ms,所以参数不可以超过这个值
void delay_ms(u32 nms)
{
	SysTick->CTRL = 0; 						 			// 向控制状态寄存器中写入0,目的关闭系统嘀嗒定时器
	SysTick->LOAD = (nms * 21*1000) - 1;// 指的是计数次数,定时时间 = 计数次数 * 计数周期
	SysTick->VAL  = 0; 						 			// 清除当前数值寄存器的值
	SysTick->CTRL = 1; 						 			// 开启了定时器,并且定时器的时钟源选择了21MHZ--> 计数周期 = 1/21us
	while ((SysTick->CTRL & 0x00010000)==0);//等待延时时间到达
	SysTick->CTRL = 0; 						 			// 向控制状态寄存器中写入0,目的关闭系统嘀嗒定时器
}

//延时秒
void delay_s(u32 ns)
{
	while(ns--)
	{
		delay_ms(500);
		delay_ms(500);
	}
}

int main()
{
	
	//1.硬件的初始化
	LED_Config();  
	KEY_Config();
	BEEP_Config();
	
	while(1)
	{
		  GPIO_ToggleBits(GPIOF,GPIO_Pin_8);//BEEP每隔500ms电平翻转一次
			delay_ms(500);
		
	}
}





posted @ 2025-08-30 12:21  w1888  阅读(17)  评论(0)    收藏  举报