✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进

❤欢迎关注我的知乎:对error视而不见

代码获取、问题探讨及文章转载可私信。

☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。

🍎获取更多嵌入式资料可点击链接进群领取,谢谢支持!👇

点击领取更多详细资料

一、引言

在嵌入式系统开发中,串口通信是一种常见且重要的通信方式。STM32 系列微控制器凭借其高性能、低功耗等特点,被广泛应用于各种领域。利用 STM32 的串口通信功能,可以实现与其他设备的数据交互,如传感器数据采集、与上位机通信等。本文将详细介绍 STM32 串口通信的原理、硬件连接、软件配置,并给出具体的代码示例,帮助读者掌握 STM32 串口通信的发送与接收信息功能。

二、串口通信原理

串口通信(Serial Communication)是指数据一位一位地按顺序传输,其特点是通信线路简单,只要一对传输线就可以实现双向通信,从而大大降低了成本,特别适用于远距离通信,但传输速度较慢。

在异步串口通信中,数据以帧为单位进行传输,每帧包含起始位、数据位、奇偶校验位(可选)和停止位。起始位通常为低电平,用于标志一帧数据的开始;数据位可以是 5、6、7 或 8 位,用于传输实际的数据;奇偶校验位用于检测数据传输过程中是否发生错误;停止位通常为高电平,用于标志一帧数据的结束。

三、硬件连接

以 STM32F103C8T6 为例,其 USART1 的 TX 引脚为 PA9,RX 引脚为 PA10。在进行串口通信时,需要将 STM32 的 TX 引脚连接到外部设备的 RX 引脚,将 STM32 的 RX 引脚连接到外部设备的 TX 引脚,同时要确保两者的地(GND)连接在一起,以提供统一的参考电位。

此外,为了实现与计算机的通信,还需要一个 USB 转串口模块,如 CH340 或 CP2102,将串口信号转换为 USB 信号,以便计算机能够识别。

四、软件配置

在进行软件配置之前,需要使用 STM32CubeMX 工具进行初始化配置。以下是具体的配置步骤:

  1. 创建新项目:选择合适的 STM32 芯片型号,如 STM32F103C8T6。
  2. 配置 RCC:选择外部晶振作为时钟源,配置系统时钟。一般将系统时钟设置为 72MHz。
  3. 配置 USART:选择要使用的串口,如 USART1,将模式设置为异步通信(Asynchronous),波特率设置为 115200,数据位为 8 位,停止位为 1 位,无校验位。
  4. 配置 GPIO:STM32CubeMX 会自动将与串口相关的 GPIO 引脚(PA9 和 PA10)配置为复用推挽输出(TX)和浮空输入(RX)。
  5. 生成代码:选择 Keil MDK 作为开发环境,生成代码。
五、代码实现

以下是一个完整的 STM32 串口通信发送与接收信息的代码示例:

#include "main.h"
#include "stm32f1xx_hal.h"

UART_HandleTypeDef huart1;

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

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();

  char send_data[] = "Hello, STM32 Serial Communication!\r\n";
  char receive_data[20];

  while (1)
  {
    // 发送数据
    HAL_UART_Transmit(&huart1, (uint8_t *)send_data, sizeof(send_data), 1000);

    // 接收数据
    HAL_UART_Receive(&huart1, (uint8_t *)receive_data, sizeof(receive_data), 1000);

    // 处理接收到的数据
    if (receive_data[0] != '\0') {
      // 这里可以添加对接收到数据的处理逻辑
      HAL_UART_Transmit(&huart1, (uint8_t *)receive_data, sizeof(receive_data), 1000);
    }

    HAL_Delay(1000);
  }
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != 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)
{
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
}

void Error_Handler(void)
{
  while(1)
  {
  }
}
六、代码解释
  1. 初始化部分

    • HAL_Init():初始化 HAL 库,为后续的硬件操作提供基础。
    • SystemClock_Config():配置系统时钟,确保芯片以正确的时钟频率运行。
    • MX_GPIO_Init():初始化 GPIO 引脚,将与串口相关的引脚配置为合适的模式。
    • MX_USART1_UART_Init():初始化 USART1 串口,设置波特率、数据位、停止位等参数。
  2. 数据发送

    • HAL_UART_Transmit(&huart1, (uint8_t *)send_data, sizeof(send_data), 1000);:使用 HAL 库提供的函数将 send_data 数组中的数据发送出去。&huart1 是串口句柄,(uint8_t *)send_data 是要发送的数据指针,sizeof(send_data) 是数据的长度,1000 是超时时间(单位:毫秒)。
  3. 数据接收

    • HAL_UART_Receive(&huart1, (uint8_t *)receive_data, sizeof(receive_data), 1000);:使用 HAL 库提供的函数接收数据,并将其存储在 receive_data 数组中。
  4. 数据处理

    • if (receive_data[0] != '\0'):判断是否接收到了数据。如果接收到了数据,则可以在这个条件语句中添加具体的处理逻辑。这里只是简单地将接收到的数据再次发送出去。
七、注意事项
  1. 波特率匹配:STM32 的串口波特率必须与外部设备的波特率一致,否则会导致数据传输错误。
  2. 数据长度:在接收数据时,要确保接收缓冲区的大小足够大,避免数据溢出。
  3. 超时时间HAL_UART_TransmitHAL_UART_Receive 函数中的超时时间需要根据实际情况进行调整,避免因等待时间过长或过短而影响通信效果。
八、总结

通过以上步骤和代码示例,我们可以实现 STM32 的串口通信发送与接收信息功能。在实际应用中,还可以根据具体需求对代码进行扩展,如使用中断方式进行数据接收,以提高系统的实时性;或者实现更复杂的数据处理逻辑,以满足不同的应用场景。掌握 STM32 串口通信技术,对于嵌入式系统开发具有重要的意义。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