野火学习笔记(13) —— USART —串口通讯

2023-05-16

文章目录

  • 1. 串口通讯协议简介
    • 1.1 物理层
      • 1.1.1 电平标准
      • 1.1.2 RS-232 信号线
    • 1.2 协议层
      • 1.2.1 波特率
      • 1.2.2 通讯的起始和停止信号
      • 1.2.3 有效数据
      • 1.2.4 数据校验
  • 2. STM32 的 USART 简介
  • 3. USART 功能框图
    • 3.1 校验控制
    • 3.2 中断控制
  • 4. USART 初始化结构体详解
  • 5. USART1 接发通信实验
    • 5.1 硬件设计
    • 5.2 软件设计
      • 5.2.1 编程要点
      • 5.2.2 代码分析




1. 串口通讯协议简介

串口通讯 (Serial Communication) 是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式,电子工程师在调试设备时也经常使用该通讯方式输出调试信息。

在计算机科学里,大部分复杂的问题都可以通过分层来简化。如芯片被分为内核层和片上外设;STM32 标准库则是在寄存器与用户代码之间的软件层。对于通讯协议,我们也以分层的方式来理解,最基本的是把它分为物理层和协议层。物理层规定通讯系统中具有机械、电子功能部分的特性,确保原始数据在物理媒体的传输。协议层主要规定通讯逻辑,统一收发双方的数据打包、解包标准。简单来说物理层规定我们用嘴巴还是用肢体来交流,协议层则规定我们用中文还是英文来交流。


1.1 物理层

串口通讯的物理层有很多标准及变种,我们主要讲解 RS-232 标准, RS-232 标准主要规定了信号的用途、通讯接口以及信号的电平标准。

使用 RS-232 标准的串口设备间常见的通讯结构见 图串口通讯结构图。


图串口通讯结构图
在这里插入图片描述


在上面的通讯方式中,两个通讯设备的 “DB9 接口”之间通过串口信号线建立起连接,串口信号线中使用“RS-232 标准”传输数据信号。由于 RS-232 电平标准的信号不能直接被控制器直接识别,所以这些信号会经过一个“电平转换芯片”转换成控制器能识别的 “TTL 标准”的电平信号,才能实现通讯。


1.1.1 电平标准

根据通讯使用的电平标准不同,串口通讯可分为 TTL 标准及 RS-232 标准,见 表 TTL 电平标准与 RS232 电平标准。


表 TTL 电平标准与 RS232 电平标准
在这里插入图片描述


我们知道常见的电子电路中常使用 TTL 的电平标准,理想状态下,使用 5V 表示二进制逻辑 1,使用 0V 表示逻辑 0;而为了增加串口通讯的远距离传输及抗干扰能力,它使用 -15V 表示逻辑 1,+15V 表示逻辑 0。使用 RS232 与 TTL 电平校准表示同一个信号时的对比见图 RS-232 与 TTL 电平标准下表示同一个信号。


在这里插入图片描述


因为控制器一般使用 TTL 电平标准,所以常常会使用 MA3232 芯片对 TTL 及 RS-232 电平的信号进行互相转换。


1.1.2 RS-232 信号线

在最初的应用中, RS-232 串口标准常用于计算机、路由与调制调解器 (MODEN,俗称“猫” ) 之间的通讯,在这种通讯系统中,设备被分为数据终端设备 DTE(计算机、路由) 和数据通讯设备 DCE(调制调解器)。我们以这种通讯模型讲解它们的信号线连接方式及各个信号线的作用。

在旧式的台式计算机中一般会有 RS-232 标准的 COM 口 (也称 DB9 接口),见 图电脑主板上的 COM 口及串口线。


图电脑主板上的 COM 口及串口线
在这里插入图片描述


其中接线口以针式引出信号线的称为公头,以孔式引出信号线的称为母头。在计算机中一般引出公头接口,而在调制调解器设备中引出的一般为母头,使用上图中的串口线即可把它与计算机连接起来。通讯时,串口线中传输的信号就是使用前面讲解的 RS-232 标准调制的。

在这种应用场合下, DB9 接口中的公头及母头的各个引脚的标准信号线接法见 图 DB9 标准的公头及母头接法 及 表 DB9 信号线说明。


图 DB9 标准的公头及母头接法
在这里插入图片描述


表 DB9 信号线说明
在这里插入图片描述


上表中的是计算机端的 DB9 公头标准接法,由于两个通讯设备之间的收发信号 (RXD 与 TXD) 应交叉相连,所以调制调解器端的 DB9 母头的收发信号接法一般与公头的相反,两个设备之间连接时,只要使用“直通型”的串口线连接起来即可,见 图计算机与调制调解器的信号线连接。


