第4章 串口通信实验
第四章 串口通信实验
1. 硬件设计
本实验需要使用的硬件资源有:
-
指示灯DS0
-
串口1
串口 1 之前还没有介绍过,本实验用到的串口 1 与 USB 串口并没有在 PCB 上连接在一起,需要通过跳线帽来连接一下。这里我们把 P6 的 RXD 和 TXD 用跳线帽与 PA9 和 PA10 连接起来。
2. 软件设计
2.1 编程大纲
-
串口GPIO配置
-
串口参数配置
-
主函数测试串口收发
2.2 代码分析
2.2.1 串口GPIO初始化
// 此函数会被HAL_UART_Init()调用,用于初始化串口外设的GPIO
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
GPIO_InitTypeDef GPIO_InitStructure;
if(huart->Instance==USART1) // 如果是串口1,则初始化GPIO和NVIC
{
__HAL_RCC_USART1_CLK_ENABLE(); // 使能串口1时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
// 初始化串口1的TX、RX引脚
GPIO_InitStructure.Pin = GPIO_PIN_9 | GPIO_PIN_10;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStructure.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
// NVIC配置
HAL_NVIC_EnableIRQ(USART1_IRQn);
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
}
}
2.2.2 串口配置
UART_HandleTypeDef UART1_Handler;
void UART_Init(uint32_t baudrate)
{
UART1_Handler.Instance = USART1;
UART1_Handler.Init.BaudRate = baudrate;
UART1_Handler.Init.WordLength = UART_WORDLENGTH_8B;// 8位数据位
UART1_Handler.Init.StopBits = UART_STOPBITS_1; // 1位停止位
UART1_Handler.Init.Parity = UART_PARITY_NONE; // 无校验位
UART1_Handler.Init.HwFlowCtl = UART_HWCONTROL_NONE;// 无硬件流控
UART1_Handler.Init.Mode = UART_MODE_TX_RX; // 收发模式
HAL_UART_Init(&UART1_Handler);
}
2.2.3 主函数
extern UART_HandleTypeDef UART1_Handler; // 串口句柄
int main(void)
{
HAL_Init();
UART_Init(115200); // 初始化串口1,波特率115200
uint8_t buf[100]; // 接收缓冲区
uint16_t len = 0; // 接收到的长度
while(1)
{
memset(buf, 0, sizeof(buf)); // 清空接收缓冲区
HAL_UART_Receive(&UART1_Handler, buf, 100, 100); // 接收数据
// 找到接收到的数据末尾并手动添加结束符
len = strlen((char*)buf);
if (len > 0 && buf[len - 1] != '\0')
{
buf[len] = '\0'; // 确保字符串以NULL结尾
}
HAL_UART_Transmit(&UART1_Handler, buf, len, 100); // 发送接收到的字符串
}
}
在此我们需要分析三个重要的HAL库函数:
2.2.3.1 memset函数
memset
是 C 语言标准库中的一个函数,用于设置一块内存区域的值。它通常用于初始化数组或内存块,将特定的字节值填充到内存中。
void *memset(void *s, int c, size_t n);
参数说明:
s
: 指向要设置值的内存区域的指针,通常是一个数组或者一块动态分配的内存。c
: 要设置的值,memset
会将这个值填充到内存区域中的每个字节。虽然参数类型是int
,但memset
会将其转换为unsigned char
类型,然后填充到内存中。n
: 要设置的字节数,即将c
的值写入s
所指向内存块的前n
个字节。
2.2.3.2 HAL_UART_Receive函数
HAL_UART_Receive
是 STM32 HAL 库中用于接收串口数据的函数,它通过 UART 外设接收数据并将其存储在提供的缓冲区中。
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
参数说明:
-
huart
: 指向UART_HandleTypeDef
结构体的指针。这个结构体包含了 UART 外设的配置信息,指明了要操作的 UART 外设(如USART1
,USART2
等),以及该外设的配置参数(波特率、数据位、停止位等)。 -
pData
: 指向接收数据缓冲区的指针。在函数执行时,接收到的数据将被存储在这个缓冲区中。缓冲区需要足够大来存储预期的接收数据。 -
Size
: 接收的数据字节数,即期望从 UART 接收多少个字节的数据。如果是一个字符,可以设置为 1;如果需要接收多个字节,可以设置为更大的值。 -
Timeout
: 接收超时时间(以毫秒为单位)。这是函数等待数据接收的最大时间。如果在此时间内未能接收到所需的字节,函数将返回超时错误。
2.2.3.3 HAL_UART_Transmit函数
HAL_UART_Transmit
是 STM32 HAL 库中用于发送数据通过 UART 外设的函数。它将数据从内存缓冲区传输到 UART 外设并通过串口发送出去。
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
参数说明:
-
huart
: 指向UART_HandleTypeDef
结构体的指针,该结构体包含了 UART 外设的配置和状态信息(例如波特率、数据位、停止位等),指明了要操作的 UART 外设(如USART1
,USART2
等)。 -
pData
: 指向包含要发送数据的缓冲区的指针。该缓冲区中的数据将被逐字节发送到 UART 外设。 -
Size
: 要发送的数据字节数。即你希望从缓冲区发送的字节数。 -
Timeout
: 发送数据的超时时间(以毫秒为单位)。如果在此时间内数据没有成功发送完毕,函数将返回超时错误。
3. 小结
本章经过改写后,应该是变简单了许多,第一版因为考虑到可以用到os,编写了其他函数,但是我们如果单单学习串口的话就显得复杂了。
2024.9.28 第一次修订,后期不再维护
2024.12.21 整体大改,因为只是学习串口,移除了第一版的自编通讯协议