USB驱动之CDC类的介绍与应用20160905

时间:2021-10-17 16:10:30

USB的协议其实是很复杂的,如果要深入学习估计要一两年才能熟悉透。本文主要是讲如何使用官方已经写好的库进行二次开发,以达到我们自己使用的目的。我们知道USB可以用来接U盘,声卡,读卡器,鼠标键盘等等,这里主要是讲USB接口用来当虚拟串口使用,这个VCP(虚拟串口)是通过USB的CDC(通信设备类)类来实现的,本文是基于CPU是STM32F4的USB来讲解的:

1.安装和使用STM32 CubeMx软件:

    该软件是STM官方提供的图形化配置底层驱动的软件,可生成工程与代码,可去官方下载安装:

1)安装后如下界面:

 USB驱动之CDC类的介绍与应用20160905

2)接下来再点击菜单栏中的help选择安装库:

 USB驱动之CDC类的介绍与应用20160905

我们使用的是F4的底层库,该库为HAL库,不再是以前STM32的标准库,大约到2014年左右,ST在标准库的基础上又推出了HAL库。实际上,HAL库和标准库本质上是一样的,都是提供底层硬件操作API,而且在使用上也是大同小异。有过标准库基础的同学对HAL库的使用也很容易入手。个人认为ST官方之所以这几年大力推广HAL库,是因为HAL的结构更加容易整合STM32Cube,而STM32CubeMX是ST这几年极力推荐的程序生成开发工具。所以这两年新出的STM32芯片,ST直接只提供HAL库。在新型的STM32芯片中,用HAL库逐步淘汰标准库。

3)选择自己的mcu型号,选择好后双击打开:

 USB驱动之CDC类的介绍与应用20160905

4)配置RCC,USB等:

 USB驱动之CDC类的介绍与应用20160905

5)配置时钟树,根据自己硬件情况:

 USB驱动之CDC类的介绍与应用20160905

6)点击工具栏的生成代码工具,注意填写的堆栈空间要大一点,防止空间不够的意外:

 USB驱动之CDC类的介绍与应用20160905

点击OK后生成工程代码,可以下载测试验证,接下我们来分析生成的代码,并修改成自己想要的:

2.分析与修改代码:

1)生成的代码我们首先来看,初始化USB功能的

 USB驱动之CDC类的介绍与应用20160905

点击其中的Init

 USB驱动之CDC类的介绍与应用20160905

这里是关键,主要的功能是把CDC类的功能和我们用户要调用的_fops_FS函数都注册到USB的设备类里,这样在USB内核运行的时候就会调动我们注册进去的函数,点击USBD_Interface_fops_FS进去,这里面的函数指针 指向的函数就是我们需要使用和修改的了

 USB驱动之CDC类的介绍与应用20160905

函数在如下文件中:

 USB驱动之CDC类的介绍与应用20160905

2)我们修改这个文件:

首先在里面定义个串口属性的结构体:

USBD_CDC_LineCodingTypeDef linecoding =

  {

    USB_VIRTUAL_COM_BAUDRATE, /* baud rate*/

    0x00,   /* stop bits-1*/

    0x00,   /* parity - none*/

    0x08    /* nb. of bits 8*/

  };

然后修改CDC_Control_FS函数:

{

  /* USER CODE BEGIN 5 */

  switch (cmd)

  {

  case CDC_SEND_ENCAPSULATED_COMMAND:

  break;

 case CDC_GET_ENCAPSULATED_RESPONSE:

  break;

 case CDC_SET_COMM_FEATURE:

  break;

  case CDC_GET_COMM_FEATURE:

  break;

 case CDC_CLEAR_COMM_FEATURE:

 break;

 

  /*******************************************************************************/

  /* Line Coding Structure                                                       */

  /*-----------------------------------------------------------------------------*/

  /* Offset | Field       | Size | Value  | Description                          */

  /* 0      | dwDTERate   |   4  | Number |Data terminal rate, in bits per second*/

  /* 4      | bCharFormat |   1  | Number | Stop bits                            */

  /*                                        0 - 1 Stop bit                       */

  /*                                        1 - 1.5 Stop bits                    */

  /*                                        2 - 2 Stop bits                      */

  /* 5      | bParityType |  1   | Number | Parity                               */

  /*                                        0 - None                             */

  /*                                        1 - Odd                              */

  /*                                        2 - Even                             */

  /*                                        3 - Mark                             */

  /*                                        4 - Space                            */

  /* 6      | bDataBits  |   1   | Number Data bits (5, 6, 7, 8 or 16).          */

  /*******************************************************************************/

  case CDC_SET_LINE_CODING:

    linecoding.bitrate    = (uint32_t)(pbuf[0] | (pbuf[1] << 8) |\

                            (pbuf[2] << 16) | (pbuf[3] << 24));

    linecoding.format     = pbuf[4];

    linecoding.paritytype = pbuf[5];

    linecoding.datatype   = pbuf[6];

      /* Add your code here */

    break;

 

  case CDC_GET_LINE_CODING:

    pbuf[0] = (uint8_t)(linecoding.bitrate);

    pbuf[1] = (uint8_t)(linecoding.bitrate >> 8);

    pbuf[2] = (uint8_t)(linecoding.bitrate >> 16);

    pbuf[3] = (uint8_t)(linecoding.bitrate >> 24);

    pbuf[4] = linecoding.format;

    pbuf[5] = linecoding.paritytype;

    pbuf[6] = linecoding.datatype;    

     /* Add your code here */

    break;

 case CDC_SET_CONTROL_LINE_STATE:

 break;

 case CDC_SEND_BREAK:

  break;   

 default:

    break;

  }

return (USBD_OK);

  /* USER CODE END 5 */

}

3)基本配置完毕,接下来就是发送和接收的,发送主要调用CDC_Transmit_FS函数:

 USB驱动之CDC类的介绍与应用20160905

 

示例:

 USB驱动之CDC类的介绍与应用20160905

很简单吧,由于我们的USB是从端,PC是主端,这里发送最后是写入到一个BUF里,PC会主动过来查询并读取.

继续看接收,接收的我们在CDC_Receive_FS函数加入自己的代码即可

 USB驱动之CDC类的介绍与应用20160905

示例:

 USB驱动之CDC类的介绍与应用20160905

到此,我们就完成了USB的配置,发送,接收等,最后看下效果:

PC装上stm的官方USB VCP驱动,然后连上电脑:

 USB驱动之CDC类的介绍与应用20160905

通信结果OK:

 USB驱动之CDC类的介绍与应用20160905