图计算机与调制调解器的信号线连接
在这里插入图片描述


串口线中的 RTS、 CTS、 DSR、 DTR 及 DCD 信号,使用逻辑 1 表示信号有效,逻辑 0 表示信号无效。例如,当计算机端控制 DTR 信号线表示为逻辑 1 时,它是为了告知远端的调制调解器,本机已准备好接收数据, 0 则表示还没准备就绪。

在目前的其它工业控制使用的串口通讯中,一般只使用 RXD、 TXD 以及 GND 三条信号线,直接传输数据信号,而 RTS、 CTS、 DSR、 DTR 及 DCD 信号都被裁剪掉了。


1.2 协议层

串口通讯的数据包由发送设备通过自身的 TXD 接口传输到接收设备的 RXD 接口。在串口通讯的协议层中,规定了数据包的内容,它由启始位、主体数据、校验位以及停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据,其组成见 图串口数据包的基本组成。


图串口数据包的基本组成
在这里插入图片描述


1.2.1 波特率

本章中主要讲解的是串口异步通讯,异步通讯中由于没有时钟信号 (如前面讲解的 DB9 接口中是没有时钟信号的),所以两个通讯设备之间需要约定好波特率,即每个码元的长度,以便对信号进行解码,图串口数据包的基本组成 中用虚线分开的每一格就是代表一个码元。常见的波特率为 4800、 9600、 115200 等。


1.2.2 通讯的起始和停止信号

串口通讯的一个数据包从起始信号开始,直到停止信号结束。数据包的起始信号由一个逻辑 0 的数据位表示,而数据包的停止信号可由 0.5、 1、 1.5 或 2 个逻辑 1 的数据位表示,只要双方约定一致即可。


1.2.3 有效数据

在数据包的起始位之后紧接着的就是要传输的主体数据内容,也称为有效数据,有效数据的长度常被约定为 5、 6、 7 或 8 位长。


1.2.4 数据校验

在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验 (odd)、偶校验(even)、 0 校验 (space)、 1 校验 (mark) 以及无校验 (noparity)。

奇校验要求有效数据和校验位中“1”的个数为奇数,比如一个 8 位长的有效数据为: 01101001,此时总共有 4 个“1”,为达到奇校验效果,校验位为“1”,最后传输的数据将是 8 位的有效数据加上 1 位的校验位总共 9 位。

偶校验与奇校验要求刚好相反,要求帧数据和校验位中“1”的个数为偶数,比如数据帧: 11001010,此时数据帧“1”的个数为 4 个,所以偶校验位为“0”。

0 校验是不管有效数据中的内容是什么,校验位总为“0”, 1 校验是校验位总为“1”。


2. STM32 的 USART 简介

通用同步异步收发器 (Universal Synchronous Asynchronous Receiver and Transmitter) 是一个串行通信设备,可以灵活地与外部设备进行全双工数据交换。有别于 USART 还有一个 UART(Universal Asynchronous Receiver and Transmitter),它是在 USART 基础上裁剪掉了同步通信功能,只有异步通信。简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是 UART。

串行通信一般是以帧格式传输数据,即是一帧一帧的传输,每帧包含有起始信号、数据信息、停止信息,可能还有校验信息。 USART 就是对这些传输参数有具体规定,当然也不是只有唯一一个参数值,很多参数值都可以自定义设置,只是增强它的兼容性。

USART 满足外部设备对工业标准 NRZ 异步串行数据格式的要求,并且使用了小数波特率发生器,可以提供多种波特率,使得它的应用更加广泛。 USART 支持同步单向通信和半双工单线通信;还支持局域互连网络 LIN、智能卡 (SmartCard) 协议与 lrDA(红外线数据协会) SIR ENDEC 规范。

USART 支持使用 DMA,可实现高速数据通信,有关 DMA 具体应用将在 DMA 章节作具体讲解。

USART 在 STM32 应用最多莫过于“打印”程序信息,一般在硬件设计时都会预留一个 USART 通信接口连接电脑,用于在调试程序是可以把一些调试信息“打印”在电脑端的串口调试助手工具上,从而了解程序运行是否正确、如果出错哪具体哪里出错等等。


3. USART 功能框图

USART 的功能框图包含了 USART 最核心内容,掌握了功能框图,对 USART 就有一个整体的把握,在编程时就思路就非常清晰。 USART 功能框图见 图 USART 功能框图。


图 USART 功能框图
在这里插入图片描述


① 功能引脚

TX:发送数据输出引脚。

RX:接收数据输入引脚。

SW_RX:数据接收引脚,只用于单线和智能卡模式,属于内部引脚,没有具体外部引脚。

