cortex_m3_stm32嵌入式学习笔记(四):外部中断实验

本章学习将STM32的IO口作为外部中断输入(实现和按键扫描一样的功能)

STM32 的每个 IO 都可以作为外部中断的中断输入口,这点也是 STM32 的强大之处。 STM32F103 的中断控制器支持 19
个外部中断/事件请求。每个中断设有状位,每个中断/事件都有独立的触发和屏蔽设置。 STM32F103 的19 个外部中断为:

线 0~15:对应外部 IO 口的输入中断。(本章只学习这一种)

线 16:连接到 PVD 输出。

线 17:连接到 RTC 闹钟事件。

线 18:连接到 USB 唤醒事件。

从上面可以看出, STM32 供 IO 口使用的中断线只有 16 个,但是 STM32 的 IO 口却远远不止 16 个,那么 STM32 是怎么把 16 个中断线和 IO 口一一对应起来的呢?于是 STM32 就这样设计,
GPIO 的管教 GPIOx.0~GPIOx.15(x=A,B,C,D,E, F,G)分别对应中断线 0~15。(原文是15-0 我感觉它写错了QAQ)

对应图如下:

有了映射关系 很明显 KEY0(PC5)对应中断线5(EXTI5)KEY1(PA15)对应中断线15(EXTI15) WK_UP(PA0)对应中断线0(EXTI0)

接下来就是配置中断了,编写exti.c 添加到工程

#include "exti.h"
#include "led.h"
#include "key.h"
#include "delay.h"
#include "usart.h"
void EXTIx_Init(void)
{
	EXTI_InitTypeDef EXTI_ist;
  NVIC_InitTypeDef NVIC_ist;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能 AFIO 时钟
	KEY_Init();
	//GPIOC.5 中断线以及中断初始化配置
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5);
	EXTI_ist.EXTI_Line=EXTI_Line5;
  EXTI_ist.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_ist.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
  EXTI_ist.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_ist);
	//GPIOA.15 中断线以及中断初始化配置
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource15);
	EXTI_ist.EXTI_Line=EXTI_Line15;
  EXTI_ist.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_ist.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发(1->0)
  EXTI_ist.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_ist);
	//GPIOA.0 中断线以及中断初始化配置
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
	EXTI_ist.EXTI_Line=EXTI_Line0;
  EXTI_ist.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_ist.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿触发(0->1)
  EXTI_ist.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_ist);

	//配置NVIC
	NVIC_ist.NVIC_IRQChannel = EXTI0_IRQn;//使能按键所在的外部中断通道
	NVIC_ist.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2
  NVIC_ist.NVIC_IRQChannelSubPriority = 0x01; //子优先级 1
  NVIC_ist.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
  NVIC_Init(&NVIC_ist);

	NVIC_ist.NVIC_IRQChannel = EXTI9_5_IRQn;//使能按键所在的外部中断通道
	//NVIC_ist.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2
  //NVIC_ist.NVIC_IRQChannelSubPriority = 0x01; //子优先级 1
  //NVIC_ist.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
  NVIC_Init(&NVIC_ist);

	NVIC_ist.NVIC_IRQChannel = EXTI15_10_IRQn;//使能按键所在的外部中断通道
	//NVIC_ist.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2
  //NVIC_ist.NVIC_IRQChannelSubPriority = 0x01; //子优先级 1
  //NVIC_ist.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
  NVIC_Init(&NVIC_ist);
}
void EXTI0_IRQHandler(void)//中断服务函数
{
	delay_ms(10); //消抖
	if(WK_UP==1)
	{
		LED0=!LED0;
		LED1=!LED1;
	}
	EXTI_ClearITPendingBit(EXTI_Line0); //清除 EXTI0 线路挂起位
}
void EXTI9_5_IRQHandler(void)
{
	delay_ms(10); //消抖
	if(KEY0==0)
	{
		LED0=!LED0;
	}
	EXTI_ClearITPendingBit(EXTI_Line5); //清除 LINE5 上的中断标志位
}
void EXTI15_10_IRQHandler(void)
{
	delay_ms(10); //消抖
	if(KEY1==0)
	{
		LED1=!LED1;
	}
	EXTI_ClearITPendingBit(EXTI_Line15); //清除 LINE15 上的中断标志位
}

