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

一,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));
		}
	}
  
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

将OpenWrt部署在x86服务器上

正文共:1234 字 40 图,预估阅读时间:2 分钟 如果你问ChatGPT有哪些开源的SD-WAN方案,他会这样答复你: 我们看到,OpenWrt也属于比较知名的开源SD-WAN解决方案。当然,在很久之前,我就发…

EtherNetIP转ModbusTCP网关,给风电注入“超级赛亚人”能量

EtherNetIP转ModbusTCP网关,给风电注入“超级赛亚人”能量 在工业通信领域,常常需要将不同网络协议的设备和系统连接起来,以实现更高效的数据交互和系统集成。比如,把EtherNet/IP设备及其网络连接到ModbusTCP网络系统&#xff0c…

【LeetCode】438.找到字符串中所有的字母异位词

目录 题目题目要求什么是“异位词”?如何快速判断两个字符串是否是“异位词”? 解法 滑动窗口 哈希表 (统计个数)核心思路具体步骤 代码 题目 题目链接:LeetCode-438题 给定两个字符串 s 和 p,找到 s 中所…

【设计模式】【结构型模式】装饰者模式(Decorator)

👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD 🔥 2025本人正在沉淀中… 博客更新速度 👍 欢迎点赞、收藏、关注,跟上我的更新节奏 🎵 当你的天空突…

基于Ubuntu+vLLM+NVIDIA T4高效部署DeepSeek大模型实战指南

一、 前言:拥抱vLLM与T4显卡的强强联合 在探索人工智能的道路上,如何高效地部署和运行大型语言模型(LLMs)一直是一个核心挑战。尤其是当我们面对资源有限的环境时,这个问题变得更加突出。原始的DeepSeek-R1-32B模型虽…

Windows环境搭建ES集群

搭建步骤 下载安装包 下载链接:https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.17.27-windows-x86_64.zip 解压 解压并复制出3份 es-node1配置 config/elasticsearch.yml cluster.name: xixi-es-win node.name: node-1 path.data: D:\\wor…

STM32 I2C通信协议说明

目录 背景 I2C协议 数据的有效性 I2C通信开始和停止条件 I2C数据传输 发送 响应 正常情况: 异常情况: 主机结束接收 写寄存器的标准流程 读寄存器的标准流程 仲裁机制 时钟同步 SDA线的仲裁 程序 背景 对单片机的三大通信中的I2C通信进…

Unity学习part2

为bilibili教程【【Unity教程】零基础带你从小白到超神】 https://www.bilibili.com/video/BV1gQ4y1e7SS/?p50&share_sourcecopy_web&vd_source6e7a3cbb802eb986578ad26fae1eeaab的笔记 1、灯光的使用 定向光模拟太阳,是平行光。旋转定向光,光…

Vue 实现主题切换(明暗)

项目地址:https://gitee.com/abcdfdewrw/vue3_xiaohongshu_project 效果展示: 步骤1:定义明暗scss样式 // 浅色模式 html[data-theme"light"]:root {--header-height: 72px;--color-border-bottom: #eef2f9;--color-primary-lab…

rabbitmq五种模式的总结——附java-se实现(详细)

rabbitmq五种模式的总结 完整项目地址:https://github.com/9lucifer/rabbitmq4j-learning 一、简单模式 (一)简单模式概述 RabbitMQ 的简单模式是最基础的消息队列模式,包含以下两个角色: 生产者:负责发…

数据结构 day02

3. 线性表 3.1. 顺序表 3.1.3. 顺序表编程实现 操作:增删改查 .h 文件 #ifndef __SEQLIST_H__ #define __SEQLIST_H__ #define N 10 typedef struct seqlist {int data[N];int last; //代表数组中最后一个有效元素的下标 } seqlist_t;//1.创建一个空的顺序表 seq…

STM32的HAL库开发---ADC

一、ADC简介 1、ADC,全称:Analog-to-Digital Converter,指模拟/数字转换器 把一些传感器的物理量转换成电压,使用ADC采集电压,然后转换成数字量,经过单片机处理,进行控制和显示。 2、常见的AD…

25/2/16 <算法笔记> DirectPose

DirectPose 是一种直接从图像中预测物体的 6DoF(位姿:6 Degrees of Freedom)姿态 的方法,包括平移和平面旋转。它在目标检测、机器人视觉、增强现实(AR)和自动驾驶等领域中具有广泛应用。相比于传统的位姿估…

企业级API集成方案:基于阿里云函数计算调用DeepSeek全解析

解决方案链接:https://www.aliyun.com/solution/tech-solution/deepseek-r1-for-platforms?utm_contentg_1000401616 何为DeepSeek R1 DeepSeek R1模型有诸多技术优势。高效架构设计使其能更高效提取特征,减少冗余计算,提升数据处理速度、…

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

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

ThinkPHP8视图赋值与渲染

【图书介绍】《ThinkPHP 8高效构建Web应用》-CSDN博客 《2025新书 ThinkPHP 8高效构建Web应用 编程与应用开发丛书 夏磊 清华大学出版社教材书籍 9787302678236 ThinkPHP 8高效构建Web应用》【摘要 书评 试读】- 京东图书 在控制器操作中,使用view函数可以传入视图…

渗透利器:YAKIT 工具-基础实战教程.

YAKIT 工具-基础实战教程. YAKIT(Yak Integrated Toolkit)是一款基于Yak语言开发的集成化网络安全单兵工具,旨在覆盖渗透测试全流程,提供从信息收集、漏洞扫描到攻击实施的自动化支持。其核心目标是通过GUI界面降低Yak语言的使用…

Fiori APP配置中的Semantic object 小bug

在配置自开发程序的Fiori Tile时,需要填入Semantic Object。正常来说,是需要通过事务代码/N/UI2/SEMOBJ来提前新建的。 但是在S4 2022中,似乎存在一个bug,即无需新建也能输入自定义的Semantic Object。 如下,当我们任…

shell——分支语句

文章目录 基本语法常用判断条件(1)两个整数之间比较(2)按照文件权限进行判断(3)按照文件类型进行判断(4)多条件判断(&& 表示前一条命令执行成功时,才执行后一条命令&#xf…

Ubuntu 连接 air pods

1. sudo vim /etc/bluetooth/main.conf , 修改蓝牙模式为blder 2.sudo /etc/init.d/bluetooth restart, 重启蓝牙,即可连接成功