大模型长文本分块策略与上下文窗口管理的后端架构
2026/6/11 18:32:57
本文以 STM32F103C8T6(最小系统板)为例,详细讲解串口通信的硬件连接、软件配置、代码实现及调试问题解决方案,分别覆盖标准外设库(STM32F10x_StdPeriph_Driver)和HAL 库两种主流开发方式,同时包含轮询 / 中断两种数据收发模式。
STM32F103 的 USART1 引脚为复用功能,需注意引脚定义:
| STM32 引脚 | 功能 | USB 转 TTL 模块引脚 | 说明 |
|---|---|---|---|
| PA9 | USART1_TX | RXD | 单片机发送→模块接收 |
| PA10 | USART1_RX | TXD | 单片机接收→模块发送 |
| GND | 地 | GND | 共地(必须连接,否则乱码) |
| (可选)VCC | 电源 | 3.3V | 给单片机供电(也可单独供) |
注意:STM32 为 3.3V 电平,USB 转 TTL 模块若为 5V 输出,需串接 1kΩ 电阻分压,避免烧毁单片机引脚。
plaintext
STM32F103C8T6 USB转TTL模块 PA9 (TX) ────────→ RXD PA10 (RX) ────────→ TXD GND ────────→ GND 3.3V ────────→ 3.3V(可选)串口通信依赖时钟源,STM32F103 的 USART 时钟由 APB 总线提供:
串口波特率计算公式:USART_BRR = APBx时钟 / 波特率例:APB2=72MHz,波特率 9600 → BRR=72000000/9600=7500(0x1D4C)
#define SYSCLK_FREQ_72MHz 72000000c
运行
#include "stm32f10x.h" // 串口初始化函数(USART1,轮询模式基础配置) void USART1_Init(uint32_t baudrate) { GPIO_InitTypeDef GPIO_InitStruct; USART_InitTypeDef USART_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; // 中断模式需配置 /************************** 1. 使能时钟 **************************/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); /************************** 2. 配置GPIO引脚 **************************/ // PA9 (TX):复用推挽输出 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); // PA10 (RX):浮空输入(或上拉输入) GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入 GPIO_Init(GPIOA, &GPIO_InitStruct); /************************** 3. 配置USART参数 **************************/ USART_InitStruct.USART_BaudRate = baudrate; // 波特率 USART_InitStruct.USART_WordLength = USART_WordLength_8b; // 8位数据 USART_InitStruct.USART_StopBits = USART_StopBits_1; // 1位停止位 USART_InitStruct.USART_Parity = USART_Parity_No; // 无校验 USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件流控 USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 收发使能 USART_Init(USART1, &USART_InitStruct); /************************** 4. 中断配置(可选,中断模式需开启) **************************/ // 使能接收中断 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // RXNE:接收缓冲区非空中断 // 配置NVIC NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; // USART1中断通道 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级1(需根据系统调整) NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; // 子优先级0 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; // 使能通道 NVIC_Init(&NVIC_InitStruct); /************************** 5. 使能USART **************************/ USART_Cmd(USART1, ENABLE); }c
运行
// 轮询发送单个字符(等待发送缓冲区为空) void USART1_SendChar(uint8_t ch) { // 等待TXE位置1:发送数据寄存器为空 while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); USART_SendData(USART1, ch); // 发送字符 // 可选:等待发送完成(TC位),确保数据完全发送 while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); }c
运行
// 轮询发送字符串 void USART1_SendString(uint8_t *str) { while (*str != '\0') // 遍历字符串直到结束符 { USART1_SendChar(*str); str++; } }c
运行
// 轮询接收单个字符(阻塞式) uint8_t USART1_ReceiveChar(void) { // 等待RXNE位置1:接收缓冲区非空 while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET); return USART_ReceiveData(USART1); // 读取接收数据 }c
运行
uint8_t USART1_RxBuffer; // 接收缓冲区(全局变量) uint8_t USART1_RxFlag = 0; // 接收完成标志 // USART1中断服务函数 void USART1_IRQHandler(void) { uint32_t temp_flag = 0; uint32_t temp_data = 0; /************************** 1. 检查接收中断标志 **************************/ if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { USART_ClearITPendingBit(USART1, USART_IT_RXNE); // 清除中断标志 USART1_RxBuffer = USART_ReceiveData(USART1); // 读取数据 USART1_RxFlag = 1; // 设置接收完成标志 } /************************** 2. 处理溢出错误(可选) **************************/ if (USART_GetITStatus(USART1, USART_IT_ORE) != RESET) { temp_flag = USART1->SR; // 读SR寄存器 temp_data = USART1->DR; // 读DR寄存器清除ORE标志 (void)temp_flag; // 避免未使用变量警告 (void)temp_data; } }c
运行
// 主函数中处理接收数据 int main(void) { USART1_Init(9600); // 初始化USART1,9600波特率 while (1) { if (USART1_RxFlag == 1) // 检测到接收完成 { USART1_SendChar(USART1_RxBuffer); // 回显接收到的字符 USART1_RxFlag = 0; // 清除标志 } } }c
运行
UART_HandleTypeDef huart1; // USART1初始化函数(CubeMX自动生成) void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 9600; huart1.Init.WordLength = UART_WORDLENGTH_8B; 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; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); // 初始化失败处理 } } // HAL_UART_Init回调函数(配置GPIO和中断) void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(uartHandle->Instance==USART1) { // 1. 使能时钟 __HAL_RCC_USART1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); // 2. 配置GPIO /* PA9 TX */ 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); /* PA10 RX */ GPIO_InitStruct.Pin = GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 3. 配置中断 HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(USART1_IRQn); } }c
运行
// 轮询发送单个字符 HAL_StatusTypeDef UART1_SendChar(uint8_t ch) { // HAL_UART_Transmit:阻塞发送,参数:句柄、数据指针、长度、超时时间 return HAL_UART_Transmit(&huart1, &ch, 1, 100); // 超时100ms } // 轮询发送字符串 HAL_StatusTypeDef UART1_SendString(uint8_t *str) { uint16_t len = 0; while (str[len] != '\0') len++; // 计算字符串长度 return HAL_UART_Transmit(&huart1, str, len, 100); }c
运行
// 轮询接收单个字符(阻塞式) HAL_StatusTypeDef UART1_ReceiveChar(uint8_t *ch) { // HAL_UART_Receive:阻塞接收,参数:句柄、数据指针、长度、超时时间 return HAL_UART_Receive(&huart1, ch, 1, 1000); // 超时1s }c
运行
uint8_t UART1_RxBuffer; // 接收缓冲区 uint8_t UART1_RxFlag = 0; // 接收完成标志 // 主函数中开启接收中断 HAL_UART_Receive_IT(&huart1, &UART1_RxBuffer, 1); // 开启单次接收中断 // 接收中断回调函数(HAL库自动调用) void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart->Instance == USART1) { UART1_RxFlag = 1; // 设置接收完成标志 // 重新开启接收中断(HAL库中断接收为单次,需手动重启) HAL_UART_Receive_IT(&huart1, &UART1_RxBuffer, 1); } } // USART1中断服务函数(CubeMX自动生成) void USART1_IRQHandler(void) { HAL_UART_IRQHandler(&huart1); // 调用HAL库中断处理函数 } // 主函数处理接收数据 int main(void) { HAL_Init(); SystemClock_Config(); MX_USART1_UART_Init(); HAL_UART_Receive_IT(&huart1, &UART1_RxBuffer, 1); // 开启首次接收中断 while (1) { if (UART1_RxFlag == 1) { HAL_UART_Transmit(&huart1, &UART1_RxBuffer, 1, 100); // 回显 UART1_RxFlag = 0; // 清除标志 } } }USART_ITConfig和 NVIC 配置;__enable_irq())__enable_irq());USART_Cmd(USART1, ENABLE)已执行;NVIC_IRQChannelCmd = ENABLE;HAL 库的HAL_UART_Receive_IT为单次中断,触发后需手动重启。
在HAL_UART_RxCpltCallback回调函数中重新调用HAL_UART_Receive_IT。
USART_FLAG_TXE或USART_FLAG_TC;STM32F103 串口通信实现的核心步骤为:
两种库的选择:标准外设库更接近底层,适合深入理解原理;HAL 库简化开发,适配 STM32Cube 生态,适合快速开发。实际项目中可根据需求选择,同时注意处理串口错误(如溢出、帧错误),提升通信稳定性。