这里面有4个函数,一个初始化中断的函数,3个中断服务函数(就是中断了之后你让他去干什么)

初始化中比较麻烦

因为3个按键用到了3条中断线,所以3条中断线都要初始化,但3条线的初始化很相似,我们就以 EXTI0 为例吧 将代码抠出来

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
EXTI_ist.EXTI_Line=EXTI_Line0;
EXTI_ist.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_ist.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿触发(0->1)
EXTI_ist.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_ist);

第一句是将 GPIO 端口与中断线映射起来,然后选中断线,选择中断模式(还有一种模式为事件模式,去论坛搜了一下没太明白。。算了学到再说吧)

接下来选择触发模式,一般有上升沿触发(电平从0->1),下降沿触发(电平从1->0),和任意触发模式。根据按键的有效性(因为WK_UP是高电平有效,所以选择上升沿触发,而另外两个按键选择下降沿触发模式),最后使能外部中断通道(不太懂。。强记吧先)

在接下来就要配置NVIC中断优先级,NVIC又是一个陌生词,度娘了一下:提供中断控制器,用于总体管理异常,称之为“嵌套向量中断控制器:Nested
Vectored Interrupt Controller (NVIC)”。

就是用来管理中断优先级的

中断优先级有两项:抢占优先级和响应优先级,手册上原话:

第一,如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;第二,高优先级的抢占优先级是可以打断正在进行的低抢占优先级

中断的。而抢占优先级相同的中断,高优先级的响应优先级不可以打断低响应优先级的中断。

意思是好像抢占优先级的地位比响应优先级的地位高?

但我没实现优先级的实验,因为好像是只有在中断同时进行的时候才会用到优先级,而次实验中断是靠按键触发的,也就是说要两个按键同时按下。。这几乎是不可能的

中断服务函数就相对简单了 注意最后清除中短线上中断标志位那条语句,一定要写。。没有的后果是你按下键后他可能不灵敏,就是有可能需要按多次才能看到应有的效果

exti.h 基本没东西

#ifndef  _EXTI_H
#define  _EXIT_H
#include "sys.h"
void EXTIx_Init(void);
#endif

主函数就是调用一堆初始化的函数。。

#include "led.h"
#include "key.h"
#include "sys.h"
#include "delay.h"
#include "exti.h"
#include "usart.h"
void init(void)
{
	delay_init();
	LED_Init();
	EXTIx_Init();
	NVIC_Configuration();
	uart_init(9600);

}
int main(void)
{
	init();
	LED0=0;
	while(1)
	{
		//检测程序是否正常运行,没什么用 去掉也行
		printf("OK\n");
		delay_ms(100);
	}
}

注意。。有一些相关的文件没贴。。那都是之前写过的。。像led.c key.c 什么的

时间: 2024-10-27 00:21:08

cortex_m3_stm32嵌入式学习笔记(四):外部中断实验的相关文章

cortex_m3_stm32嵌入式学习笔记(十五):待机唤醒实验(WK_UP外部中断)

很多单片机都有低功耗模式, STM32 也不例外.在系统或电源复位以后,微控制器处于运行状态.运行状态下的 HCLK 为 CPU 提供时钟,内核执行程序代码.当 CPU 不需继续运行时,可以利用多个低功耗模式来节省功耗,例如等待某个外部事件时.用户需要根据最低电源消耗,最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式. STM32 的低功耗模式有 3 种: 1)睡眠模式( CM3 内核停止,外设仍然运行) 2)停止模式(所有时钟都停止) 3)待机模式( 1.8V 内核电源关闭) 在这

STM32学习笔记(九) 外部中断,待机模式和事件唤醒

学会知识只需要不段的积累和提高,但是如何将知识系统的讲解出来就需要深入的认知和系统的了解.外部中断和事件学习难度并不高,不过涉及到STM32的电源控制部分,还是值得认真了解的,在本文中我将以实际代码为例详细讲解这些内容,希望对每一个阅读者有帮助. 1.外部中断 如果已经学习了SysTick系统时钟滴答实验,掌握了Cortex-M3中断的相关知识,那么外部中断也是比较好理解的,和SysTick中断一样,外部中断也是当有信号触发时,如果中断屏蔽寄存器允许触发,就会产生中断,这时CPU查找中断向量表,

