STM32固件库(标准外设库)入门学习 第五章 EXTI中断(二)

STM32固件库(标准外设库)入门学习 第五章 EXTI中断(二)



前言

本学习教程,参考B站江科大自化协STM32视频,型号为STM32F103C8T6。

什么样得设备需要用到外部中断,外部中断得好处?若STM32想要获取的信号,是外部驱动得很快的突发信号,比如:

(1)旋转编码器的输出信号,可能很久不去拧它,这时不需要STM32做任何事情,但是我一拧它就会产生很多脉冲波形需要STM32接收,这个信号是突发的,STM32不知道什么时候会来,同时它是外部驱动,STM32只能被动读取,最后这个信号非常快,STM32稍微晚一些,就会错过很多波形,对于这种情况来说,就可以考虑使用STM32的外部中断了。有脉冲过来,STM32立即进入中断函数处理,无脉冲来,STM32就专心做其他事情。

(2)红外遥控接收头的输出,接收到遥控数据后,他会输出一端波形,这个波形转瞬即逝,所以就需要用外部中断读取。

(3)按键,虽然它的动作也是外部驱动突发事件,但并不推荐用外部中断来读取按键,因为外部中断不好处理按键抖动和松手检测的问题,对于按键来说,输出波形也不是转瞬即逝的,要求不高的话可以在主程序中循环读取,若不想用此方法,可以考虑用定时器中断读取方式,这样既可以后台读取按键值、不阻塞主程序,也可以很好的处理按键抖动和松手检测的问题。


一、旋转编码器简介

旋转编码器:用来测量位置、速度或旋转方向的装置,当其旋转轴旋转时,其输出端可以输出与旋转速度和方向对应的方波信号,读取方波信号的频率和相位信息即可得知旋转轴的速度和方向。

类型:机械触点式、霍尔传感器式、光栅式。
在这里插入图片描述
左1图用了对射式红外传感器来测速,为了测速,还需要配合一个这样的光栅编码盘,编码盘转动时,红外传感器的红外光就会出现遮挡、透过、遮挡、透过这样的现象,对应模块输出的电平就是高低电平交替的方波,方波的个数代表转过的角度,方波的频率代表转速。就可以用外部中断来捕获这个方波的边沿,以此判断位置和速度。这个模块只有一路输出,正转翻转输出波形无法区分,所以不能测旋转方向。为了进一步测旋转方向,可以用后面几种编码器。

2图为旋转编码器左为外观,右为内部拆解结构。内部用金属触点进行通断,所以时一种机械触点式编码器,这种方式可用来调节音量等,不适合电机这种高速旋转的地方。左右是两部分开关触点,其中内侧的这两根细的触点,和中间引脚(c上方)连接,外侧左边的接左引脚,右边的连右引脚。中间圆的金属片是一个按键。这个旋转编码器的轴式可以按下去的,按键的两根线,在上面印出来,轴按下,上面两根线短路,松手,上面两根线断开,就是一个普通按键。再看一下编码盘,也是一系列像光栅一样的东西,只不过这是金属触点,旋转时,依此接通和断开两边的触点,还有个关键的部分是,金属盘的位置是经过设计的,他能让两侧触点的通断产生一个90度的相位差,最终配合外部电路,这个编码器的两个输出就会输出下图这样的波形,正转时,左边A相引脚输出一个方波波形,同时右侧B相,输出一个和他相位相差90度的波形,正向旋转时,B相输出滞后90度,返现旋转时,B相会提前90度。这样区分正转和反转,这种相位相差90度的波形就叫正交波形,这种编码器可以用来测方向的。也有编码器不是输出正交波形,一个引脚输出方波信号代表转速,另一个引脚输出高低电平代表旋转方向。
在这里插入图片描述
3图直接附在电机后面的编码器,这种事霍尔传感器形式的编码器,中间是一个圆形磁铁,边上有两个位置错开的霍尔传感器,当磁铁旋转时,通过霍尔传感器,就可以输出正交的方波信号。

4图就是一个独立的编码原件,输入轴转动时,输出就会有波形,这个也是可以测速和测方向的,具体用法看手册。

**编码器硬件电路。**因为只有开关信号,所以需要配合外围电路进行使用,左边接了10k的上拉电阻,默认没旋转的情况下,被上拉为高电平,通过R3电阻,输入A端口的也是高电平,旋转时,内部触点导通,被拉到GND,再通过R3输出,A端口就是低电平了。R3是一个输出限流电阻,它是为了防止模块引脚电流过大,C1为输出滤波电容,可防止一些输出信号抖动。
右侧使用电路图很简单。
在这里插入图片描述
NVIC是内核外设,要在cortex-M3编程手册找。


