12_STM32Cubeide开发_USB从设备串口驱动程序

本文介绍了如何使用STM32CubeIDE配置和修改驱动程序,以实现USB从设备作为串口的功能。通过cubeMX配置时钟、USB硬件参数和堆栈大小,然后修改驱动程序,包括接收和发送协议、头文件和应用程序,实现USB通信。实验表明,上位机的波特率可任意设置,仍能正常通信。

一、USB相关介绍

通用串行总线(英语:Universal Serial Bus,缩写:USB)是一种串口总线标准,也是一种输入输出接口的技术规范,被广泛地应用于个人电脑和移动设备等信息通讯产品,并扩展至摄影器材、数字电视(机顶盒)、游戏机等其它相关领域。最新一代是USB4,传输速度为40Gbit/s。
stm32f103单片机内部自带USB外设,但是最高只支持USB2.0,并且只可以作为从设备来使用。
在这里插入图片描述
从电路原理、所用元器件来看,USB可以直接连单片机,
但是,我们设计单片机的串口电路时候,通常在USB和单片机(使用串口功能)之间会添加一个串口转换转换芯片(比如CH340等),
USB接口可以衍化出很多高级功能,远远比串口通信功能强大得多。

二、cubeMX配置

1.时钟配置

在这里插入图片描述

2.USB硬件参数配置

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

3.USB驱动程序配置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
只会影响电脑上的设备属性,不影响使用。

4.重新设置堆栈空间大小

在这里插入图片描述

三、驱动程序的修改

在这里插入图片描述
此时生成的初始化和中断的代码已经生成,用户发送和接收数据只需要调用两个函数就可以(也可以进行修改,实现自定义的通讯协议和功能)

in8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len);
uin8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len);

类似于串口功能中的发送和接收一个字节数据的串口相关函数。

主要修改下图中的两个文件
在这里插入图片描述

1.接收和发送的相关协议修改配置

注:以下是在usbd_desc.c文件中修改

1)定义接收缓存区USB_RX_BUF和自定义接收标志USB_RX_STA

在这里插入图片描述

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
uint8_t USB_RX_BUF[USB_REC_LEN];//接收缓冲,最大USB_REC_LEN个字节.
uint16_t USB_RX_STA=0;//接收状态标记(接收到的有效字节数量)
/* USER CODE END PV */

2)将接收到的数据一一放进缓存区中

在这里插入图片描述

static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
  /* USER CODE BEGIN 6 */
	if(*Len<USB_REC_LEN)//判断收到数据量是否小于寄存器上限
	{
	   uint16_t i;
	   USB_RX_STA = *Len;//将数据量值放入标志位
	   for(i=0;i<*Len;i++)//循环(循环次数=数据数量)
		   USB_RX_BUF[i] = Buf[i];//将数据内容放入数据寄存器
	}
  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);  //将接收数组buff清空
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);  //再次开启虚拟串口接收
  return (USBD_OK);
  /* USER CODE END 6 */
}

3)将需要发送的数据发送(先判断空闲才能发送,调用的都是底层寄存器)

在这里插入图片描述

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
  uint8_t result = USBD_OK;
  /* USER CODE BEGIN 7 */

  uint32_t TimeStart = HAL_GetTick();
  USBD_CDC_HandleTypeDef *hcdc =  (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
  //if (hcdc->TxState != 0) return  USBD_BUSY;
  while(hcdc->TxState)
  {
     if(HAL_GetTick()-TimeStart > 10)
    	 return USBD_BUSY;
     else
    	 break;
  }
  USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf,  Len);
  result =  USBD_CDC_TransmitPacket(&hUsbDeviceFS);
  TimeStart = HAL_GetTick();
  while(hcdc->TxState)
	{
		if(HAL_GetTick()-TimeStart > 10)
		return USBD_BUSY;
	}
  /* USER CODE END 7 */
  return result;
}

4)自定义USB_printf()发送函数

在这里插入图片描述

/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */
#include <stdarg.h>
void USB_printf(const char *format, ...)//USB模拟串口的打印函数
{
    va_list args;
    uint32_t length;
    va_start(args, format);
    length = vsnprintf((char  *)UserTxBufferFS, APP_TX_DATA_SIZE, (char  *)format, args);
    va_end(args);
    CDC_Transmit_FS(UserTxBufferFS, length);
}
/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */

2.头文件中相关修改

注:以下是在usbd_desc.h文件中修改
在这里插入图片描述

/* USER CODE BEGIN INCLUDE */
#define USB_REC_LEN   200//定义USB串口最大接收字节数
extern uint8_t USB_RX_BUF[USB_REC_LEN];//接收缓冲,最大USB_REC_LEN个字节.末字节为换行符
extern uint16_t USB_RX_STA;//接收状态标记(接收到的有效字节数量)
/* USER CODE END INCLUDE */

自定义函数声明
在这里插入图片描述

/* USER CODE BEGIN EXPORTED_FUNCTIONS */
void USB_printf(const char *format,  ...);//USB模拟串口的打印函数
/* USER CODE END EXPORTED_FUNCTIONS */

四、main.c中应用程序的修改

1.头文件的包含

在这里插入图片描述

/* USER CODE BEGIN Includes */
#include "../../USB_DEVICE/App/usbd_cdc_if.h"
#include "../../icode/led/led.h"
/* USER CODE END Includes */

2.while()中循环

在这里插入图片描述

		//USB模拟串口的查寻接收处理(其编程原理与USART1串口收发相同)
		if(USB_RX_STA!=0)//判断是否有数据
		{
			USB_printf("USB_RX:");//向USB模拟串口发送字符串
			CDC_Transmit_FS(USB_RX_BUF,USB_RX_STA);//USB串口发送:将接收的数据发回给电脑端(参数1是数据内容,参数2是数据量)
			USB_printf("\r\n");//向USB模拟串口发送字符串(回车)
			USB_RX_STA=0;//数据标志位清0
			memset(USB_RX_BUF,0,sizeof(USB_RX_BUF));//USB串口数据寄存器清0
		}

五、实验现象

可以像之前的串口程序一样使用,但是上位机的波特率似乎是任意值,都可以正常使用。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值