中断及中断服务函数

1.引入
按键点灯的问题一般用轮询的方式去解决。

	轮询天生有缺陷:		
			1.浪费CPU
			2.占用总线,Bus is always busy.
			3.轮询响应时差,响应不及时的。
	有没有办法不让CPU主动去询问事件是否发生,而是当事件发生																																																																																																																																										             		
	后,主动去通知CPU去处理。---> 中断机制

2.中断的概念
一般中断定义为打断CPU指令正常执行顺序的事件。

现代CPU架构为了能够及时的响应外部或者内部的一些紧急事件,都支持
中断,并且会提供相应的中断响应机制-->中断机制

3.ARM Cortex-M4中断机制
当NVIC(中断控制器)通过CPU产生了某个事件,此时,CPU就会停止正在做的事情,转而切换处理模式去处理这个事件(去执行中断服务函数)。
M4给不同的中断一个唯一的编号(中断编号:用来区分不同的中断事件)。
当不同的中断事件产生时,CPU会做不同的处理。
中断向量表:一个数组,保存不同的中断事件处理函数的地址。
实际上就是一个函数指针数组
中断编号:就是该数组的下标。

中断处理函数:
	void Handler(void)
	CPU被动调用,不是用户主动调用的。是当有紧急事件发生时,CPU才会
被动去执行中断函数。它可以在用户指令,的任何时刻去调用因为中断在
任何时刻都有可能发生。

4.STM32F4xx的中断管理机制
任何中断的产生到CPU的响应,都要经过以下阶段:
1)中断源阶段
中断源是指产生了中断的设备。

	设备要能够产生中断,就必须要有一 根中断请求线(IRQ Line),并
且这根中断请求线必须要连接到中断控制器(NVIC)的中断输入引脚上。

2)NVIC中断控制器阶段
中断控制器是对所有中断输入引脚进行管理和控制。

	可以根据输入的中断请求给CPU内核一个中断信号,通过CPU某某设备
产生了中断,外部硬件在通过INTR发送中断请求信号时,还要向CPU给出一
个8位的中断编号。CPU在响应这个中断请求的时候,同时读取到了这个由
外部硬件给出的中断编号,然后以这个中断编号为下标就会去对应的中断
向量表中找到对应的元素,将元素中的值(地址)取出来后,跳转过去执行
这个函数(中断处理函数)。

CPU响应中断汇编实现:

MRS R0,IPSR			;将中断编号给到R0
MOV R1,#0x00000000	    ;中断向量表的基址
LDR R2,[R1,R0,LSL #2]	;R2 <-- R1 + (R0 << 2)
MOV PC,R2				;跳转到中断服务函数中去执行

一个设备产生了中断首先要经过中断源这一级,而中断源可以屏蔽或者使能中断的,即使外部设备产生了中断,中断源也可以不向上一级中断控制器发送中断请求信号。
中断控制器(NVIC)它也可以控制中断,当NVIC收到中断源发起的中断请求信号之后,也可以选择ENABLE(使能)/DISABLE(禁止)这个中断,意思是NVIC收到请求后,但是不报告给CPU。
5.STM32F4xx外部中断
外部中断(EXTI:EXTernal Interrupt)是指GPIO的外部电路上产生的中断。
比如:在GPIO口的外部电路上产生了一个上升沿(或者下降沿)将可能会导致一个外部中断的产生。
F407一共有23个外部中断。记为:EXTI0/EXT01…EXTI22

EXTI0的产生来源于所有编号为0的GPIO引脚:
	PA0/PB0.....PI0	
EXTI1的产生来源于所有编号为1的GPIO引脚:
	PA1/PB1.....PI1
	.....
EXTI15的产生来源于所有编号为15的GPIO引脚:
	PA15/PB15.....PI15

GPIO外部信号输入(高跳变/低跳变):

	GPIO控制器(GPIO控制器应该要配置成输入模式
	SYSCFG选择器(选择由哪个GPIO产生EXTI)
	EXTI外部中断控制器(边沿触发选择/外内部中断/屏蔽和使能)
	NVIC中断控制器
	CPU停止正常执行顺序
			-->1.获取NVIC报告的中断编号
			-->2.去中断向量表中以此编号为下标去中断处理函数的地址
			-->3.根据此地址跳转过去执行中断处理函数(处理中断)

6.外部中断代码实现

	KEY0-->PA0-->EXTI0-->NVIC->CPU->EXTI0_IRQHandler
	KEY1-->PE2-->EXTI2-->NVIC->CPU->EXTI2_IRQHandler
	KEY2-->PE3	......
	KEY3-->PE4	......

1)配置GPIO控制器

a.	使能GPIO分组时钟
void RCC_AHB1PeriphClockCmd(uint32_t RCC_AHB1Periph,FunctionalState NewState)
b.初始化GPIO(输入模式)
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef *GPIO_InitStruct)

