1、EXTI功能

  外部中断/事件控制器EXTI管理了STM32的20个中断/事件线。

  EXTI的功能框图如下:

  在功能框图中,可以看到很多在信号线上打了一个斜杠并标注“20”的字样,这是表示在STM32内部类似的信号线路有20个,也就是EXTI的20个中断/事件线。

  EXTI可以分为两大部分功能:

  产生中断:如功能图中的红色线。

  产生事件:如功能图中的绿色线。

  EXTI中断功能说明:

  电路1:  

  在功能框图中,电路1是脚位输入线,EXTI有19个中断/事件输入线,这些输入线可以通过外部中断配置寄存器AFIO_EXTI1~AFIO_EXTI2设置为任意一个GPIO,也可以是一些外设的事件。输入线一般是电平变化的信号。

电路2:

  电路2是边沿检测电路。该边沿检测电路是根据EXTI_RTSR上升沿触发选择寄存器和EXTI_FTSR下降沿选择寄存器的设置来控制信号触发。

  如果检测到与EXTI_RTSR和EXTI_FTSR寄存器设置相对应的边沿跳变信号,就出输出有效信号到电路3。通过EXTI_RTSR和EXTI_FTSR寄存器,可以设置触发的信号为:上升沿触发、下降沿触发、电平变化触发(即上升沿和下降沿都可以触发)。

电路3:

  电路3是一个或们电路,两路输入只要有一路输入有效信号,则输出有效信号。

  从功能图中可以看出,电路3的一路输入来自电路2的输出,另一路来自EXTI_SWIER软件中断事件寄存器。

  EXTI_SWIER寄存器可以通过程序控制启动中断/事件线,即只要在程序中将EXTI_SWIER寄存器的对应位设置为1,那么电路3就会输出有效信号,这样就可以实现软件模拟中断或事件。

电路4:

  电路4是一个门电路,只有当两路都输入有效信号时,电路4才会输出有效信号。

  电路4的输入一路来自电路3的输出,一路来自EXTI_IMR中断屏蔽寄存器。只有当电路3输出有效信号,而且EXTI_IMR寄存器的对应位使能,电路4才会输出有效信号。

  EXTI_IMR寄存器用来使能或屏蔽相应的中断线。

电路5:

  电路5是将EXTI_PR寄存器的内容输出到NVIC中,从而实现系统中断控制。

  EXTI事件功能说明:

  EXTI的事件产生线路,最终输出一个脉冲信号。

  产生事件的线路是在电路3之后才与产生中断的线路有所不同,之前的电路都是共用的。

  电路6:

  电路3产生的有效信号会被输入到电路6中。电路6是一个门控电路,电路3的输出和EXTI_EMR事件屏蔽寄存器作为电路6的输入。只有当电路3输出有效信号且EXTI_EMR寄存器的相应位使能,电路6才会输出有效信号。

  EXTI_EMR寄存器用来使能或屏蔽相应的事件线。

电路7:

  电路7是一个脉冲发生器电路,当电路6产生一个有效信号时将会输出到电路7当中,这时电路7就会产生一个脉冲。

电路8:

  电路8是一个脉冲信号,这个脉冲信号就是电路7产生的脉冲信号。这个脉冲信号可以给其它外设电路使用,比如TIM定时器、ADC模拟数字转换器等等,这样的脉冲信号一般用来触发TIM或者开始ADC转换。

  产生中断线路目的是运行相应的中断服务函数,实现功能。

  而产生事件的目的是传输一个脉冲信号给其它外设使用,而且产生事件的是电路级别的信号传输,属于硬件级。

