STM入门学习32固件库(标准外设库) 第五章 EXTI中断(二)
文章目录
- STM入门学习32固件库(标准外设库) 第五章 EXTI中断(二)
- 前言
- 一、旋转编码器简介
- 二、对射红外传感器计次
-
- 1.接线图
- 2.配置外部中断
-
- 2.1 第一步配置RCC
- 2.2 第二步配置GPIO
- 2.3 第三步配置AFIO
- 2.4 第四步配置EXTI
- 2.5 第五步配置NVIC
- 3.编写中断程序
- 三、旋转编码器计次
-
- 1 接线图
- 2 程序编写
- 总结
前言
本学习教程参考B站江科大自化协会STM32视频,型号为STM32F103C8T6。
什么样的设备需要外部中断,外部中断的好处?STM32想要获得的信号是外部驱动快速的突发信号,如:
(1)旋转编码器的输出信号可能长时间不拧,此时不需要STM32做任何事情,但是我一拧它就会产生很多脉冲波形需要STM32接收,信号突然,STM32不知道什么时候会来,同时是外部驱动,STM32只能被动读取,最后信号很快,STM稍晚一点,就会错过很多波形,对于这种情况,可考虑使用STM32外部中断。脉冲过来,STM32立即进入中断函数处理,无脉冲,STM专心做别的事。
(2)红外遥控接收头的输出,接收遥控数据后,会输出一端波形,波形转瞬即逝,需要外部中断读取。
(3)按钮,虽然其动作也是外部驱动紧急情况,但不建议使用外部中断读取按钮,因为外部中断不容易处理按钮抖动和松开检测问题,对于按钮,输出波形不转瞬即逝,要求不高可以在主程序中循环读取,如果你不想使用这种方法,可以考虑使用定时器中断读取,这样你就可以在后台读取按钮值,不要阻塞主程序,还可以处理按键抖动和松手检测的问题。
一、旋转编码器简介
:用于测量位置、速度或旋转方向的装置,当旋转轴旋转时,输出端可以输出与旋转速度和方向相对应的方波信号,读取方波信号的频率和相位信息,了解旋转轴的速度和方向。
:机械接触式、霍尔传感器式、光栅式。 左1图用对射红外传感器测量速度。为了测量速度,还需要配合这样的光栅编码盘。编码盘旋转时,红外传感器的红外光会被屏蔽、通过、屏蔽和通过。相应模块输出的电平为高低电平交替方波,方波数量代表转角,方波频率代表转速。方波的边缘可以通过外部中断来捕获,以判断位置和速度。该模块仅一路输出,正转翻转输出波形无法区分,因此无法测量旋转方向。为了进一步测量旋转方向,可以使用以下编码器。
2图为旋转编码器左侧为外观,右侧为内部拆解结构。内部用金属触点进行通断,所以时一种机械触点式编码器,这种方式可用来调节音量等,不适合电机这种高速旋转的地方。左右为两部分开关触点,其中内侧两个细触点和中间引脚(c上方)连接,外侧左侧左引脚,右侧右引脚。中间圆的金属片是按钮。旋转编码器的轴可以按下。按钮的两条线印在上面,轴按下,上面两条线短路,松开,上面两条线断开,这是一个普通的按钮。看看编码盘,也是一系列像光栅一样的东西,但这是金属触点,旋转,两侧触点,另一个关键部分是设计的金属盘位置,他可以让两侧触点产生90度的相位差,最终与外部电路,编码器两个输出将输出下图中的波形,正转,左相引脚输出方波波形,同时,右侧B相输出与他相位相差90度的波形,正向旋转,B返现旋转时,相输出滞后90度,B会议提前90度。这种相位相差90度的波形称为正交波形,可用于测量方向。这样区分正转和反转,这种相位相差90度的波形就叫正交波形,这种编码器可以用来测方向的。也有编码器不是输出正交波形,一个引脚输出方波信号代表转速,另一个引脚输出高低电平代表旋转方向。 3图直接附着在电机后面的编码器,中间有一个圆形磁铁,边缘有两个错开的霍尔传感器。当磁铁旋转时,方波信号可以通过霍尔传感器输出。
4图为独立编码原件。输入轴旋转时,输出会有波形,也可以测量速度和方向。具体用法见手册。
**编码器硬件电路。**因为只有开关信号,需要与外围电路配合使用,左侧连接10k默认情况下,上拉电阻被上拉为高电平而不旋转R3电阻,输入A端口也是高电平,旋转时,内部触点导通,被拉到GND,再通过R3输出,A端口为低电平。R三是输出限流电阻,防止模块引脚电流过大,C一是输出滤波电容,可防止部分输出信号抖动。 右侧使用电路图很简单。 NVIC是内核外设,要在cortex-M3编程手册找。
二、对射红外传感器计次
1.接线图
当挡光片或编码盘经过对射红外传感器中间时,DO输出电平跳变信号,触发电平跳变信号STM32 PB在中断函数中,在中断函数中执行变量 然后在主循环中调用程序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的。
用来复位AFIO外设,调用此函数,AFIO外设的配置就会全部清除;
配置AFIO事件输出功能,用的不多;
用于进行引脚重映射,第一个参数选择重映射的方式,第二个参数选择新的状态,使用简单,但是目前还未需要用到;
比较重要,是本节外部中断需要用到的函数,调用此函数可以配置AFIO的数据选择器,来选择想要的中断引脚;
函数与以太网有关,这个芯片用不到。 现在想要配置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配置清除,恢复成上电默认的状态;
(2),调用此函数可以根据结构体里的参数配置EXTI外设,初始化EXTI主要用的就是这个函数,使用方法与GPIO_Init一样;
(3),调用此函数可以把参数传递的结构体变量赋值一个默认值。 注:以上三个函数,基本所有外设都有,就像库函数的模板函数一样,基本每个外设都需要这些类型的函数,模板函数使用方法和意思也都一样,会使用一个,再见到这种函数就很容易的上手。当学GPIO的时候,觉得为啥要用结构体来初始化模块呢,还需要定义结构体,结构体赋值,然后再传递结构体的地址,简直太麻烦了。但当学习其他外设之后,就会发现,外部中断也是使用结构体初始化的方式、定时器也是、ADC也是、串口也是,都是一样的。而且结构体可以看到参数的名字,参数也是复制粘贴来的,根本不需要看寄存器,随便选择参数就配置好了,从这个角度看,STM32的库函数是不是比寄存器方便多了,这就是库函数的优势。
(4),这个函数是用来软件触发外部中断的,调用此函数,参数给一个指定的中断线,就能软件触发一次这个外部中断,若程序中需要这个功能,可以使用这个函数,若只需要外部引脚触发中断,则不需要这个函数。
(5)剩下四个函数也是库函数的模板函数,很多模块也都有。因为再外设运行的过程中,会产生一些状态标志位,比如外部中断来了,是不是会有一个挂起寄存器置了一个标志位,对于其他外设,比如串口收到数据会置标志位,定时器时间到也会置标志位,这些标志位都是放在状态寄存器中,当程序想要看到这些标志位时,就可以用到这四个函数。可以获取指定的标志位是否被置1**;EXTI_ClearFlagEXTI_GetITStatus**获取中断标志位是否被置1、清除中断挂起标志位。 总结,如果想在主程序里查看和清除标志位,就用上两个函数,如果想在中断函数里查看和清除标志位就用下面两个函数。其实本质上,这四个函数都是对状态寄存器的读写,下面两个函数只能读写与中断有关的标志位,并且对中断是否允许做出了判断。而上面的两个函数只是一般的读写标志位,没有额外的处理,能不能触发中断的标志位都能读取,建议在主程序里用上面两个,中断程序里用下面两个。非要在中断里用上面两个,其实也没有问题,只不过库函数针对这两种场景,区分了这两类读写函数。
对于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文件看一下,复制此函数。 中断函数无需声明,自动调用。 最终函数。
三、旋转编码器计次
1 接线图
封装旋转编码器函数。如果把一相的下降沿作触发中断,在中断时候读取另一相的电平,正转(右转)就是高电平,反转(左转)就是低电平,这样就可以区分正反转了。但是在操作时有一些问题,正转的时候,由于A相先出现下降沿,所以刚开始转动时,就进中断了,而反转是A相后出现下降沿,所以是转到位了,才进入中断,实际上也没有问题。我们这里准备的是AB相都触发中断,只有在B相下降沿和A相低电平时,才判断为正转,在A相下降沿和B相低电平时,才判断为反转,这样就能保证正传、反转都是转到位了,才执行数字加减的操作。
2 程序编写
展示两个中断的初始化代码。
总结
(1)中断函数里,不要执行耗时过长的代码,中断函数要简短快速,别刚进中断就执行一个Delay多少毫秒这样的代码。因为中断时处理突发的事情,如果为了处理一个突发的事情,呆在中断不出来,那主程序就会严重堵塞。
(2)最好不要在中断函数和主函数调用相同的函数或操作同一硬件,尤其时硬件相关的函数。比如OLED显示函数,如果既在主程序调用OLED,又在中断里调用OLED,OLED就会显示错误, 因为在主程序里,OLED刚显示一半,进中断了,结果中断里还是OLED显示函数,那OLED就挪到其他地方显示了,这时还没有问题,但中断结束后,需要继续原来的显示,就会出现问题,因为硬件的显示位置被挪到其他地方了,所以再回来时,继续显示的内容就会跟着跑到其他地方去。虽然在中断进入和退出的时候,会保护现场和恢复现场,但这只能保证CPU程序能正常返回不出问题,对于外部硬件的话,没有在进入中断时,进行现场保护,所以中断返回后,就出问题了,为了避免这样的问题,最好不要在主程序和中断程序里,操作可能产生冲突的硬件。最好在中断里操作变量和标志位,当中断返回时,再对这个变量进行显示和操作,这样既能保证中断函数的简短快速,又能保证不产生冲突的硬件操作。
(3)其他地方也可以多用变量和标志位,减少代码之间的耦合性,让各部分代码相互独立,仅使用变量、标志位或者函数作为接口,这样让程序更加清晰,代码更加强健。