野火F1mini关于systick系统定时器和EXTI外部中断的学习

本文详细介绍了STM32中的systick系统定时器和EXTI外部中断的应用方法。对于systick系统定时器,文章深入讲解了其寄存器配置、中断设置以及查询操作,并提供了具体的代码实现。对于EXTI外部中断,文章则阐述了如何配置GPIO口和EXTI的信号源,以及如何设置中断触发方式。

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

学习目标:

关于systick系统定时器和EXTI外部中断的学习

学习内容:

1、 关于systick系统定时器的学习 2、 关于EXTI外部中断的学习

学习时间:

1、 周六上午 8 点-上午 11 点

学习产出:

1.优快云 技术博客 1 篇

一、systick系统定时器

1.关于中断操作

SysTick—系统定时器有 4 个寄存器,简要介绍如下。在使用 SysTick 产生定时的时候,只需要配置前三个寄存器,最后一个校准寄存器不需要使用。

CTRL SysTick 控制及状态寄存器

LOAD SysTick 重装载数值寄存器

VAL SysTick 当前数值寄存器

CALIB SysTick 校准数值寄存器

寄存器控制相关

位段 			名称 			类型 		复位值 		描述 
16 			COUNTFLAG 		R/W 		0 			如果在上次读取本寄存器后, SysTick 已经计到了 0,则该位为 1。
2 			CLKSOURCE 		R/W 		0 			时钟源选择位,0=AHB/8,1=处理器时钟 AHB
1 			TICKINT 		R/W 		0 			1=SysTick 倒数计数到 0 时产生 SysTick 异常请求,0=数到 0 时无动作。也可以通过读取COUNTFLAG 标志位来确定计数器是否递减到0 
0 			ENABLE 			R/W 		0 			SysTick 定时器的使能位

SysTick 重装载数值寄存器
位段 		名称 		类型 		复位值 		描述
23:0 	RELOAD 		R/W 		0 		当倒数计数至零时,将被重装载的值

SysTick 当前数值寄存器
位段 		名称 		类型 		复位值 		描述 
23:0 	CURRENT 	R/W 		0 		读取时返回当前倒计数的值,写它则使之清零,同时还会清除在 SysTick 控制及状态寄存器中的COUNTFLAG标志

SysTick 属于内核的外设,有关的寄存器定义和库函数都在内核相关的库文件core_cm3.h 中。

static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{ 
  if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /*不可能的重装值 寄存器24bit,最大值2^24*/
                                                               
  SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /*设置重装载寄存器*/
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* 中断优先级 设置为15最低*/
  SysTick->VAL   = 0; 										/* SysTick 当前数值 */
  
  /* 设置系统定时器的时钟源为AHBCLK=72M SysTick_CTRL_CLKSOURCE_Msk为1<<2 */
  /* 使能系统定时器SysTick_CTRL_TICKINT_Msk为1<<1  */
  /* 使能定时器SysTick_CTRL_ENABLE_Msk为0<<1 */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | 
                   SysTick_CTRL_TICKINT_Msk   | 
                   SysTick_CTRL_ENABLE_Msk;                    
  return (0);                                                  /* Function successful */
}

//关于中断优先级的设置
static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
/* 
先判断形参IRQn的大小,如果是小于 0,则表示这个是系统异常,系统异常的优先级由内核外设SCB的寄存器 SHPRx 控制,如果大于 0 则是外部中断,外部中断的优先级由内核外设 NVIC 中的 IPx 寄存器控制。
SPRH1-SPRH3 是一个 32 位的寄存器,但是只能通过字节访问,每 8 个字段控制着一个内核外设的中断优先级的配置。在 STM32F103 中,只有位 7:3 这高四位有效,低四位没有用到,所以内核外设的中断优先级可编程为:0~15,只有 16 个可编程优先级,数值越小,优先级越高。如果软件优先级配置相同,那就根据他们在中断向量表里面的位置编号来决定优先级大小,编号越小,优先级越高。
*/
  if(IRQn < 0) {
    SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M3 System Interrupts */
  else {
    NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff);    }        /* set Priority for device specific Interrupts  */
}

main.c


#include "stm32f10x.h"
#include "bsp_SysTick.h"
#include "bsp_led.h"

/*
 * t : 定时时间
 * Ticks : 多少个时钟周期产生一次中断
 * f : 时钟频率 72000000
 * t = Ticks * 1/f = (72000000/100000) * (1/72000000) = 10us 
 */ 

int main(void)
{	
	/* LED 初始化 */
	LED_GPIO_Config();

	/*配置systick为10us中断一次*/
	SysTick_Init();	
	for(;;)
	{
		LED1( ON ); 
	    Delay_us(500000);    	//5s延时
		//Delay_ms(500);
		LED1( OFF );
	  
		LED2( ON );
	    Delay_us(500000);		//5s延时
		//Delay_ms(500);
		LED2( OFF );	

	}     

}


/*********************************************END OF FILE**********************/

bsp_SysTick.h

#ifndef __SYSTICK_H
#define __SYSTICK_H

#include "stm32f10x.h"

void SysTick_Init(void);
void Delay_us(__IO u32 nTime);
#define Delay_ms(x) Delay_us(100*x)	 //单位ms

#endif /* __SYSTICK_H */

bsp_SysTick.c

  
#include "bsp_SysTick.h"
#include "core_cm3.h"
#include "misc.h"

static __IO u32 TimingDelay;

/**
  * @brief  启动系统滴答定时器 SysTick
  */
void SysTick_Init(void)
{
	/* SystemFrequency / 1000    1ms
	 * SystemFrequency / 100000	 10us
	 * SystemFrequency / 1000000 1us
	 */
	if (SysTick_Config(SystemCoreClock / 100000))
	{ 
		/* Capture error */ 
		while (1);
	}
}
/*us延时程序,10us为一个单位*/
void Delay_us(__IO u32 nTime)
{ 
	TimingDelay = nTime;	

	//使能滴答定时器 
	SysTick->CTRL |=  SysTick_CTRL_ENABLE_Msk;

	while(TimingDelay != 0);
}

/**
  * @brief  获取节拍程序
  * @attention  在 SysTick 中断函数 SysTick_Handler()µ÷ÓÃ
  */
void TimingDelay_Decrement(void)
{
	if (TimingDelay != 0x00)
	{ 
		TimingDelay--;
	}
}



/*********************************************END OF FILE**********************/

stm32f10x_it.h

void SysTick_Handler(void);

stm32f10x_it.c

extern void TimingDelay_Decrement(void);
void SysTick_Handler(void)
{
	TimingDelay_Decrement();	
}

2.查询操作:COUNTFLAG 如果在上次读取本寄存器后, SysTick 已经计到了 0,则该位为 1。

bsp_SysTick.h

#ifndef __SYSTICK_H
#define __SYSTICK_H

#include "stm32f10x.h"

void SysTick_Delay_Us( __IO uint32_t us);
void SysTick_Delay_Ms( __IO uint32_t ms);

#endif /* __SYSTICK_H */

bsp_SysTick.c

#include "bsp_SysTick.h"
#include "core_cm3.h"
#include "misc.h"

void SysTick_Delay_Us( __IO uint32_t us)
{
	uint32_t i;
	SysTick_Config(SystemCoreClock/1000000);
	
	for(i=0;i<us;i++)
	{
		// 当计数器的值减小到0的时候,CRTL寄存器的位16置1,当位置1时,读取该位会清0
		while( !((SysTick->CTRL)&(1<<16)) );
	}
	//关闭systick定时器
	SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;
}

void SysTick_Delay_Ms( __IO uint32_t ms)
{
	uint32_t i;	
	SysTick_Config(SystemCoreClock/1000);
	
	for(i=0;i<ms;i++)
	{
		// 当计数器的值减小到0的时候,CRTL寄存器的位16置1,当位置1时,读取该位会清0
		while( !((SysTick->CTRL)&(1<<16)) );
	}
	//关闭systick定时器
	SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk;
}

/*********************************************END OF FILE**********************/

core_cm3.h中会使用到有关systick_config()的代码

static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{ 
  if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /*不可能的重装值 寄存器24bit,最大值2^24*/
                                                               
  SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /*设置重装载寄存器*/
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* 中断优先级 设置为15最低*/
  SysTick->VAL   = 0; 										/* SysTick 当前数值 */
  
  /* 设置系统定时器的时钟源为AHBCLK=72M SysTick_CTRL_CLKSOURCE_Msk为1<<2 */
  /* 使能系统定时器SysTick_CTRL_TICKINT_Msk为1<<1  */
  /* 使能定时器SysTick_CTRL_ENABLE_Msk为0<<1 */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | 
                   SysTick_CTRL_TICKINT_Msk   | 
                   SysTick_CTRL_ENABLE_Msk;                    
  return (0);                                                  /* Function successful */
}

main.c

#include "stm32f10x.h"
#include "bsp_SysTick.h"
#include "bsp_led.h"


int main(void)
{	
	/* 配置LED的端口初始化 */
	LED_GPIO_Config();
	for(;;)
	{
		LED1( ON ); 
		SysTick_Delay_Ms( 1000 );
		LED1( OFF );
	  
		LED2( ON );
		SysTick_Delay_Ms( 1000 );
		LED2( OFF );
	} 
}

/*********************************************END OF FILE**********************/

二、关于EXTI外部中断

bsp_exti.h

#ifndef __EXTI_H
#define	__EXTI_H
#include "stm32f10x.h"
//引脚定义
#define KEY1_INT_GPIO_PORT         GPIOA
#define KEY1_INT_GPIO_CLK          (RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO)
#define KEY1_INT_GPIO_PIN          GPIO_Pin_0
#define KEY1_INT_EXTI_PORTSOURCE   GPIO_PortSourceGPIOA
#define KEY1_INT_EXTI_PINSOURCE    GPIO_PinSource0
#define KEY1_INT_EXTI_LINE         EXTI_Line0
#define KEY1_INT_EXTI_IRQ          EXTI0_IRQn

