0
点赞
收藏
分享

微信扫一扫

第四节:中断与串口(黄老师)

萨摩斯加士奇 2022-02-25 阅读 128

一、中断

中断的概念我在51篇已经有整理过了,这次就不再详细描述了,只介绍在STM32中的中断相关内容。
中断示意图

1.Cortex-M3的中断

其中断的框架是由内核设计者ARM公司设计的,设计了256个,很多型号的芯片由于资源不够,是用不了那么多个中断的,例如F1型号的芯片最多70多个中断,而在本次MINI开发板上的芯片,大概只有40多个。

2.中断有哪些

在这里插入图片描述
这是F1系列芯片的中断表。可以看到,分为系统异常外部中断,系统异常是由CPU内核产生的,而外部中断是由外设产生的,在效果上两者是一样的,通常统一称为中断。

在表上还有一点需要注意的,优先级类型,固定则代表其不能修改,而可编程就代表可以利用我们下面要讲到的NVIC去配置。

3.中断优先级

STM32的中断优先级分为抢占优先级子优先级。每个中断都要指定这两种优先级。
在这里插入图片描述
抢占优先级决定的是中断嵌套,例如抢占优先级高的中断可以中断抢占优先级低的中断
子优先级决定的是响应顺序,即两个中断同时产生,子优先级高的先执行。

优先级的指定或者说配置是通过NVIC中断控制器。
在这里插入图片描述

4.GPIO中断

对于GPIO中断来说,除了NVIC之外,还有EXTI也是来控制它的。(下图EXIT打错了)
在这里插入图片描述
中断的原理图如下:
在这里插入图片描述
可以看到,GPIO的中断需要先通过EXTI,再到NVIC。
EXTI分为外部中断以及事件控制器,其中外部中断就是我们常见的,中断出现后,执行我们自定义的函数。而事件控制器则不需要我们自定义函数,当中断出现后,会自动联动其他外设做指定的事,例如可以是:中断出现后,自动进行ADC采集,这部分的代码是不需要我们自己编写的,而且由于它是自动处理的,它的响应速度会更快。

在原理图中我们还注意到,PA0 ~ PG0是通过同一个AFIO,最后通过EXTI0的。这代表它们是处于同一条中断线,即当出现中断时,我们并不能区分是PA0 ~ PG0中的哪一个,因此,在编程中我们要避开这种情况,当PA0做中断引脚时,其他的第0口不能作为中断源。

5.使用STM32CubeMX创建一个简单的按键中断程序

作为初学者,我们应该学会如何用STM32CubeMX去配置一个带有中断的程序。这里我们创建一个程序,当按下按键时产生中断,从而控制开发板的LED亮灭。

①将PA0口设置为GPIO_EXIT0

前面我们已经知道,按键对应的GPIO口是PA0口,所以这里我们将PA0口设置为中断模式。
在这里插入图片描述

②设置触发方式

因为开发板上的按键默认是高电平,所以我们配置为下降沿触发(Falling),即当我们按下按键后触发中断。
在这里插入图片描述

③配置NVIC

在这里插入图片描述
在NVIC中,我们首先需要开启中断使能。同时我们也可以在后面设置优先级。
然后是点击Code generation,跳转到下面示意图,勾选生成代码方框。
在这里插入图片描述

④生成代码

最后点击生成代码。

⑤编写代码实现功能

首先我们在startup_stm32f103xb.s汇编文件中,找到EXTI0的中断处理函数名,接着右键点击跳转到函数的定义。
在这里插入图片描述
可以看到里面有一个HAL库的处理函数,我们再次跳转。
在这里插入图片描述
HAL库的函数表明,当中断到来时,会自动判断是否是该中断引脚,若是,则清除中断标志,然后调用回调函数,我们需要做的,就是编写回调函数,在其中实现我们的功能。
在这里插入图片描述
在该HAL库函数定义的下方,我们可以看到回调函数的定义,回调函数是一个弱函数,因此我们要自己编写它。因为本次中断与GPIO有关,所以我们将回调函数写在gpio.c文件里。
在这里插入图片描述
对回调函数的编写结果如下,先判断按下的是哪个按键,因为PA0,PB0…都能够进入该中断,并且用key_flag来做标志位,使每次按下按键时,灯的亮灭状态翻转。
在这里插入图片描述
同时我们编写函数来在主函数调用,返回key_flag的值。注意该函数需要在头文件中进行声明。
在这里插入图片描述
最后是在主函数中实现。
在这里插入图片描述
注:
1.中断函数里不要进行复杂操作
2.对两种优先级的分配并不是随便设置的,还需要在NVIC里通过Priority Group对两种优先级的控制位数进行分组,总共只有4位,例如这里是给前面的抢占优先级分配了4位,所以就没有给子优先级的分配位数了。这样,我们就可以对抢占优先级设置2的4次方,即16级,而对子优先级就设置不了。如果我们给抢占优先级分配了2位,则自动给子优先级分配2位,这样每种优先级都能设置4级。
在这里插入图片描述

