历史上的今天
今天是:2025年08月10日(星期日)
2021年08月10日 | STM32 | 通俗易懂地串口通讯解析
2021-08-10 来源:eefocus
平时使用串口打印出现乱码的绝大部分原因是串口波特率没对。那么我们怎么测量实际的波特率呢?在这之前,顺便一起回顾一下波特率的概念。
什么是波特率、比特率?
比特率(Bitrate)表示每秒钟传输的二进制位数,单位为比特每秒(bit/s)。
波特率(Baudrate)表示每秒钟传送的码元符号的个数,是衡量数据传送速率的指标。
码元是通讯信号调制的概念,通讯中常用时间间隔相同的符号来表示一个二进制数字,这样的信号称为码元。
常见的通讯传输中,用 0V 表示数字 0, 5V 表示数字 1,那么一个码元可以表示两种状态 0 和 1,所以一个码元等于一个二进制比特位,此时波特率的大小与比特率一致。
如果在通讯传输中,有 0V、2V、 4V 以及 6V 分别表示二进制数 00、 01、 10、 11,那么每个码元可以表示四种状态,即两个二进制比特位,所以码元数是二进制比特位数的一半,这个时候的波特率为比特率的一半。
因为很多常见的通讯(比如串口通讯)中一个码元都是表示两种状态,所以大家常常直接以波特率来表示比特率 。
串口通讯协议
在串口通讯的协议层中,规定了数据包的内容,它由启始位、主体数据、校验位以及停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据,其数据帧组成如下:

下面我们来实际验证一下其数据帧是不是真的是这样的。编写如下代码:

代码很简单,就是使用串口不断地往外发数据0xAA(当然发送其它数据也是可以的) 。我们的串口配置如下:

我们可以使用示波器或者逻辑分析仪抓取实际信号看看数据是不是符合上面的帧格式。这里,我们使用逻辑分析仪抓取USART1的发送信号线(TX):

从实际结果中我们可以看到的确是按帧格式来发的。这里可能会有人有疑问,上面那个数据帧的图片中有个空闲状态,这个又是什么呢?空闲、空闲,当然是没有在发数据时候的状态呀,我们把我们的代码改为:

在初始化完成之后只发送一次0xAA,逻辑分析仪抓到的数据为:

可见,空闲状态是个高电平。在上一个的范例中,我们一直在while循环中发送数据0xAA,所以就没有空闲状态。
在这个实验中我们需要知道的是两个点是:
串口发送数据是低位先发的。我们单片机发0xAA(10101010B),所以逻辑分析仪抓到的有效数据是01010101B。
单片机的串口使用的是TTL电平,为正逻辑电平信号。逻辑分析仪抓到的数据0对应着实际电压0~0.5V,数据1对应着实际电压2.4V-5V,
经常与TTL电平标准做对比的是RS-232电平标准,如:

常见的电子电路中常使用 TTL 的电平标准,理想状态下,使用 5V 表示二进制逻辑 1,使用 0V 表示逻辑 0;而为了增加串口通讯的远距离传输及抗干扰能力,RS-232电平标准使用-15V 表示逻辑 1, +15V 表示逻辑 0。
在旧式的台式计算机中一般会有 RS-232 标准的 COM 口(也称 DB9 接口) :

在这个示例程序中,我们设置的串口波特率为115200bps。在串口通讯中,码元只用1个二进制数来表示(即只有0 和 1两种状态),所以波特率与比特率在数值上是相等的。
而比特率表示的是每秒钟传输的二进制位数,那我们知道传一位数据的时间岂不是就可以反推出波特率是多少了吗?从逻辑分析仪中,我们可以知道发送一位数据的时间如下:

发送一位数据的时间大约为8.667us,所以1秒钟发送多少位数据是可以算出来的:

算出来的波特率为115380bps,与115200bps很相近。最终肯定是有一定的误差,这个误差产生的原因包括逻辑分析仪的质量及我们的测量环境等等因素。但是这个误差也是在允许的范围内的,可以看看串口助手接收到的数据是不是正确的:

可见,数据接收正确,也就是波特率对的上了。
串口波特率对不上怎么解决?
在实际中。我们可能会遇到这样的情况,代码里配置的波特率与串口助手上设置的波特率一样了,但还是出现异常情况。
异常情况如我们往串口助手发送字符串,串口助手上本该显示的字符串出现了乱码。或者我们往串口助手发送一个数据,发现数据移位了。
出这种情况大多是波特率对应不上,我们就得自己检查我们的底层文件了,代码中的某个与波特率计算相关的值(时钟)与实际不匹配了,就会出现这样的现象,比如之前我的一位同事就遇到这样的情况就是这个原因导致的。
我们用STM32的时候,一般都是使用外部晶振,比如STM32F103系列,可输入的外部晶振的范围是4~16MHz:

