STM32 串口转 虚拟串口---实现USB转串口功能

news2025/7/9 9:45:21

一,USART与UART 区别

USART(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步串行接收/发送器

相较于UART:通用异步收发传输器(Universal Asynchronous Receiver/Transmitter)多了一个S,即synchronous(同步)。

也就是说UART相较于USART只是少了一个同步方式而已,而串口在嵌入式中经常使用,但是我们一般使用UART就够

这些操作可以在Cubemx下自动生成。

二,串口初始化

void MX_USART1_Init(void)
{

  husart1.Instance = USART1;
  husart1.Init.BaudRate = 115200;
  husart1.Init.WordLength = USART_WORDLENGTH_8B;
  husart1.Init.StopBits = USART_STOPBITS_1;
  husart1.Init.Parity = USART_PARITY_NONE;
  husart1.Init.Mode = USART_MODE_TX_RX;
  husart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  husart1.Init.OverSampling = UART_OVERSAMPLING_16;
  husart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  husart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&husart1) != HAL_OK)
  {
    Error_Handler();
  }
    
    //HAL_UART_Receive_IT(&husart1, (u8 *)aRxBuffer, RXBUFFERSIZE);//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量
    
    //HAL_UARTEx_ReceiveToIdle_IT(&husart1, (u8 *)aRxBuffer, RXBUFFERSIZE);//串口接收任意字长字符串
}

三。IO初始化,DMA通道的设置


void HAL_UART_MspInit(UART_HandleTypeDef* usartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(usartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */

  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
  			

		  GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
		
		/* USART1 DMA Init */
    /* USART1_RX Init */
    hdma_usart1_rx.Instance = DMA1_Channel5;
    hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_rx.Init.Mode = DMA_NORMAL;
    hdma_usart1_rx.Init.Priority = DMA_PRIORITY_HIGH;
    if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(usartHandle,hdmarx,hdma_usart1_rx);

    /* USART1_TX Init */
    hdma_usart1_tx.Instance = DMA1_Channel4;
    hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_tx.Init.Mode = DMA_NORMAL;
    hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(usartHandle,hdmatx,hdma_usart1_tx);

   
 #if EN_USART1_RX
		 /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 1,1);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
#endif	
  }
}

四。DMA 中断的设置,注意,如果USART或DMA的中断优先级被设置得太低,它们可能会被其他高优先级的中断延迟。