nRTS:请求以发送 (Request To Send), n 表示低电平有效。如果使能 RTS 流控制,当 USART 接收器准备好接收新数据时就会将 nRTS 变成低电平;当接收寄存器已满时, nRTS 将被设置为高电平。该引脚只适用于硬件流控制。

nCTS:清除以发送 (Clear To Send), n 表示低电平有效。如果使能 CTS 流控制,发送器在发送下一帧数据之前会检测 nCTS 引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完当前数据帧之后停止发送。该引脚只适用于硬件流控制。

SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。

USART 引脚在 STM32F103ZET6 芯片具体分布见表 STM32F103VET6 芯片的 USART 引脚。


在这里插入图片描述


STM32F103VET6 系统控制器有三个 USART 和两个 UART,其中 USART1 和时钟来源于 APB2 总线时钟,其最大频率为 72MHz,其他四个的时钟来源于 APB1 总线时钟,其最大频率为 36MHz。UART 只是异步传输功能,所以没有 SCLK、 nCTS 和 nRTS 功能引脚。

② 数据寄存器

USART 数据寄存器 (USART_DR) 只有低 9 位有效,并且第 9 位数据是否有效要取决于 USART 控制寄存器 1(USART_CR1) 的 M 位设置,当 M 位为 0 时表示 8 位数据字长,当 M 位为 1 表示 9 位数据字长,我们一般使用 8 位数据字长。

USART_DR 包含了已发送的数据或者接收到的数据。 USART_DR 实际是包含了两个寄存器,一个专门用于发送的可写 TDR,一个专门用于接收的可读 RDR。当进行发送操作时,往 USART_DR 写入数据会自动存储在 TDR 内;当进行读取操作时,向 USART_DR 读取数据会自动提取 RDR 数据。

TDR 和 RDR 都是介于系统总线和移位寄存器之间。串行通信是一个位一个位传输的,发送时把 TDR 内容转移到发送移位寄存器,然后把移位寄存器数据每一位发送出去,接收时把接收到的每一位顺序保存在接收移位寄存器内然后才转移到 RDR。

USART 支持 DMA 传输,可以实现高速数据传输,具体 DMA 使用将在 DMA 章节讲解。

③ 控制器

USART 有专门控制发送的发送器、控制接收的接收器,还有唤醒单元、中断控制等等。使用 USART 之前需要向 USART_CR1 寄存器的 UE 位置 1 使能 USART, UE 位用来开启供给给串口的时钟。

发送或者接收数据字长可选 8 位或 9 位,由 USART_CR1 的 M 位控制。

发送器

当 USART_CR1 寄存器的发送使能位 TE 置 1 时,启动数据发送,发送移位寄存器的数据会在 TX 引脚输出,低位在前,高位在后。如果是同步模式 SCLK 也输出时钟信号。

一个字符帧发送需要三个部分:起始位 + 数据帧 + 停止位。起始位是一个位周期的低电平,位周期就是每一位占用的时间;数据帧就是我们要发送的 8 位或 9 位数据,数据是从最低位开始传输的;停止位是一定时间周期的高电平。

停止位时间长短是可以通过 USART 控制寄存器 2(USART_CR2) 的 STOP[1:0] 位控制,可选 0.5 个、 1 个、 1.5 个和 2 个停止位。默认使用 1 个停止位。 2 个停止位适用于正常 USART 模式、单线模式和调制解调器模式。 0.5 个和 1.5 个停止位用于智能卡模式。

当选择 8 位字长,使用 1 个停止位时,具体发送字符时序 图见图字符发送时序图。


图见图字符发送时序图
在这里插入图片描述


当发送使能位 TE 置 1 之后,发送器开始会先发送一个空闲帧 (一个数据帧长度的高电平),接下来就可以往 USART_DR 寄存器写入要发送的数据。在写入最后一个数据后,需要等待 USART 状态寄存器 (USART_SR) 的 TC 位为 1,表示数据传输完成,如果 USART_CR1 寄存器的 TCIE 位置 1,将产生中断。

在发送数据时,编程的时候有几个比较重要的标志位我们来总结下。


在这里插入图片描述


接收器

如果将 USART_CR1 寄存器的 RE 位置 1,使能 USART 接收,使得接收器在 RX 线开始搜索起始位。在确定到起始位后就根据 RX 线电平状态把数据存放在接收移位寄存器内。接收完成后就把接收移位寄存器数据移到 RDR 内,并把 USART_SR 寄存器的 RXNE 位置 1,同时如果 USART_CR2 寄存器的 RXNEIE 置 1 的话可以产生中断。

在接收数据时,编程的时候有几个比较重要的标志位我们来总结下。


在这里插入图片描述


