按键中断、systick()函数和exti()函数的使用和区别

文章详细介绍了如何在STM32F4xx平台上使用EXTI进行外部中断,以实现按键控制LED,并配置NVIC的抢占优先级和子优先级,以优化中断处理。内容涉及EXTI初始化、中断服务函数和中断优先级设置方法。
摘要由CSDN通过智能技术生成

exti.c

#include "exti.h"


/*
引脚说明
//KEY0 -- 按键PE4--灯PA6
KEY0 -- PE4
PE4 -- EXTI4

KEY1 -- PE3

*/
void Exti_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStruct;
	EXTI_InitTypeDef  EXTI_InitStruct;
	NVIC_InitTypeDef  NVIC_InitStruct;
	//1、使能SYSCFG时钟: 使能这个时钟才能使用外部中断
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
	
	
	GPIO_InitStruct.GPIO_Pin	= GPIO_Pin_4;	//引脚4
	GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_IN; //输入
	GPIO_InitStruct.GPIO_PuPd	= GPIO_PuPd_UP; //上拉
	//2、 初始化IO口为输入。
	GPIO_Init(GPIOE, &GPIO_InitStruct);		
	
	//3、设置IO口与中断线的映射关系。
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource4);
		
	EXTI_InitStruct.EXTI_Line	= EXTI_Line4; 				//中断线4
	EXTI_InitStruct.EXTI_Mode	= EXTI_Mode_Interrupt;		//中断模式
	EXTI_InitStruct.EXTI_Trigger= EXTI_Trigger_Falling;		//下降沿
	EXTI_InitStruct.EXTI_LineCmd= ENABLE;					//使能中断线
	//4、初始化线上中断,设置触发条件等。
	EXTI_Init(&EXTI_InitStruct);
	
	NVIC_InitStruct.NVIC_IRQChannel						= EXTI4_IRQn;  	//选择通道
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority	= 2;			//抢占优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority			= 2; 			//响应优先级
	NVIC_InitStruct.NVIC_IRQChannelCmd					= ENABLE;		//通道使能	
	//5、配置中断分组(NVIC),并使能中断。
	NVIC_Init(&NVIC_InitStruct);
	

}

//6、 编写中断服务函数。 这个函数在startup_stm32f40_41.s中查阅
//不需要自己调用,中断响应后,CPU自动去执行的函数
void EXTI4_IRQHandler(void)
{

	
	if(EXTI_GetITStatus(EXTI_Line4) == SET)  //判断中断线0是否置1
	{
		GPIO_ToggleBits(GPIOA, GPIO_Pin_6);//置1,灯亮
	}
	//7、清除中断标志位
	EXTI_ClearITPendingBit(EXTI_Line4);

}

/*
外部中断PA0设置步骤
	
	1、理解按键电路原理	
	按键KEY0连接PA0
	
	当按键按下时,  PA0电平为低电平(0)
	当按键未按下时,PA0电平为高电平(1)
	
	2、设置NVIC分组(记住,整个工程只能设置一次分组)
	void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
	
	3、使能SYSCFG时钟: 
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
			 
	4、 初始化IO口为输入。
		   GPIO_Init();
		   
	5、设置IO口与中断线的映射关系。
			void SYSCFG_EXTILineConfig();
			
	6、初始化线上中断,设置触发条件等。
		   EXTI_Init();
		   
	7、配置中断分组(NVIC),并使能中断。
		   NVIC_Init();
		   
	8、 编写中断服务函数。
		  EXTIx_IRQHandler();
		  
	9、清除中断标志位
		  EXTI_ClearITPendingBit();

*/

以上函数实现了连接按键控制led

exti.h

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


void Exti_Init(void);

#endif

 main.c

#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "exti.h"



//粗延时
void delayms(int n)
{
	int i, j;
	
	for(i=0; i<n; i++)
		for(j=0; j<30000; j++);

}


