前导:本文的目的与,意在于面向应用的学习单片机,故不会涉及太多的原理知识,例如寄存器之类的。

主要目的在于面向应用的学习单片机,学会单片机的基础用法,开发板采取野火的指南者f103。

作者大二小白,写的不好的地方轻点喷,欢迎评论区交流

全部工程代码开源在Gitee仓库

文章目录

  • 1 中断简介
    • 1.1 为什么需要中断?
    • 1.2 中断
    • 1.3 EXTI外部中断事件
    • 1.4 NVIC中断组
    • 1.5 代码编写步骤
  • 2 中断例子代码
    • 2.1 按键中断1
      • 2.1.1需求
      • 2.1.2EXTI配置
      • 2.1.3NVIC配置
      • 2.1.4逻辑代码
    • 2.2 按键中断2
      • 2.2.1 需求
      • 2.2.2EXTI配置
      • 2.2.3NVIC配置
      • 2.2.4逻辑代码

1 中断简介

1.1 为什么需要中断?

​ 想象一个生活场景,在生活中,我是一个处理能力的主体,做饭,烧水,买菜,打游戏等等的,在没有任何提醒的下,我是只能做一件事情的。

​ 例如我在打游戏的时候,我只能打游戏,做饭的时候,只能做饭。

​ 显然这样的效率是十分低下的,但是在真实的生活中,是充斥着各自提示消息的,例如水烧开的时候,发出响声,我听到水烧开的声音,放下手头的工作,去把烧水壶拿开,然后接着回头干我自己的事情。

假设我不去听水烧开的声音,我只是看着水在那边开始冒热气,直到烧开,那这几分钟内我什么事情都干不了。

​ 同样,洗衣机洗衣服也是同理,我不会看着衣服洗完,我只会等待洗衣机洗好后发出滴滴声提醒我。

生活的存在着各种信息,提醒我们暂时放下手头的工作,转而完成另外一件事情,再回到手头工作

​ 而在计算机中,这种机制叫做中断处理机制

1.2 中断

中断机制生活例子 对应代码
开始洗衣服时,我会注意洗衣机洗完的响声 写代码绑定一个中断事件,进行监听
当洗衣机的响声和烧水壶的响声同时响起时,我会先去拿开烧水壶 配置中断优先组,当两个中断同时发生的时候,优先处理优先级高的事情
听到响声 配置中断触发条件
去拿走烧水壶 将操作写进中断服务函数
处理完事件后,回到手头上正在做的事情 清除标志位

中断整体工作流程如下

​ 注意,跳转到中断服务程序的时候,我需要问你一个问题,怎么跳转?程序怎么知道,我要跳转到哪里。

​ 这里要提及一个概念,函数在程序中,是有自己的地址的。程序是依靠着地址,跳转到函数,执行函数里的操作的。

​ 中断以及对应函数是由stm32提供的,自然,官方也就给我们准备好了各种中断函数。

​ 在**startup.s里有一系列的中断函数定义,也叫做异常向量组。**当某个中断发生的时候,就会跳转到对应的中断函数里,执行我们要做的操作。执行完再返回主函数。

​ 这意味着,中断函数的名字我们是不要去改变的,我们要去这个文件里复制对应的中断服务函数,然后在里面写代码

1.3 EXTI外部中断事件

External interrupt / event controller 外部中断/事件控制器

管理了一组中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。

平时我们会使用 EXTI0至 EXTI15对应的就是GPIO的0-15号引脚的中断

1.4 NVIC中断组

Nested vectoredinterrupt controller,即嵌套向量中断控制器。

嵌套的理解就是,多个中断接连发生,嵌套在一起的时候,该以什么顺序处理这些中断。

他具有五个分组,两个属性

分组部分:

记住整个程序只能配置一个分组,相当于是一个规则

这里的主和子,指的就是后面的抢占和优先的取值。

属性部分:

一个为抢占属性,另一个为响应属性,其属性编号越小,表明它的优先级别越高。

  • 抢占,是指打断其他中断的属性,即因为具有这个属性会出现嵌套中断(在执行中断服务函数A 的过程中被中断B 打断,执行完中断服务函数B 再继续执行中断服务函数A),抢占属性由NVIC_IRQChannelPreemptionPriority 的参数配置。
  • 响应,则应用在抢占属性相同的情况下,当两个中断向量的抢占优先级相同时,如果两个中断同时到达, 则先处理响应优先级高的中断, 响应属性由NVIC_IRQChannelSubPriority 参数配置。

​ 若内核正在执行C 的中断服务函数,则它能被抢占优先级更高的中断A 打断

​ 由于B 和C 的抢占优先级相同,所以C 不能被B 打断