④ 小数波特率生成

波特率指数据信号对载波的调制速率,它用单位时间内载波调制状态改变次数来表示,单位为波特。比特率指单位时间内传输的比特数,单位 bit/s(bps)。对于 USART 波特率与比特率相等,以后不区分这两个概念。波特率越大,传输速率越快。

USART 的发送器和接收器使用相同的波特率。计算公式如下:


在这里插入图片描述


其中, fPLCK 为 USART 时钟, USARTDIV 是一个存放在波特率寄存器 (USART_BRR) 的一个无符号定点数。其中 DIV_Mantissa[11:0] 位定义 USARTDIV 的整数部分, DIV_Fraction[3:0] 位定义USARTDIV 的小数部分。

例如: DIV_Mantissa=24(0x18), DIV_Fraction=10(0x0A),此时 USART_BRR 值为 0x18A;那么 USARTDIV 的小数位 10/16=0.625;整数位 24,最终 USARTDIV 的值为 24.625。

波特率的常用值有 2400、 9600、 19200、 115200。下面以实例讲解如何设定寄存器值得到波特率的值。

我们知道 USART1 使用 APB2 总线时钟,最高可达 72MHz,其他 USART 的最高频率为 36MHz。我们选取 USART1 作为实例讲解,即 fPLCK=72MHz。为得到 115200bps 的波特率,此时:

115200 = 72000000 / (16 * USARTDIV)

解得 USARTDIV=39.0625,可算得 DIV_Fraction = 0.0625 * 16 = 1 = 0x01, DIV_Mantissa = 39 = 0x17,即应该设置 USART_BRR 的值为 0x171。


3.1 校验控制

STM32F103 系列控制器 USART 支持奇偶校验。当使用校验位时,串口传输的长度将是 8 位的数据帧加上 1 位的校验位总共 9 位,此时 USART_CR1 寄存器的 M 位需要设置为 1,即 9 数据位。将 USART_CR1 寄存器的 PCE 位置 1 就可以启动奇偶校验控制,奇偶校验由硬件自动完成。启动了奇偶校验控制之后,在发送数据帧时会自动添加校验位,接收数据时自动验证校验位。接收数据时如果出现奇偶校验位验证失败,会见 USART_SR 寄存器的 PE 位置 1,并可以产生奇偶校验中断。

使能了奇偶校验控制后,每个字符帧的格式将变成:起始位 + 数据帧 + 校验位 + 停止位。


3.2 中断控制

USART 有多个中断请求事件,具体见 表 USART 中断请求。


表 USART 中断请求
在这里插入图片描述


4. USART 初始化结构体详解

标准库函数对每个外设都建立了一个初始化结构体,比如 USART_InitTypeDef,结构体成员用于设置外设工作参数,并由外设初始化配置函数,比如 USART_Init() 调用,这些设定参数将会设置外设相应的寄存器,达到配置外设工作环境的目的。

初始化结构体和初始化库函数配合使用是标准库精髓所在,理解了初始化结构体每个成员意义基本上就可以对该外设运用自如了。初始化结构体定义在 stm32f10x_usart.h 文件中,初始化库函数定义在 stm32f10x_usart.c 文件中,编程时我们可以结合这两个文件内注释使用。


UART 初始化结构体

typedef struct {
	uint32_t USART_BaudRate; 			// 波特率
	uint16_t USART_WordLength; 			// 字长
	uint16_t USART_StopBits; 			// 停止位
	uint16_t USART_Parity; 				// 校验位
	uint16_t USART_Mode; 				// USART 模式
	uint16_t USART_HardwareFlowControl; // 硬件流控制
}USART_InitTypeDef;

  1. USART_BaudRate:波特率设置。一般设置为 2400、 9600、 19200、 115200。标准库函数会根据设定值计算得到 USARTDIV 值,从而设置 USART_BRR 寄存器值。

  2. USART_WordLength:数据帧字长,可选 8 位或 9 位。它设定 USART_CR1 寄存器的 M 位的值。如果没有使能奇偶校验控制,一般使用 8 数据位;如果使能了奇偶校验则一般设置为 9 数据位。

  3. USART_StopBits:停止位设置,可选 0.5 个、 1 个、 1.5 个和 2 个停止位,它设定 USART_CR2 寄存器的 STOP[1:0] 位的值,一般我们选择 1 个停止位。

  4. USART_Parity:奇偶校验控制选择,可选 USART_Parity_No(无校验)、 USART_Parity_Even(偶校验) 以及 USART_Parity_Odd(奇校验),它设定 USART_CR1 寄存器的 PCE 位和 PS 位的值。

  5. USART_Mode: USART 模式选择,有 USART_Mode_Rx 和 USART_Mode_Tx,允许使用逻辑或运算选择两个,它设定 USART_CR1 寄存器的 RE 位和 TE 位。

  6. USART_HardwareFlowControl:硬件流控制选择,只有在硬件流控制模式才有效,可选有⑴ 使能 RTS、⑵ 使能 CTS、⑶ 同时使能 RTS 和 CTS、⑷ 不使能硬件流。

