STM32教程-----USART串口通讯
STM32教程,UART串口、STM32F103C8T6,
一、USART/UART串口介绍
(一)串口通讯的简介
一条信息的各位数据被逐位按顺序传送的通讯方式称为串行通讯。串行通讯的特点是:数据位的传送,按位顺序进行,最少只需一根传输线即可完成;成本低但传送速度慢。串行通讯的距离可以从几米到几千米;根据信息的传送方向,串行通讯可以进一步分为单工、半双工和全双工三种。
(二)不同设备间的通方式
| 并行通讯 | 串行通讯 | |
| 传输方式 | 多个数据位一起传输 | 一个bit位一个bit位传输 |
| 优点 | 速度快 | 占用资源少 |
| 缺点 | 占用资源多 | 速度慢 |
(三)串行通信分类
1、按数据传输方向
| 模式 | 介绍 |
| 单工 | 单工通信是一种单向传输数据的通信方式。 |
| 半双工 | 半双工通信允许数据双向传输,但发送和接收不能同时进行,双方需要轮流发送和接收数据。 |
| 全双工 | 全双工通信可以同时进行数据的发送和接收,两者互不干扰。 |
2、按通讯方式
| 模式 | 介绍 |
| 同步通讯(USART) | 同步通信依赖共享的时钟信号,发送方和接收方根据时钟信号的节奏来传输和接收数据。这种通信方式的效率高,通常用于实时性要求较高的场景,如嵌入式系统中的I2C、SPI等协议。 |
| 异步通讯(UART) | 异步通信无需共享时钟信号,发送方和接收方以各自的速度传输和接收数据。常见的异步通信协议有UART、RS-232等,通常用于突发性、间歇性数据传输。 |
(四)UART串口通讯介绍
1、串口通讯接线

TX:数据发送端
RX : 数据接收端
2、串口传输数据帧

起始位:代表一个帧数据的开始一个低电平
数据位:有效数据的个数,5~8个数据位,一般配置为8个(一个byte)。
奇偶校验位:可配置为奇校验(奇数个1)、偶校验(偶数个1)、无校验(即不传输此位)。
停止位:是一个帧数据的结束,可以是1个、1.5个、2个空闲电平(高电平)
波特率:每秒传输二进制数的个数,
二、STM32串口通讯模块
(一)STM32串口特性
- 全双工
- 数据长度可编程(8位或9位)
- 停止位可配置(1个或2个)
- 可配置DMA
(二)STM32 USART硬件框图

发送数据:
通过写操作,将数据写入TDR,写入完成后,硬件就会自动检查发送移位寄存器中是否有数据正在进行移位,有则等待,若没有,则数据就会立刻转入发送移位寄存器,此时会将标志位TXE(发送寄存器空)置1,代表TDR为空,新转入的数据进入准备发送状态。此时发送移位寄存器就会在下面的发送器控制下,将数据输出到TX引脚。这样可以保证连续发送数据的时候,数据帧之间不会有空闲,提高了工作效率。
接收数据:
通过RX引脚接收到的数据会进入接收移位寄存器,数据由高位向低位逐渐移位,然后全部保存到接收数据寄存器(RDR),当完成一个字节的移位后,会将标志位RXNE(接收寄存器非空)置1,通过标志位,就可以对数据进行读取处理。数据寄存器USART_DR:
位 31:9 保留,必须保持复位值
位 8:0 DR[8:0]:数据值
因为数据寄存器包含两个寄存器,一个用于发送 (TDR),一个用于接收 (RDR),因此它具有 双重功能(读和写)。根据所执行的操作确定是“读取”还是“写入”。
三、相关寄存器
寄存器映射:

