第四篇,STM32中断控制编程

1.中断概念

中断指的是在计算机工作期间,出现了需要立即停止正在运行的程序,转而去处理意外发生的情形。发生中断之后,CPU会去执行事先写好的处理中断的代码,处理完成后回到被打断的位置继续执行。

编写中断程序需要注意事项:

a.中断处理程序执行事件尽量短(不能睡眠以及延时),给其他程序让出CPU。

b.中断程序中访问的共享数据必须进行保护。

Stm32中断流程,Stm32中,中断源产生中断信号,提交给向量中断控制器(NVIC),中断控制器做进一步处理再提交给CPU,CPU执行中断处理中断处理程序

2.向量中断控制器(NVIC

(1)NVIC介绍

NVIC外部中断(中断信号来自于芯片外部),一共有23个外部中断源,包括16个GPIO中断和7个其他中断。

(2)中断优先级 (数字越小,优先级越高) 这点需要特别注意。

stm32的中断优先级分为2类:抢占优先级和响应优先级

抢占优先级:抢占优先级高的中断可以打断抢占优先级低的中断

响应优先级:响应优先级高的不能打断响应优先级低的中断,当两个抢占优先级相同的两个中断同时发生,CPU优先处理响应优先级比较高的中断。抢占优先级和响应优先级一起最多占8位或者4位字节,配置两个优先级所占的位数叫做中断优先级分组。

以上NVIC的配置,通过库函数NVIC_Init()来实现

优先级分组是通过NVIC_PriorityGroupConfig来配置,该函数只能在程序开头调用,并且只能调用一次

NVIC配置函数

void NVIC_Init  (NVIC_InitTypeDef* NVIC_InitStruct);

//传入NVIC初始化结构体

typedef struct

{

  uint8_t NVIC_IRQChannel;                     /*!< 中断通道 @ref IRQn_Type */

  uint8_t NVIC_IRQChannelPreemptionPriority;      /*!< 抢占优先级 */

  uint8_t NVIC_IRQChannelSubPriority;            /*!< 响应优先级 */

  FunctionalState NVIC_IRQChannelCmd;          /*!< 使能/禁止 ENABLE or DISABLE */  

} NVIC_InitTypeDef;

优先级分组配置函数

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);

参数:

  *     @arg NVIC_PriorityGroup_0: 0 bits for pre-emption priority

  *                                                    4 bits for subpriority

  *     @arg NVIC_PriorityGroup_1: 1 bits for pre-emption priority

  *                                                     3 bits for subpriority

  *     @arg NVIC_PriorityGroup_2: 2 bits for pre-emption priority

  *                                                     2 bits for subpriority

  *     @arg NVIC_PriorityGroup_3: 3 bits for pre-emption priority

  *                                                    1 bits for subpriority

  *     @arg NVIC_PriorityGroup_4:4 bits for pre-emption priority

  *                                                    0 bits for subpriority

3.外部中断源EXIT

(1)EXIT主要的特性(在编写程序时常用特性)

每个中断/事件线上都具有独立的触发和屏蔽

每个中断线具有专用的状态位

支持多达23个软件事件/中断请求

(2)EXIT处理框图

(3)外部中断源映射

在stm32中,一共有16个GPIO中断,stm32中的GPIO引脚,一共有16(A~I)组引脚,每一个GPIO都能配置成一个外部中断,通过不同的引脚序号将不同中断触发源分成不同的组,这也是stm32的一个强大之处。

PA0,PB0,PC0, ... ...PH0,PI0为一组中断源,以此类推,一共有16组中断源,每一组只能有一个中断触发源工作,那么,整个中断源做多工作的也就16个外部中断。STM32F103 的中断控制器⽀持 19 个外部中断/事件请求。每个中断设有状态位,每个中断/事件都有独⽴的触发和屏蔽设置。STM32F103 的19 个外部中断为:

中断线 0~15:对应外部 IO 的输入中断。

中断线 16:连接到 PVD 输出。

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

中断线 18:连接到 USB 唤醒事件

注意:GPIO设置为外部中断时需要将其配置为中断模式

——————————————————————————————————————————————————————————————————————————————————————

4.编程实现GPIO中断,主要步骤如下。

工程中添加中断库函数文件

(1)配置中断优先级分组,下面函数中,抢占优先级和响应优先级一共占4

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);