​ 但如果B 和C 中断是同时到达的,程序就会首先执行响应优先级别更高的B 中断

(高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的,而抢占优先级相同的中断,高优先级的响应优先级不可以打断低响应优先级的中断)。

优先级取值范围如下

1.5 代码编写步骤

说到编写步骤,不如先来看看,中断的整体执行流程(忽略我不好看的字)

根据这张图,我们可以写出,代码大致的配置流程如下

  • 开启复用时钟(别问为什么哈哈)
  • 配置指定端口的中断线
  • 配置中断触发模式,中断触发的条件
  • 使能中断线,并初始化EXTI
  • 配置优先组,绑定中断源(也就是所要触发的中断线)
  • 配置抢占优先级,响应优先级
  • 使能并初始化

2 中断例子代码

2.1 按键中断1

2.1.1需求

  • 我需要在按键按下,并且没有松手的时候,程序能够正常运行,松手的时候能够正常记录按键按下次数。

显然,之前的程序是有问题的。

当我们在按键扫描的函数里,增加判断松手的时候,也就是

#define KEY1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)
if(KEY1)
{Delay(2500000);while(KEY1);key = '1';
}

​ 会导致一个bug,也就是,当我们按下,但不松手的时候,主函数就什么都执行不了因为他疯狂的扫描按键1的电平,而我们一直按着,就一直卡在while(1)里导致死循环。

​ 就像是我最开始举的例子,我只能在水旁边看着它烧开。

​ 所以我们现在就需要检查“听水烧开的声音” 这个信号。

也就是检查按键按下然后松手时触发的“信号”,配置中断了。

2.1.2EXTI配置

按照我们前面所说的流程进行配置。开启复用时钟后。

去stm32f10x_exti.h里找到对应的初始化结构体。

​ 可以发现里面就有中断线,中断模式,中断触发器(触发条件),中断线使能四个参数,这些参数对应的定义在头文件里也有

得到这些信息后,我们开始配置,可以复制一份之前LCD的工程,在那上面进行改进。(在KEY_Init里配置)

//声明EXTI初始化结构体
EXTI_InitTypeDef EXTI_InitStructure;
//开启复用时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//配置PA0的中断线
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
//选择0号中断线,因为是PA0
EXTI_InitStructure.EXTI_Line=EXTI_Line0;
//配置模式为中断触发模式,一般只用这个。
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
//配置为下降沿触发,按键按下时是高电平,也就是上升沿,一松手就是下降沿了
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
//使能中断线
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
//初始化中断
EXTI_Init(&EXTI_InitStructure);

到这,EXTI的配置部分就已经完成了。

2.1.3NVIC配置

NVIC的相关内容存在misc.h里,我们还是照例跳进去看。发现一个这样的结构体

可以看到四个参数

  • 1:中断源的通道,也就是我们的中断线0
  • 2:抢占优先级
  • 3:响应优先级
  • 4:使能

代码编写,就像1.5里讲的一样,从组开始配置,我们查看misc.h的最下方,第一个函数。翻译过来就是

NVIC优先组配置。

并且在上方会发现它的取值有以下四个

代码编写如下(也可以在KEY_Init里配置)

//声明NVIC初始化结构体
NVIC_InitTypeDef NVIC_InitStructure;
//配置中断组1,我们就一个按键中断,这个组怎么配置其实都可以了
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//配置中断源
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//这个参数去stm32f10x.h里找
//配置抢占优先级
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
//配置响应优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
//使能
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//初始化NVIC
NVIC_Init(&NVIC_InitStructure);

到这。NVIC的配置部分也完成了。然后,可以删掉我们的KEY_Scan函数了,因为用的不是扫描法

2.1.4逻辑代码

​ 所有的配置部分写完之后,我们就准备开始编写业务逻辑代码。首先要转换一下思路之前我们是利用GPIO_ReadInputDataBit不断的扫描读取按键上的电平。

就像是我们看着水,水烧开了再进行操作。

​ 现在因为我们刚刚配置了 下降沿的中断触发,也就是,每当我们按键按下时,松开时,产生的那个下降沿,就会被程序监听到。然后产生一个中断信号,然后跳转到中断函数中进行逻辑处理。

​ 因为按键按下是高电平,产生上升沿,松手后变回低电平,下降沿产生。中断捕获到。跳转到中断函数进行处理。

问题来了,中断服务函数从何而来?在我1.2的中断讲解里有提到。可以回去观察。会发现里面有一个

EXTI0_IRQHandler这就是EXTI0的中断服务函数的函数名了。

KEY也是连接在PA0上的,自然配置的也就是EXTI0的中断,那么复制这行函数,写到stm32f10x_it.c里面。