2、中断/事件线

  EXTI有20个中断/事件线,每个GPIO都可以被设置为输入线,占用EXTI0和EXTI15,还有4个用于特点的外设事件。它们如下:

    • EXTI0中断/事件线:输入由PA0~PI0等组成。
    • EXTI1中断/事件线:输入由PA1~PI1等组成。
    • EXTI2中断/事件线:输入由PA2~PI2等组成。
    • EXTI3中断/事件线:输入由PA3~PI3等组成。
    • EXTI4中断/事件线:输入由PA4~PI4等组成。
    • EXTI5中断/事件线:输入由PA5~PI5等组成。
    • EXTI6中断/事件线:输入由PA6~PI6等组成。
    • EXTI7中断/事件线:输入由PA7~PI7等组成。
    • EXTI8中断/事件线:输入由PA8~PI8等组成。
    • EXTI9中断/事件线:输入由PA9~PI9等组成。
    • EXTI10中断/事件线:输入由PA10~PI10等组成。
    • EXTI11中断/事件线:输入由PA11~PI11等组成。
    • EXTI12中断/事件线:输入由PA12~PI12等组成。
    • EXTI13中断/事件线:输入由PA13~PI13等组成。
    • EXTI14中断/事件线:输入由PA14~PI15等组成。
    • EXTI15中断/事件线:输入由PA15~PI15等组成。
    • EXTI16中断/事件线:PVD输出。
    • EXTI17中断/事件线:RTC闹钟事件。
    • EXTI18中断/事件线:USB唤醒事件。
    • EXTI19中断/事件线:以太网唤醒事件(只适用互联型)。

  从上面可以看出,EXTI0到EXTI15都是用GPIO口做为中断/事件线,需要通过AFIO_EXTICR1到AFIO_EXTICR4这几个寄存器来配置具体使用哪一个位来作为中断/事件线。

  比如AFIO_EXTICR1寄存器的bit3~bit0位用来选择EXTI0的中断/事件线的输入脚位,如下:

    • Bit3~bit0 = 0000:则选择PA0作为EXTI0的输入脚位。
    • Bit3~bit0 = 0001:则选择PB0作为EXTI0的输入脚位。
    • Bit3~bit0 = 0010:则选择PC0作为EXTI0的输入脚位。
    • Bit3~bit0 = 0011:则选择PD0作为EXTI0的输入脚位。
    • Bit3~bit0 = 0100:则选择PE0作为EXTI0的输入脚位。
    • Bit3~bit0 = 0101:则选择PF0作为EXTI0的输入脚位。
    • Bit3~bit0 = 0110:则选择PG0作为EXTI0的输入脚位。

  其它EXTI也是一样的配置,不一样的只是它们的配置位在AFIO_EXTICR1~AFIO_EXITCR4寄存器中的位置不一样而已。

  AFIO_EXTICR寄存器只有低16位有效,每4个bit配置一个EXTI,一个AFIO_EXTICR可以配置4个EXTI,4个AFIO_EXTICR就可以配置16个EXTI,也就是说AFIO_EXTICR1~AFIO_EXITCR4寄存器刚好可以配置EXTI0~EXTI15的输入脚位。

  需要特别注意的是,每一个EXIT只能设置一个IO作为输入线,比如说,如果设置PA0作为EXTI0的输入线之后,PB0和其它P0口就不能作为EXTI0的输入线了。

3、EXTI的中断服务函数

  通过查询IRQn_Type结构体中的中断编号,会发现并不是每个外部中断都有一个对应中断编号。有一些外部中断的中断编号是组合在一起的,如下:

    • EXTI0的中断编号:EXTI0_IRQn。
    • EXTI1的中断编号:EXTI1_IRQn。
    • EXTI2的中断编号:EXTI2_IRQn。
    • EXTI3的中断编号:EXTI3_IRQn。
    • EXTI4的中断编号:EXTI4_IRQn。
    • EXTI5~EXTI9的中断编号:EXTI9_5_IRQn。
    • EXTI10~EXTI5的中断编号:EXTI15_10_IRQn。

  从上面可以看到,EXTI5~EXTI9的中断编号是同一个,也就是说EXTI5~EXIT9是共用一个中断服务函数,如果要区分是哪一个EXTI产生中断,可以在中断服务函数内查询EXTI_PR。EXTI10~EXTI5的中断也是一样的。

