STM32自学笔记--2.中断

        导语:看了我写的上一个笔记的朋友知道,示例中让LED灯亮是通过不断检测按键的电平高低来实现的,即把if检测语句放在While(1)里不断循环。但如果用STM32的中断思路来编写程序,就不需要在主程序里用while(1)来进行轮询(即不断检测),用中断的话CPU会自动后台帮你监控,一旦按下按钮,即跳转至中断服务函数(中断服务函数是我们自己编写,目的是发生中断后告诉CPU我们要做什么,拿示例来说就是我们要让灯亮变灭或者灭变亮),因此我的理解是中断函数可以极大的简化程序,不需要用各种if的嵌套和while的轮询。

        看了导语,对中断就应该有一个大致的初步认识,即设置一个条件,发生了该条件,运行中断服务,跳转至我们自己设置的中断服务函数并执行,然后回到主函数中,有这么一个大概的感觉就好,后文会更详细的提到。本文适合初学者。

     


  学习中断,先来理清一下思路,如上一段所提,

                我们需要配置的是:1.什么条件

                                                2.运行什么

这只是两个很浅显的思路,具体到程序要复杂的多,先来了解两个重要的知识点:NVIC和EXTI


NVIC:

        一个复杂的工程肯定不止一个中断,既然涉及到多个中断,如果同时发生,先执行谁呢?

因此,中断的优先级由此产生,即如果多个中断产生,我该怎么去排执行顺序。

         NVIC的作用就是如此,他会把我们配置的每个中断给排序,分先后,每个中断的排序有两个参数,相应优先级和抢占优先级,通俗来讲抢占优先级就是第一排序数,响应优先级就是第二排序数,先比第一排序数大小,再比第二排序数大小,越小优先级越大。

以两中断A和B为例:

若A两优先级为1和3(前者为抢占,后者为响应) B为2和3,则A先执行,且如果B正在执行,A发生,则A打断B先执行,执行完再执行B

若A两优先级为2和3(前者为抢占,后者为响应) B为2和4,则A先执行

若A两优先级为1和3(前者为抢占,后者为响应) B为1和3,则根据硬件内部编号大小决定


到这里可能又有一个新问题,我能设置多大的优先级数,换言之,这两个排序数的大小范围多大?

NVIC中的优先级分为5组,分别为0,1,2,3,4组。

网上其他该分组的具体教程也很多,如果只是运用,只需要记住该组号用二进制运算赋值给抢占优先级,然后4-(组号)得到的数字用二进制运算再减一赋给响应优先级。

比如设置为组号1,则抢占优先级最小为2的1次方减一即1,可设置该优先级范围为0到1;

而响应优先级为2的(4-1)次方减一,即为7,可设置该优先级范围为0到7;

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_X);

该函数即是用来分组,X为我们给的值(0,1,2,3,4)

在NVIC中还需要配置中断源,即选择不同的通道来选择不同的中断来源,不同的中断源的编号不一样。

分为:1.通道0到4    EXTIX_IRQn   X为0到4中一数字

           2.通道5到9    都用EXTI9_5_IRQn

           3.通道10到15    都用EXTI15_10_IRQn  

新人只需跟我一样记住配置为使用的IO口的引脚号就好,我还没理解透彻QAQ

比如我用PA4口,那我设置为EXTI4_IRQn

最后还要中断使能,后面上代码会提到,很简单,固定的一句话。

EXTI

我们配置完NVIC后,还需要配置一个新的函数,通俗讲就是配置EXTI

我理解可能比较浅,我理解的EXTI就是用来设置中断来源是哪儿(不要与上一个配置NVIC通道搞混),是上升沿触发还是下降沿触发还是都触发。

EXTI的配置需要

1.使能新的时钟源 不同于GPIO(后面代码会提到)

然后配置中断来源,SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOX,EXTI_PinSourceY);

比如配置为PA4, SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource4);

2.选择EXTI模式,分为中断事件