USART_SR :状态寄存器
USART_DR :数据寄存器
USART_BRR :波特率寄存器
USART_CRx :控制寄存器x(x = 1,2,3)
USART_GTPR :保护时间和预分频器寄存器(用来控制预分频值)
寄存器各个位功能详情参考STM32F1xx参考手册
四、STM32串口通讯配置
(一)配置流程
- 配置串口工作参数(波特率、数据长度、奇偶校验位等)
- 使能USART模块和使用到的GPIO时钟
- 配置串口的Tx和Rx引脚的GPIO模式:
- 使能串口、启动串口通讯
- 发送和接收数据
(二)相关函数
//1、初始化串口函数
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart);
/*2、串口初始化回调函数,在HAL_UART_Init中会调用该函数来使能串口时钟和GPIO时钟,以及配置GPIO
此函数需要自己实现,在HAL中是一个弱定义函数,类似的HAL_xxx_MspInit()都是类似的
*/
void HAL_UART_MspInit(UART_HandleTypeDef *huart);
//3、串口发送
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart,
const uint8_t *pData, uint16_t Size,
uint32_t Timeout); //以阻塞的方式发送
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart,
const uint8_t *pData, uint16_t Size); //以中断的方式发送
//4、串口接收
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData,
uint16_t Size, uint32_t Timeout); //以阻塞的方式接收
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData,
uint16_t Size); //以中断的方式接收
HAL_StatusTypeDef UART_Start_Receive_IT(UART_HandleTypeDef *huart,
uint8_t *pData, uint16_t Size); //开启接收中断
五、实战编程
使用的开发板芯片:STM32F103C8t6
使用到的串口:UART1
引脚:Tx(PA9)、Rx(PA10)
usart.h:
#ifndef __USART_H
#define __USART_H
extern UART_HandleTypeDef huart1;
void MX_USART1_UART_Init(void);
void Usart1_SendByte(char ch); // 发送一个字节
void Usart1_SendString(u8 *str);
#endif //__USART_H
usart.c:
#include "usart.h"
#include <stdio.h>
#include <string.h>
UART_HandleTypeDef huart1;
//配置串口1的工作参数
void MX_USART1_UART_Init(void) {
huart1.Instance = USART1; //串口1
huart1.Init.BaudRate = 115200; //波特率:115200
huart1.Init.WordLength = UART_WORDLENGTH_8B; //8位数据位
huart1.Init.StopBits = UART_STOPBITS_1; //一个停止位
huart1.Init.Parity = UART_PARITY_NONE; //无奇偶校验位
huart1.Init.Mode = UART_MODE_TX_RX; //收发模式
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; //无硬件流控制
huart1.Init.OverSampling = UART_OVERSAMPLING_16; //16倍采样率
if (HAL_UART_Init(&huart1) != HAL_OK) {
Error_Handler();
}
}
//配置串口使用到的GPIO
void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
if (uartHandle->Instance == USART1) {
//使能串口1 时钟
__HAL_RCC_USART1_CLK_ENABLE();
//使能串口1使用到的GPIO时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
/**USART1 GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; //复用推挽输出
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; //快速
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT; //输入模式
GPIO_InitStruct.Pull = GPIO_NOPULL; //无上下拉
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); //设置中断优先级
HAL_NVIC_EnableIRQ(USART1_IRQn); //使能串口中断
}
}
//发送一个字符
void Usart1_SendByte(char ch) {
HAL_UART_Transmit(&huart1, (u8 *)&ch, 1, 1000);
while (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) != SET)
;
}
//发送一个字符串
void Usart1_SendString(u8 *str) {
unsigned int num = 0;
char ch = str[num];
while (num < strlen(str)) {
Usart1_SendByte(ch);
num++;
ch = str[num];
}
}
在main.c中添加如下代码以支持printf功能:
#ifdef __GNUC__
/* With GCC, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
extern UART_HandleTypeDef huart1;
PUTCHAR_PROTOTYPE {
Usart1_SendByte(ch);
return ch;
}
int _write(int file, char *ptr, int len) {
int DataIdx;
for (DataIdx = 0; DataIdx < len; DataIdx++) {
__io_putchar(*ptr++);
}
return len;
}
更多推荐



所有评论(0)