参数: //抢占优先级占0位,响应优先级占4

* @arg NVIC_PriorityGroup_0: 0 bits for pre-emption priority *

                                                  4 bits for subpriority

 * @arg NVIC_PriorityGroup_1: 1 bits for pre-emption priority *

                                                   3 bits for subpriority

 * @arg NVIC_PriorityGroup_2: 2 bits for pre-emption priority *

                                                   2 bits for subpriority

 * @arg NVIC_PriorityGroup_3: 3 bits for pre-emption priority *

                                                  1 bits for subpriority

 * @arg NVIC_PriorityGroup_4: 4 bits for pre-emption priority *

                                                   0 bits for subpriority

——————————————————————————————————————————-

(2)外部中断源初始化

(3GPIO时钟和SYSCFG时钟初始化

RCC_AHB1...                                           //初始化GPIO时钟,此处省略

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);  //初始化SYSCFG时钟

——————————————————————————————————————————

(4GPIO配置为输入模式

 GPIO_init();                                             //此处省略

  1. 设置GPIO和外部中断线的关系
    Void SYSCFG_EXITLineConfig(uint8_t EXIT_PortSourceGPIOx,uint8_t EXIT_PinSourcex);
    
    参数:EXIT_PortSourceGPIOx             // 哪一组引脚
    
          EXIT_PinSourcex                  // 哪个脚

———————————————————————————————————————————

5)初始化外部中断

void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);

参数:

typedef struct

{
  uint32_t EXTI_Line;               /*!< 哪条外部中断线 @ref EXTI_Lines */  
  EXTIMode_TypeDef EXTI_Mode;     /*!< 模式选择 事件/中断 @ref EXTIMode_TypeDef */
  EXTITrigger_TypeDef EXTI_Trigger; /*!< 触发边沿选择 @ref EXTITrigger_TypeDef */
  FunctionalState EXTI_LineCmd;     /*!< 使能/禁止 ENABLE or DISABLE */
} EXTI_InitTypeDef;

——————————————————————————————————————————

NVIC向量中断控制器初始化

6)初始化NVIC

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

//传入NVIC初始化结构体

typedef struct

{ 
   uint8_t NVIC_IRQChannel; /*!< 中断通道 @ref IRQn_Type */
   uint8_t NVIC_IRQChannelPreemptionPriority; /*!< 抢占优先级 */
   uint8_t NVIC_IRQChannelSubPriority; /*!< 响应优先级 */
   FunctionalState NVIC_IRQChannelCmd; /*!< 使能/禁止 ENABLE or DISABLE */
} NVIC_InitTypeDef;

———————————————————————————————————————————

7)实现中断处理函数

函数名在启动文件的异常向量表中去找,比如:EXTI0_IRQHandler

中断处理函数无参无返回值

中断处理函数中必须清除中断标志

———————————————————————————————————————————

8)清除中断标志位

void EXTI_ClearITPendingBit(uint32_t EXTI_Line);

//传入初始化的外部中断线

========================================================

按下S1,监控MQ2状态,超标则蜂鸣器报警;按下S2,D1闪烁

key.h

#ifndef _KEY_H_
#define _KEY_H_

#define S1 PAin(0)
#define S1 PAin(2)
#define S1 PAin(3)
#define S1 PAin(4)

void key_init(void);
void exti_init(void);

#endif

key.c

#include<stm32f4xx.h>
#include<key.h>

void key_init(void)
{
   GPIO_InitTypeDef GPIO_InitStruct;
   RCCAHB1PeriphClockCmd(RCC_AHB1periphGPIOA|RCC_AHB1periphGPIOE,ENABLE);

   GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
   GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
   GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_0
   GPIO_Init(GPIOA,GPIO_InitStruct)

   GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;
   GPIO_Init(GPIOE,GPIO_InitStruct);
}

