STM32F103C8T6串口通信程序实例,包含初始化、数据收发、中断处理和实用功能,基于HAL库开发。
代码实现
c
#include "stm32f1xx_hal.h"
/* 串口配置 */
#define USARTx USART1
#define USARTx_CLK_ENABLE() __HAL_RCC_USART1_CLK_ENABLE()
#define USARTx_RX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define USARTx_TX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define USARTx_FORCE_RESET() __HAL_RCC_USART1_FORCE_RESET()
#define USARTx_RELEASE_RESET() __HAL_RCC_USART1_RELEASE_RESET()
#define USARTx_TX_PIN GPIO_PIN_9
#define USARTx_TX_GPIO_PORT GPIOA
#define USARTx_TX_AF GPIO_AF1_USART1
#define USARTx_RX_PIN GPIO_PIN_10
#define USARTx_RX_GPIO_PORT GPIOA
#define USARTx_RX_AF GPIO_AF1_USART1
/* 缓冲区大小 */
#define RX_BUFFER_SIZE 128
#define TX_BUFFER_SIZE 128
/* UART句柄 */
UART_HandleTypeDef huart1;
/* 接收缓冲区 */
uint8_t rxBuffer[RX_BUFFER_SIZE];
uint16_t rxIndex = 0;
uint8_t rxReady = 0;
/* 发送缓冲区 */
uint8_t txBuffer[TX_BUFFER_SIZE];
/* 函数声明 */
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
void USART1_IRQHandler(void);
void ProcessReceivedData(uint8_t* data, uint16_t len);
void SendString(const char* str);
void SendData(uint8_t* data, uint16_t len);
void PrintHex(uint8_t* data, uint16_t len);
void PrintDecimal(uint32_t num);
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
/* 启动串口接收中断 */
HAL_UART_Receive_IT(&huart1, &rxBuffer[0], 1);
/* 发送欢迎信息 */
SendString("\r\nSTM32F103C8T6 UART Communication Demo\r\n");
SendString("Build Date: " __DATE__ " " __TIME__ "\r\n");
SendString("Enter commands (HELP for list):\r\n");
while (1) {
if (rxReady) {
/* 处理接收到的数据 */
ProcessReceivedData(rxBuffer, rxIndex);
/* 重置接收状态 */
rxIndex = 0;
rxReady = 0;
/* 重新启动接收 */
HAL_UART_Receive_IT(&huart1, &rxBuffer[0], 1);
}
/* 主循环中可以执行其他任务 */
HAL_Delay(100);
}
}
/* USART1初始化函数 */
static void MX_USART1_UART_Init(void) {
huart1.Instance = USARTx;
huart1.Init.BaudRate = 115200;
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();
}
}
/* UART底层硬件初始化 */
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
if (uartHandle->Instance == USARTx) {
/* USART1时钟使能 */
USARTx_CLK_ENABLE();
/* GPIOA时钟使能 */
USARTx_TX_GPIO_CLK_ENABLE();
USARTx_RX_GPIO_CLK_ENABLE();
/* USART1 GPIO配置 */
GPIO_InitStruct.Pin = USARTx_TX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = USARTx_RX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStruct);
/* USART1中断配置 */
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}
}
/* USART1中断服务函数 */
void USART1_IRQHandler(void) {
HAL_UART_IRQHandler(&huart1);
}
/* UART接收完成回调函数 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USARTx) {
if (rxBuffer[rxIndex] == '\r' || rxBuffer[rxIndex] == '\n') {
if (rxIndex > 0) {
rxReady = 1; // 标记数据接收完成
}
} else {
rxIndex++;
if (rxIndex >= RX_BUFFER_SIZE) {
rxIndex = 0; // 防止缓冲区溢出
}
}
/* 继续接收下一个字节 */
HAL_UART_Receive_IT(&huart1, &rxBuffer[rxIndex], 1);
}
}
/* 处理接收到的数据 */
void ProcessReceivedData(uint8_t* data, uint16_t len) {
/* 去除回车换行符 */
if (len > 0 && (data[len-1] == '\r' || data[len-1] == '\n')) {
data[len-1] = '\0';
if (len > 1 && (data[len-2] == '\r' || data[len-2] == '\n')) {
data[len-2] = '\0';
len--;
}
len--;
}
/* 命令处理 */
if (strcmp((char*)data, "HELP") == 0) {
SendString("\r\nAvailable Commands:\r\n");
SendString("HELP - Show this help\r\n");
SendString("VERSION - Show firmware version\r\n");
SendString("LED ON - Turn on onboard LED\r\n");
SendString("LED OFF - Turn off onboard LED\r\n");
SendString("TEMP - Read temperature (simulated)\r\n");
SendString("ECHO - Echo back received data\r\n");
SendString("HEX - Show hex dump of received data\r\n");
SendString("DEC - Convert to decimal\r\n");
}
else if (strcmp((char*)data, "VERSION") == 0) {
SendString("\r\nFirmware Version: 1.0.0\r\n");
SendString("MCU: STM32F103C8T6\r\n");
SendString("UART: 115200, 8N1\r\n");
}
else if (strcmp((char*)data, "LED ON") == 0) {
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); // 假设PC13是板载LED
SendString("\r\nLED turned ON\r\n");
}
else if (strcmp((char*)data, "LED OFF") == 0) {
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
SendString("\r\nLED turned OFF\r\n");
}
else if (strcmp((char*)data, "TEMP") == 0) {
// 模拟温度读数
uint16_t temp = 25 + (HAL_GetTick() % 100) / 10;
char msg[30];
sprintf(msg, "\r\nTemperature: %d.%d C\r\n", temp/10, temp%10);
SendString(msg);
}
else if (strncmp((char*)data, "ECHO ", 5) == 0) {
SendString("\r\nEcho: ");
SendData(data + 5, len - 5);
SendString("\r\n");
}
else if (strcmp((char*)data, "HEX") == 0) {
SendString("\r\nHex Dump: ");
PrintHex(data, len);
SendString("\r\n");
}
else if (strcmp((char*)data, "DEC") == 0) {
uint32_t num = 0;
for (uint16_t i = 0; i < len; i++) {
if (data[i] >= '0' && data[i] <= '9') {
num = num * 10 + (data[i] - '0');
}
}
SendString("\r\nDecimal: ");
PrintDecimal(num);
SendString("\r\n");
}
else if (len > 0) {
SendString("\r\nUnknown command. Type HELP for available commands.\r\n");
}
}
/* 发送字符串 */
void SendString(const char* str) {
HAL_UART_Transmit(&huart1, (uint8_t*)str, strlen(str), HAL_MAX_DELAY);
}
/* 发送数据 */
void SendData(uint8_t* data, uint16_t len) {
HAL_UART_Transmit(&huart1, data, len, HAL_MAX_DELAY);
}
/* 打印十六进制数据 */
void PrintHex(uint8_t* data, uint16_t len) {
char hexStr[3];
for (uint16_t i = 0; i < len; i++) {
sprintf(hexStr, "%02X ", data[i]);
SendString(hexStr);
}
}
/* 打印十进制数 */
void PrintDecimal(uint32_t num) {
char buffer[12];
sprintf(buffer, "%lu", num);
SendString(buffer);
}
/* GPIO初始化 */
static void MX_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/* 配置PC13为输出(板载LED) */
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* 初始关闭LED */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
}
/* 系统时钟配置 */
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/* 初始化RCC振荡器 */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
/* 初始化CPU、AHB和APB总线时钟 */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
Error_Handler();
}
}
/* 错误处理函数 */
void Error_Handler(void) {
while (1) {
/* 错误时闪烁LED */
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
HAL_Delay(200);
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line) {
/* 用户可在此添加断言失败处理 */
}
#endif
程序功能说明
1. 基本功能
- 串口初始化:115200bps, 8位数据位, 1位停止位, 无校验位
- 中断驱动的接收机制
- 支持命令交互式操作
- 实现基本的AT指令集
2. 支持的命令
| 命令 | 功能描述 |
|---|---|
| HELP | 显示可用命令列表 |
| VERSION | 显示固件版本信息 |
| LED ON | 打开板载LED |
| LED OFF | 关闭板载LED |
| TEMP | 读取模拟温度值 |
| ECHO [text] | 回显输入的文本 |
| HEX | 以十六进制显示接收的数据 |
| DEC | 将输入转换为十进制数并显示 |
3. 关键函数说明
串口初始化函数
c
static void MX_USART1_UART_Init(void)
- 配置USART1参数:115200bps, 8N1
- 设置硬件流控制为无
- 使用16倍过采样
中断处理
c
void USART1_IRQHandler(void)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
- 使用HAL库的中断处理机制
- 每接收到一个字节触发一次回调
- 检测回车/换行符判断命令结束
数据处理
c
void ProcessReceivedData(uint8_t* data, uint16_t len)
- 解析接收到的命令
- 执行相应操作并返回结果
- 支持多种实用功能
实用工具函数
c
void SendString(const char* str); // 发送字符串
void SendData(uint8_t* data, uint16_t len); // 发送二进制数据
void PrintHex(uint8_t* data, uint16_t len); // 十六进制打印
void PrintDecimal(uint32_t num); // 十进制打印
使用说明
1. 硬件连接
- PA9 (TX) → USB转串口模块的RX
- PA10 (RX) → USB转串口模块的TX
- GND → GND
- 3.3V → 3.3V (可选,如果模块需要供电)
2. 开发环境配置
- 使用STM32CubeMX创建工程
- 选择STM32F103C8Tx MCU
- 配置USART1为异步模式,115200bps
- 配置PA9为USART1_TX,PA10为USART1_RX
- 配置GPIOC Pin13为输出(板载LED)
- 配置系统时钟为72MHz
- 生成MDK-ARM或STM32CubeIDE工程
3. 编译烧录
- 将完整代码复制到工程中
- 编译工程
- 使用ST-Link或J-Link烧录到开发板
- 使用串口调试助手(如Putty、SecureCRT)连接开发板
4. 测试示例
c
STM32F103C8T6 UART Communication Demo
Build Date: Jun 15 2023 14:30:00
Enter commands (HELP for list):
> HELP
Available Commands:
HELP - Show this help
VERSION - Show firmware version
LED ON - Turn on onboard LED
LED OFF - Turn off onboard LED
TEMP - Read temperature (simulated)
ECHO - Echo back received data
HEX - Show hex dump of received data
DEC - Convert to decimal
> LED ON
LED turned ON
> TEMP
Temperature: 28.3 C
> ECHO Hello World!
Echo: Hello World!
> HEX
Hex Dump: 48 45 58 0D 0A
> DEC
Decimal: 1234
参考代码 STM32F103C8T6 串口通讯程序实例 www.youwenfan.com/contentcss/183130.html
扩展功能建议
-
添加DMA支持
c// 在MX_USART1_UART_Init后添加 HAL_UART_Receive_DMA(&huart1, rxBuffer, RX_BUFFER_SIZE); -
实现Modbus协议
cvoid ProcessModbusFrame(uint8_t* frame, uint16_t len) { // 实现Modbus RTU协议解析 } -
添加JSON支持
cvoid ParseJsonCommand(char* json) { // 使用cJSON库解析JSON命令 } -
实现固件升级功能
cvoid ProcessFirmwareUpdate(uint8_t* data, uint16_t len) { // 通过Ymodem协议实现OTA升级 } -
添加看门狗支持
cvoid MX_IWDG_Init(void) { hiwdg.Instance = IWDG; hiwdg.Init.Prescaler = IWDG_PRESCALER_32; hiwdg.Init.Reload = 4095; HAL_IWDG_Init(&hiwdg); }
常见问题解决
- 串口无输出
- 检查波特率是否匹配(115200)
- 确认TX/RX线序正确
- 检查开发板供电是否正常
- 使用示波器检查TX引脚是否有信号
- 接收数据乱码
- 检查系统时钟配置是否正确
- 确认外部晶振是否起振
- 尝试降低波特率测试
- 中断不触发
- 确认NVIC中断已启用
- 检查USART中断标志位
- 验证HAL_UART_Receive_IT调用是否正确
- 程序卡死
- 检查堆栈大小是否足够
- 确认没有死循环
- 添加看门狗复位机制