stm32单线串口(空闲中断+DMA接收+阻塞式发送)模式控制舵机

这篇文章描述单线串口怎么用?

一、基本介绍:单线+上拉+开漏输出

【STM32的TTL逻辑电平是3.3V,因此拉高到3.3V】

单线串口是一种采用单根数据线(有时会共用一根地线)进行半双工异步串行通信的接口。它的核心工作原理是在一根线(原先TX/RX中的TX引脚承担收发功能上分时复用发送和接收数据,并通过特定的时序协议来协调通信,从而节省硬件引脚资源。

其主要工作原理和关键点如下:

  1. 硬件基础 单线通信:仅使用一根信号线(如DATA)传输数据。通常需要一根公共的参考地线(GND)。
    开漏输出 :总线上通常采用开漏输出结构,需要外接一个上拉电阻 (如4.7kΩ)将总线电平拉到高电平(如VCC)。这样,多个设备可以"线与"在总线上,任何设备都可以将总线拉低(输出0) ,而释放总线时由上拉电阻拉高(输出1),实现了多主机通信的基础。
  2. 通信逻辑与电平 两种状态:总线只有两种逻辑状态:高电平(通常代表逻辑'1')和低电平(通常代表逻辑'0')。 逻辑'0':由主机或从机主动将总线拉低产生。 逻辑'1':由设备释放总线,由上拉电阻拉高产生。在空闲状态下,总线保持高电平。

二、cubemx配置:



生成的代码串口初始化部分如下:

c 复制代码
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    usart.c
  * @brief   This file provides code for the configuration
  *          of the USART instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2026 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usart.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

UART_HandleTypeDef huart2;

/* USART2 init function */

void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_HalfDuplex_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */

}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART2)
  {
  /* USER CODE BEGIN USART2_MspInit 0 */

  /* USER CODE END USART2_MspInit 0 */
    /* USART2 clock enable */
    __HAL_RCC_USART2_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART2 GPIO Configuration
    PA2     ------> USART2_TX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USART2 interrupt Init */
    HAL_NVIC_SetPriority(USART2_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART2_IRQn);
  /* USER CODE BEGIN USART2_MspInit 1 */

  /* USER CODE END USART2_MspInit 1 */
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==USART2)
  {
  /* USER CODE BEGIN USART2_MspDeInit 0 */

  /* USER CODE END USART2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART2_CLK_DISABLE();

    /**USART2 GPIO Configuration
    PA2     ------> USART2_TX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2);

    /* USART2 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART2_IRQn);
  /* USER CODE BEGIN USART2_MspDeInit 1 */

  /* USER CODE END USART2_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

三、代码实现单线串口发送功能

c 复制代码
int main(void)
{
    SystemClock_Config();
    MX_GPIO_Init();
    MX_USART2_UART_Init();
    while (1)
    {
		HAL_Delay(1000);
		HAL_HalfDuplex_EnableTransmitter(&huart2);
		HAL_UART_Transmit(&huart2, (uint8_t*)"Test\n", 5, 100);
		HAL_HalfDuplex_EnableReceiver(&huart2);
    }

}

测试OK

这是单线串口分析仪

有数据时,黄色LED亮,否则熄灭;

**

四、单总线+串口空闲中断+DMA接收+发送实现回显测试

**

测试结果OK

配置步骤

1-cubemx配置单线串口+DMA接收+空闲中断




2-代码实现main函数初始化部分的,开启DMA接收和中断

3-代码实现中断函数处理

4-业务逻辑实现回显

五、全部代码

usart.c

c 复制代码
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    usart.c
  * @brief   This file provides code for the configuration
  *          of the USART instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2026 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usart.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_usart2_rx;

/* USART2 init function */

void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_HalfDuplex_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */

}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART2)
  {
  /* USER CODE BEGIN USART2_MspInit 0 */

  /* USER CODE END USART2_MspInit 0 */
    /* USART2 clock enable */
    __HAL_RCC_USART2_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART2 GPIO Configuration
    PA2     ------> USART2_TX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USART2 DMA Init */
    /* USART2_RX Init */
    hdma_usart2_rx.Instance = DMA1_Stream5;
    hdma_usart2_rx.Init.Channel = DMA_CHANNEL_4;
    hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart2_rx.Init.Mode = DMA_NORMAL;
    hdma_usart2_rx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_usart2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_usart2_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart2_rx);

    /* USART2 interrupt Init */
    HAL_NVIC_SetPriority(USART2_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART2_IRQn);
  /* USER CODE BEGIN USART2_MspInit 1 */

  /* USER CODE END USART2_MspInit 1 */
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==USART2)
  {
  /* USER CODE BEGIN USART2_MspDeInit 0 */

  /* USER CODE END USART2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART2_CLK_DISABLE();

    /**USART2 GPIO Configuration
    PA2     ------> USART2_TX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2);

    /* USART2 DMA DeInit */
    HAL_DMA_DeInit(uartHandle->hdmarx);

    /* USART2 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART2_IRQn);
  /* USER CODE BEGIN USART2_MspDeInit 1 */

  /* USER CODE END USART2_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

usart.h

c 复制代码
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    usart.h
  * @brief   This file contains all the function prototypes for
  *          the usart.c file
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2026 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USART_H__
#define __USART_H__

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

extern UART_HandleTypeDef huart2;

/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */

void MX_USART2_UART_Init(void);

/* USER CODE BEGIN Prototypes */

/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif

#endif /* __USART_H__ */

在stm32f4xx_it.c里实现这个

c 复制代码
int single_rx2_len = 0;
uint8_t single_rx2_buff[100] = 0;
int single_rx2_complete = 0;
void USART2_IRQHandler(void)
{

  if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE) != RESET)
  {
        HAL_UART_DMAStop(&huart2);
      __HAL_UART_CLEAR_IDLEFLAG(&huart2);
      // 计算接收到的数据长度
      single_rx2_len = sizeof(single_rx2_buff) - __HAL_DMA_GET_COUNTER(huart2.hdmarx);
      // 设置标志
      single_rx2_complete = 1;
      // 重要:在NORMAL模式下,必须重新启动DMA
      HAL_UART_Receive_DMA(&huart2, single_rx2_buff, sizeof(single_rx2_buff));
    }    
    /* USER CODE END USART2_IRQn 0 */
    HAL_UART_IRQHandler(&huart2);
}

