STM32简单串口通信
引言:
在本文中,将介绍如何在STM32微控制器上实现简单的串口通信。通过串口通信,我们可以实现与外部设备(如电脑、传感器等)之间的数据交互,从而实现各种功能,如数据采集、远程控制等。我们将使用HAL提供的库函数来配置串口,并编写简单的代码实现数据的发送和接收。
通过本文的学习,读者将能够掌握STM32串口通信的基本原理和操作方法,为后续的嵌入式开发提供基础知识和实践经验。无论是初学者还是有一定经验的开发者,都可以通过本文快速上手STM32串口通信,并在实际项目中应用。让我们一起开始探索STM32串口通信的奇妙世界吧!
╭ ( `∀´ )╯ ╰ ( ’ ’ )╮
文章目录
一、CH340介绍
芯片使用简介
CH340是一个USB总线的转接芯片,实现USB转串口或者USB转打印口。
在串口方式下,CH340提供常用的MODEM联络信号,用于为计算机扩展异步串口,或者将普通的串口设备直接升级到USB总线。
特点
- 全速USB设备接口,兼容USB V2.0。
- 仿真标准串口,用于升级原串口外围设备,或者通过USB增加额外串口。
- 计算机端Windows操作系统下的串口应用程序完全兼容,无需修改。
- 硬件全双工串口,内置收发缓冲区,支持通讯波特率50bps~2Mbps。
- 支持常用的MODEM联络信号RTS、DTR、DCD、RI、DSR、CTS。
- 通过外加电平转换器件,提供RS232、RS485、RS422等接口。
- CH340R芯片支持IrDA规范SIR红外线通讯,支持波特率2400bps到115200bps。
- 内置固件,软件兼容CH341,可以直接使用CH341的VCP驱动程序。
- 支持5V电源电压和3.3V电源电压。
- CH340C/N/K/E及CH340B内置时钟,无需外部晶振,CH340B还内置EEPROM用于配置序列号等。
- 提供SOP-16、SOP-8和SSOP-20以及ESSOP-10、MSOP-10无铅封装,兼容RoHS。
USB转TTL
- 实物图
-
模块使用方法
由于我们需要让电脑与Stm32进行数据通信,通过USART1进行数据传输
因此对应 CH340 模块的 TXD 应该接到 Stm32的 PA10(RX)
对应 CH340 模块的 RXD 应该接到 Stm32的 PA9(TX)
二、USART
串口通信
串口通信是指外设和计算机间,通过数据信号线 、地线、控制线等,按位进行传输数据的一种通讯方式,如SPI通信、USART通信、EEPROM通信等。简单讲,串口通信实现了上位机(PC)与下位机(如STM32)之间的信息交互。
串行通信按通信的方式可分为:
-
同步通信:带时钟同步信号传输,如SPI、IIC通信等
-
异步通信:不带时钟同步信号,如UART(通用异步收发器)、单总线等。
STM32的串口通信接口
- UART:通用异步收发器
- USART:通用同步/异步收发器(两种模式可切换)
STM32F103系列提供5路串口,包含3个 USART 和2个 UART 。
串口的引脚如下图所示:
数据传输的格式/通信协议
串行通信一定要有适合的通信协议。
通信协议指通信双方之间为完成信息交互所必须遵守的一种规则和约定。比如两个人约定在何时交流、用中文还是英文交流、交流什么内容。
- 起始位
当未有数据发送时,数据线处于逻辑“1”状态;先发出一个逻辑“0”信号,表示开始传 输字符。
- 数据位
紧随起始位之后,数据位表示真正要发送或接收的信息,位数一般有8位或9位
-
奇偶校验位
数据位末尾可以选择是否添加奇偶校验位,用于检测数据传输是否正确
-
停止位
代表信息传输结束的标志位,可以是1位,1.5位或2位。停止位的位数越多,数据传 输的速率也越慢。
- 波特率设置
波特率表示每秒钟传输码元的个数,是衡量数据传输速率的指标,单位Baud。另外 有个名词叫比特率,比特率表示每秒钟传输二进制位bit的个数,单位 bit/s。
- 波特率的计算
波特率是由USART_BRR波特率寄存器控制的,TR/Tx的波特率 = 串口时钟 / BRR的 值。
USART的使用步骤
串口设置的一般步骤可以总结为如下几个步骤:
1)串口时钟使能 GPIO 时钟使能
2)串口复位
3)GPIO 端口模式设置
4)串口参数初始化
5)开启中断 并且初始化 NVIC(如果需要开启中断才需要这个步骤)
6)使能串口
7)编写中断处理函数
三、基本函数介绍
串口发送数据:
HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
功能:串口发送指定长度的数据。如果超时没发送完成,则不再发送,返回超时标志(HAL_TIMEOUT)。
参数:
-
UART_HandleTypeDef *huart UATR的别名 如 : UART_HandleTypeDef huart1; 别名就是huart1
-
*pData 需要发送的数据
-
Size 发送的字节数
-
Timeout 最大发送时间,发送数据超过该时间退出发送
-
举例:
HAL_UART_Transmit(&huart1, (uint8_t *)ZZX, 3, 0xffff); //串口发送三个字节数据,最大传输时间0xffff
中断接收数据:
HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
功能:串口中断接收,以中断方式接收指定长度数据。
大致过程是,设置数据存放位置,接收数据长度,然后使能串口接收中断。接收到数据时,会触发串口中断。
再然后,串口中断函数处理,直到接收到指定长度数据,而后关闭中断,进入中断接收回调函数,不再触发接收中断。(只触发一次中断)
因此在中断函数的最后推荐再重新开启对应的中断。
参数:
-
UART_HandleTypeDef *huart UATR的别名 如 : UART_HandleTypeDef huart1; 别名就是huart1
-
*pData 接收到的数据存放地址
-
Size 接收的字节数
-
举例:
HAL_UART_Receive_IT(&huart1,(uint8_t *)&value,1); //中断接收一个字符,存储到value中
四、工程建立
CubeMX配置
基本的配置在我之前的文章中有,这里我们直接跳到对应串口通信的配置
- 选择对应的 RX、TX数据发送接收的GPIO口
- USART1 的相关配置
Asynchronous:全双工异步通信
Disable: 只通过RX和TX实现基本的串口通信
-
通信协议相关数据配置
Parameter Settings:
**Baud Rate:**波特率。 通过波特率寄存器(USART_BRR)设置。
**Word Length:**字长。 数据位可选8位或9位 ,通过控制寄存器1(USART_CR1)中的M位设置。
**Parity:**奇偶校验选择。 校验位可选无校验(None)、偶校验(Even)、奇校验(Odd)。通过控制寄存器1(USART_CR1)中的PCE位和PS位设置。
**Stop Bits:**停止位。 停止位可选1位、2位。通过控制寄存器2(USART_CR2)中的STOP位设置。
**Data Direction:**数据方向。 可选收发(Receive and Transmit)、只接收(Receive Only)、只发送(Transmit Only)。通过控制寄存器1(USART_CR1)中的TE和RE位设置。
-
开启对应的中断
重定向printf函数
说到串口,肯定为了调试程序,使用HAL_UART_Transmit发送字符串很不方便,经常会用printf()函数输出一些调试信息;
如果使用到串口的时候,可以在 usart.c 里面进行串口重定向
/* USER CODE BEGIN 0 */
// printf重定向代码,修改其底层fputc
#if 1
#include <stdio.h>
/* 告知连接器不从C库链接使用半主机的函数 */
#pragma import(__use_no_semihosting)
/* 定义 _sys_exit() 以避免使用半主机模式 */
void _sys_exit(int x)
{
x = x;
}
/* 标准库需要的支持类型 */
struct __FILE
{
int handle;
};
FILE __stdout;
/* */
int fputc(int ch, FILE *stream)
{
/* 堵塞判断串口是否发送完成 */
/* 不同芯片的串口标志位不一定相同! */
while ((USART1->SR & 0X40) == 0)
;
/* 串口发送完成,将该字符发送 */
USART1->DR = (uint8_t)ch;
return ch;
}
#endif
/* USER CODE END 0 */
示例:
/* 串口重定向,一般用printf()比较多 */
printf("hello lu shi jun \r\n");
HAL_Delay(500);
代码
STM32系统给上位机(win10)连续发送“hello windows!”。win10采用“串口助手”工具接收。
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(1000);
// HAL_UART_Transmit(&huart1, tx_buf, sizeof(tx_buf), 100);
printf("Hello Windows!!! \r\n");
}
当上位机给stm32发送一个字符“#”后,stm32暂停发送“hello windows!”;发送一个字符“*”后,stm32继续发送;
main.c
/* USER CODE BEGIN 0 */
uint8_t rx_buf[1]; // 存储接收到了的数据
uint8_t flag = 1; // flag=1 开始发送 flag=0 停止发送
/* USER CODE END 0 */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if (flag)
{
HAL_Delay(1000);
// HAL_UART_Transmit(&huart1, tx_buf, sizeof(tx_buf), 100);
printf("Hello Windows!!! \r\n");
}
}
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1) // 判断是否为对应的串口通信
{
if (rx_buf[0] == '#')
flag = 0;
else
flag = 1;
HAL_UART_Transmit_IT(&huart1, rx_buf, sizeof(rx_buf)); // 发送接收到的数据
HAL_UART_Receive_IT(&huart1, rx_buf, sizeof(rx_buf)); // 重新开启中断
}
}
/* USER CODE END 4 */
五、效果展示
第一个现象:
Video1:
VID_20231024_201257
第二个现象:
Video2:
VID_20231024_204830
KEIL 波形观察
六、总结
在本文中,我们了解了串口通信的基本原理和常见的通信协议,如UART和USART。然后,我们学习了HAL库对应的基本函数,并编写了简单的代码实现数据的发送和接收。
我们学习了如何设置串口的波特率、数据位数、停止位数和校验位,以确保数据的正确传输。我们还学习了如何使用中断方式进行数据的接收和发送
通过本文的学习,我学习并且掌握STM32串口通信的基本操作方法,并能够根据实际需求进行相应的配置和编程
总而言之,通过此次的串口通信学习,我收获了大量的基础知识和实践经验
最后感谢大佬友情链接:
- https://blog.youkuaiyun.com/Dir_x/article/details/128932736
- https://blog.youkuaiyun.com/AriesPIG/article/details/119840979
- https://www.cnblogs.com/ZenoBlog/articles/15971551.html
- https://blog.youkuaiyun.com/as480133937/article/details/99073783