cortex_m3_stm32嵌入式学习笔记(八):定时器中断实验

STM32 的定时器功能十分强大,有 TIME1 和 TIME8 等高级定时器,也有 TIME2~TIME5 等通用定时器,还有 TIME6 和TIME7 等基本定时器. 本节学习通用定时器 TIM3 STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等. STM3 的通用 TIMx (TIM2. TIM3. TIM4 和 TIM5)定时器功能包括: 1)16 位向上.向下.向上/向下自动装载计数器( TIMx_CNT). 2)16 位可

cortex_m3_stm32嵌入式学习笔记(十四):RTC实时时钟(秒中断)

STM32 的实时时钟( RTC)是一个独立的定时器. STM32 的 RTC 模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能.修改计数器的值可以重新设置系统当前的时间和日期. 由于时钟只需要配置一次,下次开机不需要重新配置(开发板有电池的情况下),所以需要用到备份区域(BKP)来标记是否配置过时钟 简单介绍BKP:备份寄存器是 42 个 16 位的寄存器( Mini 开发板就是大容量的),可用来存储 84 个字节的用户应用程序数据.他们处在备份域里, 当 VDD 电源被切

cortex_m3_stm32嵌入式学习笔记(二十四):内存管理实验(动态内存)

有用过C语言编程的童鞋对动态管理内存肯定有点了解..好处就不多说了 今天实现STM32的动态内存管理 内存管理,是指软件运行时对计算机内存资源的分配和使用的技术.其最主要的目的是如何高效,快速的分配,并且在适当的时候释放和回收内存资源. 内存管理的实现方法有很多种,他们其实最终都是要实现两个函数:malloc 和 free(好熟悉): malloc 函数用于内存申请, free 函数用于内存释放. 实现方式:分块式内存管理 从上图可以看出,分块式内存管理由内存池和内存管理表两部分组成.内存池被等

cortex_m3_stm32嵌入式学习笔记(十六):ADC实验(模数转换)

之前没学过数模电,对A/D D/A转换一窍不通,也百度了很多资料大都深奥难懂..算了,先自以为是一下吧,等以后学了专业课再说..(寒假回家一定要学..恩 就这么决定了)看了那么多资料,感觉 A/D转换就是将电压(或者是其他模拟量:如 压力,图像等)转换为数字,D/A就是反过来,而ADC就是A/D转换器,他可以采集外部电压转化为数字.本节实验通过ADC采集外部电压转换为数字显示在屏幕上. STM32 拥有 1~3 个 ADC( STM32F101/102 系列只有 1 个 ADC),这些 ADC

cortex_m3_stm32嵌入式学习笔记(二十一):SPI实验(通信总线)

SPI 是英语 Serial Peripheral interface 的缩写,顾名思义就是串行外围设备接口.是 Motorola首先在其 MC68HCXX 系列处理器上定义的. SPI 接口主要应用在 EEPROM, FLASH,实时时钟, AD 转换器,还有数字信号处理器和数字信号解码器之间. SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为 PCB 的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信

cortex_m3_stm32嵌入式学习笔记(三):串口实验(串口通信)

串口,可以理解为是用来和上位机(比如电脑)对话的,本节实验实现的是stm32接收上位机发送过来的信息,在原原本本的返回过去 stm32有5路串口,本节学习的是其中之一的USB串口(USART1)和学习IO口一样,首先要配置串口,由于原子已经配好了写在sys文件里,本渣就本着不造轮子的理念(其实是太难不懂orz),先跳过去了.. 所以本工程只需要一个main函数即可 #include "led.h" #include "sys.h" #include "de

cortex_m3_stm32嵌入式学习笔记(十九):DMA实验(高速传输)

DMA,全称为: Direct Memory Access,即直接存储器访问. DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路, 能使 CPU 的效率大为提高. 即DMA传输前,CPU要把总线控制权交给DMA控制器,而在结束DMA传输后,DMA控制器应立即把总线控制权再交回给CPU. 一个完整的DMA传输过程必须经过下面的4个步骤. 1.DMA请求 CPU对DMA控制器初始化,并向I/O接