二、对射式红外传感器计次

1.接线图

当挡光片或编码盘在这个对射式红外传感器中间经过时,DO就会输出电平跳变的信号,这个电平跳变的信号触发STM32 PB14号口的中断,在中断函数里,执行变量++的程序,然后主循环里调用OLED显示这个变量,这个程序就完成了。
在这里插入图片描述

2.配置外部中断

沿用上文OLED显示屏程序,把传感器的功能封装在一个模块里,Hardware文件下添加.c和.h文件CountSensor,并修改路径。
在这里插入图片描述
写上固定部分代码。
在这里插入图片描述
在这里插入图片描述
配置外部中断。看EXTI基本结构图,就知道要配置哪些东西了,简单来说就需要把外部中断从GPIO到NVIC这一路中出现的外设模块都配置好,把这条信号电路打通。
在这里插入图片描述

2.1 第一步配置RCC

把所有涉及的外设时钟都打开。这里主要开GPIOB和AFIO的时钟,EXTI和NVIC默认是一直打开的,不需要我们再开启时钟。

注:EXTI作为一个独立外设,按理来说应该需要开启时钟,但是寄存器里却没有EXTI时钟的控制位,应该是与EXTI唤醒有关,或者是其他的一些电路设计上的考虑,只要知道不需要开启其时钟就可以了。NVIC也不需要开启时钟,是因为NVIC是内核的外设,内核的外设都不需要开启时钟,其与CPU一起住在皇宫里,而RCC管的都是内核外的外设,所以RCC管不着NVIC。
在这里插入图片描述

2.2 第二步配置GPIO

选择端口为输入模式。GPIO_Mode要选择浮空输入、上来输入或者下拉输入,这其中的一个模式,若不清楚,查阅参考手册8.1.11 外设的GPIO配置,里面有每个外设的各个引脚需要配置为什么模式。这里给上拉输入,默认为高电平的输入方式。
在这里插入图片描述
在这里插入图片描述

2.3 第三步配置AFIO

选择我们用的这一路GPIO,连接到后面的EXTI。AFIO外设,ST并未分配给他专门的库函数文件,其库函数与GPIO在一个文件里,从gpio.h文件看最后的库函数。之前在GPIO部分已经说过一些函数,今天看有关AFIO的。

GPIO_AFIODeInit用来复位AFIO外设,调用此函数,AFIO外设的配置就会全部清除;

GPIO_EventOutputConfig、GPIO_EventOutputCmd配置AFIO事件输出功能,用的不多;

GPIO_PinRemapConfig用于进行引脚重映射,第一个参数选择重映射的方式,第二个参数选择新的状态,使用简单,但是目前还未需要用到;

GPIO_EXTILineConfig比较重要,是本节外部中断需要用到的函数,调用此函数可以配置AFIO的数据选择器,来选择想要的中断引脚;

GPIO_ETH_MediaInterfaceConfig函数与以太网有关,这个芯片用不到。
在这里插入图片描述
现在想要配置AFIO外部中断引脚选择,直接用GPIO_EXTILineConfig函数,这个函数虽然是GPIO开头的函数,但实际上里面操作的是AFIO的寄存器,所以这个函数实际上是AFIO的函数。配置这一个函数,就可以完成AFIO的配置,执行完这个函数后,AFIO的第14个数据选择器就拨好了,其中输入端被拨到GPIOB外设上,对应PB14号引脚,输出端固定连接EXTI的第14个中断线路,这样PB14号引脚的电平信号就可以顺利通过AFIO,进入到后级EXTI电路了。
在这里插入图片描述

2.4 第四步配置EXTI

选择边沿触发方式,比如上升沿、下降沿或者双边沿。还要选择触发响应方式,可以选择中断响应和事件响应,一般为中断响应。看EXTI的库函数文件,看一些EXTI有哪些库函数可用,找到exti.h文件,拖到最后。
在这里插入图片描述
(1)EXTI_DeInit,调用此函数可以把EXTI配置清除,恢复成上电默认的状态;

(2)EXTI_Init,调用此函数可以根据结构体里的参数配置EXTI外设,初始化EXTI主要用的就是这个函数,使用方法与GPIO_Init一样;

(3)EXTI_StructInit,调用此函数可以把参数传递的结构体变量赋值一个默认值。
注:以上三个函数,基本所有外设都有,就像库函数的模板函数一样,基本每个外设都需要这些类型的函数,模板函数使用方法和意思也都一样,会使用一个,再见到这种函数就很容易的上手。当学GPIO的时候,觉得为啥要用结构体来初始化模块呢,还需要定义结构体,结构体赋值,然后再传递结构体的地址,简直太麻烦了。但当学习其他外设之后,就会发现,外部中断也是使用结构体初始化的方式、定时器也是、ADC也是、串口也是,都是一样的。而且结构体可以看到参数的名字,参数也是复制粘贴来的,根本不需要看寄存器,随便选择参数就配置好了,从这个角度看,STM32的库函数是不是比寄存器方便多了,这就是库函数的优势。

