STM32 | 通俗易懂地串口通讯解析

发布者:Blissful444最新更新时间:2021-08-10 来源: eefocus关键字:STM32  串口通讯  比特率 手机看文章 扫描二维码
随时随地手机看文章

平时使用串口打印出现乱码的绝大部分原因是串口波特率没对。那么我们怎么测量实际的波特率呢?在这之前,顺便一起回顾一下波特率的概念。


什么是波特率、比特率?

  • 比特率(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这个值要与实际做对应。


遇到这种问题找谁说理去。。经验就是不断采坑不断积累的一个过程,早点遇到坑可能也是一件好事。像类似底层的问题很少遇到,但是一旦遇到那就得比较棘手的问题了,需要很有耐心地去查找。


能用稳定的芯片是一件很幸福的事情,用不稳定、不成熟的芯片的时候,那个才是真的难啊,遇到问题真是让人怀疑人生啊,软件、硬件、芯片都可能有问题。。。

关键字:STM32  串口通讯  比特率 引用地址:STM32 | 通俗易懂地串口通讯解析

上一篇:STM32 | map文件详解
下一篇:STM32 | hex文件、bin文件、axf文件的区别?

推荐阅读最新更新时间:2024-11-07 17:26

STM32 结构体定义地址对齐
在MDK下定义一个结构体,对一段报文,强制转换为结构体类型,实际运行地址错位。 Heartbeat_Message *tmp_Heartbeat; tmp_Heartbeat=(Heartbeat_Message *) &sen_dma_tmpbuf ; typedef struct { uint16_t Sync; uint16_t Packet_Length; uint8_t ID ; uint8_t Frame_Type; uint8_t Packet_Type; uint32_t time; uint16_t CRC16; }Heartbeat_Message;
[单片机]
字符转整型STM32史上最短 字符转整形 简简单单
一直奇怪为什么stm32处理数据那么麻烦,要指针数组判断等等跳来跳去的。 直到今天,我发现了 #include “string.h” #include “stdlib.h” !!! 那我就可以两句话搞定我的数据了!!! 而不是像之前那样子那么麻烦了:STM32字符转整型处理 ’ stm32c语言字符转正型,并且进行数据分割 #include string.h #include stdlib.h u8 DATA = X12Y34Y56Y78 ; int shuju_chuli(const char *shuju,char zifu ) { char *shu_ju_1=strchr(shuju,zifu)+1; /
[单片机]
字符转整型<font color='red'>STM32</font>史上最短 字符转整形 简简单单
stm32程序下载调试之swd
说明: IAR环境版本 IAR ARM 6.30.0 1.swd使用jtag的4根线VCC,GND,JTMS,JTCK 注意 :必须将boot0=0,boot1=x 2.JLINK(20pin)的引脚对应引脚定义如下图 3.iar环境的设置 第一步:Options- Debugger- Setup选项中driver选择Jlink/J-TRAC 第二步: Options- Debugger- Download选项中我习惯选成verify download(其实不选也没关系) 对于use flash loader,这个选项的意思可能是用iar自带的flash loader去下载程序,不选时使用j-l
[单片机]
<font color='red'>stm32</font>程序下载调试之swd
共用中断和共用中断函数的判断
STM32外部中断查询: 15-10线的外部中断共用一个中断函数,怎么在该函数里查询是哪个中断线产生了中断呢? 使用 EXTI_GetITStatus()来查询哪根线产生了中断。比如EXTI_GetITStatus(EXTI_Line13)就是查询13线是否产生了中断的。 还有 :当初你在设置中断引脚的时候都是不能把PB1和PD1同时设置为中断源的。如果非要设置,后面设置的会把前面的覆盖掉的。 编写中断服务函数经常需要使用两个函数。 第一个是判断某个中断线上的中断是否发生(即标志位是否置位): ITStatus EXTI_GetITStatus(uint32_t EXTI_line); //放在中断服务函数开头,
[单片机]
IAR下stm32使用12M外部晶振
系统默认的是使用8M外部晶振,需修改三个地方: 第一步,打开stm32f10x.h,将 define HSE_VALUE ((uint32_t)8000000) /! Value of the External oscillator in Hz / 修改为: define HSE_VALUE ((uint32_t)12000000) /! Value of the External oscillator in Hz / 第二步,打开system_stm32f10x.c,修改PLL参数,将 /* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */ RCC- CFGR &=
[单片机]
正点原子STM32 USB读卡器代码分析
USB读卡器的基本原理就是向主机提供SD读写功能,并不需要加入文件系统功能。 USB设备的实现步骤: 1、 初始化系统时钟,设置USB时钟 2、 配置USB中断,选择通道,设置优先级,使能中断 3、 配置GPIO 4、 USB的初始化,对描述符、设备的端点接口等的初始化 5、 FLASH的初始化 sd_size=(long long)SD_GetSectorCount()*512; //得到SD卡容量,字节. Mass_Memory_Size =sd_size%4294967296; //当SD卡容量超过4G的时候,需要用到两个u32来表示 Mass_Memory_Size
[单片机]
STM32学习笔记:外部中断的使用
中断对于开发嵌入式系统来讲的地位绝对是毋庸置疑的,在C51单片机时代,一共只有5个中断,其中2个外部中断,2个定时/计数器中断和一个串口中断,但是在STM32中,中断数量大大增加,而且中断的设置也更加复杂。今天就将来探讨一下关于STM32中的中断系统。 1 基本概念 ARM Coetex-M3内核共支持256个中断,其中16个内部中断,240个外部中断和可编程的256级中断优先级的设置。STM32目前支持的中断共84个(16个内部+68个外部),还有16级可编程的中断优先级的设置,仅使用中断优先级设置8bit中的高4位。 STM32可支持68个中断通道,已经固定分配给相应的外部设备,每个中断通道都具备自己的中断优先级控制字节PRI
[单片机]
STM32平衡小车】线性CCD( TSL1401CL)巡线
一、手册概览 功能概览如下 TSL1401CL 线性传感器阵列由一个 128×1 的光电二极管阵列,相关的电荷放大器电路和一个内部的像素数据保持功能组成,它提供了同时集成起始和停止时间的所有像素。 该阵列 128 个像素,其中每一个具有光敏面积 3,524.3 平方微米。 像素之间的间隔是 8 微米。操作简化内部控制逻辑,只需要一个串行输入端(SI)的信号和时钟 CLK。 每个像素所采集的图像灰度值与它所感知的光强和积分时间成正比。 其中的积分时间也就是我们常说的曝光时间! (曝光时间是指底片的感光时间,曝光时间越长底片上生成的相片越亮,相反越暗。) 内部电路如下 引脚功能描述 128 个像素是怎么
[单片机]
【<font color='red'>STM32</font>平衡小车】线性CCD( TSL1401CL)巡线
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved