【STM32】【标准库开发】【固件函数库】STM32F103C8芯片学习日记(小白学习心得)【2】【外部中断介绍和软件编写】

本文详细介绍了STM32中GPIO外设初始化、AFIO中断引脚设置、EXTI的配置,包括EXTI_GetFlagStatus和EXTI_GetITStatus的区别,以及NVIC的抢占优先级和响应优先级设置。通过实战练习,演示了如何使用中断实现按键控制LED亮暗变化。
摘要由CSDN通过智能技术生成

目录

【1】外部中断

一.GPIO外设的初始化

二.AFIO中断引脚的设置

三.EXTI的配置

1.EXTI_DeInit();

2.EXTI_Init()

【外设的初始化和设置】

3.EXTI_GenerateSWInterrupt()

4.EXTI_GetFlagStatus()

5.EXTI_ClearFlag()

6.EXTI_GetITStatus()

【EXTI_GetFlagStatus和EXTI_GetITStatus的区别】

7.EXTI_ClearITPendingBit()

8.软件代码配置

四、NVIC的配置

【NVIC的分组】

【抢占优先级和响应优先级的介绍】

1.NVIC_PrioritygRoupConfig()

2.NVIC_Init()

3.软件编写

1.先进行优先级分组

2.定义结构体变量

3.引出成员变量

第一个成员变量:

第二个成员变量:

第三个成员变量:

第四个成员变量:

4.NVIC初始化

5.中断函数

【2】实战练习


【1】外部中断

外部中断就是芯片识别外部的信号,进行判断,如果满足自己设置的中断条件就会自动跳转到中断

函数内部执行函数里面的内容。因为平时我们的程序都放在while下的,执行主要内容,但有时我

们有一些紧急的情况需要处理,这时候中断就会打断主程序先把紧急的事情干完了,再干自己的正常工作;

一.GPIO外设的初始化

初始化还是跟上节的初始化流程是一样的,如果忘记了可以看一下上一节,注意中断是检测的外部

信号脉冲,所以记得把这里的GPIO_Mode改成输入模式,输入模式有三种,忘记了的同学可以看

一下上一节,代码举例如下:

		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

		GPIO_InitTypeDef GPIO_InitStructure;
		
		GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
		GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;
		GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	
		GPIO_Init(GPIOA,&GPIO_InitStructure);

二.AFIO中断引脚的设置

当然AFIO作为挂载在APB2上的外设第一步就是打开时钟:

		RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

STM32的外部中断的第二步就是中断引脚的设置,AFIO给出了16个通道给中断,而且就是对应

Pin0~15的端口;那么只给出了这么多的通道,而且有GPIOA或GPIOB或GPIOX等这么多外设容

易冲突,那么就有个规则:比如,当GPIOA_Pin_1即GPIOA已经占了通道1(通道几对应它的端口

几),通道1就已经用完了,那么这些GPIOB或GPIOC啥的GPIOX它们的Pin_1即它们的端口1就

不能在选择这个通道作为中断,只能用除了1之外的通道;也可以这么理解,相当于给了16条通道

线,每条通道线,对应连接端口0~15即Pin_X(0~15),但是每条线只能选择一个GPIO类型的外设。

这个函数就是用来配置这个AFIO的中断线的,虽然它的名字里面没有AFIO,但其实函数内部是操

作AFIO的,第一个参数就是GPIO_PortSourceGPIOx(x:A~G);--用来选择用哪一个GPIO外设

第二个参数就是GPIO_PinSourcex(x:0~15);   --用来选择哪一个中断线

		GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1);

三.EXTI的配置

首先这里先介绍一下有关EXTI(外部中断事件控制器)的库函数:

1.EXTI_DeInit();

这个函数说将EXTI外设的配置重新配置为缺省值,那么缺省值是什么呢,缺省值其实就是官方人

员配置的默认值,这个默认值呢,就是刚开始上电时的值,那么这个函数其实就是起到了一个清除

配置的作用;

2.EXTI_Init()

这个函数就是对EXTI外设的初始化,跟GPIO_Init有异曲同工之妙;

其实,看到这里会发现,STM32的外设的函数都有个惯用套路:


【外设的初始化和设置】

1.打开时钟XXX_Cmd

2.声明一个结构体变量:XXX_InitTypeDef 变量;

3.为结构体变量的成员变量填充值;

4.调用数 XXX_Init()来初始化外设

注:EXTI和NVIC的时钟是一直开启的,就不需要手动开启了

3.EXTI_GenerateSWInterrupt()