(4)EXTI_GenerateSWInterrupt,这个函数是用来软件触发外部中断的,调用此函数,参数给一个指定的中断线,就能软件触发一次这个外部中断,若程序中需要这个功能,可以使用这个函数,若只需要外部引脚触发中断,则不需要这个函数。

(5)剩下四个函数也是库函数的模板函数,很多模块也都有。因为再外设运行的过程中,会产生一些状态标志位,比如外部中断来了,是不是会有一个挂起寄存器置了一个标志位,对于其他外设,比如串口收到数据会置标志位,定时器时间到也会置标志位,这些标志位都是放在状态寄存器中,当程序想要看到这些标志位时,就可以用到这四个函数。EXTI_GetFlagStatus可以获取指定的标志位是否被置1**;EXTI_ClearFlag可以对置1的标志位进行清除;对于这些标志位,有的比较紧急,在置标志位后会触发中断,在中断函数里,如果想查看标志位和清除标志位,那么就用下面两个函数EXTI_GetITStatus**获取中断标志位是否被置1、EXTI_ClearITPendingBit清除中断挂起标志位。
总结,如果想在主程序里查看和清除标志位,就用上两个函数,如果想在中断函数里查看和清除标志位就用下面两个函数。其实本质上,这四个函数都是对状态寄存器的读写,下面两个函数只能读写与中断有关的标志位,并且对中断是否允许做出了判断。而上面的两个函数只是一般的读写标志位,没有额外的处理,能不能触发中断的标志位都能读取,建议在主程序里用上面两个,中断程序里用下面两个。非要在中断里用上面两个,其实也没有问题,只不过库函数针对这两种场景,区分了这两类读写函数。

对于EXTI初始化配置,很明显,用EXTI_Init函数就行了。回到初始化程序里,与配置GPIO类似完成配置,但是注释里有一个地方写错了,需要修改。配置好后,PB14的电平信号就能够通过EXTI通向下一级NVIC了。
在这里插入图片描述
在这里插入图片描述

2.5 第五步配置NVIC

给中断选择一个合适的优先级,最后通过NVIC,外部中断信号就能进入CPU了。先看库函数文件里的函数,NVIC是内核外设,所以库函数被分配到杂项misc.h里,点开,拖到下面。这里有4个NVIC函数和1个SysTick的一个函数。
在这里插入图片描述
(1)NVIC_PriorityGroupConfig用来中断分组,参数是中断分组的方式。
(2)NVIC_Init根据结构体里指定的参数初始化NVIC。
(3)NVIC_SetVectorTable,设置中断向量表,用的比较少
(4)NVIC_SystemLPConfig,系统低功耗配置,用的比较少

NVIC库函数只需要用上两个,在配置中断之前,先指定一下中断的分组没然后使用NVIC_Init初始化NVIC就行了。
赋值NVIC_PriorityGroupConfig到.c文件里配置中断分组,点函数然后F12转到定义,根据实际需求选择几位抢占,几位响应,一般的话中断不多,很难导致中断冲突,对于优先级分组来说,就比较随意了,哪个都行,这里选择2位抢占,2位响应,比较平均。
注意:这个分组方式,整个芯片只能用一种,所以这个分组的代码整个工程只需要执行一次就行了,如果放在模块里进行分组,需要确保每个模块分组都选的是同一个。也可以把代码放到主函数的最开始,这样模块里就不用再进行分组了。
在这里插入图片描述
回到初始化程序里,与配置GPIO类似完成配置。
在这里插入图片描述NVIC_IRQChannel查找定义,找到注释,选中再次F12
在这里插入图片描述
进入stm32f10x.h文件,因为这个库函数可以兼容所有的F1系列芯片,但是不同的芯片中断通道列表是不一样的,所以要根据所用芯片选择中断通道列表,找到MD,找到EXTI15_10_IRQn,放到配置里,这样就完成通道指定。
在这里插入图片描述
在这里插入图片描述
最后完成配置。
在这里插入图片描述

3.中断程序的编写

