首页 > 其他分享 >STM32第五课:外部中断

STM32第五课:外部中断

时间:2024-06-20 20:00:29浏览次数:12  
标签:NVIC USART 中断 第五课 STM32 InitStructure GPIO EXTI

文章目录


需求

1.设备上电后打开串口。
2.按下KEY1,串口打印“按键1触发中断”。
3.以此类推,设置4个按键。
4.其中按键1,2采用寄存器开发,3,4采用库函数开发。


一、外部中断

外部中断
由图可知,当外部产生信号时,会先进入边沿检测电路,此时我们需要配置是上升沿还是下降沿检测。
配置完成后,该电路会检测是否收到该上升沿/下降沿信号。此时我们还需要配置中断屏蔽寄存器,将其置为1,这样当请求挂起寄存器为1时,就会给NVIC中断寄存器发送一个中断信号。

二、外部中断配置(以按键为例)

1.开时钟

PA0,key1为例,寄存器编写

代码如下:

	RCC->APB2ENR |= 0x05;//打开GPIO和AFIO时钟

首先,由手册可知:
通过AFIO_EXTICRx配置GPIO线上的外部中断/事件,必须先使能AFIO时钟。

所以直接找到APB2 外设复位寄存器来开时钟
在这里插入图片描述
可见,GPIOA和AFIO的时钟在第2位和第0位(0101)
所以直接将APB2ENR或上0x05即可打开GPIO和AFIO的时钟。

2.配置IO

代码如下:

	GPIOA->CRL &=~(0X0F << 0);//PA0   key1
	GPIOA->CRL |= 0X04 << 0;
    AFIO->EXTICR[0] &= ~(0x0F);//配置GPIOA映射EXTI线

PA0是key1按键,直接无脑先清0,再配置成0100浮空输入即可。
AFIO需要配置外部中断配置寄存器:
在这里插入图片描述
在这里插入图片描述
其中EXTICR数组分别有四个,从零开始。因为四位配置一个引脚,每组配置4个引脚,总计16个引脚(中断)。
所以配置引脚PA0,就是将EXTICR数组的第0个配置成0000即可。(也可不配置,默认就为0)

3.配置检测模式和屏蔽位

代码如下:

  EXTI->RTSR &= ~(0x1); //关闭上升沿检测
  EXTI->FTSR |= 0x01;  //打开下降沿检测
  EXTI->IMR |= 0x01; //打开exti的屏蔽位

在这里插入图片描述
在这里插入图片描述
根据具体情况选择上升沿还是下降沿,这里选则下降沿触发。
又因为key1是第零位引脚,所以不用移位,直接上升沿最后一位置零关闭,下降沿最后一位或1开启。

屏蔽器:
在这里插入图片描述
屏蔽位的开启直接看引脚,第几位引脚就将IMR第几位置1。

4.开NVIC,主函数分组

开NVIC
代码如下:

    NVIC_SetPriority(EXTI0_IRQn,2);NVIC设置优先级00 10
	NVIC_EnableIRQ(EXTI0_IRQn); //NVIC使能中断通道

这个直接跳转选参数就行,引脚是第几位就是几号line。
优先级是二进制,前两位为抢占位,后两位为次级。

主函数分组(该部分写到main函数中while(1)前)
代码如下:

NVIC_SetPriorityGrouping(5);//两位抢占两位次级

三、中断函数

代码如下:

//exti0的中断服务函数
void EXTI0_IRQHandler(void)
{
	//判断中断标志是否被置位
	if((EXTI->PR&(0x1<<0))!=0){
		//如果置位,就清理标志位
		EXTI->PR |= 0x1<<0;//写1是清除
		printf("按键1触发中断\r\n");
	}
}

中断服务函数在启动文件中查找,不用声明。
要先进行PR挂起寄存器判断,为1即为发生触发请求,进入该中断。
写1清除是规定。
在这里插入图片描述

四、需求实现

结果显示:
在这里插入图片描述

完整代码:
main.c

#include "stm32f10x.h"
#include "key.h"
#include "usart.h"
#include "stdio.h"

int main()
{
		NVIC_SetPriorityGrouping(5);//两位抢占两位次级
    Usart1_Config(); 
	  KEY1_Exti_PA0_init();
		KEY2_Exti_PC4_init();
		KEY3_Exti_PC5_init();
		KEY4_Exti_PC6_init(); 
    while(1)
    {	
			
    }
}

usart.c

#include "usart.h"
#include "stdio.h"