经验值往往是8MHz,而且一般的demo工程底层代码里默认的也是设置为8MHz,比如:

但是,如果实际晶振贴的不是8M的话,就出问题了(比如串口波特率就不正确了)。追根溯源,串口波特率是配进USART_Init函数中的,打开这个函数:

计算串口波特率需要一个apbclock变量,而这个值得来源从RCC_GetClocksFreq函数来,再打开这个函数:

所以要注意的是,HSE_VALUE这个值要与实际做对应。
遇到这种问题找谁说理去。。经验就是不断采坑不断积累的一个过程,早点遇到坑可能也是一件好事。像类似底层的问题很少遇到,但是一旦遇到那就得比较棘手的问题了,需要很有耐心地去查找。
能用稳定的芯片是一件很幸福的事情,用不稳定、不成熟的芯片的时候,那个才是真的难啊,遇到问题真是让人怀疑人生啊,软件、硬件、芯片都可能有问题。。。
史海拾趣
|
项目简介 江苏省常熟市 吴栋梁 1 技术项目名称: 超音频宽带功率正弦波逆变电源;2 项目所属技术领域: 电力电子变流技术;3 项目现处发展阶段: 中试前期,工业化前期,应用产品后续研发阶 ...… 查看全部问答> |
|
请教高手怎么解决将linux系统移植到6410开发板上usb不能用的问题 如题:将android-linux-2.6.28的系统移植到s3c6410开发板上usb不能用 编译通过,初始化也通过,可是一插上U盘就报错: 提示错误: usb 1-1: new full speed USB device using s3c2410-ohci and address 2 usb 1-1: device descriptor read/64, ...… 查看全部问答> |
|
我用的是pxa270 现在把原来的64m的内存换成了128m可是系统还是只认到64m,在4.2下可以认到128m但是在5.0下就不行。我想在bootloader下遍历一下内存,应该怎么遍历,在eboot中好像mmu已经起来了… 查看全部问答> |
|
软件自毁技术 能不能用软件编写 程序彻底删除本软件的数据或者是删除整个硬盘的数据 软件自毁技术 能不能用软件编写 程序彻底删除本软件的数据或者是删除整个硬盘的数据 应该看哪些方面的书啊 高人指点下 … 查看全部问答> |
|
现有两个WINCE下驱动项目外包: 1、S3C2416下驱动16C554多串口芯片的驱动程序 2、S3C2416的声音驱动(芯片的驱动代码有2442平台下的可以做参考) 有意者请加QQ嵌入式外包群:48348107 谢谢各位!… 查看全部问答> |
|
问题有点怪怪。 开发实验箱是UPNET-2410 ,一般无操作系统开发在WINDOWS下用。ADS1.2进行编写代码。然后编译链接成elf再转BIN文件。最后通过串口下载到FLASH 现在我想在linux上编写代码,或者说我想脱离 ADS1.2。linux上面的交叉编译工具链都有 ...… 查看全部问答> |
|
~~~~~~~~数字钟出现~~~~~~~~~~~ #include<reg52.h> #define uchar unsigned char uchar DspFlag; //数码管显示模式uchar DspBit; //数码管位扫描uchar KeyFlag; //按键扫描uchar sec;uchar ...… 查看全部问答> |
|
厦门acai2012推荐到JNN,通过会议推荐到SCI\EI期刊,靠谱不? 今天收到个厦门的ACAI2012,一个自动控制和人工智能会议,期间还会有个无线通信和网络技术的会议,是IET主办,IET出版论文集,入IEEE Xplore,然后EI检索。如果文章优秀,扩展的话可以推荐到 J. Nanoscience & Nanotechnology (JNN),本人毕业就差 ...… 查看全部问答> |
|
本帖最后由 paulhyde 于 2014-9-15 03:54 编辑 我刚刚接触开关电源,以前都是做稳压电源,现在没想好如何通过单片机控制开关电源的输出 有两个想法:1,单片机通过DA改变基准电源以达到调整输出的目的,控制环路依然是硬件反馈 2,单片机通过AD ...… 查看全部问答> |
|
都知道高速PCB上走线拐角不能太小,因为可能造成反射。但是过孔的两条交叉线拐角是不是也必须遵循这个原则呢?关于过孔的论文基本上都没提这个。从原理上来看过孔的两条交叉线拐角也应该不能太小,但看看别人设计的产品,有不少拐角呈锐角的,比如 ...… 查看全部问答> |