在业务逻辑文件里,比如USER_TASK.c里实现

c 复制代码
extern int single_rx2_len ;
extern uint8_t single_rx2_buff[100] ;
extern int single_rx2_complete ;
void single_rx2_handler(void)
{
    if(single_rx2_complete)
    {
            HAL_HalfDuplex_EnableTransmitter(&huart2);
            HAL_UART_Transmit(&huart2, single_rx2_buff, single_rx2_len, 100);
           

        single_rx2_complete = 0;
        single_rx2_len = 0;
        memset(single_rx2_buff,0,100);
         HAL_HalfDuplex_EnableReceiver(&huart2);    
    }
}

在主函数里:

相关推荐
雾削木2 小时前
STM32HAL输入捕获定时器测量PWM频率和占空比
stm32·单片机·嵌入式硬件
FreakStudio2 小时前
一行命令搞定驱动安装!MicroPython 开发有了自己的 “PyPI”包管理平台!
python·stm32·单片机·嵌入式·arm·电子diy
forAllforMe2 小时前
基于STM32+LAN9252的ether CAT 开发环境搭建
stm32·单片机·嵌入式硬件
半空扫地僧一枚3 小时前
10期:转速模式 (Speed Mode) 和 扭矩模式 (Torque Mode)
单片机·嵌入式硬件·汽车
爱上珍珠的贝壳5 小时前
ESP32-S3-CAM:接MAX98357A+喇叭播放音频
嵌入式硬件·音频·esp32-s3·喇叭·max98357a
敬畏_上帝6 小时前
PCtolLCD2002完美版下载以及教程
单片机·嵌入式硬件
学嵌入式的小杨同学6 小时前
STM32 进阶封神之路(五):库函数移植全解析 —— 从底层原理到移植实操(含环境适配 + 报错解决)
vscode·单片机·嵌入式硬件·代理模式·智能硬件·pcb工艺·嵌入式实时数据库
天月风沙7 小时前
幻尔总线舵机测试板BusLinker V2.5 控制代码
单片机·嵌入式硬件·机器人·舵机
somi77 小时前
51单片机-01-基础概念
单片机·嵌入式硬件·学习·51单片机