void Usart1_Config()
{
	  //开时钟:GPIOA,USART1
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE);
	  //配置对应的IO口 PA9(tx):复用推挽 PA10(RX):浮空输入
	  GPIO_InitTypeDef GPIO_InitStruct = {0};
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOA,&GPIO_InitStruct);
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
		GPIO_Init(GPIOA,&GPIO_InitStruct);
	  //配置串口1    8数据位,0校验位,1停止位,波特率115200
		USART_InitTypeDef USART_InitStruct = {0};//可以通过结构体类型跳转
		USART_InitStruct.USART_BaudRate = 115200;//波特率
		USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件控制流不开
		USART_InitStruct.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;//打开发送和接收
		USART_InitStruct.USART_Parity = USART_Parity_No;
		USART_InitStruct.USART_StopBits = USART_StopBits_1;
		USART_InitStruct.USART_WordLength = USART_WordLength_8b;
		USART_Init(USART1,&USART_InitStruct);
		USART_Cmd(USART1,ENABLE);
  //配置串口1的中断
	//在串口1产生接收的时候,会产生中断,我们直接去中断函数里面处理就可以了
	//选择串口1的中断原因
  USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//USART1->CR1 |= 0x1<<5;//使能串口1的接收非空中断
	NVIC_SetPriority(USART1_IRQn,7);//设置优先级0~15
	NVIC_EnableIRQ(USART1_IRQn);//使能中断通道
}

void SendData(uint8_t data)
{
	while((USART1->SR&0x01<<6)==0){}//等待上次发送完成
	USART1->DR = data;//发送数据
}

int fputc(int ch, FILE *f)
{
	//printf函数最终会跳转到这里来运行
	while((USART1->SR&0x1<<6)==0);
	//发送数据
	USART1->DR = (uint8_t)ch;
  return ch;
}

usart.h

#ifndef _USART_H_
#define _USART_H_
#include "stm32f10x.h"
#include "stdio.h"

void Usart1_Config();
void SendData(uint8_t data);
int fputc(int ch, FILE *f);


#endif
		

key.c

#include "stm32f10x.h"
#include "stdio.h"

//PA0
void KEY1_Exti_PA0_init()
{
	RCC->APB2ENR |= 0x05;//打开GPIO和AFIO时钟
	GPIOA->CRL &=~(0X0F << 0);//PC4   key2
	GPIOA->CRL |= 0X04 << 0;
  AFIO->EXTICR[0] &= ~(0x0F);//配置GPIO映射EXTI线
  EXTI->RTSR &= ~(0x1); //关闭上升沿检测
	EXTI->FTSR |= 0x01;  //打开下降沿检测
  EXTI->IMR |= 0x01; //打开exti的屏蔽位
  NVIC_SetPriority(EXTI0_IRQn,2);NVIC设置优先级
	NVIC_EnableIRQ(EXTI0_IRQn); //NVIC使能中断通道
}

//exti0的中断服务函数
void EXTI0_IRQHandler(void)
{
	//判断中断标志是否被置位
	if((EXTI->PR&(0x1<<0))!=0){
		//如果置位,就清理标志位
		EXTI->PR |= 0x1<<0;//写1是清除
		printf("按键1触发中断\r\n");
	}
}

//PC4
void KEY2_Exti_PC4_init()
{
	RCC->APB2ENR |= (0x01<<4); //打开GPIOC时钟
	RCC->APB2ENR |= 0x01; //AFIO时钟
  GPIOC->CRL &=~(0X0F<<16);//配置PC4   key2
	GPIOC->CRL |= (0X04<<16);//浮空输入
  AFIO->EXTICR[1] |= 0x02;//配置GPIOC映射EXTI线,外部中断配置寄存器
  EXTI->RTSR |= (0x01<<4) ; //打开上升沿检测
	EXTI->FTSR &= ~(0x1<<4);  //关闭下降沿检测
  EXTI->IMR |= (0x01<<4); //打开exti的屏蔽位
  NVIC_SetPriority(EXTI4_IRQn,2);NVIC设置优先级
	NVIC_EnableIRQ(EXTI4_IRQn); //NVIC使能中断通道
}

void EXTI4_IRQHandler(void)
{
	//判断中断标志是否被置位
	if((EXTI->PR&(0x1<<4))!=0){
		//如果置位,就清理标志位
		printf("按键2触发中断\r\n");
		EXTI->PR |= (0x1<<4);//写1是清除
	}
}



//PC5
void KEY3_Exti_PC5_init()
{
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
  GPIO_InitTypeDef GPIO_InitStructure={0};
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOC, &GPIO_InitStructure);

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource5);
	EXTI_InitTypeDef EXTI_InitStructure={0};
  EXTI_InitStructure.EXTI_Line = EXTI_Line5;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  EXTI_Init(&EXTI_InitStructure);
  NVIC_SetPriority(EXTI9_5_IRQn,2);NVIC设置优先级00 10
	NVIC_EnableIRQ(EXTI9_5_IRQn); //NVIC使能中断通道
}

//PC6
void KEY4_Exti_PC6_init()
{
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
  GPIO_InitTypeDef GPIO_InitStructure={0};
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOC, &GPIO_InitStructure);

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource6);
	EXTI_InitTypeDef EXTI_InitStructure={0};
  EXTI_InitStructure.EXTI_Line = EXTI_Line6;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  EXTI_Init(&EXTI_InitStructure);
  NVIC_SetPriority(EXTI9_5_IRQn,2);NVIC设置优先级00 10
	NVIC_EnableIRQ(EXTI9_5_IRQn); //NVIC使能中断通
}