当使用同步模式时需要配置 SCLK 引脚输出脉冲的属性,标准库使用一个时钟初始化结构体 USART_ClockInitTypeDef 来设置,该结构体内容也只有在同步模式才需要设置。


USART 时钟初始化结构体

typedef struct {
	uint16_t USART_Clock; // 时钟使能控制
	uint16_t USART_CPOL; // 时钟极性
	uint16_t USART_CPHA; // 时钟相位
	uint16_t USART_LastBit; // 最尾位时钟脉冲
}USART_ClockInitTypeDef;

  1. USART_Clock:同步模式下 SCLK 引脚上时钟输出使能控制,可选禁止时钟输出 (USART_Clock_Disable) 或开启时钟输出 (USART_Clock_Enable);如果使用同步模式发送,一般都需要开启时钟。它设定 USART_CR2 寄存器的 CLKEN 位的值。

  2. USART_CPOL:同步模式下 SCLK 引脚上输出时钟极性设置,可设置在空闲时 SCLK 引脚为低电平 (USART_CPOL_Low) 或高电平 (USART_CPOL_High)。它设定 USART_CR2 寄存器的 CPOL位的值。

  3. USART_CPHA:同步模式下 SCLK 引脚上输出时钟相位设置,可设置在时钟第一个变化沿捕获数据 (USART_CPHA_1Edge) 或在时钟第二个变化沿捕获数据。它设定 USART_CR2 寄存器的 CPHA 位的值。 USART_CPHA 与 USART_CPOL 配合使用可以获得多种模式时钟关系。

  4. USART_LastBit:选择在发送最后一个数据位的时候时钟脉冲是否在 SCLK 引脚输出,可以是不输出脉冲 (USART_LastBit_Disable)、输出脉冲 (USART_LastBit_Enable)。它设定 USART_CR2 寄存器的 LBCL 位的值。


5. USART1 接发通信实验

USART 只需两根信号线即可完成双向通信,对硬件要求低,使得很多模块都预留 USART 接口来实现与其他模块或者控制器进行数据传输,比如 GSM 模块, WIFI 模块、蓝牙模块等等。在硬件设计时,注意还需要一根“共地线”

我们经常使用 USART 来实现控制器与电脑之间的数据传输。这使得我们调试程序非常方便,比如我们可以把一些变量的值、函数的返回值、寄存器标志位等等通过 USART 发送到串口调试助手,这样我们可以非常清楚程序的运行状态,当我们正式发布程序时再把这些调试信息去除即可。

我们不仅仅可以将数据发送到串口调试助手,我们还可以在串口调试助手发送数据给控制器,控制器程序根据接收到的数据进行下一步工作。

首先,我们来编写一个程序实现开发板与电脑通信,在开发板上电时通过 USART 发送一串字符串给电脑,然后开发板进入中断接收等待状态,如果电脑有发送数据过来,开发板就会产生中断,我们在中断服务函数接收数据,并马上把数据返回发送给电脑。


5.1 硬件设计

为利用 USART 实现开发板与电脑通信,需要用到一个 USB 转 USART 的 IC,我们选择 CH340G 芯片来实现这个功能, CH340G 是一个 USB 总线的转接芯片,实现 USB 转 USART、 USB 转 lrDA 红外或者 USB 转打印机接口,我们使用其 USB 转 USART 功能。具体电路设计见 图 USB 转串口硬件设计。

我们将 CH340G 的 TXD 引脚与 USART1 的 RX 引脚连接, CH340G 的 RXD 引脚与 USART1 的TX 引脚连接。 CH340G 芯片集成在开发板上,其地线 (GND) 已与控制器的 GND 连通。


图 USB 转串口硬件设计
在这里插入图片描述


5.2 软件设计

这里只讲解核心的部分代码,有些变量的设置,头文件的包含等并没有涉及到,完整的代码请参考本章配套的工程。我们创建了两个文件: usart.c 和 usart.h 文件用来存放 USART 驱动程序及相关宏定义。

5.2.1 编程要点

  1. 使能 RX 和 TX 引脚 GPIO 时钟和 USART 时钟;
  2. 初始化 GPIO,并将 GPIO 复用到 USART 上;
  3. 配置 USART 参数;
  4. 配置中断控制器并使能 USART 接收中断;
  5. 使能 USART;
  6. 在 USART 接收中断服务函数实现数据接收和发送。