就个人的简单理解来说,中断就是条件满足后,发送数据给CPU,CPU收到数据进行处理,然后执行我们编写的中断服务函数(即发生中断后我们想让它干嘛,亮灯,灭灯?等等)

事件是条件满足后,我们不发送数据给CPU,而是跳过CPU,直接产生一个触发信号,这个触发信号可以通向其他外设,比如可以用来触发ADC转换等等。

通常所说的中断都是EXTI的中断,事件用的较少,先不涉及。(其实是我自己都还没学懂事件hhh)

3.选择触发方式

4.使能通道

5.引用库函数初始化

(没具体讲的,代码都很固定,代码后面会给,先不给代码,结合代码和注释理解更深刻。


GPIO

我们中断产生的来源可以是内部也可以是外部,内部比较常见的就是定时器的中断(我还没学会QAQ),暂时讲的是外部的中断,一般用外设板块接入单片机,外设板块输出脉冲到单片机上,单片机接收然后产生特定脉冲就中断。

如上述,若用外设(超声波模块,红外模块等等)接单片机,则需要将GPIO配置为输入模式,我的上一个文章有涉及到。

该处不在赘述。


中断服务函数配置

之前我们都配置好了优先级,中断源等参数,现在需要配置运行内容,即如果发生了中断,我要CPU去做什么,比如最简单的、我就让灯亮。

该中断函数在stm32f4xx_it.c文件中,每个不同中断源都需要用不同的函数。

具体配置马上结合代码说,不难




 示例分析

之前的比赛多了个红外模块,我以红外模块为例,如果检测到反射光,设置中断,开发板自带的LED模块由亮变灭或者由灭变量,即开关作用。

我选择PA4作为接受红外信号的IO口

主函数

#include"stm32f4xx.h"
#include "led.h"
#include"EXTI.h"
int main(void)
{
	LED_GPIO_Config();//控制LED的GPIO口初始化(查手册得是那个IO口)
	NVIC_Config();    //NVIC配置
	EXTI_Key_Config();//EXTI配置
	GPIO_config();    //接受红外模块脉冲的IO口配置
	while(1);         //设置死循环,保证STM32正常工作
}

NVIC函数

void NVIC_Config(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;                      //结构体引用
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);           //优先级分组设置为1
                                                            
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级设置为1(0到1均可)
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;        //响应优先级设置为1(0到7均可)
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           //通道使能(如前述,记住就好)
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;        //引脚号为4,故为EXTI4_IRQn
  NVIC_Init(&NVIC_InitStructure);                           //引用库函数,初始化NVIC结构体
}

EXTI函数

void EXTI_Key_Config(void)
{

	EXTI_InitTypeDef EXTI_InitStructure;
  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);  //使能SYSCFG时钟

  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource4);	//连接EXTI中断源PA4
  EXTI_InitStructure.EXTI_Line = EXTI_Line4;  //选择EXTI中断源为line4 
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;  //设置为中断,而不是事件
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;    //上升沿触发
  
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;      //通道使能
  EXTI_Init(&EXTI_InitStructure);                  //引用库函数初始化EXTI结构体
}

接收口GPIO配置(PA4)

void GPIO_config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure; 
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA ,ENABLE);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;		
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  //注意是浮空输入,高低电平全由红外决定
  
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;	
  GPIO_Init(GPIOA, &GPIO_InitStructure);

}

中断服务函数stm32f4xx_it.c

void EXTI4_IRQHandler(void)
{
  if(EXTI_GetITStatus(EXTI_Line4) != RESET)  //如果中断发生
  {
    GPIOF->ODR ^=GPIO_Pin_6;  //直接对寄存器读写,电平求反
    EXTI_ClearITPendingBit(EXTI_Line4);  //清除中断标志位,每一次中断都要进行清除
  }
}

最后别忘了在各自的头文件声明主程序要使用的函数

最后放一张测试图emmm虽然图片也看不出什么,但是是可以正常运行的。

原创文,甚至是今天刚学会QAQ,怕忘了。

肯定有很多错,希望大佬指出呜呜呜,我想学我想学

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值