void exit_init(void)
{   
     GPIO_InitTypeDef GPIO_InitStruct;
     EXTI_InitTypeDef EXTI_InitStruct;
     NVIC_InitTypeDef NVIC_InitStruct;
    
     //开启时钟
     RCCAHB1PeriphClockCmd(RCC_AHB1periphGPIOA|RCC_AHB1periphGPIOE,ENABLE);
     RCCAHB1PeriphClockCmd(RCC_ABH2Periph_SYSCFG,ENABLE);
     //GPIO初始化
     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
     GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
     GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_0;
     GPIO_Init(GPIOA,GPIO_InitStruct);
   
     GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;
     GPIO_Init(GPIOE,GPIO_InitStruct);

     //设置GPIO与外部中断线的映射关系
     SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);
     SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource2);
     SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource3);
     SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource4);


    //初始化外部中断
     EXTI_InitStruct.EXTI_Line = EXTI_Line0|EXTI_Line2|EXTI_Line3|EXTI_Line4;//外部中断线0
     EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
     EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿
     EXTI_InitStruct.EXTI_LineCmd = ENABLE;
     EXTI_Init(&EXTI_InitStruct);
    
    //初始化NVIC
    //**************************************************************************
    EXT0_IRQn
    EXT2_IRQn
    EXT3_IRQn
    EXT4_IRQn   外部中断通道是枚举结构体,不能按位或运算

  *****************************************************************************//
    NVIC_InitStruct.NVIC_IRQChannal = EXT0_IRQn ;//通道0
    NVIC_InitStruct.NVIC_IRQChannalPreemptionPriority = 0x1;//抢占优先级
    NVIC_InitStruct.NVIC_IRQChannalSPriority = 0x1;
    NVIC_InitStruct.NVIC_IRQChannalCmd = ENABLE; 
    NVIC_Init(&NVIC_InitStruct);   

    NVIC_InitStruct.NVIC_IRQChannal = EXT2_IRQn ;//通道2
    NVIC_InitStruct.NVIC_IRQChannalPreemptionPriority = 0x1;//抢占优先级
    NVIC_InitStruct.NVIC_IRQChannalSPriority = 0x1;
    NVIC_InitStruct.NVIC_IRQChannalCmd = ENABLE; 
    NVIC_Init(&NVIC_InitStruct);   

    NVIC_InitStruct.NVIC_IRQChannal = EXT3_IRQn ;//通道3
    NVIC_InitStruct.NVIC_IRQChannalPreemptionPriority = 0x1;//抢占优先级
    NVIC_InitStruct.NVIC_IRQChannalSPriority = 0x1;
    NVIC_InitStruct.NVIC_IRQChannalCmd = ENABLE; 
    NVIC_Init(&NVIC_InitStruct);   

    NVIC_InitStruct.NVIC_IRQChannal = EXT4_IRQn ;//通道4
    NVIC_InitStruct.NVIC_IRQChannalPreemptionPriority = 0x1;//抢占优先级
    NVIC_InitStruct.NVIC_IRQChannalSPriority = 0x1;
    NVIC_InitStruct.NVIC_IRQChannalCmd = ENABLE; 
    NVIC_Init(&NVIC_InitStruct);   
              
}

//外部中断处理函数
void EXTI0_IRQHandler(void)
{
   //中断程序需要完成的工作
   D1 = ~D1;
  //清除中断标志位
  EXTI_ClearITPendingBit(EXTI_Line0);

}


void EXTI2_IRQHandler(void)
{
   //中断程序需要完成的工作
   D2 = ~D2;
  //清除中断标志位
  EXTI_ClearITPendingBit(EXTI_Line2);

}

void EXTI3_IRQHandler(void)
{
   //中断程序需要完成的工作
   D3 = ~D3;
  //清除中断标志位
  EXTI_ClearITPendingBit(EXTI_Line3);

}

void EXTI4_IRQHandler(void)
{
   //中断程序需要完成的工作
   D4 = ~D4;
  //清除中断标志位
  EXTI_ClearITPendingBit(EXTI_Line4);

}

mq2.h

#ifndef _MQ2_H_
#define _MQ2_H_

#include<sys.h>
#define MQ2 PAin(2)
void mq2_init(void)
#endif

mq2.c

#include<stm32f4xx.h>
#include<key.h>
include<led.h>


void mq2_init(void)
{
  GPIO_IiitTypeDef GPIO_InitStruct;
  RCCAHB1PerichClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);

  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_2;//PA2
  GPIO_Init(GPIOA,GPIO_InitStruct); 

}

main.c

#include<stm32f4xx.h>
#include<include.h>

int main()
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    mq2_init();
    exit_init();
   
    while(1)
   {
       if(MQ2)
           D1=1;
       else
      {  
         D1=0;
      }
   }
}

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

肖爱Kun

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值