1. 串口通信基础与开发环境搭建
作为一名物联网开发者,掌握串口通信是必备技能。在STM32开发中,USART(通用同步异步收发器)是最常用的通信接口之一。本文将基于蓝桥杯CT127C开发板(主控STM32WLE5CCU6),详细介绍串口发送功能的完整实现过程。
1.1 硬件平台与开发工具
CT127C开发板采用STM32WLE5CCU6作为主控芯片,这是一款支持LoRa的无线微控制器。开发板仅有一个USB接口,同时承担供电、程序下载和串口通信三重功能。这种设计在节省空间的同时,也带来了一些配置上的特殊性。
开发环境需要准备:
- STM32CubeMX 6.9.0及以上版本
- Keil MDK 5.37及以上版本
- 串口调试助手(推荐SSCOM或野火串口助手)
注意:开发板通过CH443K模拟开关芯片实现串口通道切换,默认情况下SEL引脚为低电平,选择NODE A板的通信通道。比赛环境下无需手动配置此芯片。
1.2 串口通信核心参数
在开始配置前,必须明确以下关键参数:
- 通信模式:异步串行通信(UART)
- 波特率:115200bps(比特每秒)
- 数据位:8位
- 校验位:无
- 停止位:1位
- 流控:无
这些参数必须与串口调试助手完全匹配,否则会出现乱码。在嵌入式开发中,115200 8N1是最常用的配置组合。
2. STM32CubeMX工程配置详解
2.1 新建工程与芯片选择
- 启动STM32CubeMX,点击"ACCESS TO MCU SELECTOR"
- 在搜索框输入"STM32WLE5CCU6"
- 从右侧列表中选择对应型号,点击"Start Project"
提示:STM32WLE5CCU6是STM32WL系列中的一款芯片,集成了LoRa射频功能。虽然我们本次不涉及无线通信,但需要确保选择的芯片型号完全匹配开发板。
2.2 系统核心配置
2.2.1 调试接口配置
- 在左侧导航栏选择"System Core" → "SYS"
- 将"Debug"设置为"Serial Wire"
- 其余参数保持默认
这一步配置了SWD调试接口,对应开发板上的DAPLink调试器。如果漏配此选项,将无法通过Keil下载程序。
2.2.2 时钟配置
时钟配置是保证串口通信准确性的关键:
- 选择"System Core" → "RCC"
- 将"High Speed Clock (HSE)"设置为"Crystal/Ceramic Resonator"
- 切换到"Clock Configuration"标签页
- 按以下参数配置:
- HSE输入频率:32MHz(开发板晶振实际值)
- 系统主频:48MHz(芯片最大频率)
- USART2时钟源选择系统时钟
经验分享:波特率的准确性直接依赖于时钟配置。如果发现串口通信有误码,首先应该检查时钟树配置是否正确。
2.3 USART2外设配置
2.3.1 引脚功能映射
- 在芯片引脚图中找到PA2和PA3
- 分别设置为USART2_TX和USART2_RX
- 配置完成后,这两个引脚会显示为绿色
2.3.2 通信参数设置
- 选择"Connectivity" → "USART2"
- 配置参数如下:
- Mode: Asynchronous
- Baud Rate: 115200
- Word Length: 8 Bits
- Parity: None
- Stop Bits: 1
- Data Direction: Receive and Transmit
- Oversampling: 16 Samples
3. Keil工程开发与代码实现
3.1 工程生成与基础配置
在STM32CubeMX中完成配置后:
- 切换到"Project Manager"标签页
- 设置工程名称(避免使用中文和特殊字符)
- Toolchain/IDE选择"MDK-ARM V5"
- 在"Code Generator"中勾选"Generate peripheral initialization as a pair of '.c/.h' files per peripheral"
- 点击"GENERATE CODE"生成工程
工程生成后,用Keil打开并进行以下关键配置:
- 点击魔术棒图标打开工程选项
- 在"Target"标签页勾选"Use MicroLIB"
- 点击"OK"保存
避坑指南:不启用MicroLIB会导致printf函数无法正常工作,这是新手最常见的坑之一。MicroLIB是Keil针对嵌入式系统优化的精简C库,必须勾选。
3.2 代码架构设计
我们采用模块化设计,将串口相关功能封装在独立的app.c和app.h文件中:
3.2.1 app.h头文件
c复制#ifndef __APP_H
#define __APP_H
#include "stm32wlxx_hal.h"
#include "string.h"
void uart2_send_string(const unsigned char *Data);
#endif
这个头文件做了三件事:
- 防止重复包含的保护宏
- 包含必要的库头文件
- 声明串口发送函数
3.2.2 app.c源文件
c复制#include "app.h"
#include "stdio.h"
extern UART_HandleTypeDef huart2;
void uart2_send_string(const unsigned char *Data)
{
HAL_UART_Transmit(&huart2, Data, strlen((const char *)Data), 0xFFFF);
}
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart2, (unsigned char *)&ch, 1, 0xFFFF);
return ch;
}
这里实现了两个关键功能:
- 字符串发送封装函数
- printf重定向函数
技术细节:fputc是C标准库中printf的底层输出函数,重写它后,所有printf输出都会通过串口发送。0xFFFF是超时时间,单位是毫秒。
3.3 主程序实现
在main.c中添加以下代码:
c复制#include "app.h"
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART2_UART_Init();
uint8_t test_cnt = 0;
while (1)
{
uart2_send_string((unsigned char *)"【CT127C】串口测试\r\n");
printf("测试计数: %d\r\n", test_cnt++);
HAL_Delay(1000);
}
}
这段代码实现了:
- 初始化HAL库和所有外设
- 每秒发送一次测试字符串和计数
- 使用\r\n实现串口换行
4. 调试与验证
4.1 串口助手配置
- 打开串口调试助手
- 选择正确的COM口(在设备管理器中查看)
- 设置参数:115200波特率,8数据位,无校验,1停止位
- 点击打开串口
4.2 常见问题排查
-
无输出:
- 检查开发板供电
- 确认程序已下载
- 验证串口线连接
- 检查Keil中是否启用了MicroLIB
-
乱码:
- 确认波特率等参数匹配
- 检查时钟配置是否正确
- 验证串口助手设置
-
数据不完整:
- 检查发送缓冲区大小
- 确认串口线质量
- 降低波特率测试
调试技巧:在初期调试时,可以先用简单的字符串测试,如"Hello World",确认基本通信正常后再进行复杂数据发送。
5. 进阶应用与优化
5.1 发送性能优化
默认的HAL_UART_Transmit是阻塞式发送,会影响系统实时性。可以考虑以下优化:
- 使用DMA传输
- 实现环形缓冲区
- 采用中断方式发送
5.2 数据格式化
利用printf的格式化功能,可以方便地发送各种数据:
c复制float voltage = 3.3;
printf("电压值: %.2fV\r\n", voltage);
uint32_t timestamp = HAL_GetTick();
printf("系统运行时间: %lums\r\n", timestamp);
5.3 多串口管理
当需要同时使用多个串口时,建议采用统一接口:
c复制typedef enum {
UART_1,
UART_2,
UART_3
} UART_Port;
void uart_send_string(UART_Port port, const char *data);
这种封装可以提高代码的可维护性和可移植性。
在实际项目中,串口通信往往需要处理更复杂的协议,如Modbus、AT指令等。掌握了基础发送功能后,可以进一步学习这些协议的实现方法。