通讯的分类—UART的工作原理及其使用方法—HAL库的代码解读—利用USART回显

摘要:通讯的分类、UART的工作原理及其使用方法、HAL库的代码解读、利用USART回显

通讯的三个分类以及各分类详解

————你了解通讯吗???

通讯的三个分类:                               

 串行通讯、并行通讯

      全双工、半双工、单工通讯

      同步通讯、异步通讯

串行通讯、并行通讯:

串行通讯是值设备之间通过少量的数据线(8根以下),地线以及控制信号线,按数据位的形式一位一位地传输的通讯方式。抗干扰能力较强,速率低,成本低、传输距离较远

并行通讯一般指使用8、16、32、64以及更大数据线传输的方式。一次可以发送大量的数据,抗干扰能力较弱,速率高,成本高、传输距离较近

全双工、半双工、单工通讯:

全双工:同一时刻两个设备可以同时收发数据

半双工:两个设备之间可以收发数据,但不能同一时间进行

单工:在任何时刻,都只能进行一个方向的通讯,即一个固定为发送设备,另外一个固定为接收设备。

同步通讯、异步通讯:

一般可以根据通讯过程中,是否有使用到时钟信号进行简单的区分,

同步通信方式:有共同的时钟信号,设备A与设备B之间有两条线:时钟线和数据线。在时钟信号的驱动下设备A与设备B才能进行通讯。双方会规定在时钟信号的上升沿或者下降沿同时进行采样(双方规定),同步通信传输的数据大部分是有效数据。

异步通信方式:只用一条线:数据线。通过通讯起始位、校验位、停止位、以及所需要传输的数据打包,以数据帧的格式传输。双方需要约定好传输速率:波特率。异步通信传输的数据包含了起始位、校验位、停止位等无效数据。

三个率的概念

通讯速率:在单位时间内(通常为一秒)传输的比特数。

比特率(Bitrate):即每秒传输的二进制位数,单位为比特每秒(bit/s)

波特率:表示每秒中传输了多少个码元,单位是baud/s,一个码元可以由多个二进制表示。

当波特和比特等价的时候,默认为一个码元用一个bit表示:即1波特=1比特

USART

————你了解UART吗???

USART是一个STM32的一个外设。通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),简称UATRT。STM32上的USART外设可以实现同步传输功能,所以外设名为USART,比UART多了一个S,即为同步:synchronous, Universal synchronous Asynchronous Receiver/Transmitter。在STM32中,USART配置成异步通信的时候是与UART是相等的,以下都以USART进行描述。

UART的电平标准

UART的器件主要是用来产生相关接口的协议信号,如RS232/RS485等串行接口标准规范和总线标准规范,要使用传输数据的这些接口,就要按照接口规定的协议信号发送数据。UART器件广泛应用于串口通信协议中,扮演着传送器的角色。

RS-232:

RS-232标准接口(又称EIA RS-232)是常用的串行通信接口标准之一,它是由美国电子工业协会(Electronic Industry Association,EIA)联合贝尔系统公司、调制解调器厂家及计算机终端生产厂家于1970年共同制定,其全名是“数据终端设备( DTE)和数据通信设备(DCE)之间串行二进制数据交换接口技术标准”。

RS-232标准规定了连接电缆和机械、电气特性、信号功能及其发送过程。

TTL:

TTL(transistor transistor logic)即晶体管-晶体管逻辑电平。TTL电平信号规定,+5V等价于逻辑“1”,0 V等价于逻辑“0”(采用二进制来表示数据时)。这样的数据通信及电平规定方式,被称做TTL(晶体管-晶体管逻辑电平)信号系统,这是计算机处理器控制的设备内部各部分之间通信的标准技术。一般的电子设备用的多是TTL电平,但是它的驱动能力和抗干扰能力很差,不适合作为外部的通信标准

TTL标准与RS-232

通讯标准

电平标准(发送端)

5v TTL

逻辑1:2.4V~5V

逻辑0:0V~0.5V

RS-232

逻辑1:-15V~-3V

逻辑0:+3V~15V

控制器一般使用的是TTL电平标准,使用常常会使用MAX3232芯片对TTL及RS-232电平信号进行转换,RS-232提高了传输时的抗干扰能力。

RXD:接收数据 。

TXD:发送数据。

GND:信号地