#define KEY1_IRQHandler            EXTI0_IRQHandler

#define KEY2_INT_GPIO_PORT         GPIOC
#define KEY2_INT_GPIO_CLK          (RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO)
#define KEY2_INT_GPIO_PIN          GPIO_Pin_13
#define KEY2_INT_EXTI_PORTSOURCE   GPIO_PortSourceGPIOC
#define KEY2_INT_EXTI_PINSOURCE    GPIO_PinSource13
#define KEY2_INT_EXTI_LINE         EXTI_Line13
#define KEY2_INT_EXTI_IRQ          EXTI15_10_IRQn

#define KEY2_IRQHandler            EXTI15_10_IRQHandler

void EXTI_Key_Config(void);

#endif /* __EXTI_H */

bsp_exti.c

#include "./KEY/bsp_exti.h"

static void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  /*配置NVIC为中断优先级组*/
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  
  /* 配置中断源:key1 */
  NVIC_InitStructure.NVIC_IRQChannel = KEY1_INT_EXTI_IRQ;
  /* 配置抢占优先级:1 */
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 配置子优先级:1 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中断通道 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  
  /* 配置中断源:key2 采取和key1相同的配置*/  
  NVIC_InitStructure.NVIC_IRQChannel = KEY2_INT_EXTI_IRQ;
  NVIC_Init(&NVIC_InitStructure);
}

//EXTI中断配置
void EXTI_Key_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure; 
	EXTI_InitTypeDef EXTI_InitStructure;

	/*开启按键的GPIO口时钟*/
	RCC_APB2PeriphClockCmd(KEY1_INT_GPIO_CLK,ENABLE);
												
	/*配置NVIC中断*/
	NVIC_Configuration();
	
/*--------------------------KEY1-----------------------------*/
  /*GPIO口*/	
  GPIO_InitStructure.GPIO_Pin = KEY1_INT_GPIO_PIN;
  /*浮空输入*/	
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);

	/*EXTI的信号源*/
  GPIO_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE, KEY1_INT_EXTI_PINSOURCE); 
  EXTI_InitStructure.EXTI_Line = KEY1_INT_EXTI_LINE;
	
	/*EXTI为中断模式*/
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	/*上升沿中断*/
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  /*使能中断*/	
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
	
  /*--------------------------KEY2-----------------------------*/
  GPIO_InitStructure.GPIO_Pin = KEY2_INT_GPIO_PIN;
  /*浮空输入*/	
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStructure);

	/*EXTI的信号源*/
  GPIO_EXTILineConfig(KEY2_INT_EXTI_PORTSOURCE, KEY2_INT_EXTI_PINSOURCE); 
  EXTI_InitStructure.EXTI_Line = KEY2_INT_EXTI_LINE;
	
	/*EXTI为中断模式*/
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	/*下降沿中断*/
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  /*使能中断*/	
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
}
/*********************************************END OF FILE**********************/

main.c

#include "stm32f10x.h"
#include "./KEY/bsp_exti.h"
#include "bsp_led.h"

int main(void)
{	
	LED_GPIO_Config();
	EXTI_Key_Config(); 
	while(1)                            
	{
	} 
}

/*********************************************END OF FILE**********************/

stm32f10x_it.c中key1和key2的中断服务函数

void KEY1_IRQHandler(void)
{
  //是否产生EXTI Line中断
  
  //stm32f10x_exit.c中
  /*
  		ITStatus EXTI_GetITStatus(uint32_t EXTI_Line)
        {
          ITStatus bitstatus = RESET;
          uint32_t enablestatus = 0;
          /* Check the parameters */
          assert_param(IS_GET_EXTI_LINE(EXTI_Line));

          enablestatus =  EXTI->IMR & EXTI_Line;
          if (((EXTI->PR & EXTI_Line) != (uint32_t)RESET) && (enablestatus != (uint32_t)RESET))
          {
            bitstatus = SET;
          }
          else
          {
            bitstatus = RESET;
          }
          return bitstatus;
        }
  */
	if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) 
	{
		// LED1反转	
		LED1_TOGGLE;
         //清除标志位
		EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);     
		
		//stm32f10x_exit.c中
        /*
  		void EXTI_ClearITPendingBit(uint32_t EXTI_Line)
        {
          /* Check the parameters */
          assert_param(IS_EXTI_LINE(EXTI_Line));

          EXTI->PR = EXTI_Line;
        }
       */
	}  
}

void KEY2_IRQHandler(void)
{
	if(EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET) 
	{
		//LED2反转		
		LED2_TOGGLE;
         //清除标志位
		EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);     
	}  

总结:由于设置的key1为上升沿触发中断,key2为下降沿触发中断,当按下key1时led1反转,当按下key2时led2不会反转,需要等待key2松开时才会触发led2反转。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

visual_eagle

欢迎交流学习

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值