2)配置SYSCFG选择器
SYSCFG选择器也是一个外设,需要使能时钟:

a.使能SYSCFG选择器时钟(SYSCFG选择器处于APB2总线上)
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
b.初始化SYSCFG选择器(选择由哪个GPIO产生EXTI)
void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex)
比如:配置PA0产生外部中断0							
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);

3)初始化EXTI外部中断控制器

a.使能EXTI外部中断控制器
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
b.初始化外部中断控制器
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct)

4)配置NVIC控制器

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)

按照上述流程就可以配置好外部中断,当配置好外部中断之后,此时如果满足产生外部中断的条件,触发外部中断,CPU就会自动去调用对应的中断处理函数。
因此,在配置完中断后,应该要编写对应的中断处理函数,以供CPU在产生中断之后调用。

//中断服务函数
void xxx_IRQHandler(void)
{
	//获取中断的中断标志位
	
	//根据中断标志位可以得知是否产生了中断
				
	//用户代码去处理中断
			
	//清除中断标志位
}
a.	获取中断标志位
		ITStatus EXTI_GetITStatus(uint32_t EXTI_Line)
		FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line)
			@EXTI_Line:指定外部中断线
			返回值:
				SET		表示获取的外部中断已经产生
				RESET	表示获取的外部中断未产			
b.	清除中断标志位
		void EXTI_ClearFlag(uint32_t EXTI_Line)
		void EXTI_ClearITPendingBit(uint32_t EXTI_Line)

下附,外部中断处理逻辑图
外部中断处理逻辑图

  • 4
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
//出入均设有缓冲区,大小可任意设置。 //可供使用的函数名: //char getbyte(void);从接收缓冲区取一个byte,如不想等待则在调用前检测inbufsign是否为1。 //getline(char idata *line, unsigned char n); 获取一行数据回车结束,必须定义最大输入字符数 //putbyte(char c);放入一个字节到发送缓冲区 //putbytes(unsigned char *outplace,j);放一串数据到发送缓冲区,自定义长度 //putstring(unsigned char code *puts);发送一个定义在程序存储区的字符串到串口 //puthex(unsigned char c);发送一个字节的hex码,分成两个字节发。 //putchar(uchar c,uchar j);输出一个无符号字符数的十进制表示,必须标示小数点的位置,自动删除前面无用的零 //putint(uint ui,uchar j);输出一个无符号整型数的十进制表示,必须标示小数点的位置,自动删除前面无用的零 //delay(unsigned char d); 延时n x 100ns //putinbuf(uchar c);人工输入一个字符到输入缓冲区 //CR;发送一个回车换行 //************************************************************************* #include <w77e58.h> #define uchar unsigned char #define uint unsigned int #define OLEN 32 /* size of serial transmission buffer */ idata unsigned char outbuf[OLEN]; /* storage for transmission buffer */ unsigned char idata *outlast=outbuf; //最后由中断传输出去的字节位置 unsigned char idata *putlast=outbuf; //最后放入发送缓冲区的字节位置 #define ILEN 12 /* size of serial receiving buffer */ idata unsigned char inbuf[ILEN]; unsigned char idata *inlast=inbuf; //最后由中断进入接收缓冲区的字节位置 unsigned char idata *getlast=inbuf; //最后取走的字节位置 bit outbufsign0; //最后一个数据覵BUF发完标志 发完=0 bit outbufsign; //输出缓冲区非空标志 有=1 bit inbufsign; //接收缓冲区非空标志 有=1 bit inbufful; //输入缓冲区满标志 满=1 #define CR putstring("\r\n") //CR=回车换行 //***************************** //延时n x 100ns void delay(unsigned char d) //在源程序开头定义是否用w77e58或22。1184M晶振 {unsigned char j; do{ d--; //110592 & 89c52 #ifndef cpuw77e58 #ifndef xtal221184 j=21; //k=38 cpu80320 100us k="21" cpu 8052 #else j=42; #endif #else #ifndef xtal221184 j=38; #else j=76;

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

m0_60265426

都是好兄弟

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

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

打赏作者

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

抵扣说明:

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

余额充值