5.2.2 代码分析

注意事项:

  • 硬件连接。主机 TX 引脚接从机 RX 引脚,主机 RX 引脚接从机 TX 引脚,必须交叉连接。主机的地线必须与从机地线相连。
  • 使用串口时,主机与从机的配置要一致(波特率、校验位、数据位、停止位,传输数据类型是 HEX,还是其他类型)。
  • 使用 printf 函数时,要包含 stdio.h 文件。用以下代码,或者野火的代码,需要勾选一下设置

STM32 use microlib是干什么的


在这里插入图片描述



uart.h

#ifndef __UART_H
#define __UART_H	


#include "stm32f10x.h"
#include <stdio.h>


void UART_GPIO_Init(void);
void UART_Config(u32 bound);
void UART_NVIC_Init(void);
void UART_Init(void);
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);
void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num);
void Usart_SendString( USART_TypeDef * pUSARTx, char *str);
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch);


#endif


uart.c

#include "uart.h"


/*******************************************************************************
* 函 数 名         : UART_GPIO_Init
* 函数功能		   : UART GPIO 初始化函数
* 输    入         : 无
* 输    出         : 无
* 说	明		   :无
*******************************************************************************/
void UART_GPIO_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	// 使能PA端口时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// USART1_TX  GPIOA.9
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 
	// 复用推挽输出
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	
	// IO口速度为50MHz	
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	// 根据设定参数初始化
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	// USART1_RX  GPIOA.10初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	// 浮空输入模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	// 根据设定参数初始化
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}


/*******************************************************************************
* 函 数 名         : UART_Config
* 函数功能		   : UART 配置初始化函数
* 输    入         : 串口波特率
* 输    出         : 无
* 说	明		   :无
*******************************************************************************/
void UART_Config(u32 bound)
{
	USART_InitTypeDef USART_InitStructure;
	
	// 使能 USART1 时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	
	// 串口波特率
	USART_InitStructure.USART_BaudRate = bound;
	// 字长为8位数据格式
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	// 一个停止位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	// 无奇偶校验位
	USART_InitStructure.USART_Parity = USART_Parity_No;
	// 无硬件数据流控制
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	// 收发模式
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	
	// 初始化串口1
	USART_Init(USART1, &USART_InitStructure); 
}


/*******************************************************************************
* 函 数 名         : UART_NVIC_Init
* 函数功能		   : UART NVIC 初始化函数
* 输    入         : 无
* 输    出         : 无
* 说	明		   :无
*******************************************************************************/
void UART_NVIC_Init(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	
	// Usart1 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	// 抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
	// 子优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
	// IRQ通道使能
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	// 根据指定的参数初始化VIC寄存器
	NVIC_Init(&NVIC_InitStructure);	
	
	// 开启串口接受中断
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
}


/*******************************************************************************
* 函 数 名         : UART_Init
* 函数功能		   : UART 总初始化函数
* 输    入         : 无
* 输    出         : 无
* 说	明		   :无
*******************************************************************************/
void UART_Init(void)
{
	// UART GPIO 初始化
	UART_GPIO_Init();
	// UART 配置初始化,波特率为 9600
	UART_Config(9600);
	// UART NVIC 初始化
	UART_NVIC_Init();
	
	// 使能串口1 
	USART_Cmd(USART1, ENABLE);
}



/*******************************************************************************
* 函 数 名         : Usart_SendByte
* 函数功能		   : Usart 发送一个字节
* 输    入         : 
					pUSARTx:串口
					ch:字节
* 输    出         : 无
* 说	明		   :无
*******************************************************************************/
void Usart_SendByte(USART_TypeDef * pUSARTx, uint8_t ch)
{
	// 发送一个字节数据到USART
	USART_SendData(pUSARTx,ch);
		
	// 等待发送数据寄存器为空
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}


/*******************************************************************************
* 函 数 名         : Usart_SendArray
* 函数功能		   : Usart 发送数组
* 输    入         : 
					pUSARTx:串口
					array:数组头
					num:数组个数
* 输    出         : 无
* 说	明		   :无
*******************************************************************************/
void Usart_SendArray(USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
{
	uint8_t i;
	
	for(i=0; i<num; i++)
	{
		// 发送一个字节数据到USART
		Usart_SendByte(pUSARTx,array[i]);	
	}
	
	// 等待发送完成
	while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET);
}