//这是一个主函数
int main(void)
{
	
	//NVIC分组 抢占优先级两位:0~3  响应优先级两位:0~3 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	Led_Init();
	Exti_Init();
	
	
	while(1)
	{
		delayms(1000);
		
	}
	
	return 0;
}

led.c  和led.h函数在上几篇,没有改动。

上面用的延时是粗延时,如果要精准延时,加上systick定时器。如下函数:

delay.c

#include "delay.h"

/*
Systick定时器是芯片外设
*/

u32 my_nus = 21;  		//1us计21个数
u32 my_nms = 21000;  	//1ms计21000个数

void Delay_Init(void)
{
	//Systick频率 168/8 = 21MHZ
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);

}

//微秒延时  1
//最大范围为798915us
void delay_us(u32 nus)
{
	
	u32 temp = 0;
	
	SysTick->LOAD = my_nus * nus - 1;// 重装寄存器 要计数的值 
	SysTick->VAL  = 0;	//当前值寄存器值为0
	
	SysTick->CTRL |= (1<<0); //使能定时器

	do
	{
		temp = SysTick->CTRL;  
		
	}while( temp&(1<<0) && 	!(temp&(1<<16)) );         //检测CTRL第十六是否为1
		
	SysTick->CTRL &= ~(1<<0); //不使能定时器

}


//毫秒延时  
//最大范围为798.915ms
void delay_ms(u32 nms)
{
	
	u32 temp = 0;
	
	SysTick->LOAD = my_nms * nms - 1;// 重装寄存器 要计数的值 
	SysTick->VAL  = 0;	//当前值寄存器值为0
	
	SysTick->CTRL |= (1<<0); //使能定时器

	do
	{
		temp = SysTick->CTRL;  
		
	}while( temp&(1<<0) && 	!(temp&(1<<16)) );         //检测CTRL第十六是否为1
		
	SysTick->CTRL &= ~(1<<0); //不使能定时器

}

//秒延时
void delay_s(u32 ns)
{
	u32 i;
	
	for(i=0; i<ns; i++)
	{
		delay_ms(500);
		delay_ms(500);
	}

}

delay.h

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


void Delay_Init(void);


void delay_us(u32 nus); //微秒延时
void delay_ms(u32 nms);
void delay_s(u32 ns);

#endif

SysTick 中断和 EXTI(外部中断)中断 区别

SysTick 中断和 EXTI(外部中断)中断是两种不同类型的中断,它们在功能和触发条件上有一些区别:

1. **SysTick 中断**:
   - SysTick 定时器是 ARM Cortex-M 架构中的一个内置计时器,用于生成固定时间间隔的定时中断。
   - SysTick 中断是基于定时器的,它提供了一个周期性触发的定时中断,可用于系统的定时和调度,例如实现延迟、定时任务等。
   - SysTick 中断的间隔由加载到 SysTick 寄存器的值决定,因此可以通过调整该值来更改中断的触发频率。
   - SysTick 中断通常用于实现系统的时间相关功能,如任务调度、定时器等。

2. **EXTI 中断**:
   - EXTI(外部中断)是由外部事件触发的中断,例如外部引脚的状态变化(上升沿、下降沿、或者双边沿触发)。
   - EXTI 中断是基于硬件外部事件的,它允许外部事件触发处理器中断,从而执行相应的中断服务程序。
   - EXTI 中断允许 MCU 对外部信号的变化做出快速响应,常用于处理外部事件,如按钮按下、传感器触发等。
   - EXTI 中断的触发条件由外部事件的状态变化确定,可以通过配置 EXTI 寄存器来选择中断触发条件和外部引脚。

总的来说,SysTick 中断是基于内置定时器的周期性定时中断,而 EXTI 中断是基于外部事件(例如外部引脚状态变化)的触发中断。它们分别用于不同的应用场景,SysTick 用于系统的定时和调度,而 EXTI 用于对外部事件的快速响应。

 为什么用EXTI

代码就能实现按键控制led,为什么还要用exti? 

通过使用 EXTI(外部中断)来处理按键事件,这种方法具有以下优点:

1. **实时性**: 使用外部中断可以实现按键按下时立即响应,无需等待主循环的轮询或其他延时操作。这可以确保在按键按下时系统能够立即执行相应的操作,提高了系统的实时性和响应速度。

2. **节省资源**: 通过使用外部中断,系统只有在按键按下时才会唤醒处理器执行中断服务程序,而在按键未按下时处于休眠或低功耗状态,可以有效节省处理器的能耗。

3. **避免忙等待**: 如果使用轮询或忙等待的方式来检测按键状态,可能会导致处理器在等待按键按下时持续消耗 CPU 时间,降低系统的效率和功耗表现。

综上所述,通过使用外部中断来处理按键事件可以提高系统的实时性,节省资源,并避免忙等待的情况发生,是一种较好的实现方式。

重要函数    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    //NVIC分组 抢占优先级两位:0~3  响应优先级两位:0~3 
 

在嵌入式系统中,通常需要对中断或任务进行优先级排序,以确保系统对重要事件或任务的响应能力。这种优先级排序主要有两个方面:

1. 抢占优先级(Preemption Priority): 抢占优先级决定了当一个具有更高优先级的中断请求到来时,是否可以中断正在执行的低优先级中断或任务。更高的抢占优先级允许更快地中断正在执行的低优先级任务或中断。这使得系统能够在紧急情况下优先处理重要的任务。

2. 子优先级(Subpriority):在同一抢占优先级内,子优先级决定了在多个具有相同抢占优先级的中断请求中,哪一个会被优先执行。具有更高子优先级的中断会优先于具有较低子优先级的中断。这使得在同一优先级下,可以更细致地控制中断请求的执行顺序。

在一个系统中可能存在多个中断源,这些中断源可能在某些情况下会同时发生,或者在非常接近的时间内发生。为了合理地处理这些中断,需要对它们进行优先级排序。

通过使用两个优先级:抢占优先级和子优先级,可以确保系统在发生多个中断时能够按照预期的顺序进行处理。抢占优先级确保了当具有更高抢占优先级的中断请求到来时,能够立即中断正在执行的低优先级任务或中断;而子优先级则确保了在同一抢占优先级内,可以按照一定的顺序依次执行多个中断请求。

函数说明

/**
  * @brief  Configures the priority grouping: pre-emption priority and subpriority.
  * @param  NVIC_PriorityGroup: specifies the priority grouping bits length. 
  *   This parameter can be one of the following values:
  *     @arg NVIC_PriorityGroup_0: 0 bits for pre-emption priority
  *                                4 bits for subpriority
  *     @arg NVIC_PriorityGroup_1: 1 bits for pre-emption priority
  *                                3 bits for subpriority
  *     @arg NVIC_PriorityGroup_2: 2 bits for pre-emption priority
  *                                2 bits for subpriority
  *     @arg NVIC_PriorityGroup_3: 3 bits for pre-emption priority
  *                                1 bits for subpriority
  *     @arg NVIC_PriorityGroup_4: 4 bits for pre-emption priority
  *                                0 bits for subpriority
  * @note   When the NVIC_PriorityGroup_0 is selected, IRQ pre-emption is no more possible. 
  *         The pending IRQ priority will be managed only by the subpriority. 
  * @retval None
  */
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
{
  /* Check the parameters */
  assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));
  
  /* Set the PRIGROUP[10:8] bits according to NVIC_PriorityGroup value */
  SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
}

使用哪个参数? 

`NVIC_PriorityGroup_1` 和 `NVIC_PriorityGroup_2` 两个参数都定义了不同的优先级分组方式,其主要区别在于预抢占优先级和子优先级的分配方式不同。