串口数据包的格式

在串口通讯协议层中,规定了数据包的内容,它有起始位、主体数据、检验位、停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据,不然就牛头不对马尾啦!!两者需要约定好波特率,常见的波特率为4800、9600、115200等。

起始位一般为一个逻辑0的数据位表示,停止位可以用0.5、1、1.5、2个逻辑1的数据位表示。有效数据通常被约定位5、6、7、8、位长。数据校验在有效数据之后,有一个可选的数据校验位,用赖校验数据是否出现偏差,校验方法有奇检验、偶校验、0校验、1校验以及无校验。如果校验发现错误,那么这个数据包就会被丢弃。

拿STM32F10xx来看,他的数据包的基本格式如下:

USART的框图和工作原理

分析一些USART实现功能的底层逻辑,下图为STM32F10xx的参考手册中关于USART的框图,

我们重点看TX(发送)和RX(接收)功能的实现,其实他们两个功能是实现的方式是一样的。当IrDASIR编解码模块接收数据的时候,将接收到的数据,一位一位填进去移位寄存器中,当其填满的时候,接收数据寄存器RDR就会一次性的读取接收移位寄存器中的数据,从而交给DATA总线(可以通过CPU或者DMA的方式来读取)。当要发送数据的时候,将要发送的数据写入发送数据寄存器TDR中,当TDR满了之后,会一次性的把数据交给发送移位寄存器,然后发送数据移位寄存器通过IrDASIR编解码模块发送数据

还要一种常用的转串口的方式:USB转串口,他是通过CH340G来完成的,拿STM32103开发板来看,其USB转串口的原理图如下:

USART的CubeMX的配置

————你会运用USART吗??

CubeMX的配置步骤

首先我们打开CubeMX,设置常规时钟,然后看到USART的部分。解释都在图中,

然后我们生成工程。

HAL库USART的代码解读

———你理解HAL库关于USART的代码吗?

生成完工程之后,我们会看到CubeMX会调用这4个初始化函数:HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_USART1_UART_Init();

HAL_Init()的定义

我们首先去看看HAL_Init()的定义:

根据搜索我们可以找到HAL库调用的HAL_Init();我们可以直接看看HAL库对这个函数的介绍:

  1. 这个函数用于初始化HAL库;它必须是主程序中执行的第一条指令(在调用任何其他HAL函数之前)
  2. 它执行以下操作:配置Flash预取。
  3. 将SysTick配置为每1毫秒产生一次中断,由HSI进行时钟处理(在此阶段,时钟尚未配置,因此系统从内部HSI运行,频率为16 MHz)。
  4. 设置“NVIC组优先级”为“4”。
  5. 调用用户文件“stm32f1xx_hal_msp.c”中定义的HAL_MspInit()回调函数来执行全局低级硬件初始化。
  6. SysTick被用作HAL_Delay()函数的时间基础,应用程序需要确保SysTick的时间基础始终设置为1毫秒才能正确地进行HAL操作。

SystemClock_Config();MX_GPIO_Init();在这就不多赘述,感兴趣的小伙伴可以直接去研究。

MX_USART1_UART_Init()的实现流程梳理

我们再来看看USART是如何被初始化的MX_USART1_UART_Init();梳理一下MX_USART1_UART_Init()的实现流程。

找到MX_USART1_UART_Init()的定义:

可以看见CubeMX已经将基础的usart的环境配置好了,是基于我们上文对Usart的配置来配置的。让我们去看看HAL库是如何驱动USART的吧,这需要去阅读stm32f1xx_hal_usart.c文件的HOW TO USE THIS DRIVER。

HOW TO USE THIS DRIVER驱动解释

1.UART_HandleTypeDef

定义一个UART_HandleTypeDef结构体句柄声明UART_HandleTypeDef句柄结构(例如UART_HandleTypeDef huart)

那么CubeMX配置的UART_HandleTypeDef句柄结构是这样的,对UART_HandleTypeDef的成员分析如下:

UART_InitTypeDef这个初始化成员分析如下:具体的分析步骤在前几个文章也有说,大家可以去看看前面几篇文章,在此不多赘述了。

对成员Mode查看他有几种模式可以配置,

发现他有3种模式:分别是接收、发送、接收和发送。

2.HAL_UART_MspInit()

