STM32中断和外部中断

 

NVIC:嵌套中断向量控制器:用于统一分配中断优先级和管理中断

响应式优先级:也可以称为插队式优先级哪个优先级高优先处理哪个

抢占式优先级:优先级高的可以优先被处理,相当于CPU可以暂时中断当前处理的程序,优先处理优先级更高的程序,该程序执行完成后再执行原先没有执行完毕的程序,也可以称之为嵌入式中断优先级

AFIO中断引脚选择:是一个中断引脚选择器可以在前面GPIO外设的16个引脚中选择一个连接到EXTI边沿检测及控制中所以

相同的Pin不能同时触发中断,因为PA0,PB0,PC0通过AFIO选择后只有其中一个可以连接到EXTI的通道0上,PB1,PC1等也只有一个可以接入EXTI上

模拟电子技术与或门基础

旋转编码器讲解

旋转编码器的硬件电路

外部中断寄存器代码

1:接线

#include "stm32f10x.h"                  // Device header


// 编写初始化函数--->模块化的第一步是编写初始化函数
void CountSersor_Init(void){
    /*
	   外部中断配置  
	   1: 配置RCC进涉及的外部中断时钟全部打开
	   2:配置GPIO选择端口为输入模式
	   3: 配置AFIO选择需要使用到的GPIO并连接后面的exit
	   4:配置EXTI选择边沿触发的方式如上升沿,下降沿,或者是双边沿,选择触发响应的方式
	   5:配置NVIC给中断选择一个合适的优先级
	  */
	  

}

AFIO相关函数


             用于复位AFIO外设,调用这个函数会清除AFIO外设
             void GPIO_AFIODeInit(void);
             用于锁定GPIO配置调用这个函数参数指定某个引脚,锁定引脚配置防止意外更改
             void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
             以下的两个函数是用于配置AFIO的事件输出功能
           void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
           void GPIO_EventOutputCmd(FunctionalState NewState);

             这个函数可以用作引脚重映射,第一个参数是重映射的方式,第二个参数是新的状态
             void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);
          
  这个函数外部中断需要使用到的函数,调用这个函数可以选择我们的中断引脚
       void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
             和以太网相关外设暂时没有使用到
             void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);

EXTI相关函数

NVIC配置

编写中断函数代码实现当遮挡传感器时oled显示屏中的数字加1

中断函数代码

#include "stm32f10x.h"                  // Device header
uint16_t CountSensor_Count;

// 编写初始化函数--->模块化的第一步是编写初始化函数
void CountSersor_Init(void){
	  //1------>todo : 配置RCC进涉及的外部中断时钟全部打开
	  // 开启GPIOB的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	  // 开启AFIO的时钟
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	  // EXPI和NVIC的时钟一直处于打开状态不需要我们手动开启
	  
	  //2------>todo : 配置GPIO选择端口为输入模式
	  GPIO_InitTypeDef GPIO_InitStructure;
	  // 引出结构体模式
	  GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPU ; // 配置模式
	  GPIO_InitStructure.GPIO_Pin =GPIO_Pin_14 ;
	  GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;
	  // 调用GPIO初始化函数,初始GPIOB
	  GPIO_Init(GPIOB,&GPIO_InitStructure);
	
	  // 3:todo ------->  配置AFIO选择需要使用到的GPIO并连接后面的exit
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);
	  
	  // 3:todo ------->配置EXTI选择边沿触发的方式如上升沿,下降沿,或者是双边沿,选择触发响应的方式
		EXTI_InitTypeDef Exit_InitStruct;
		// 引出结构体成员
		Exit_InitStruct.EXTI_Line =EXTI_Line14; // 指定需要配置的中断线
		Exit_InitStruct.EXTI_LineCmd =ENABLE; // 开启中断
		Exit_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; // 模式:中断模式
		Exit_InitStruct.EXTI_Trigger =EXTI_Trigger_Falling ;// 下降沿触发
	  EXTI_Init(&Exit_InitStruct);
		
		// 选择中断分组函数
		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
		NVIC_InitTypeDef  NVIC_Initstructure;
		NVIC_Initstructure.NVIC_IRQChannel = EXTI15_10_IRQn;
		NVIC_Initstructure.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority = 1;
		NVIC_Initstructure.NVIC_IRQChannelSubPriority = 1;
		NVIC_Init(&NVIC_Initstructure);
		
	
}
uint16_t CountSensor_Get(void){
     return CountSensor_Count;
}

void  EXTI15_10_IRQHandler(void){
   if(EXTI_GetITStatus(EXTI_Line14) == SET){
		    CountSensor_Count++;
	      // 中断程序结束后一定要清除中断程序标志位函数
		    EXTI_ClearITPendingBit(EXTI_Line14);
	 }
}

中断函数头文件

#ifndef __COUNT_SENSOR_H__
#define __COUNT_SENSOR_H__
    /*
	   外部中断配置  
	   1: 配置RCC进涉及的外部中断时钟全部打开
	   2:配置GPIO选择端口为输入模式
	   3: 配置AFIO选择需要使用到的GPIO并连接后面的exit
	   4:配置EXTI选择边沿触发的方式如上升沿,下降沿,或者是双边沿,选择触发响应的方式
	   5:配置NVIC给中断选择一个合适的优先级
	  */
void CountSersor_Init(void);
uint16_t CountSensor_Get(void);

#endif

主函数调用代码

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "CounterSensor.h"

int main(void)
{
  // 初始化oled
	OLED_Init();
	CountSersor_Init();
	// 使用OLED显示字符串
	OLED_ShowString(1,3,"Count:");
	

	while (1)
	{
	   OLED_ShowNum(1, 7, CountSensor_Get(), 5);   
	}
}

旋转编码器中断

接线

编写中断函数模块部分代码

Encoder.c

#include "stm32f10x.h"                  // Device header

int16_t Encoder_Count;



// 编辑初始化函数
void Encoder_Init(void){
      	  //1------>todo : 配置RCC进涉及的外部中断时钟全部打开
	  // 开启GPIOB的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	  // 开启AFIO的时钟
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	  // EXPI和NVIC的时钟一直处于打开状态不需要我们手动开启
	  
	  //2------>todo : 配置GPIO选择端口为输入模式
	  GPIO_InitTypeDef GPIO_InitStructure;
	  // 引出结构体模式
	  GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPU ; // 配置模式
	  GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0|GPIO_Pin_1;
	  GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;
	  // 调用GPIO初始化函数,初始GPIOB
	  GPIO_Init(GPIOB,&GPIO_InitStructure);
	
	  // 3:todo ------->  配置AFIO选择需要使用到的GPIO并连接后面的exit
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);
	  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);
	  // 3:todo ------->配置EXTI选择边沿触发的方式如上升沿,下降沿,或者是双边沿,选择触发响应的方式
		EXTI_InitTypeDef Exit_InitStruct;
		// 引出结构体成员
		Exit_InitStruct.EXTI_Line =EXTI_Line0 | EXTI_Line1; // 指定需要配置的中断线
		Exit_InitStruct.EXTI_LineCmd =ENABLE; // 开启中断
		Exit_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; // 模式:中断模式
		Exit_InitStruct.EXTI_Trigger =EXTI_Trigger_Falling ;// 下降沿触发
	  EXTI_Init(&Exit_InitStruct);
		
		// 选择中断分组函数
		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
		NVIC_InitTypeDef  NVIC_Initstructure;
		NVIC_Initstructure.NVIC_IRQChannel = EXTI0_IRQn;
		NVIC_Initstructure.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority = 1;
		NVIC_Initstructure.NVIC_IRQChannelSubPriority = 1;
		NVIC_Init(&NVIC_Initstructure);
		
	
		NVIC_Initstructure.NVIC_IRQChannel = EXTI1_IRQn;
		NVIC_Initstructure.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority = 1;
		NVIC_Initstructure.NVIC_IRQChannelSubPriority = 2;
		NVIC_Init(&NVIC_Initstructure);
}

//中断函数
void EXTI0_IRQHandler(void){
    // 检查中断标志位
	  if(EXTI_GetITStatus(EXTI_Line0) ==  SET){
			  // 判断另外一个引脚的电平
			  if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0){
					    // 向着相反的方向旋转
				      Encoder_Count--;
				}
		    EXTI_ClearITPendingBit(EXTI_Line0);
		}
}

// 调用函数后返回count的变化值
int16_t Encoder_Get(void){
    int16_t Temp;
	  Temp = Encoder_Count;
	  Encoder_Count = 0;
	  return Temp;
}

void EXTI1_IRQHandler(void){
    // 检查中断标志位
	  if(EXTI_GetITStatus(EXTI_Line1) ==  SET){
			  // 判断引脚的电平
			  if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0) == 0){
					    // 向着正方向旋转
				      Encoder_Count++;
				}
		    EXTI_ClearITPendingBit(EXTI_Line1);
		}
}



Encoder.h代码

#ifndef  __ENCODER_H__
#define  __ENCODER_H__
void Encoder_Init(void);
int16_t Encoder_Get(void);
#endif

main.c调用编写好的中断函数

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Encoder.h"

int16_t Num;
int main(void)
{
  // 初始化oled
	OLED_Init();
  Encoder_Init();
	// 使用OLED显示字符串
	OLED_ShowString(1,1,"Num:");
	
	while (1)
	{
	   Num += Encoder_Get();
		 OLED_ShowSignedNum(1,5,Num,5);
	}
}

注:编写中断函数代码时尽量做到简洁,同时主函数中使用到的功能模块函数不要编写在中断函数中,会出行编译错误,中断程序中避免添加延时函数,中断函数多事件的实时性处理能力较强。

以上是本人基于STM32中断部分知识的学习总结,参考B站江科大教程

相关推荐

  1. STM32 外部中断的理解

    2024-03-14 17:26:04       8 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-14 17:26:04       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-14 17:26:04       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-14 17:26:04       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-14 17:26:04       18 阅读

热门阅读

  1. Python 实现一个简单的中文分词处理?

    2024-03-14 17:26:04       22 阅读
  2. [ffmpeg] 获取编译配置信息

    2024-03-14 17:26:04       17 阅读
  3. ffmpeg 通过遍历视频流,对视频帧进行打标

    2024-03-14 17:26:04       18 阅读
  4. Lua速成(1)

    2024-03-14 17:26:04       20 阅读
  5. Spring 整合 MyBatis、Junit

    2024-03-14 17:26:04       17 阅读
  6. springboot使用EasyExcel实现Excel导入导出

    2024-03-14 17:26:04       18 阅读