Proteus8 + STM32CubeMX 实现 STM32F103R6 串口通信教程

通过简单的几个步骤,你就能让 STM32F103R6 实现串口通信,轻松发送和接收数据,甚至控制 LED 状态。

一、准备工作

1.1 所需软件

  • Proteus8(推荐 8.9 及以上版本)

  • STM32CubeMX(6.0 及以上版本)

  • Keil MDK-ARM(V5 或 V6 版本)

  • 串口调试助手(如 XCOM、SSCOM 等)

  • 虚拟串口工具(如 VSPD,用于仿真环境调试)

1.2 硬件模型

  • 核心芯片:STM32F103R6(中等容量 STM32F1 系列微控制器)

  • 辅助元件:虚拟串口模块、LED(用于状态指示)、晶振、电阻等

二、使用 STM32CubeMX 创建工程

2.1 新建工程并选择芯片

  1. 打开 STM32CubeMX,点击主界面的ACCESS TO MCU SELECTOR。

  2. 在搜索框输入STM32F103R6,在搜索结果中选择对应芯片(注意封装匹配,如 LQFP64),点击Start Project。

2.2 配置系统时钟

  1. 左侧导航栏选择RCC,在右侧配置界面中:
  • 高速外部时钟(HSE)选择Crystal/Ceramic Resonator(晶体振荡器)。
  1. 点击左侧Clock Configuration,配置系统时钟树:
  • PLL 源选择HSE,PLL 倍频系数设置为9(8MHz HSE → 72MHz 系统时钟)。

  • APB1 时钟分频设置为2(36MHz),APB2 时钟分频设置为1(72MHz)。

2.3 配置串口参数

  1. 左侧导航栏选择USART1,模式设置为Asynchronous(异步模式)。

  2. 配置串口基本参数:

  • 波特率:115200

  • 数据位:8 Bits

  • 停止位:1 Bit

  • 校验位:None(无奇偶校验)

  • 硬件流控:Disable(无硬件流控)

  1. 此时 PA9(USART1_TX)和 PA10(USART1_RX)会自动配置为串口功能,无需手动修改 GPIO 模式。

2.4 生成工程代码

  1. 点击菜单栏Project → Settings,设置:
  • Project Name:自定义工程名(如STM32_UART_Demo)

  • Project Location:选择保存路径

  • Toolchain/IDE:选择MDK-ARM

  1. 点击GENERATE CODE生成 Keil 工程,等待代码生成完成。

三、编写串口通信代码

在 Keil 中打开生成的工程,找到main.c文件,添加串口发送函数和主循环逻辑:

复制代码
#include "main.h"
#include <string.h>  // 需包含字符串处理库

UART_HandleTypeDef huart1;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);

/**
 * @brief  串口发送字符串函数
 * @param  huart: 串口句柄(如&huart1)
 * @param  str: 待发送的字符串
 */
void UART_SendString(UART_HandleTypeDef *huart, uint8_t *str)
{
  // 发送字符串,超时时间设为最大(HAL_MAX_DELAY)
  HAL_UART_Transmit(huart, str, strlen((char*)str), HAL_MAX_DELAY);
}

int main(void)
{
  // 初始化HAL库
  HAL_Init();
  
  // 配置系统时钟
  SystemClock_Config();
  
  // 初始化GPIO和USART1
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  
  // 定义发送和接收缓冲区
  uint8_t welcome_msg[] = "STM32F103R6 UART Example: Send any data\r\n";
  uint8_t rx_buf[100] = {0};  // 接收缓冲区
  uint8_t tx_buf[100] = {0};  // 发送缓冲区
  
  // 上电后发送欢迎消息
  UART_SendString(&huart1, welcome_msg);
  
  while (1)
  {
    // 接收数据(超时时间100ms)
    if (HAL_UART_Receive(&huart1, rx_buf, sizeof(rx_buf)-1, 100) == HAL_OK)
    {
      // 构建应答消息(将接收的数据回传)
      sprintf((char*)tx_buf, "Received: %s\r\n", rx_buf);
      
      // 发送应答消息
      UART_SendString(&huart1, tx_buf);
      
      // 清空接收缓冲区,准备下次接收
      memset(rx_buf, 0, sizeof(rx_buf));
    }
    
    // 短暂延时,降低CPU占用
    HAL_Delay(100);
  }
}

// 以下为自动生成的系统时钟、USART1和GPIO初始化代码(保持默认即可)
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  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();
  }

  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();
  }
}

static void MX_USART1_UART_Init(void)
{
  huart1.Instance = USART1;
  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();
  }
}

static void MX_GPIO_Init(void)
{
  // 可在此添加LED等GPIO的初始化代码(如PA0接LED)
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  __HAL_RCC_GPIOA_CLK_ENABLE();
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void Error_Handler(void)
{
  __disable_irq();
  while (1)
  {
    // 错误处理:可添加LED闪烁提示
    HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0);
    HAL_Delay(500);
  }
}

#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif

四、编译生成 Hex 文件

  1. 在 Keil 中点击工具栏的Build按钮(或按F7)编译工程。

  2. 编译成功后,在工程目录的Debug文件夹下会生成.hex文件(如STM32_UART_Demo.hex),用于后续 Proteus 仿真。

五、Proteus 仿真电路设计