/*******************************************************************************
* 函 数 名         : Usart_SendString
* 函数功能		   : Usart 发送字符串
* 输    入         : 
					pUSARTx:串口
					str:字符串
* 输    出         : 无
* 说	明		   :无
*******************************************************************************/
void Usart_SendString(USART_TypeDef * pUSARTx, char *str)
{
	unsigned int k=0;
	
	do 
	{
		Usart_SendByte( pUSARTx, *(str + k) );
		k++;
	}while(*(str + k)!='\0');
  
	// 等待发送完成
	while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET);
}


/*******************************************************************************
* 函 数 名         : Usart_SendHalfWord
* 函数功能		   : Usart 发送一个16位数
* 输    入         : 
					pUSARTx:串口
					ch:16位数
* 输    出         : 无
* 说	明		   :无
*******************************************************************************/
void Usart_SendHalfWord(USART_TypeDef * pUSARTx, uint16_t ch)
{
	uint8_t temp_h, temp_l;
	
	// 取出高八位
	temp_h = (ch&0XFF00)>>8;
	// 取出低八位
	temp_l = ch&0XFF;
	
	// 发送高八位
	USART_SendData(pUSARTx,temp_h);	
	// 等待发送完毕
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
	
	// 发送低八位
	USART_SendData(pUSARTx,temp_l);	
	// 等待发送完毕
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}



/*******************************************************************************
* 函 数 名         : fputc
* 函数功能		   : 重定向c库函数printf到串口,重定向后可使用printf函数
* 输    入         : 无
* 输    出         : 无
* 说	明		   :无
*******************************************************************************/
int fputc(int ch, FILE *f)
{
	// 发送一个字节数据到串口
	USART_SendData(USART1, (uint8_t) ch);
	
	// 等待发送完毕
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);		

	return (ch);
}


/*******************************************************************************
* 函 数 名         : fgetc
* 函数功能		   : 重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
* 输    入         : 无
* 输    出         : 无
* 说	明		   :无
*******************************************************************************/
int fgetc(FILE *f)
{
	// 等待串口输入数据
	while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);

	return (int)USART_ReceiveData(USART1);
}



/*******************************************************************************
* 函 数 名         : USART1_IRQHandler
* 函数功能		   : USART1 中断函数
* 输    入         : 无
* 输    出         : 无
* 说	明		   :每接收到一个数据就发送出去
*******************************************************************************/
void USART1_IRQHandler(void)
{
	uint8_t ucTemp;
	if(USART_GetITStatus(USART1, USART_IT_RXNE)!= RESET)
	{
		// 接收数据
		ucTemp = USART_ReceiveData(USART1);
		// 发送接收到的数据
		USART_SendData(USART1,ucTemp);    
	}
}


main.c

#include "uart.h"


int main(void)
{	
	// 串口初始化
	UART_Init();
	
	Usart_SendString(USART1,"这个使用Usart_SendString发送的\n");
	printf("这个使用printf发送的\n\n\n\n");
	
	while(1);
}

摘抄自:
[野火EmbedFire]《STM32库开发实战指南——基于野火霸道开发板》.pdf

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

