嵌入式笔记 | 正点原子STM32F103ZET6 5 | 串口通信
1. 串口通信协议数据帧格式
串口通信使用的是异步串行通信协议,常见的数据帧格式如下:
起始位 | 数据位 | 校验位(可选) | 停止位 |
---|---|---|---|
1 bit | 5-9 bits | 0/1 bit | 1/2 bits |
- 起始位:低电平表示数据开始
- 数据位:通常为 8 位
- 校验位(可选):可选奇偶校验
- 停止位:用于标记数据结束,通常为 1 或 2 位高电平
2. STM32F103ZET6 提供 5 路串口
STM32F103ZET6 具有 5 个串口(USART1、USART2、USART3、UART4、UART5),支持同步和异步通信模式,主要用于数据传输和调试。
3. USART 框图
USART 由多个模块组成,主要包括:
- 发送器(Transmitter):将数据从 MCU 发送出去
- 接收器(Receiver):接收外部数据并存储到缓冲区
- 波特率发生器(Baud Rate Generator):控制数据传输速率
- 控制寄存器:用于配置数据格式、校验方式等
4. 串口波特率计算和设置
波特率计算公式:
波特率=串口时钟16×USARTDIV波特率 = \frac{串口时钟}{16 \times USARTDIV}
其中:
- 串口时钟:通常为 APB1 或 APB2 时钟
- USARTDIV 由
BRR
寄存器控制
示例:计算 115200bps 的波特率:
uint32_t baudrate = 115200;
g_uart1_handle.Init.BaudRate = baudrate;
HAL_UART_Init(&g_uart1_handle);
5. HAL 库回调机制
HAL 库采用回调函数处理串口中断,提高代码的可读性和移植性。
当串口收到数据后,STM32 进入中断,HAL 库调用 HAL_UART_RxCpltCallback()
处理接收数据。
6. GPIO 引脚复用
STM32 的 GPIO 可以配置为复用功能,用于串口通信。例如:
- TX(发送):配置为 复用推挽输出(AF_PP)
- RX(接收):配置为 复用输入(AF_INPUT)
示例:
gpio_init_struct.Pin = GPIO_PIN_9;
gpio_init_struct.Mode = GPIO_MODE_AF_PP;
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &gpio_init_struct);
7. STM32F103ZET6 的 USART 异步通信配置
uint8_t g_rx_buffer[1];
uint8_t g_usart1_rx_flag = 0;
UART_HandleTypeDef g_uart1_handle;
// 串口初始化
void usart_init(uint32_t baudrate) {
g_uart1_handle.Instance = USART1;
g_uart1_handle.Init.BaudRate = baudrate;
g_uart1_handle.Init.WordLength = UART_WORDLENGTH_8B;
g_uart1_handle.Init.StopBits = UART_STOPBITS_1;
g_uart1_handle.Init.Parity = UART_PARITY_NONE;
g_uart1_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
g_uart1_handle.Init.Mode = UART_MODE_TX_RX;
HAL_UART_Init(&g_uart1_handle);
HAL_UART_Receive_IT(&g_uart1_handle, g_rx_buffer, 1);
}
// 串口 MSP 初始化(引脚、时钟、中断配置)
void HAL_UART_MspInit(UART_HandleTypeDef *huart) {
GPIO_InitTypeDef gpio_init_struct;
if(huart->Instance == USART1) {
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
gpio_init_struct.Pin = GPIO_PIN_9;
gpio_init_struct.Mode = GPIO_MODE_AF_PP;
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &gpio_init_struct);
gpio_init_struct.Pin = GPIO_PIN_10;
gpio_init_struct.Mode = GPIO_MODE_AF_INPUT;
gpio_init_struct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &gpio_init_struct);
HAL_NVIC_SetPriority(USART1_IRQn, 3, 3);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}
}
// 串口中断服务函数
void USART1_IRQHandler(void) {
HAL_UART_IRQHandler(&g_uart1_handle);
}
// 串口接收回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if(huart->Instance == USART1) {
g_usart1_rx_flag = 1;
HAL_UART_Receive_IT(&g_uart1_handle, g_rx_buffer, 1);
}
}
8. 中断回调函数处理字符串数据
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART1) {
if ((g_usart_rx_sta & 0x8000) == 0) {
if (g_usart_rx_sta & 0x4000) {
if (g_rx_buffer[0] != 0x0A) {
g_usart_rx_sta = 0;
} else {
g_usart_rx_sta |= 0x8000;
}
} else {
if (g_rx_buffer[0] == 0x0D) {
g_usart_rx_sta |= 0x4000;
} else {
g_usart_rx_buf[g_usart_rx_sta & 0x3FFF] = g_rx_buffer[0];
g_usart_rx_sta++;
if (g_usart_rx_sta > (USART_REC_LEN - 1)) {
g_usart_rx_sta = 0;
}
}
}
}
HAL_UART_Receive_IT(&g_uart1_handle, g_rx_buffer, 1);
}
}