it是interrupt中断的意,约定俗成的我们中断服务函数都会写到stm32f10x_it.c里,当然要写其他地方也行。就像这样,这里面要放的就是我们产生中断后要进行的处理了。

​ 接下来,我们可以写我们的逻辑了,思考一下,在中断函数里需要什么

​ 既然已经跳转到中断函数里了,那么证明这个中断被触发了,也就是,按键产生下降沿了,意味着我们已经松手了,松手后需要的就是。 按键次数++

​ 我们现在这里 extern 一个主函数的按键次数变量。
c语言中,其他的c文件要使用不属于自己的.c文件时,需要使用extern,具体规则可以查一下csdn。

extern int key1_count;
void EXTI0_IRQHandler(void)
{Delay(2500000);//同样也需要消抖,否则还是有可能多次触发key1_count++;
}

可,这样可以了吗?

答案是否定的,计算机不像人那么聪明,听到水烧开,就去拿开水壶,拿开水壶后就回去接着干自己的事情。

​ 计算机会进入这个中断,是因为产生中断信号后,某个标志位变为1了,标志为1的时候就会跳转到中断函数中。这段代码里,我们并没有把标志位清0,也就是说,在我们一次松手后,这个中断还是会不断的触发。因为进入这个中断的标志位一直为1。

​ 解决方案也很简单,清除标志位就好,stm32官方肯定也考虑到了。在stm32f10x_exti.h里有这样一行函数

void EXTI_ClearITPendingBit(uint32_t EXTI_Line);

​ 很明显,参数为中断线,效果为清除中断线的标志,那么最终代码改造如下

extern int key1_count;
void EXTI0_IRQHandler(void)
{Delay(2500000);//同样也需要消抖,否则还是有可能多次触发key1_count++;EXTI_ClearITPendingBit(EXTI_Line0); //产生中断后清除标志位
}

此时,我们加入流水灯和液晶屏进行测试。显示方面就不说了,上一章提到过了。

#include "stm32f10x.h"
#include "./lcd/bsp_ili9341_lcd.h"
#include "led.h"
#include "key.h"
#include <stdio.h>char disp[20];
int key1_count = 0;void LCD_Show();int main (void)
{KEY_Init();//LED初始化LED_Init();//按键初始化ILI9341_Init();//液晶初始化    LCD_SetColors(BLACK,WHITE);//设置白底黑字LCD_SetFont(&Font8x16);//设置字体大小ILI9341_Clear(0,0,LCD_X_LENGTH,LCD_Y_LENGTH);//清屏ILI9341_GramScan ( 6 );//设置显示模式LED_Color(LED_OFF);//关灯while (1){LED_Flashing(LED_RED);LCD_Show();}
}void LCD_Show()
{sprintf(disp,"KEY1_Count:%3d",key1_count);ILI9341_DispStringLine_EN(LINE(4),disp);
}

这时我们就会发现了,当按键按下,并且不松手的时候,流水灯不会卡死。而松手的时候,次数将会被记录并显示。

2.2 按键中断2

2.2.1 需求

配置KEY2的中断触发。

首先我们会想到,KEY2连接的是PC13,就会去寻找Exti_Line13,幸运的,我们找到了。

2.2.2EXTI配置

 GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource13);EXTI_InitStructure.EXTI_Line=EXTI_Line13;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);

2.2.3NVIC配置

​ 和之前的一样,我们去寻找EXTI13_IRQn中断源。运气不好的是,我们发现里面并没有EXTI13_IRQn!!!,可以理解为因为芯片并没有办法为我们提供那么多的线路去连接。

但是我们在stm32f10x.h里会找到这个家伙,EXTI15_10IRQn,好家伙,10-15的中断源被定义在这一个里面了

那么我们如下改造

 NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;           NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;                 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                            NVIC_Init(&NVIC_InitStructure);

2.2.4逻辑代码

又是和上次一样的坑,并没有13号中断线的中断服务函数。取而代之的是EXTI15_10_IRQHandler

所以这次我们在stm32f10x_it.c里就用这个函数写,写出如下代码

extern int key2_count;
void EXTI15_10_IRQHandler(void)
{Delay(2500000);key2_count++;EXTI_ClearITPendingBit(EXTI_Line13);
}

接下来,在LCD测试的地方增加入key2按键次数的显示就可以了

void LCD_Show()
{sprintf(disp,"KEY1_Count:%3d",key1_count);ILI9341_DispStringLine_EN(LINE(2),disp);sprintf(disp,"KEY2_Count:%3d",key2_count); //增加按键2ILI9341_DispStringLine_EN(LINE(4),disp);
}