二、串口

这里同样在51单片机篇已经介绍过了。

1.同步/异步通信

在这里插入图片描述
在异步通信中,我们需要指定波特率,在同步中则不用。同步通信的协议有例如I2CSPI,它们需要通信双方连接时钟线,这里两种协议也是需要重点掌握的,后面学习到再整理。

2.串口电平

像我们平常的学习过程中,单片机通常和我们的模块距离很近,这时候我们选择TTL电平即可进行单片机与模块间的通信,例如本次实验与WIFI模块。
而在实际工程中,有时候会遇到单片机与模块间的距离较远,这时候只使用TTL电平就会干扰很大,因为远距离传输会使信号衰减,选用TTL电平会导致我们对高低电平的识别出现差错。因此需要转换成其他电平。
在这里插入图片描述

3.串口的连接和时序

一般串口之间的连接有3个引脚就足够了,要注意的是TxRx必须交叉连线。
在这里插入图片描述
串口传输一帧数据即一个字节的示意图如下,与51单片机篇一样:
默认状态是高电平,当变为低电平时,进入到开始位。最后传输结束时又将电平拉高,进入默认状态。
在这里插入图片描述
在本开发板上串口的作用主要有两个:一是单片机与单片机的通信,二是做调试用,需要将TTL电平转换USB电平。
在这里插入图片描述

4.使用CubeMX创建一个简单的调试打印程序

这里与51单片机不同的是,我们可以不选用中断。有一个原因是在本程序中我们只需要单片机向电脑发送数据而已,并不需要向单片机发送程序,在下一个有关接收的程序则会用到中断。
开发板的串口1是用来调试打印的,因此我们对串口1进行配置。

①将串口1设置为“异步通信”

在这里插入图片描述

②配置波特率等参数

在这里插入图片描述
我们可以在Configuration里配置串口的波特率、数据位数、奇偶校验位和停止位,还可以在高级选项中设置数据的方向,例如可以只接收不发送,只发送不接收,当然,默认情况下我们是选择双向。

③编写代码

配置后即可生成代码。
HAL库中同样也有关于串口发送接收的函数。例如:
在这里插入图片描述
可以看到这个发送函数还有DMA的以及IT(中断)的类型。
DMA即不用经过CPU处理,直接利用DMA将数据从某个点传送到另一个点,后面会学到。
IT则是带有中断处理函数的,用中断方式进行传输,在下一个程序会用到。
Transmit函数的使用很不方便,需要的参数比较多。当我们需要打印出多行内容时,很繁琐,因此这里我们用重定向打印函数来打印内容,具体方式见学习手册。
具体操作就是将下列函数放在uart.c文件中,并且加上<stdio.h>头文件。然后我们就可以在主函数中直接使用printfscanf来处理内容。
注:函数中的参数&huart1代表该方式仅应用于串口1。
在这里插入图片描述
在这里插入图片描述
最终我们直接在主函数里使用printf函数,并用**串口助手
**类型的软件,显示出内容即可。

5.使用CubeMX创建一个带有中断的串口程序

这里我们编写一个程序,将单片机与WIFI模块进行连接,然后简单的向WIFI模块发送AT指令,并且单片机接收到WIFI模块返回的数据并且打印出来。
开发板的串口2是用来和外部模块通信的。

①将串口2设置“异步通信”并配置中断

设置成异步通信方式与上一个程序同理,而配置中断则和按键的中断配置一样。

②编写代码

与GPIO中断一样,串口中断后一样是进入回调函数。
第一步:使用Receive_IT函数来等待接收串口2的数据,并保存在rx_data中。
在这里插入图片描述
第二步:当接收到数据时,会自动进入中断程序,最终来到回调函数,所以我们要编写回调函数。
这里我们将接收到的数据存储在buf数组中,并且再次调用Receive_IT函数等待下一次数据的到来。
在这里插入图片描述
第三步:再将buf数组中的数据读取,并最终打印出来。
在这里插入图片描述
下面的函数是写在主函数里的。
在这里插入图片描述
注:这里还有几点需要注意的。
1.我们还需要在上电之后给WIFI模块发送AT指令,WIFI模块才会返回信息到单片机;
在这里插入图片描述
在这里插入图片描述
2.每次打印出内容后,我们需要清除buf,因为buf里存储了上一次的数据,在我们进行下一次循环时,如果不进行清除,会再次读取buf中保存的上一次接收的数据,并再次打印出来,最终显示的结果会是一直进行打印;
3.连接示意图如下:
在这里插入图片描述

举报

相关推荐

0 条评论