- `NVIC_PriorityGroup_1`: 此参数指定了1位用于抢占优先级,3位用于子优先级。这意味着在系统中,有8个抢占优先级(2^1 = 2,共2个级别)和8个子优先级(2^3 = 8,共8个级别)可供分配。

- `NVIC_PriorityGroup_2`: 此参数指定了2位用于抢占优先级,2位用于子优先级。这意味着在系统中,有4个抢占优先级(2^2 = 4,共4个级别)和4个子优先级(2^2 = 4,共4个级别)可供分配。

所以,当选择使用哪个参数时,需要考虑系统的需求和实际情况:

- 如果系统需要更精细的优先级控制,即需要更多的子优先级来区分任务或中断的优先级,可以选择`NVIC_PriorityGroup_1`,因为它提供了更多的子优先级。
  
- 如果系统的需求对于预抢占优先级较为关键,而子优先级的区分度要求不高,可以选择`NVIC_PriorityGroup_2`,因为它提供了更多的预抢占优先级。

在实际选择时,应根据系统的实际需求来决定,以满足对系统性能和响应时间的要求。

 

重要概念理解

什么是芯片外设 

芯片外设(Peripheral)是指嵌入式系统中与主处理器核心(CPU)相连的辅助模块或硬件组件,它们扩展了芯片的功能,使其能够执行各种特定任务或处理外部事件。这些外设通常包括各种接口、控制器、传感器、存储设备等,用于连接外部设备或执行特定的功能。

芯片外设的功能包括但不限于以下几个方面:

1. **通信接口:** 包括串行通信接口(如UART、SPI、I2C)、以太网接口、USB接口等,用于与外部设备进行数据交换和通信。

2. **定时器和计数器:** 用于生成精确的时间间隔或进行定时操作,如控制定时器、PWM(脉冲宽度调制)输出等。

3. **模拟/数字转换器(ADC/DAC):** 用于将模拟信号转换为数字信号(ADC),或将数字信号转换为模拟信号(DAC),常用于传感器接口、信号采集等。

4. **存储器控制器:** 包括闪存控制器、SRAM控制器等,用于管理外部存储器的读写操作。

5. **中断控制器:** 用于管理中断请求,优先级分配和中断处理。

6. **GPIO(通用输入/输出):** 用于连接外部设备、传感器或执行控制操作的通用IO口。

7. **电源管理单元:** 控制芯片的供电、功耗管理和休眠模式等。

8. **加速器和协处理器:** 用于加速特定计算任务,如加密引擎、数字信号处理器等。

这些外设通常由硬件逻辑实现,与主处理器核心通过总线或专用接口连接。通过这些外设,芯片能够实现更多的功能,适应不同的应用场景,提高系统的性能和灵活性。

与外部设备有什么不同?

外部设备是指连接到嵌入式系统的独立硬件组件或模块,这些设备通常不在芯片内部,而是外部连接到芯片的引脚或接口上。外部设备可以是传感器、执行器、存储设备、显示器、键盘、鼠标、网络设备等,它们提供了与嵌入式系统进行交互的方式。

与芯片外设不同,外部设备通常是独立的单元,它们具有自己的处理器、控制逻辑和接口电路,通过各种物理接口(如USB、串口、并口等)连接到嵌入式系统。这些外部设备可以由不同的制造商生产,具有不同的规格和功能。

与外部设备相比,芯片外设是直接集成在嵌入式系统芯片内部的功能模块或硬件组件。它们与主处理器核心(CPU)连接在一起,通常通过内部总线或专用接口进行通信。外设由芯片厂商设计和实现,为了方便系统开发者使用,通常提供了软件接口(如寄存器映射、驱动程序等),使得开发者可以通过软件控制和配置外设功能。

总的来说,外部设备是独立的硬件单元,连接到嵌入式系统外部,而芯片外设是嵌入式系统内部集成的功能模块,与主处理器核心连接在一起。

README

 实验效果

每个模块分别学完了,接下来会做一些复盘和总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值