这个函数是用来程序触发中断的特殊类型中断的函数,比如你写了一些代码,在这个地方需要它进入中断,就用这个函数直接生成软件中断;

4.EXTI_GetFlagStatus()

当外部中断线已经达成了触发条件,那么这个EXTI的线路标志位就会被置1,那么这个函数就可以直接获取这个线路标志位的状态;

5.EXTI_ClearFlag()

外部中断的标志位需要手动清0,那么该函数就是用来清除外部中断触发中断条件标志位;

6.EXTI_GetITStatus()

【EXTI_GetFlagStatus和EXTI_GetITStatus的区别】

这个函数也是用来读取中断标志位的,区别于EXTI_GetFlagStatus(),它多了一个判断是否被特定

的寄存器进行了中断屏蔽,也就是说,当触发了中断条件时,这时单纯是满足条件而将标志位置

1,如果被特定寄存器进行中断屏蔽了,就是单纯的置位而不响应中断,那么EXTI就是单纯读取标

志位,而EXTI_GetITStatus还会判断是否被中断屏蔽,也就是这个函数进行读取中断是否响应时的

标志位,也就是读取中断状态;

7.EXTI_ClearITPendingBit()

这个函数就是对应EXTI_GetITStatus(),状态标志位的清除了

8.软件代码配置

如同上面介绍的外设的基本套路的配置这里也是这样做的

		EXTI_InitTypeDef EXTI_InitStructure;		
		EXTI_InitStructure.EXTI_Line=EXTI_Line1;
		EXTI_InitStructure.EXTI_LineCmd=ENABLE;
		EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
		EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;	
		EXTI_Init(&EXTI_InitStructure);

这里解释一下上面的代码含义

1. EXTI_InitTypeDef EXTI_InitStructure;     这个很熟悉了,就是结构体变量的定义

2.第一个成员变量:

EXTI_Line这个是指的是你选择的哪一条中断线,

参数:EXTI_LineX(X:0~19),这个中断线就是我们上面AFIO选择的那一条中断线,这里同样也可

以进行或运算,选中多条中断线;当然这里总共二十条中断线,有四条特殊的中断线

3.第二个成员变量:

EXTI_LineCmd这个指的是否开启你选中的中断的线

参数:ENABLE或DISABLE

4.第三个成员变量:

EXTI_Mode指的是你要选择的中断方式,这里分别是中断方式和事件方式;中断方式就是字面意

思,选择触发中断进入中断函数;事件方式指的是就是当检测外部的信号时,此时的动作是触发某

个事件,比如说是当检测到外部信号后,信号是流入其他外设,让那些外设工作;

参数:EXTI_Mode_Interrupt(中断)或EXTI_Mode_Event(事件)

5.第四个成员变量:
EXTI_Trigger指的是触发方式,这里有三种触发方式分别是上升沿或下降沿或上升沿和下降沿触发

上升沿和下降沿触发自然是上升沿触发了,下降沿也要触发了

参数:EXTI_Trigger_Rising(上升)

 EXTI_Trigger_Falling(下降)

EXTI_Trigger_Rising_Falling(上升沿和下降沿)

6.结构变量初始化EXTI_Init();

四、NVIC的配置

NVIC:嵌套中断向量列表控制器;

【NVIC的分组】

NVIC是用来设置中断优先级的,毕竟有这么多中断线输入进来,不可能同时发生,这时就要用中

断优先级给它们排个队,那么这里的优先级又分为抢占优先级和响应优先级,首先这里就给出了几

种排队分组的方式,你要先选择一种排队分组的方式,才能进行设置优先级去排列的先后顺序

【抢占优先级和响应优先级的介绍】

数值越小的优先级越高,这里从三种情况来解释抢占优先级(先占优先级)和响应优先级(从优先

级);比如,甲程序的抢占优先级和乙程序的抢占优先级相同时,当甲程序比乙程序的响应优先级

高,那么当甲和乙的中断程序同时到来时,系统会先响应甲的中断;当甲程序的响应优先级和乙程

序的响应优先级相同时或不同时,甲程序的抢占优先级比乙的抢占优先级高,那么这时候如果乙进

入了中断程序就会被甲的程序给打断,执行完甲的再回头来执行乙的;假如抢占优先级和响应优先

级都相同就按照系统排列的中断号进行排队,数字越小,中断优先级越高;

这里的第二列的数字优先级就是当抢占优先级和响应优先级相同时,这个数字越小,中断优先级越高;

这里先了解一些有关NVIC的有关函数:

1.NVIC_PrioritygRoupConfig()