4、EXTI配置流程

  初始化IO口:

  使能要相应IO的时钟。

  将IO口配置上拉或下拉或浮空输入。设置为浮空输入的时候,脚位外部最好接上拉电阻或下拉电阻,防止IO口状态不稳而定,而导致频繁触发中断。

  配置IO与中断线的映射关系:

  由于要配置AFIO_EXTICR1~AFIO_EXITCR4寄存器,所以需要开启复用功能的时钟。

  根据IO配置AFIO_EXTICR寄存器的相应位,使IO作为EXTI功能。

  开启与该IO相对应的中断/事件线并设置触发条件:

  通过EXTI_RTSR和EXTI_FTSR寄存器设置外部中断的触发条件,配置成上升沿触发或下降沿触发或电平变化触发。还需要通过EXTI_IMR寄存器使能相应的外部中断的中断使能位。

  需要注意的是,如果使用外部中单,并设置该中断的EMR事件使能位的话,会引起软件仿真不能跳到中断,而硬件上可以。如果不是这ERM事件使能位的话,软件仿真就可以进入中断服务函数,并且硬件上也可以。

  配置NVIC:

  通过NVIC配置EXTI的中断优先级,并使能中断。

  编写中断服务函数:

  中断服务函数是必不可少的,如果在代码里面开启了中断,但没有编写中断服务函数,就可以引起硬件错误,从而导致程序崩溃。

5、HAL库初始化EXTI 

  以配置PA0为EXT0为例,代码如下:

void EXIT_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); HAL_NVIC_SetPriority(EXTI0_IRQn,,);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}

  通过设置GPIO_InitStruct.Mode为GPIO_MODE_IT_FALLING,从而区分是设置IO状态还是设置EXTI功能,这里将PA0配置为下降沿触发的EXTI0。

  在HAL_GPIO_Init函数中已经开启了复用功能的时钟。

  通过HAL_NVIC_SetPriority函数设置EXTI0的抢占优先级和响应优先级。

  通过HAL_NVIC_EnableIRQ函数使能EXIT0中断。

  中断服务函数如下:

void EXTI0_IRQHandler(void )
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
} void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
  /* EXTI line interrupt detected */
  if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
  {
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
    HAL_GPIO_EXTI_Callback(GPIO_Pin);
  }
}

  在EXTI0中断服务函数中调用HAL_GPIO_EXTI_IRQHandler函数,HAL_GPIO_EXTI_IRQHandler是HAL库内定义的一个函数,该函数在进入的时候就通过宏清除了中断标志位,然后通过调用HAL_GPIO_EXTI_Callback回调函数实现中断服务函数的功能。

  HAL_GPIO_EXTI_Callback回调函数是一个弱定义的函数,可以通过重新定义来覆盖。

6、使用EXTI0产生软件中断

  代码如下:

void EXTI_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); EXTI->IMR |= 0x01; HAL_NVIC_SetPriority(EXTI0_IRQn,,);
HAL_NVIC_EnableIRQ(EXTI0_IRQn); while ()
{
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) != )
{
HAL_Delay();
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) != )
{
EXTI->SWIER |= 0x01; while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) != )
{ }
}
}
}
}

  首先将PA0口设为浮空输入,外接下拉电阻。

  然后通过EXTI_IMR寄存器设置EXIT0中断使能。

  通过HAL_NVIC_SetPriority函数设置EXTI0的抢占优先级和响应优先级。

  通过HAL_NVIC_EnableIRQ函数使能EXIT0中断。

  最后在主循环中不断检测PA是否是高电平,如果是高电平,则给EXTI_SWIER寄存器置位bit0位,这样就会触发EXTI0中断,使得程序跑到EXTI0的中断服务函数中。