5.1 新建 Proteus 工程

  1. 打开 Proteus8,点击New Project,输入工程名和路径,选择Create a schematic from scratch。

  2. 跳过 PCB 设计步骤(仅需仿真原理图),完成工程创建。

5.2 添加元件

点击界面左侧的Component Mode(P 图标),搜索并添加以下元件:

  • STM32F103R6(核心芯片)

  • COMPIM(虚拟串口模块)

  • RES(电阻,1kΩ)

  • LED(发光二极管)

  • CRYSTAL(晶振,8MHz)

  • CAP(电容,2 个 30pF,用于晶振;1 个 10uF,用于电源滤波)

  • POWER(电源接口)

  • GROUND(接地接口)

5.3 电路连接

  1. 核心电路连接:
  • STM32F103R6 的PA9(USART1_TX) → COMPIM的RXD

  • STM32F103R6 的PA10(USART1_RX) → COMPIM的TXD

  • 晶振两端分别连接OSC_IN(PA8)和OSC_OUT(PA9),并通过 30pF 电容接地

  • VDD和VSS分别连接电源和地,VDD 与地之间接 10uF 滤波电容

  1. 状态指示电路(可选):
  • LED 正极通过 1kΩ 电阻连接PA0,负极接地(用于指示系统运行状态)

5.4 配置虚拟串口

  1. 双击COMPIM模块,在弹出的配置窗口中:
  • Physical Port选择一个虚拟串口(如COM1,需与后续调试助手对应)

  • Baud Rate设置为115200,Data Bits为8,Stop Bits为1,Parity为None

  • 其他参数保持默认,点击OK保存。

六、仿真运行与调试

6.1 加载程序到 STM32

  1. 双击 Proteus 中的STM32F103R6芯片,在Program File选项中选择之前生成的.hex文件。

  2. 勾选Reset after Program,点击OK。

6.2 配置虚拟串口与调试助手

  1. 使用 VSPD 创建一对虚拟串口(如COM1和COM2,需确保未被占用)。

  2. 打开串口调试助手,选择与COMPIM配对的串口(如COM2),配置参数:

  • 波特率:115200

  • 数据位:8

  • 停止位:1

  • 校验位:无

  • 勾选发送新行(自动添加 \r\n)

6.3 运行仿真

  1. 点击 Proteus 界面左下角的Run Simulation按钮(三角形图标)启动仿真。

  2. 此时调试助手会收到 STM32 发送的欢迎消息:STM32F103R6 UART Example: Send any data。

  3. 在调试助手的发送框输入任意字符(如Hello UART),点击发送,会收到 STM32 的应答:Received: Hello UART。

  4. 若添加了 LED 电路,LED 会间隔 100ms 闪烁,指示系统正常运行。

七、常见问题解决

7.1 仿真无反应,无串口数据

  • 检查 Hex 文件是否正确加载(STM32 属性中确认 Program File 路径)。

  • 确认系统时钟配置(HSE 是否使能,PLL 倍频是否正确)。

  • 检查 Proteus 中 STM32 的电源和地是否连接正确。

7.2 串口通信失败,无应答

  • 确认COMPIM与调试助手的串口参数完全一致(波特率、校验位等)。

  • 检查 TX/RX 引脚是否交叉连接(STM32_TX → COMPIM_RX,STM32_RX → COMPIM_TX)。

  • 虚拟串口未正确创建:使用 VSPD 确认串口对已激活,且无占用冲突。

7.3 Keil 编译报错

  • 检查是否遗漏#include <string.h>(strlen和sprintf函数依赖)。

  • 确认 STM32CubeMX 生成的代码完整(未手动删除关键初始化函数)。

八、扩展应用

本教程实现了基础的串口回传功能,可扩展为:

  • 串口指令控制(如通过特定字符控制 LED 开关)

  • 传感器数据采集(如通过串口发送温湿度数据)

  • 与上位机通信(如 Python/Qt 编写的控制软件)

通过 Proteus 仿真验证后,可直接将代码烧录到实际硬件(STM32F103R6 开发板)进行测试,硬件电路需与仿真电路保持一致。

创作不易,如有帮助请点赞 + 收藏,欢迎留言交流技术问题!

相关推荐
ManThink Technology6 小时前
热计量表通过M-Bus接口实现无线集抄系统的几种解决方
物联网
KWTXX7 小时前
单片机键盘接口程序设计(汇编语言)
单片机·计算机外设·nosql
La Pulga8 小时前
【STM32】定时器输入捕获
c语言·stm32·单片机·嵌入式硬件·mcu
DebugKitty9 小时前
硬件开发1-51单片机3-串口
单片机·嵌入式硬件·51单片机·串口·全双工·同步通信·串口寄存器
殷忆枫10 小时前
基于STM32的智能家居语音控制系统设计
stm32·嵌入式硬件·智能家居
hazy1k10 小时前
8051单片机-成为点灯大师
驱动开发·嵌入式硬件·51单片机
weixin_4715257812 小时前
【单片机day02】
单片机·嵌入式硬件
翻斗花园牛姥姥13 小时前
51单片机GPIO与中断全解析
单片机·嵌入式硬件
三佛科技-1873661339716 小时前
辉芒微MCU需要熟悉哪些指令?这15条核心指令与入门要点必须掌握
单片机·嵌入式硬件