通过实现HAL_UART_MspInit()API初始化UART低级别资源,HAL_MspInit广泛存在每一个外设中

HAL库驱动调用流程:HAL_XXX_Init---调用HAL_MspInit---初始化对应外设使用的GPIO引脚、特殊功能、时钟使能等。

HAL_MspInit对于每一个外设都是不一样的,如这里用到的UART外设,对于串口而言就会有HAL_UART_MspInit,通过HAL_UART_MspInit函数来实现串口外设的底层初始化,要做下列几个功能:

(1)使能UATRT外设时钟

(2)配置UART使用的引脚模式

(3)如果要用中断就配置中断

(4)如果要用DMA,就配置DMA

3:弱定义

通过前面定义的结构体句柄,来配置串口的波特率、数据字长、停止位、奇偶检验位、硬件流的控制。

通过搜索发现HAL_UART_MspInit()函数是一个弱定义!!对于弱定义的理解就是:如果你自己定义的话就是强定义,那么强定义的功能就会替代这个弱定义的功能,如果你自己没有定义,那么他就默认的会使用这个弱定义来做UNUSED(huart);

4:HAL_UART_Init()

通过调用HAL_UART_Init()函数,来将串口配置为异步模式。HAL_UART_Init(&huart1)传入&huart1这个句柄,那让我们看看这个函数做了什么。

感兴趣的小伙伴可以再看看UART_SetConfig(huart),也就是HAL库是如何从寄存器入手具体实现配置寄存器内容的。其实HAL库的实现机制不是特别的复杂,但就是绕来绕去,有时候会绕的头疼,所以我们一步步的来梳理HAL库,就可以对未来程序的移植等工作有所帮助!

5:…………其他API不常用,如果使用到再详细看

6:配置中断

利用USART做串口回显上位机的实验

———你会运用UART吗?

到这里MX_USART1_UART_Init();的初始化函数就完全梳理一遍了,那么接下来我们就来实现一下串口最简单的功能,也就是通过串口来回显一些字符到上位机(串口调试助手)来显示。

重定向printf()和Scanf

在这里有一个重点,在PC端上用我们可以用《C语言程序设计》中的格式化输出函数Printf()将我们想要输出的字符或者程序的运行结果发送到显示屏中显示,也可以用输入函数Scanf()读取键盘输入信息,但是HAL库提供的串口收发函数功能太过简单,不能进行c语言格式化的输入与输出[Scanf()、Printf()],所以我们如果要实现类似于C语言中的Printf()和Scanf(),我们就必须要将他们重新定向到串口。

Prinf是指向fputc然后指向真正的串口来发送,如果不重新定义fputc的话就不可能用串口来输出。在此谨记,我们用到printf的时候,需要勾选上使用微库。不然所做的一起都是徒劳!!!!亲身经历!!!!!!

HAL库实现解读

原理:调用HAL库串口发送的一个函数HAL_UART_Transmit(),我们为什么要调用HAL_UART_Transmit()来发送呢,这就要去看HOW TO USE THIS DRIVER

发送一定量的数据用HAL_UART_Transmit()

接收一定量的数据用HAL_UART_Receive()

也可以用中断和DMA的方式进行传输

HAL_UART_Transmit()和HAL_UART_Receive()的4个参数

HAL_UART_Transmit()和HAL_UART_Receive()都有4个参数:

(需要用哪个串口发送也就是其串口的句柄,要发送的数据,发送数据的数量,等待时间)。

重定向c库函数printf到串口huart1,重定向后可使用printf函数

int fputc(int ch, FILE *f)

{

/* 发送一个字节数据到串口DEBUG_USART */

HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);   



return (ch);

}

重定向c库函数scanf到串口DEBUG_USART,重写向后可使用scanf、getchar等函数

int fgetc(FILE *f)

{            

int ch;

HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, 1000);     

return (ch);

}

然后直接在main.c中调用printf()即可输出到上位机,printf("如果你喜欢这篇文章,可以点赞收藏+关注哟,谢谢你的支持\n");   输出结果如下:

本文就到这里啦,希望大家通过本文可以对通信和串口USART有深入的了解,毕竟知道外设原理和代码的实现才能更好的去使用外设,如果有错大家可以指出哟,感兴趣或者有不明白的地方的小伙伴可以私信问我!!如果喜欢可以点赞+关注哟!!!


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值