STM32F103C8T6 串口通信程序实例

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. 开发环境配置

  1. 使用STM32CubeMX创建工程
  2. 选择STM32F103C8Tx MCU
  3. 配置USART1为异步模式,115200bps
  4. 配置PA9为USART1_TX,PA10为USART1_RX
  5. 配置GPIOC Pin13为输出(板载LED)
  6. 配置系统时钟为72MHz
  7. 生成MDK-ARM或STM32CubeIDE工程

3. 编译烧录

  1. 将完整代码复制到工程中
  2. 编译工程
  3. 使用ST-Link或J-Link烧录到开发板
  4. 使用串口调试助手(如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

扩展功能建议

  1. 添加DMA支持

    c 复制代码
    // 在MX_USART1_UART_Init后添加
    HAL_UART_Receive_DMA(&huart1, rxBuffer, RX_BUFFER_SIZE);
  2. 实现Modbus协议

    c 复制代码
    void ProcessModbusFrame(uint8_t* frame, uint16_t len) {
      // 实现Modbus RTU协议解析
    }
  3. 添加JSON支持

    c 复制代码
    void ParseJsonCommand(char* json) {
      // 使用cJSON库解析JSON命令
    }
  4. 实现固件升级功能

    c 复制代码
    void ProcessFirmwareUpdate(uint8_t* data, uint16_t len) {
      // 通过Ymodem协议实现OTA升级
    }
  5. 添加看门狗支持

    c 复制代码
    void MX_IWDG_Init(void) {
      hiwdg.Instance = IWDG;
      hiwdg.Init.Prescaler = IWDG_PRESCALER_32;
      hiwdg.Init.Reload = 4095;
      HAL_IWDG_Init(&hiwdg);
    }

常见问题解决

  1. 串口无输出
    • 检查波特率是否匹配(115200)
    • 确认TX/RX线序正确
    • 检查开发板供电是否正常
    • 使用示波器检查TX引脚是否有信号
  2. 接收数据乱码
    • 检查系统时钟配置是否正确
    • 确认外部晶振是否起振
    • 尝试降低波特率测试
  3. 中断不触发
    • 确认NVIC中断已启用
    • 检查USART中断标志位
    • 验证HAL_UART_Receive_IT调用是否正确
  4. 程序卡死
    • 检查堆栈大小是否足够
    • 确认没有死循环
    • 添加看门狗复位机制
相关推荐
IT方大同4 小时前
(实时操作系统)线程管理
c语言·开发语言·嵌入式硬件
意法半导体STM325 小时前
【官方原创】STM32H7双核芯片通过 STlink连接失败问题分析 LAT1654
开发语言·前端·javascript·stm32·单片机·嵌入式硬件
夜星辰20235 小时前
MobaXterm会话窗口详解
嵌入式硬件·ssh·调试串口
BT-BOX5 小时前
第7章《Stm32CubeMX+Proteus仿真入门》--独立按键扫描
stm32·嵌入式硬件·proteus
广药门徒5 小时前
PADS 等长处理方法
嵌入式硬件
zd8451015006 小时前
ESP8266 MQTT连接onenet
stm32·单片机
3壹7 小时前
STM32按键检测与上拉电阻详解
c语言·stm32·嵌入式硬件
昵称只能一个月修改一次。。。7 小时前
【无标题】
单片机·嵌入式硬件
AI+程序员在路上7 小时前
新手进入嵌入式行业方法与方向选择
c语言·开发语言·单片机·嵌入式硬件