完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
0.摘要
本文以STM32F1x系列单片机为例,主要介绍了串口的初始化、串口中断、接收/发送、串口调试等内容,也顺带讲到中断分组、半主机模式以及微库MicroLIB。 1.串口初始化 串口初始化主要包括对IO、USART和中断的初始化。根据STM32F1x手册RM0008的P166,USART在全双工模式下,发送口TX要配置成复用推挽输出,接收口RX要配置成浮空输入或上拉输入。此外,本文不使用USART的硬件流控制,所谓硬件流控制就是通过加入额外的引脚(RTS和CTS)来控制数据的收发过程,在数据传输之前确认收发双方均准备好才进行通信,用于防止接收缓冲区满而导致的数据丢失问题。
中断部分的配置较为简单,主要涉及中断分组的问题。在说中断分组之前,必须先了解中断优先级:STM32F1x的中断优先级分为抢占优先级(先优先级)和响应优先级(从优先级),不同抢占优先级的中断可相互打断(即相互嵌套)。抢占优先级相同的两个中断不可相互打断,先发生(中断)者先执行,如果同时发生(中断),则高响应优先级者先执行。这两个优先级在STM32F1x中通过寄存器的4个位来表示,究竟用多少个位表示抢占优先级,多少个位表示响应优先级呢?STM32F1x并没有定死,而是通过中断分组来让用户灵活分配。各中断分组定义如下图所示(截自UM0427的P228)。本文由于只使用了一个中断,因此选择任何一个分组的任何一个优先级都无所谓。
2.串口接收 串口接收通过中断来实现,即当接收到数据时,产生中断,程序转去处理接收到的数据。接收数据用的中断包括接收中断(RXNE)和空闲中断(IDLE),如下图所示(截自RM0008的P821)。接收中断较好理解,就是每接收到一个字节的数据,就会产生中断。而空闲中断则是在接收完多个连续的字节(即一个数据帧)之后产生中断。 本文同时开启接收中断和空闲中断,串口每收到一个字节的数据,就进入接收中断,把它读取出来放好。当收完一帧数据时,就会进入空闲中断,把所接收的n个字节的数据打印出来(串口打印见下一小节)。由于同个USART的中断共用一个中断服务函数,故在函数中需要对中断源进行判断,再执行相应的操作。值得注意的是,每次进入中断都要读一下DR寄存器(Data Register),否则将不断地进入中断。
3.串口发送与printf打印 前面说的的DR寄存器是一个可读写寄存器(实际上是由两个寄存器组成),串口的发送和接收都要围着它转,收到的数据从它里面读,而发送的数据要往它里面扔。串口的发送操作非常简单,一条语句就能搞定,就是往DR寄存器写入要发送的数据: USART1->DR = data; 或者使用库函数: USART_SendData(USART1, data); 串口在嵌入式领域不仅是一个通讯接口,还是一种调试工具,其好用程度不亚于硬件仿真。学过C语言的朋友应该都知道标准库函数printf()和scanf(),前者用于打印信息到控制台上,后者实现从键盘读入字符到程序。Keil、IAR等集成开发环境均支持标准库函数,如果在单片机的程序里调用printf()打印内容,最终会在哪里显示呢?答案是不可知的,因为单片机没有控制台这种东西,但我们可以利用它的外设来实现printf(),比如LCD或串口(串口再接到电脑上显示打印信息)。串口基本上大多数单片机都有,而LCD就不一定了,所以我们通常用串口来打印内容。 那么只要是有串口的单片机,调用一下printf()就可以打印信息了吗?还没那么简单,单片机并不能猜透你的意图,你需要告诉它往哪里printf,通过下面的fputc()函数来实现。fputc()是printf()的底层函数,需要把它改装一番,让它把要打印的数据发送到串口上去。
除此之外,我们还要再做一点配置工作——禁用半主机模式,禁用了半主机模式才能使用标准库函数printf()打印信息到串口,在程序中加入以下代码即可。那么什么是半主机模式?为什么不用它?半主机模式是ARM单片机的一种调试机制,跟串口调试不一样的是,它需要通过仿真器来连接电脑和ARM单片机,并调用相应的指令来实现单片机向电脑显示器打印信息(或者从电脑键盘读取输入)。简而言之,这种方法比串口调试更复杂(需要进行更多的配置操作),也更不灵活(一定要用仿真器)。
上面的配置似乎有点麻烦,要加入这么一堆难懂的代码,难道没有更简便点的方法吗?有,但不推荐。方法是使用微库(MicroLIB),只要在Keil的“Options for Target -> Target ->Use MicroLIB”上打钩,即可使用串口打印(fputc()函数还是要改,但上述代码不用加)。微库是区别于C标准库的另一个库,当使用微库时,就默认关闭了半主机模式,也就不用添加上面的代码。这样虽然方便,但个人建议能不用就不用,原因:第一,微库是为小内存嵌入式设备而设计的,使用它可以减少代码所占空间,但对现在STM32等单片机来说,内存一般都够用,微库并非必需;第二,微库相对于C标准库而言,支持的功能更少,主要体现在对操作系统的支持上。总的来说,标准的东西总是相对更可靠,所以不必要的掉坑,还是用C标准库,不用微库。 4.最后 我们还需要一个USB转TTL模块和一台装有串口调试软件的电脑,就可以看到单片机打印到串口上的内容了。从此,如果我们想看某个变量的值,可以打印一下,想看程序跑到哪个地方,也可以打印一下,想让单片机向世界say个hello,还是可以打印一下。妈妈再也不用担心我的调试! 主函数:
运行效果: 参考: [1] RM0008 (STM32F1x用户手册) [2] UM0427 (STM32F101x/STM32F103x固件库手册) [3] Keil官方对半主机模式semihosting的介绍 [4] Keil官方对微库MicroLib的介绍 0.摘要 本文以STM32F1x系列单片机为例,主要介绍了串口的初始化、串口中断、接收/发送、串口调试等内容,也顺带讲到中断分组、半主机模式以及微库MicroLIB。 1.串口初始化 串口初始化主要包括对IO、USART和中断的初始化。根据STM32F1x手册RM0008的P166,USART在全双工模式下,发送口TX要配置成复用推挽输出,接收口RX要配置成浮空输入或上拉输入。此外,本文不使用USART的硬件流控制,所谓硬件流控制就是通过加入额外的引脚(RTS和CTS)来控制数据的收发过程,在数据传输之前确认收发双方均准备好才进行通信,用于防止接收缓冲区满而导致的数据丢失问题。
中断部分的配置较为简单,主要涉及中断分组的问题。在说中断分组之前,必须先了解中断优先级:STM32F1x的中断优先级分为抢占优先级(先优先级)和响应优先级(从优先级),不同抢占优先级的中断可相互打断(即相互嵌套)。抢占优先级相同的两个中断不可相互打断,先发生(中断)者先执行,如果同时发生(中断),则高响应优先级者先执行。这两个优先级在STM32F1x中通过寄存器的4个位来表示,究竟用多少个位表示抢占优先级,多少个位表示响应优先级呢?STM32F1x并没有定死,而是通过中断分组来让用户灵活分配。各中断分组定义如下图所示(截自UM0427的P228)。本文由于只使用了一个中断,因此选择任何一个分组的任何一个优先级都无所谓。
2.串口接收 串口接收通过中断来实现,即当接收到数据时,产生中断,程序转去处理接收到的数据。接收数据用的中断包括接收中断(RXNE)和空闲中断(IDLE),如下图所示(截自RM0008的P821)。接收中断较好理解,就是每接收到一个字节的数据,就会产生中断。而空闲中断则是在接收完多个连续的字节(即一个数据帧)之后产生中断。 本文同时开启接收中断和空闲中断,串口每收到一个字节的数据,就进入接收中断,把它读取出来放好。当收完一帧数据时,就会进入空闲中断,把所接收的n个字节的数据打印出来(串口打印见下一小节)。由于同个USART的中断共用一个中断服务函数,故在函数中需要对中断源进行判断,再执行相应的操作。值得注意的是,每次进入中断都要读一下DR寄存器(Data Register),否则将不断地进入中断。
3.串口发送与printf打印 前面说的的DR寄存器是一个可读写寄存器(实际上是由两个寄存器组成),串口的发送和接收都要围着它转,收到的数据从它里面读,而发送的数据要往它里面扔。串口的发送操作非常简单,一条语句就能搞定,就是往DR寄存器写入要发送的数据: USART1->DR = data; 或者使用库函数: USART_SendData(USART1, data); 串口在嵌入式领域不仅是一个通讯接口,还是一种调试工具,其好用程度不亚于硬件仿真。学过C语言的朋友应该都知道标准库函数printf()和scanf(),前者用于打印信息到控制台上,后者实现从键盘读入字符到程序。Keil、IAR等集成开发环境均支持标准库函数,如果在单片机的程序里调用printf()打印内容,最终会在哪里显示呢?答案是不可知的,因为单片机没有控制台这种东西,但我们可以利用它的外设来实现printf(),比如LCD或串口(串口再接到电脑上显示打印信息)。串口基本上大多数单片机都有,而LCD就不一定了,所以我们通常用串口来打印内容。 那么只要是有串口的单片机,调用一下printf()就可以打印信息了吗?还没那么简单,单片机并不能猜透你的意图,你需要告诉它往哪里printf,通过下面的fputc()函数来实现。fputc()是printf()的底层函数,需要把它改装一番,让它把要打印的数据发送到串口上去。
除此之外,我们还要再做一点配置工作——禁用半主机模式,禁用了半主机模式才能使用标准库函数printf()打印信息到串口,在程序中加入以下代码即可。那么什么是半主机模式?为什么不用它?半主机模式是ARM单片机的一种调试机制,跟串口调试不一样的是,它需要通过仿真器来连接电脑和ARM单片机,并调用相应的指令来实现单片机向电脑显示器打印信息(或者从电脑键盘读取输入)。简而言之,这种方法比串口调试更复杂(需要进行更多的配置操作),也更不灵活(一定要用仿真器)。
上面的配置似乎有点麻烦,要加入这么一堆难懂的代码,难道没有更简便点的方法吗?有,但不推荐。方法是使用微库(MicroLIB),只要在Keil的“Options for Target -> Target ->Use MicroLIB”上打钩,即可使用串口打印(fputc()函数还是要改,但上述代码不用加)。微库是区别于C标准库的另一个库,当使用微库时,就默认关闭了半主机模式,也就不用添加上面的代码。这样虽然方便,但个人建议能不用就不用,原因:第一,微库是为小内存嵌入式设备而设计的,使用它可以减少代码所占空间,但对现在STM32等单片机来说,内存一般都够用,微库并非必需;第二,微库相对于C标准库而言,支持的功能更少,主要体现在对操作系统的支持上。总的来说,标准的东西总是相对更可靠,所以不必要的掉坑,还是用C标准库,不用微库。 4.最后 我们还需要一个USB转TTL模块和一台装有串口调试软件的电脑,就可以看到单片机打印到串口上的内容了。从此,如果我们想看某个变量的值,可以打印一下,想看程序跑到哪个地方,也可以打印一下,想让单片机向世界say个hello,还是可以打印一下。妈妈再也不用担心我的调试! 主函数:
运行效果: 参考: [1] RM0008 (STM32F1x用户手册) [2] UM0427 (STM32F101x/STM32F103x固件库手册) [3] Keil官方对半主机模式semihosting的介绍 [4] Keil官方对微库MicroLib的介绍 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1802 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1629 浏览 1 评论
1096 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
735 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1685 浏览 2 评论
1944浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
746浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
580浏览 3评论
602浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
565浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-28 04:22 , Processed in 0.768965 second(s), Total 79, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号