在STM32中,中断函数的名字都是固定的,每个中断通道都对应一个中断函数,中断函数的名字参考启动文件md.s,以IRQHandler结尾的字符串就是中断函数的名字,找到EXTI15_10_IRQHandler复制。
在这里插入图片描述
回到.c程序粘贴如下图所示,中断函数都是无参无返回值的,记住名称不能写错,写错就进不去中断了,最好就是从启动文件复制粘贴到这里。
在这里插入图片描述
在中断函数里,一般先进行一个中断标志位的判断,确保是我们想要的中断源触发的这个函数。因为这个函数EXTI10到EXTI15都可以进来,所以要先判断是不是我们想要的EXTI14进来的,这时需要到exti.h文件看一下,复制此函数。
在这里插入图片描述
这个函数的返回值是SET和RESET,最后结束时一定要再调用一下清除中断标志位的函数,因为只要中断标志置1,程序就会跳转到中断函数,如果不清除中断标志位,那它就会一直申请中断,这样程序就会不断响应中断,执行中断函数,程序就卡死在中断函数里了。
在这里插入图片描述
中断函数无需声明,自动调用。
在这里插入图片描述
最终函数。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


三、旋转编码器计次

1 接线图

在这里插入图片描述
封装旋转编码器函数。如果把一相的下降沿作触发中断,在中断时候读取另一相的电平,正转(右转)就是高电平,反转(左转)就是低电平,这样就可以区分正反转了。但是在操作时有一些问题,正转的时候,由于A相先出现下降沿,所以刚开始转动时,就进中断了,而反转是A相后出现下降沿,所以是转到位了,才进入中断,实际上也没有问题。我们这里准备的是AB相都触发中断,只有在B相下降沿和A相低电平时,才判断为正转,在A相下降沿和B相低电平时,才判断为反转,这样就能保证正传、反转都是转到位了,才执行数字加减的操作。
在这里插入图片描述

2 程序编写

展示两个中断的初始化代码。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


总结

中断编程的建议:

(1)中断函数里,不要执行耗时过长的代码,中断函数要简短快速,别刚进中断就执行一个Delay多少毫秒这样的代码。因为中断时处理突发的事情,如果为了处理一个突发的事情,呆在中断不出来,那主程序就会严重堵塞。

(2)最好不要在中断函数和主函数调用相同的函数或操作同一硬件,尤其时硬件相关的函数。比如OLED显示函数,如果既在主程序调用OLED,又在中断里调用OLED,OLED就会显示错误,
因为在主程序里,OLED刚显示一半,进中断了,结果中断里还是OLED显示函数,那OLED就挪到其他地方显示了,这时还没有问题,但中断结束后,需要继续原来的显示,就会出现问题,因为硬件的显示位置被挪到其他地方了,所以再回来时,继续显示的内容就会跟着跑到其他地方去。虽然在中断进入和退出的时候,会保护现场和恢复现场,但这只能保证CPU程序能正常返回不出问题,对于外部硬件的话,没有在进入中断时,进行现场保护,所以中断返回后,就出问题了,为了避免这样的问题,最好不要在主程序和中断程序里,操作可能产生冲突的硬件。最好在中断里操作变量和标志位,当中断返回时,再对这个变量进行显示和操作,这样既能保证中断函数的简短快速,又能保证不产生冲突的硬件操作。

(3)其他地方也可以多用变量和标志位,减少代码之间的耦合性,让各部分代码相互独立,仅使用变量、标志位或者函数作为接口,这样让程序更加清晰,代码更加强健。

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
旋转编码器和增量式编码器是两种常见的编码器类型,它们在测量和检测旋转运动时具有不同的工作原理和特点。 旋转编码器是一种基于光学或磁性原理的传感器,通常由一个光栅或磁性编码盘和一个读取头组成。编码盘上的刻度被分成许多等分,当旋转编码器与旋转的物体连接时,读取头会检测到刻度的变化,并将其转换为相应的电信号。旋转编码器可以提供准确的位置和速度信息,通常用于需要高精度测量的应用,如机械加工、机器人控制等。 增量式编码器也是一种用于测量旋转运动的传感器,但其工作原理与旋转编码器不同。增量式编码器通常由一个光栅或磁性编码盘和两个读取头组成。其中一个读取头用于测量绝对位置,另一个读取头用于测量增量位置。增量式编码器通过检测刻度的变化来测量增量位置,而绝对位置则通过在初始位置处设置一个参考点来确定。增量式编码器可以提供实时的位置变化信息,适用于需要监测速度和方向变化的应用,如电机控制、运动控制系统等。 因此,旋转编码器和增量式编码器的主要区别在于工作原理和提供的信息类型。旋转编码器提供准确的位置和速度信息,适用于需要高精度测量的应用;而增量式编码器提供实时的位置变化信息,适用于需要监测速度和方向变化的应用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ZRob

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

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

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

打赏作者

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

抵扣说明:

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

余额充值