面向应用学习stm32(4)-EXTI外部中断相关推荐

  1. STM32(五)——EXTI外部中断

    文章笔记源于--江科大自化协的视频 一. 中断系统 中断 : 在主程序运行过程中,出现特定的中断触发条件,使得CPU暂停当前正在运行的程序,而去处理中断程序,完成后,又返回原来被暂停的位置继续工作 中 ...

  2. STM32笔记——EXTI外部中断

    目录 一.概述 二.主要外设介绍 2.1 AFIO复用IO口 2.2 EXTI简介 EXTI框图: 2.3 NVIC中断优先级分组 三.EXTI外部中断整体结构 四.实验程序 4.1 对射式红外传感器 ...

  3. STM32学习笔记(三)丨中断系统丨EXTI外部中断(对射式红外传感器计次、旋转编码器计次)

    本篇文章包含的内容 一.中断系统 1.1 中断的定义 1.2 中断优先级 1.3 中断的嵌套 1.4 STM32中的中断系统 1.4.1 STM32的中断资源 1.4.2 嵌套中断向量控制器 NVIC ...

  4. STM32中断—EXTI外部中断

    5. 中断 本文来自于<STM32--江科大>的笔记整理. 中断系统 中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处 ...

  5. STM32 EXTI外部中断/事件

    一.EXTI外部中断/事件功能框图 1.中断线路:①-②-③-④-⑤ ①输入线:有19个中断/事件输入线(联网型有20个),通过寄存器将这些输入线设置为任意一个GPIO. ②边沿检测电路:选择上升沿触 ...

  6. 【MM32F5270开发板试用】GPIO输入+EXTI外部中断例程demo试用

    本篇文章来自极术社区与灵动组织的MM32F5270开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:Zeee 前言: 首先,感谢灵动微电子与极术社区给予宝贵的试用机会.借助本次对Plus-F ...

  7. 28.EXTI外部中断原理与配置

    EXTI外部中断原理与配置 参考资料 开发板配套资料 <STM32Fx开发指南-HAL库版本>-第x章 外部中断实验 STM32Fxxx官方资料: <STM32Fxx中文参考手册&g ...

  8. 02、【江科大自化协stm32F103c8t6】笔记之【入门32单片机及EXTI外部中断初始化参数配置】

    ----------接着上一篇笔记写 四.返回值函数 五.EXTI外部中断 1.配置RCC 2.配置GPIO 3.配置AFIO 4.配置EXTI 5.配置NVIC 中断函数 四.返回值函数 uint8 ...

  9. rt-thread 学习(二)外部中断 添加头文件 延时函数

    rt-thread 学习(二)外部中断 添加头文件 延时函数 设置按键外部中断 开启硬件定时器 初始化配置部分 延时函数 添加头文件 设置按键外部中断 #include <rtthread.h& ...

最新文章

  1. 超参数搜索——网格搜索和随机搜索
  2. Glide-源码分析(一)
  3. android学习日记13--数据存储之ContentProvide
  4. 联发科技嵌入式_MTK深圳公司嵌入式软件工程师笔试题(含部分答案)
  5. 计算机网络第七版谢西仁答案
  6. 电力行业适合学习的开源软件
  7. filebeat-logstash-es综合运用
  8. 智能和弦生成工具-Plugin Boutique Scaler 2 v2.3.1 WiN-MAC
  9. 2021年茶艺师(初级)考试资料及茶艺师(初级)模拟试题
  10. docker中的localhost
  11. python去除字符串中的单词_从字符串中删除特定单词的最有效方法
  12. 为什么需要软件开发报告
  13. mysql分区表去重复_MySQL分区表管理
  14. 编写优质嵌入式C程序(转)
  15. 百度云其实真的很不错
  16. 写一个关机代码让别人的电脑根据你的指令关机,c语言写小程序恶搞别人
  17. C#基于Twain协议调用扫描仪,设置多图像输出模式(Multi image output)
  18. Linux 4.15 rc7,深度操作系统 15.4 RC更新详情
  19. Flink的State详解(1)
  20. Cubox是什么应用?如何将Cubox同步至Notion、语雀、在线文档中

热门文章

  1. 梦幻西游维护测试服务器仅开放转入,梦幻西游1月28日维护内容一览
  2. datepicker 季度
  3. 一款相见恨晚SCI论文写作神器-phrasebank-润色英文表达
  4. 用Adobe AIR支持多样设备多倍屏幕尺寸
  5. 2021年塔式起重机司机最新解析及塔式起重机司机新版试题
  6. php电影播放系统在线视频点播系统 php毕业设计题目课题选题 php毕业设计项目作品源码(4)系统后台功能和界面
  7. lib和dill区别
  8. Z变换(Z-transform)
  9. C++:atan2(y, x)函数用法详解
  10. 重庆成都汽车车身贴膜隐形车衣为什么要找膜手世家