这个函数就是首先给优先级进行分组的,上面介绍了有5组的形式可以选,值得注意的是你写程序的时候,只能给中断分一次组,然后写的这些中断都是根据这个组来写优先级,不能每写一个中断就分一次组;

2.NVIC_Init()

这个函数就是经典的配置外设初始化的函数了,这里NVIC的初始化就用这个来配置

3.软件编写

1.先进行优先级分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);    //这里选择分组方式0
2.定义结构体变量
NVIC_InitTypeDef NVIC_InitStructure;
3.引出成员变量
第一个成员变量:
		NVIC_InitStructure.NVIC_IRQChannel=EXTI9_5_IRQn;

这个指的是中断通道,这个该怎么选呢,根据上一节的双击右键跳转定义再全局搜索

再根据自己芯片的型号,上一节介绍选择启动文件那里,比如我用的芯片配对的是后缀为MD的文

件可以找到EXTI的通道有两个,EXTI9_5_IRQn和EXTI15_10_IRQn,选择一个;

第二个成员变量:
 
		NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;

这个指的是要不要开启这个中断通道,参数就是ENABLE或者DISABLE

第三个成员变量:
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;

这个就是抢占优先级,根据那个分组里的范围自行选择,注意分完组后,抢占优先级和响应优先级

就有取值范围了

第四个成员变量:
 
		NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;

这个就是响应优先级

4.NVIC初始化
		NVIC_Init(&NVIC_InitStructure);

这个就是将NVIC按照自己的配置初始化了

5.中断函数

当上面都配置好了,接下来就等外部信号触发后,执行中断函数里的内容了,那么这里中断函数号也是有特定的名称的,你的特定通道是有对应的中断函数名的,可以在启动文件(启动文件在上一节有介绍)里面找

void EXTI9_5_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line6)==SET)    //当检测到中断标志位置位了,也就是进入中断了
	{
			
			EXTI_ClearITPendingBit(EXTI_Line6);    //这里必须要手动将标志位清0

	}	
}

【2】实战练习

按一下按键来改变led的亮暗状态

我这里分模块写,就不都放在main函数这一页了

init.c:

#include "stm32f10x.h"                  // Device header


uint16_t count;

void init_intial(void)
{	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);	
	GPIO_InitTypeDef InitStructure;
	InitStructure.GPIO_Mode=GPIO_Mode_IPU;    //这里采用上拉输入
	InitStructure.GPIO_Pin=GPIO_Pin_6;
	InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&InitStructure);

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource6);   //选择中断通道6
	
	EXTI_InitTypeDef EXTI_InitStructure;
	EXTI_InitStructure.EXTI_Line=EXTI_Line6;
	EXTI_InitStructure.EXTI_LineCmd=ENABLE;
	EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
	EXTI_Init(&EXTI_InitStructure);
		
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //这里只有一个中断函数可以虽然设置优先级
	NVIC_InitTypeDef NVIC_initStruct;
	NVIC_initStruct.NVIC_IRQChannel=EXTI9_5_IRQn;
	NVIC_initStruct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_initStruct.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_initStruct.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_initStruct);
		
}

uint16_t return_num(void)
{
	return count;    //将计数标志位返回
}

void EXTI9_5_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line6)==SET)    
	{
			count++;            //设置一个计数标志位,给led做判断使用
			EXTI_ClearITPendingBit(EXTI_Line6);

	}
	
}

init.h

#ifndef __INIT_H
#define __INIT_H

void init_intial(void);
uint16_t return_num(void);

#endif

led.c

#include "stm32f10x.h"                  // Device header

void led_init(void)
{	
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);	
		
		GPIO_InitTypeDef InitStucture;
		InitStucture.GPIO_Mode=GPIO_Mode_Out_PP;
		InitStucture.GPIO_Pin=GPIO_Pin_0;
		InitStucture.GPIO_Speed=GPIO_Speed_50MHz;	
		GPIO_Init(GPIOA,&InitStucture);
	
		GPIO_SetBits(GPIOA,GPIO_Pin_0);
}

led.h

#ifndef __LED_H
#define __LED_H

void led_init(void);


#endif

main.c

#include "stm32f10x.h"                  // Device header
#include "init.h"
#include "led.h"

uint16_t num;

int main()
{	
		init_intial();    //中断函数的初始化
		led_init();       //led的初始化
	
		while(1)
		{
		num=return_num();    //读取进入中断的计数标志位
		if(num%2==1)    
		GPIO_ResetBits(GPIOA,GPIO_Pin_0);
		else
		GPIO_SetBits(GPIOA,GPIO_Pin_0);			
	
		}	
}

proteus仿真:

STM32中断仿真测试

  • 22
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值