void MX_DMA_Init(void)
{

  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Channel4_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
  /* DMA1_Channel5_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);

}

 五,DMA中断服务函数 不定长接收

停止HAL_UART_DMAStop(&husart1);  


  dat_len =  sizeof(aRxBuffer) - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);     //计算接收到的数据长度
        
        USB_USART_Send(aRxBuffer,dat_len);//虚拟串口转发    
        dat_len = 0;//清零
         memset(aRxBuffer,0,sizeof(aRxBuffer)); //重置
        Error_code_uart1=HAL_UARTEx_ReceiveToIdle_DMA(&husart1, (u8 *)aRxBuffer, sizeof(aRxBuffer));//再次开启DMA

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) 
{
    
    if(huart->Instance==USART1)//如果是串口1
    {
        HAL_UART_DMAStop(&husart1);  
        dat_len =  sizeof(aRxBuffer) - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);     //计算接收到的数据长度
        
        USB_USART_Send(aRxBuffer,dat_len);//虚拟串口转发    
        dat_len = 0;
         memset(aRxBuffer,0,sizeof(aRxBuffer)); 
        Error_code_uart1=HAL_UARTEx_ReceiveToIdle_DMA(&husart1, (u8 *)aRxBuffer, sizeof(aRxBuffer));
    }
    
}
//串口1中断服务程序
void USART1_IRQHandler(void)                    
{     
    HAL_UART_IRQHandler(&husart1);    //调用HAL库中断处理公用函数    
} 
void DMA1_Channel4_IRQHandler(void)
{
 
  HAL_DMA_IRQHandler(&hdma_usart1_tx);
}

/**
  * @brief This function handles DMA1 channel5 global interrupt.
  */
void DMA1_Channel5_IRQHandler(void)
{
  HAL_DMA_IRQHandler(&hdma_usart1_rx);
}

六,初始化 及溢出错误处理

if (Error_code_uart1 != HAL_OK)//出错,重开
    {
        // 清空缓冲,置位一些标志,具体看函数内部
        HAL_UART_AbortReceive(&husart1);
        // 重启接收
        Error_code_uart1=HAL_UARTEx_ReceiveToIdle_DMA(&husart1, (u8 *)aRxBuffer, sizeof(aRxBuffer));
        }

int main(void)
{  
	u8 len;	
	

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init(); 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
	
	
	USB_Reset();       // USB断开再重连
	HAL_Delay(1);
	MX_USB_DEVICE_Init();
	MX_DMA_Init();
	MX_USART1_Init();

	HAL_Delay(2000);//等待虚拟串口初始化完成
	Error_code_uart1=HAL_UARTEx_ReceiveToIdle_DMA(&husart1, (u8 *)aRxBuffer, sizeof(aRxBuffer));
  while (1)
  {
		u8 usbstatus = 0;

    if (usbstatus != USB_GetStatus())
    {
        usbstatus = USB_GetStatus(); // 记录新的状态
    }
		if (Error_code_uart1 != HAL_OK)//出错,重开
    {
        // 清空缓冲,置位一些标志,具体看函数内部
        HAL_UART_AbortReceive(&husart1);
        // 重启接收
        Error_code_uart1=HAL_UARTEx_ReceiveToIdle_DMA(&husart1, (u8 *)aRxBuffer, sizeof(aRxBuffer));
		}
	}
  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2300440.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【进程与线程】Linux 线程、同步以及互斥

每个用户进程有自己的地址空间。 线程是操作系统与多线程编程的基础知识。 系统为每个用户进程创建一个 task_struct 来描述该进程:该结构体中包含了一个指针指向该进程的虚拟地址空间映射表: 实际上 task_struct 和地址空间映射表一起用来表示一个进程…

胶囊网络动态路由算法:突破CNN空间局限性的数学原理与工程实践

一、CNN的空间局限性痛点解析 传统CNN的瓶颈: 池化操作导致空间信息丢失(最大池化丢弃85%激活值)无法建模层次空间关系(旋转/平移等变换不敏感)局部感受野限制全局特征整合 示例对比: # CNN最大池化示例…

当pcie设备变化时centos是否会修改网络设备的名称(AI回答)

当pcie设备变化时centos是否会修改网络设备的名称 在CentOS(以及其他基于Linux的操作系统)中,网络接口的命名通常遵循特定的规则,尤其是在使用PCIe设备(如网络适配器)时。网络接口的命名通常基于设备的物理…

【做一个微信小程序】校园地图页面实现

前言 上一个教程我们实现了小程序的一些的功能,有背景渐变色,发布功能有的呢,已支持图片上传功能,表情和投票功能开发中(请期待)。下面是一个更高级的微信小程序实现,包含以下功能:…

Web后端 - Maven管理工具

一 Maven简单介绍 Maven是apache旗下的一个开源项目,是一款用于管理和构建java项目的工具。 Maven的作用 二 Maven 安装配置 依赖配置 依赖传递 依赖范围 生命周期 注意事项:在同一套生命周期中,当运行后面的阶段时,前面的阶段都…

20250217-POMO笔记

文章目录 前言一、伪代码一:POMO Training二、伪代码二:POMO Inference三、POMO注意力模型3.1、自注意力机制3.2、AM模型 前言 以下主要讲解两个算法的伪代码以及注意力模型。 一、伪代码一:POMO Training POMO Training是POMO模型训练的伪…

JavaEE-SpringBoot快速入门

文章目录 本节目标Maven什么是Maven创建一个Maven项目maven项目功能maven的依赖管理全球仓库, 私服, 本地服务器, 配置国内镜像 第一个SpringBoot项目创建项目运行SpringBoot程序 SpringBoot原理初步Web服务器 总结 本节目标 了解什么是maven, 配置国内源使用Springboot创建项…

游戏引擎学习第107天

仓库:https://gitee.com/mrxiao_com/2d_game_2 回顾我们之前停留的位置 在这段内容中,讨论了如何处理游戏中的三维效果,特别是如何处理额外的“Z层”。由于游戏中的艺术资源是位图而不是3D模型,因此实现三维效果变得非常具有挑战性。虽然可…

ComfyUI流程图生图原理详解

一、引言 ComfyUI 是一款功能强大的工具,在图像生成等领域有着广泛应用。本文补充一点ComfyUI 的安装与配置过程遇到的问题,并深入剖析图生图过程及相关参数,帮助读者快速入门并深入理解其原理。 二、ComfyUI 的安装与配置中遇到的问题 &a…

使用右侧值现象来处理一个word导入登记表的需求

需求也简单,导word文件用户登记表,有各部门的十几个版本(为什么这么多?不知道)。这里说下谈下我的一些代码做法: 需求分析: 如果能解决java字段和各项填的值怎么配对的问题,那么就…

《open3d pyqt》Alpha重建

《open3d pyqt》Alpha重建 一、效果展示二、qt设置2.1 主界面添加动作2.2 dialog 界面、布局如下:三、核心代码一、效果展示 二、qt设置 2.1 主界面添加动作 2.2 dialog 界面、布局如下: 并生成py文件,参考前述章节 三、核心代码 main.py文件增加 from Su

小程序canvas2d实现横版全屏和竖版逐字的签名组件(字帖式米字格签名组件)

文章标题 01 功能说明02 效果预览2.1 横版2.2 竖版 03 使用方式04 横向签名组件源码4.1 html 代码4.2 业务 Js4.3 样式 Css 05 竖向签名组件源码5.1 布局 Html5.2 业务 Js5.3 样式 Css 01 功能说明 技术栈:uniapp、vue、canvas 2d 需求: 实现横版的全…

MoE演变过程

MoE演变过程 1 MoE1.1 BasicMoE1.2 SparseMoE1.2.1 实现 1.3 Shared Expert SparseMoE 1 MoE 参考:https://huggingface.co/blog/zh/moe 1.1 BasicMoE 用router给出各专家的权重,然后让输入过每一个专家,然后做加权求和。 1.2 SparseMoE …

【实战项目】BP神经网络识别人脸朝向----MATLAB实现

(꒪ꇴ꒪ ),Hello我是祐言QAQ我的博客主页:C/C语言,数据结构,Linux基础,ARM开发板,网络编程等领域UP🌍快上🚘,一起学习,让我们成为一个强大的攻城狮&#xff0…

【1.8w字深入解析】从依赖地狱到依赖天堂:pnpm 如何革新前端包管理?

目录 前言npm 的诞生与发展嵌套依赖模型存在的问题npm3架构与yarnYarn 的诞生与局限Yarn 的诞生背景Yarn 仍然存在的问题 何为幽灵依赖依赖结构的不确定性pnpm王牌登场 -- 网状平铺结构安装包速度快依赖管理软链接 和 硬链接 机制 幽灵依赖产生的根本原因包管理工具的依赖解析机…

137,【4】 buuctf web [SCTF2019]Flag Shop

进入靶场 都点击看看 发现点击work会增加¥ 但肯定不能一直点下去 抓包看看 这看起来是一个 JWT(JSON Web Token)字符串。JWT 通常由三部分组成,通过点(.)分隔,分别是头部(Header&…

【c++】c++内存管理

目录 c和c的内存分布回顾C语言动态管理内存的方式malloccallocreallocfree C动态管理内存的方式new和deleteoperator new和operator delete定位new c和c的内存分布 回顾C语言动态管理内存的方式 malloc void* malloc (size_t size);malloc可以在堆上开辟指定内存的空间&#…

EtherNet/IP转Modbus TCP:新能源风电监控与分析实用案例

EtherNet/IP转Modbus TCP:新能源风电监控与分析实用案例 一、案例背景 在某新能源汽车电池生产线上,需要将采用EtherNet/IP协议的电池检测设备与采用ProfiNet协议的生产线控制系统进行集成,以实现对电池生产过程的全面监控和数据采集。 二、…

数字电路-基础逻辑门实验

基础逻辑门是数字电路设计的核心元件,它们执行的是基本的逻辑运算。通过这些基本运算,可以构建出更为复杂的逻辑功能。常见的基础逻辑门包括与门(AND)、或门(OR)、非门(NOT)、异或门…

国产编辑器EverEdit - 如虎添翼的功能:快速选择

1 快速选择 1.1 应用场景 快速选择适用于批量选择和修改的场景,比如:变量改名。 1.2 使用方法 1.2.1 逐项快速选择 将光标放置在单词前或单词中,选择主菜单查找 -> 快速选择 -> 快速选择或使用快捷键Ctrl D 注:光标放…