野火学习笔记(13) —— USART —串口通讯 的相关文章

  • 「STM32入门」USART串口通信

    通信 通信的目的 xff1a 将一个设备的数据传送到另一个设备 xff0c 扩展硬件系统 通信协议 xff1a 制定通信的规则 xff0c 通信双方按照协议规则进行数据收发 STM32常见的通信协议 本文将介绍USART 概念解释 TX R
  • ros串口通讯(读取串口数据)

    ros串口通讯是非常重要的通讯手段 xff0c 通常跟下位机或者各种usb口外设都是通过串口进行通讯的 那么我们跟着教程来学习一下如何读取手机通过无线串口发送给电脑的数据 这里我通过一个usb ttl工具将蓝牙连接到电脑上 xff0c 然后
  • ..\OBJ\USART.axf: Error: L6218E: Undefined symbol I2C_CheckEvent (referred from oled_i2c.o).

    OBJ USART axf Error L6218E Undefined symbol I2C CheckEvent referred from oled i2c o OBJ USART axf Error L6218E Undefined
  • UART串口通讯

    UART代表通用异步接收器 发送器也称为串口通讯 xff0c 它不像SPI和I2C这样的通信协议 xff0c 而是微控制器中的物理电路或独立的IC UART的主要目的是发送和接收串行数据 xff0c 其最好的优点是它仅使用两条线在设备之间传
  • 串口应用(USART)

    串行口应用 1 USART介绍 通用同步异步收发器 USART 提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的 外部设备之间进行全双工数据交换 USART利用分数波特率发生器提供宽范围的波特率选择 它支持同步单向通信和半双工单线
  • STM32F103RCTX 串口USART 不定长接收

    串口不定长接收的方法有多种 xff0c 这里我所介绍的是通过设置IDLE中断来检测串口是否接收完毕 xff0c 从而结束串口接受中断 1 首先设置串口 xff0c 如下图所示 xff1a 2 使用IDLE中断检测 xff0c 所以需要开启对
  • STM32CubeMX串口通讯

    串口的简单介绍 RS 232与TTL 根据通讯使用的电平标准不同 xff0c 串口通讯可分为 TTL 标准及 RS 232 标准 而STM32的串口是TTL电平标准的 如果需要使用到RS 232则需要一个电平转换芯片 单工通信 半双工通信和
  • NVIDIA Jetson Xavier NX 串口通讯(发送YOLO检测结果)(记录)

    目录 NVIDIA Jetson Xavier NX串口cutecom助手测试发送YOLO检测结果 开始之前声明 xff1a 本文在NVIDIA Jetson Xavier NX上跑YOLOv4模型 xff0c 配合ZED相机实时检测 xf
  • 通信方式梳理:GPIO,I2C,SPI,UART,USART,USB的区别

    GPIO xff0c I2C xff0c SPI xff0c UART xff0c USART xff0c USB的区别 1 简单区别 xff1a 1 xff09 GPIO xff08 General Purpose Input Outpu
  • 串口通讯UART/RS232/RS485/RS-422笔记

    串口通讯详解笔记 串口通讯概述串口通讯传输数据帧的结构UARTRS232RS485RS 422RS 232 RS 422和RS 485的主要区别 xff08 重要 xff09 串口通讯概述 串口通讯是指数据按位 xff08 bit xff0
  • STM32 第11讲 正点原子SYSTEM文件夹介绍及使用(sys/delay/usart)

    文章目录 sys文件夹delay文件夹函数简介Systick定时器工作原理寄存器函数介绍 usart文件夹printf函数输出流程printf函数的使用printf函数支持微库法代码法 SYSTEM 文件夹里面的代码由正点原子提供 xff0
  • 【STM32】串口通讯USART串口中断配置

    目录 STM32 USART 简介 程序编写 硬件接线 实际波形 STM32 USART 简介 STM32的USART通用同步异步收发器是一个串行通信设备 xff0c 可以灵活的与外部设备进行全双工数据交换 有别于USART xff0c 还
  • 使用STM32G4 ----串口发送数据USART_TX的使用

    一 引脚的配置 串口对应的引脚 PA10 span class token operator span span class token operator span span class token operator span span c
  • STM32中USART的使用方法

    USART作为一种标准接口在应用中十分常见 本文着重分析其作为 UART的配置和应用方法 1 STM32固件库使用外围设备的主要思路 在 STM32中 xff0c 外围设备的配置思路比较固定 首先是使能相关的时钟 xff0c 一方面是设备本
  • usart串口发送与接收问题

    项目场景 xff1a 串口通信可以说很常用的一种通信方式 xff0c 例如 蓝牙通信 openmv 与串口 通信 等等 问题描述 1 我们在进行数据传输过程中数据不时出现丢失的情况 xff0c 偶尔会丢失一部分数据 xff0c 导致数据部分
  • 串口通讯(USART)

    对于通讯协议 xff0c 我们也以分层的方式来理解 xff0c 最基本的是把它分为物理层和协议层 物理层规定通讯系统中具有机械 电子功能部分的特性 xff0c 确保原始数据在物理媒体的传输 协议层主要规定通讯逻辑 xff0c 统一收发双方的
  • STM32使用FIFO实现USART串口发送中断

    fifo就不要造轮子了 xff0c 用现成的就行了 linux内核中有目前人类写出的基于c语言的最强FIFO xff0c 请自行搜索学习 巧夺天工的kfifo xff0c kfifo精妙无比 xff0c 实在是高 xff0c 其中用到的环回
  • DSPF28335 SCI FIFO串口通讯

    在工作过程中 xff0c 通过串口进行上位机与控制器之间进行数据的传输 xff0c 标准的串口通讯容易造成数据的丢失和内存堆满的现象 xff0c 便使用SCI中的FIFO对数据进行中断处理 一 串口通信基本知识 F28335 处理器共有 3
  • 【STM32】HAL库-串口USART

    USART简介 通用同步异步收发器 USART 提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换 USART利用分数波特率发生器提供宽范围的波特率选择 一个波特率寄存器 USART BRR xff0c
  • STM32-USART串口初始化配置

    一 串行通信的基本概念 1 同步通信和异步通信 通信 xff0c 最少要两个对象 xff0c 一个收 xff0c 一个发同步通信 xff1a 通信双方根据同步信号进行通信的方式 异步通信 xff1a 数据传输速度匹配依赖于通信双方有自己独立

随机推荐