STM32F103ZET6外部中断的更多相关文章

  1. STM32F103ZET6的中断管理

    1.STM32的中断 STM32的中断管理是属于内核部分的,所以中断管理的寄存器也是属于内核组,不属于芯片外设,在查看相关资料的时候,需要查看相对应的内核手册. STM32F103ZET6是Corte ...

  2. STM32f103之外部中断

    一.背景 有个需求,IO口检测上升沿,然后做相应的动作.在此记录STM32F103的外部中断结构及配置方法, 以备下次快速上手使用. 有许多不太明白,又是老司机(:-D)帮忙,真的是站在别人的肩膀上会 ...

  3. STM32之EXTI——外部中断

    互联网的广大网友,大家早上中午晚上好.EXTI...故名思义..EX表外,出..I表示Intrrupt..所以合起来就是外部中断...说到这..我觉得我最近的六级水平(背单词)又进了一步,稍微自夸了下 ...

  4. 转别人的 STM32外部中断使用注意事项

    前言:这些问题都是我之前在工作中遇到的,后来觉得需要总结,自己记忆不好,所以在这个给自己打个mark. 一:触发方式 STM32 的外部中断是通过边沿来触发的,不支持电平触发: 二:外部中断分组 ST ...

  5. STM32外部中断初理解

    PA0,PB0...PG0--->EXTI0 PA1,PB1...PG1--->EXTI1 ....... PA15,PB15...PG15--->EXTI15 以上为GPIO和中断 ...

  6. STM32——外部中断EXIT实现

    外部中断实现步骤: 一.初始化,包括:1.AFIO时钟中断和GPIO时钟使能:                          2.GPIO初始化                           ...

  7. STM32 GPIO外部中断总结

    一.STM32中断分组: STM32 的每一个GPIO都能配置成一个外部中断触发源,这点也是 STM32 的强大之处.STM32 通过根据引脚的序号不同将众多中断触发源分成不同的组,比如:PA0,PB ...

  8. 向linux内核中添加外部中断驱动模块

    本文主要介绍外部中断驱动模块的编写,包括:1.linux模块的框架及混杂设备的注册.卸载.操作函数集.2.中断的申请及释放.3.等待队列的使用.4.工作队列的使用.5.定时器的使用.6.向linux内 ...

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

    学会知识只需要不段的积累和提高,但是如何将知识系统的讲解出来就需要深入的认知和系统的了解.外部中断和事件学习难度并不高,不过涉及到STM32的电源控制部分,还是值得认真了解的,在本文中我将以实际代码为 ...

随机推荐

  1. 选择结构二switch选择结构

     在上一章节我们讲解了if选择结构  本章我们学习 switch选择结构 还要知道if选择结构和switch结构的区别 为什么学习了if选择结构还要学习switch选择结构  以及 两种选择结构的运用 ...

  2. TypeScript Jest 调试

    本文简要介绍了如何在 Jest 单元测试中利用 Chrome Node DevTools 来辅助调试. 背景 代码是 TS 写的 所测功能无 UI 界面,出现Bug后不容易定位 用 console 式 ...

  3. TLS/SSL 梳理

    数据加密通篇都是为了防止第三方的劫持伪造,保证连接安全, 毫无遮掩的明文传输只有民风淳朴的时候才是安全的. 先是一些基础的内容: 对称加密 最开始为了对数据进行加密,使用的是对称加密算法,即双方协商好 ...

  4. C语言程序设计(九) 指针

    第九章 指针 C程序中的变量都是存储在计算机内存特定的存储单元中的,内存中的每个单元都有唯一的地址 通过取地址运算符&可以获得变量的地址 //L9-1 #include <stdio.h ...

  5. [android]从书中编码方式,看编程思想

    <Android权威编程指南第3版>今天学习到第10章,感叹经验丰富的编程理念——解耦合. 编程理念肯定是尽可能解除耦合,让代码可以复用,书中多次提到关于参数传递的解耦,这又出现一次. 本 ...

  6. go 创建slice的方式

    1.直接声明:var slice []int 2.new: slice := *new([]int) 3.字面量:slice := []int{1,2,3,4,5} 4.make: slice :=  ...

  7. 13.浏览器屏幕缩放bug修复

    目录 问题:浏览器缩放时,轮播图显示不全,滚动水平滚动条,发现图片缺失 解决:隐藏水平滚动条,页面都只提供垂直滚动条的需求 问题:浏览器缩放时,轮播图显示不全,滚动水平滚动条,发现图片缺失 解决:隐藏 ...

  8. 对象数组化 Object.values(this.totalValueObj).forEach(value => {

    对象数组化 Object.values(this.totalValueObj).forEach(value => {

  9. 【Weiss】【第03章】练习3.18:检查平衡符号

    [练习3.18]用下列语言编写检测平衡符号的程序 a.Pascal ( begin/end, ( ), [ ], { } ). b.C语言( /* */, ( ), [ ], { }). c.解释如何 ...

  10. 作为一位Vue工程师,这些开发技巧你都会吗?

    路由参数解耦 一般在组件内使用路由参数,大多数人会这样做: export default { methods: { getParamsId() { return this.$route.params. ...