void EXTI9_5_IRQHandler(void)
{
		//判断中断标志是否被置位
	if(EXTI_GetITStatus(EXTI_Line5) != RESET)
  {
		printf("按键3触发中断\r\n");
		//如果置位,就清理标志位
    EXTI_ClearITPendingBit(EXTI_Line5);
  }
	//判断中断标志是否被置位
	if(EXTI_GetITStatus(EXTI_Line6) != RESET)
  {
		printf("按键4触发中断\r\n");
		//如果置位,就清理标志位
    EXTI_ClearITPendingBit(EXTI_Line6);
  }
}

key.h

#ifndef _KEY_H_
#define _KEY_H_

void KEY1_Exti_PA0_init();
void KEY2_Exti_PC4_init();
void KEY3_Exti_PC5_init();
void KEY4_Exti_PC6_init();
	
#endif


总结

1.学会了使用按键进入外部中断。
2.了解了外部中断和内部中断。
3.对于寄存器和库函数开发流程,比较熟悉了。

标签:NVIC,USART,中断,第五课,STM32,InitStructure,GPIO,EXTI
From: https://blog.csdn.net/Jokerblank/article/details/139838218

相关文章

  • 一文带你了解STM32F4中断的概念,串口的概念,DMA的转运,以及如何运用在串口的收发上,串口收
    本篇主要实现的是用UART的接收中断接收数据,用DMA接收不定长的数据并发送回给电脑,接收信息控制LED灯的亮灭,成为点灯大师。什么是中断(EXIT)EXIT 外部中断/事件控制器,管理了控制器的20个中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下......
  • 1-STM32F103+ESP8266+ML307(中移4G Cat1)--硬件使用说明
    <p><iframename="ifd"src="https://mnifdv.cn/resource/cnblogs/ZLIOTB/ML307/my.html"frameborder="0"scrolling="auto"width="100%"height="1500"></iframe></p> 实物图 板载说......
  • 基于STM32F103 HAL库 开发 串口通讯
    目录CubeMX配置调试配置​时钟配置打开串口2的中断配置串口2波特率等代码com.hcom.cCubeMX配置调试配置时钟配置打开串口2的中断配置串口2波特率等串口3同理就不展示了代码com.h#ifndef__COM_H__#define__COM_H__typedefstruct{ charTxBuffe......
  • STM32基础篇--中断
    1.中断和异常异常主要是指来自CPU内部的意外事件,比如执行了未定义指令、算术溢出、除零运算等发生在CPU内部的意外事件,这些异常的发生,会引起CPU运行相应的异常处理程序;中断一般来自硬件(如片上外设、外部I/O输入等)发生的事件,当这些硬件产生中断信号时,CPU会暂停当前运行的程序,......
  • STM32基础篇--复位和时钟控制RCC
    1.时钟树1.1时钟问:什么是时钟?为什么要有时钟?时钟是怎么产生的?(1)什么是时钟?时钟就是具有周期性的脉冲信号,相当于单片机的心脏,给单片机提供一个统一的信号,要想使用单片机的外设必须开启相应的时钟。对CPU来说,假设CPU在一个时钟周期内执行一条指令,若时钟频率越高,则时钟周期......
  • STM32学习(WDG看门狗)
    1.WDG简介WDG(Watchdog)看门狗(简单来说就是程序运行的保障措施,我们的在程序中定期的喂狗,如果程序出问题卡死了,没有在规定的时间去喂狗,那么看门狗硬件就会自动帮我们复位一下,防止程序长时间卡死)看门狗可以监控程序的运行状态,当程序因为设计漏洞、硬件故障、电磁干扰等原因,出现卡......
  • 【单片机毕业设计选题24017】-基于STM32的禽舍环境监测控制系统(蓝牙版)
    系统功能:系统分为主机端和从机端,主机端主动向从机端发送信息和命令,从机端收到主机端的信息后回复温湿度氨气浓度和光照强度等信息。主要功能模块原理图:电源时钟烧录接口:单片机和按键输入电路:主机部分电路:从机部分电路:资料获取地址主从机部分代码:初......
  • STM32学习笔记(十)--I2C、IIC总线协议详解
    概述:InterIntegratedCircuit,一组多从多组多从有应答是一种同步(具有时钟线需要同步时钟SCL)、串行(一位一位的往一个方向发送)、半双工(发送接收存在一种)通信总线。(1)硬件电路所有I2C设备的SCL连接在一起,SDA连在一起            设备的SCL和SDA均要......
  • Linux 中断实验
    Linux中断实验先来回顾一下裸机实验里面中断的处理方法:①、使能中断,初始化相应的寄存器。②、注册中断服务函数,也就是向irqTable数组的指定标号处写入中断服务函数②、中断发生以后进入IRQ中断服务函数,在IRQ中断服务函数在数组irqTable里面查找具体的中断处理函数,找......
  • STM32 基础知识
    下面是您提到的外设的简要说明:1.**SMC(StaticMemoryController)**:静态存储控制器用于控制外部静态存储器(如ROM、RAM)的接口。它负责处理CPU与静态存储器之间的数据传输。2.**TIMER(定时器)**:定时器是一种计数器,可以在预设的时间间隔内产生中断或触发事件。它常用于......