搜索

[RISC-V MCU 应用开发] 第八十二章、CH32V103应用教程——USB模拟CDC

[复制链接]
67|1
 楼主 | 2021-3-15 14:08 | 显示全部楼层 |阅读模式
本帖最后由 RISCVLAR 于 2021-3-15 14:08 编辑

CH32V103应用教程——USB模拟CDC

本章教程主要使用CH32V103 USB模拟CDC设备(串口)与电脑上位机(串口调试助手)进行通信,实现数据收发。

1、USB简介及相关函数介绍
CH32V103芯片内嵌 USB 主从控制器及收发器,特性如下:
  • 支持 USB Host 主机功能和 USB Device 设备功能。
  • 支持 USB2.0 全速 12Mbps 或者低速 1.5Mbps。
  • 支持 USB 控制传输、批量传输、中断传输、同步/实时传输。
  • 支持最大 64 字节的数据包,内置 FIFO,支持中断和 DMA。

USB相关寄存器分为3个部分,部分寄存器是在主机和设备模式下进行复用的。三个部分分别如下:
  • USB全局寄存器
  • USB设备控制寄存器
  • USB主机控制寄存器

关于USB具体信息,可参考CH32V103应用手册。对于USB感兴趣的朋友,可参考电脑圈圈的《圈圈教你玩USB》,里面对USB各种描述符的介绍以及USB的枚举过程介绍的都挺详细,很适合初学者入门学习,本人最近也在进行USB的学习,本程序很多描述符配置都是根据《圈圈教你玩USB》的介绍来的,有不懂地方可以去参考这本书。关于程序中USB设备传输过程,可结合CH32V103应用手册的寄存器介绍来看,更便于理解学习。

2、硬件设计
本章教程主要进行USB模拟CDC实验,仅需用到开发板USB口。

3软件设计
本章程序全在主函数中进行,具体程序如下:
main.c文件
  1. /********************************** (C) COPYRIGHT *******************************
  2. * File Name          : main.c
  3. * Author             : WCH
  4. * Version            : V1.0.0
  5. * Date               : 2019/10/15
  6. * Description        : Main program body.
  7. *******************************************************************************/
  8. /*
  9. *@Note
  10. 模拟自定义USBCDC设备例程:
  11. */

  12. #include "debug.h"
  13. #include "string.h"

  14. /*Global Variable*/
  15. #define DevEP0SIZE  0x40

  16. /*Device Descriptor*/
  17. const UINT8  MyDevDescr[] =
  18. {
  19.         0x12,           //设备描述符长度,18字节
  20.         0x01,           //描述符类型,0x01为设备描述符
  21.         0x10,0x01,      //本设备所使用USB版本协议,因为是小端结构,所以低字节在前,即USB1.1版本为0x10,0x01,USB2.0为0x00,0x02
  22.         0x02,           //类代码,CDC类为0x02,CDC类必须在设备描述符中指定设备类型,即0x02,否则,由于在配置集合中有两个接口,而会被系统误认为一个USB复合设备,从而导致设备工作不正常
  23.         //当指定了设备类型为通信设备类后,子类和所使用的协议都必须指定为0.
  24.         0x00,           //子类代码,当类代码bDeviceClass为0时,下面的子类代码bDeviceSubClass也必须为0。
  25.         0x00,           //设备所使用的协议,协议代码由USB协会规定。当该字段为0时,表示设备不使用类所定义的协议。
  26.         DevEP0SIZE,     //端点0的最大包长,可以取值8、16、32、64,此处为64字节
  27.         0x86,0x1a,      //厂商ID
  28.         0x22,0x57,      //产品设备ID
  29.         0x00,0x01,      //设备版本号
  30.         0x01,           //描述厂商的字符串索引值。当该值为0时,表示没有厂商字符串
  31.         0x02,           //描述产品的字符串索引值。当该值为0时,表示没有产品字符串
  32.         0x03,           //描述设备的序列号字符串索引值。当该值为0时,表示没有序列号字符串
  33.         0x01,           //可能的配置数,通常为1
  34. };

  35. /* Configration Descriptor */
  36. const UINT8  MyCfgDescr[] =
  37. {
  38.         //配置描述符(两个接口)
  39.         0x09,          //配置描述符长度,标准USB配置描述符长度为9字节
  40.         0x02,          //描述符类型,配置描述符为0x02
  41.         0x43,0x00,     //配置描述符集合总长度,67字节
  42.         0x02,          //该配置所支持的接口数,2个接口
  43.         0x01,          //表示该配置的值
  44.         0x00,          //描述该配置的字符串的索引值,0x00表示没有字符串
  45.         0xa0,          //描述设备的一些属性,如供电方式和唤醒等,0xA0表示设备总线供电且支持远程唤醒
  46.         0x32,          //设备需要从总线获取的最大电流量,0x32表示最大电流100ma

  47.         //以下为接口0(CDC接口)描述符,接口描述符不能单独返回,必须附着在配置描述符后一并返回
  48.         0x09,          //接口描述符长度,标准的USB接口描述符长度为9字节
  49.         0x04,          //描述符类型,接口描述符为0x04
  50.         0x00,          //该接口的编号,从0开始,此处为0x00
  51.         0x00,          //该接口的备用编号,通常设置为0
  52.         0x01,          //该接口所使用的端点数,0x01表示使用1个端点。如果该字段为0,则表示没有非0端点,只使用默认的控制端点。CDC接口只使用一个中断输入端点
  53.         0x02,          //该接口所使用的类,0x02为CDC类
  54.         0x02,          //该接口所使用的子类,要实现USB转串口,就必须使用Abstract Control Model(抽象控制模型)子类,它的编号为0x02
  55.         0x01,          //该接口所使用的协议,使用Common AT Commands(通用AT命令)协议
  56.         0x00,          //该接口的字符串的索引值,0x00表示没有字符串


  57.         //以下为类特殊接口描述符
  58.         //功能描述符,主要用来描述接口的功能,功能描述符放在CDC接口(主接口)之后
  59.         //Header Functional Descriptor
  60.         0x05,          //该功能描述符的长度,5个字节
  61.         0x24,          //该描述符的类型,固定位0x24(CS_INTERFACE的编码)
  62.         0x00,          //该描述符子类型
  63.         0x10,0x01,     //USB通信设备协议的版本号。此处为USB1.1

  64.         //管理描述符(没有数据类接口)
  65.         //Call Management Functional Descriptor
  66.         0x05,          //该功能描述符的长度,5个字节
  67.         0x24,          //该描述符的类型,固定位0x24(CS_INTERFACE的编码)
  68.         0x01,          //该描述符子类型
  69.         0x00,          //描述设备的能力,只有最低两位D0和D1有意义,其余位为保留值0。D0为0,表示设备自己不处理调用管理,为1则表示自己处理。
  70.         0x00,          //表示选择用来做调用管理的数据类接口编号,由于不使用数据类接口做调用管理,因而该字段设置为0

  71.         //Abstract Control Management Functional Descriptor  抽象控制管理功能描述符
  72.         0x04,          //该功能描述符的长度,4个字节
  73.         0x24,          //该描述符的类型,固定位0x24(CS_INTERFACE的编码)
  74.         0x02,          //该描述符子类型
  75.         0x02,          //描述设备的能力,其中D7-4位为保留位,设置为0,支持Set_Line_Coding、Set_Control_Line_State、Get_Line_Coding请求和Serial_State通知
  76.                        //D0表示是否支持以下请求:Set_Comm_Feature、Clear_Comm_Feature、Get_Comm_Feature,为1表示支持;
  77.                        //D1位表示是否支持Set_Line_Coding、Set_Control_Line_State、Get_Line_Coding请求和Serial_State通知,为1表示支持
  78.                        //D2为表示是否支持Send_Break,为1表示支持
  79.                        //D3表示是否支持Network_Connection通知,为1表示支持

  80.         //Union Functional Descriptor,至少5字节,他描述一组接口之间的关系可以被当作为一个功能单元来看待,这些接口一个作为主接口,其他作为从接口
  81.         0x05,          //该功能描述符的长度,5个字节
  82.         0x24,          //该描述符的类型,固定位0x24(CS_INTERFACE的编码)
  83.         0x06,          //该描述符子类型
  84.         0x00,          //第四字节为主接口编号,此处为编号为0的CDC接口
  85.         0x01,          //第五字节为第一从接口编号,此处为编号1的数据类接口,本例程只有一个从接口

  86.         //接口0(CDC接口)的端点描述符
  87.         0x07,          //端点描述符长度,7字节
  88.         0x05,          //描述符类型,端点描述符为0x05
  89.         0x81,          //该端点的地址,0x81表示端点1作为输入
  90.         0x03,          //该端点的属性。最低两位D1-0表示该端点的传输类型,0为控制传输,1为等时传输,2为批量传输,3为中断传输
  91.         0x40,0x00,     //该端点支持的最大包长度,64字节
  92.         0xFF,          //端点的查询时间

  93.         //以下为接口1(数据接口)描述符
  94.         //CDC类接口(接口0)是负责管理整个设备的,而真正的串口数据传输是在数据类接口进行的。这里只使用一个数据类接口,编号为1
  95.         0x09,          //接口描述符长度,9字节
  96.         0x04,          //描述符类型,接口描述符为0x04
  97.         0x01,          //该接口的编号,从0开始,此处为0x01
  98.         0x00,          //该接口的备用编号
  99.         0x02,          //该接口所使用的端点数,该接口要使用一对批量传输端点,因而端点数量为2
  100.         0x0a,          //该接口所使用的类,0x0a为CDC数据类
  101.         0x00,          //该接口所使用的子类
  102.         0x00,          //该接口所使用的协议
  103.         0x00,          //该接口的字符串的索引值,0x00表示没有字符串

  104.         //接口1(数据类接口)的端点描述符
  105.         0x07,          //端点描述符长度,7字节
  106.         0x05,          //描述符类型,端点描述符为0x05
  107.         0x02,          //该端点的地址,0x02表示端点2作为输出
  108.         0x02,          //该端点的属性。最低两位D1-0表示该端点的传输类型,0为控制传输,1为等时传输,2为批量传输,3为中断传输
  109.         0x40,0x00,     //该端点支持的最大包长度,64字节
  110.         0x00,          //端点的查询时间,这里对批量端点无效

  111.         0x07,          //端点描述符长度,7字节
  112.         0x05,          //描述符类型,端点描述符为0x05
  113.         0x82,          //该端点的地址,0x82表示端点2作为输入
  114.         0x02,          //该端点的属性。最低两位D1-0表示该端点的传输类型,0为控制传输,1为等时传输,2为批量传输,3为中断传输
  115.         0x40,0x00,     //该端点支持的最大包长度,64字节
  116.         0x00,          //端点的查询时间,这里对批量端点无效
  117. };

  118. const UINT8  MyProductIDInfo[] = {0x14,0x03,0x32,0x00,0x30,0x00,0x31,0x00,0x37,0x00,0x2D,0x00,0x32,0x00,0x2D,0x00,0x32,0x00,0x35,0x00};

  119. /* Language Descriptor */
  120. const UINT8  MyLangDescr[] = { 0x04, 0x03, 0x09, 0x04 };

  121. /* Manufactor Descriptor */
  122. const UINT8  MyManuInfo[] = { 0x0E, 0x03, 'w', 0, 'c', 0, 'h', 0, '.', 0, 'c', 0, 'n', 0 };

  123. /* Product Information */
  124. const UINT8  MyProdInfo[] = { 0x0C, 0x03, 'C', 0, 'H', 0, '1', 0, '0', 0, 'x', 0 };

  125. /**********************************************************/
  126. UINT8   Ready = 0;
  127. UINT8   UsbConfig;
  128. UINT8   SetupReqCode;
  129. UINT16  SetupReqLen;

  130. //CDC参数
  131. UINT8 LineCoding[7]={0x00,0xe1,0x00,0x00,0x00,0x00,0x08};   //初始化波特率为57600,1停止位,无校验,8数据位。

  132. #define  SET_LINE_CODING                0x20            //Configures DTE rate, stop-bits, parity, and number-of-character
  133. #define  GET_LINE_CODING                0x21            //This request allows the host to find out the currently configured line coding.
  134. #define  SET_CONTROL_LINE_STATE         0x22            //This request generates RS-232/V.24 style control signals.
  135. #define  UART_REV_LEN                   0x40            //串口接收缓冲区大小

  136. UINT8 Receive_Uart_Buf[UART_REV_LEN];   //串口接收缓冲区
  137. volatile UINT8 Uart_Input_Point = 0;    //循环缓冲区写入指针,总线复位需要初始化为0
  138. volatile UINT8 Uart_Output_Point = 0;   //循环缓冲区取出指针,总线复位需要初始化为0
  139. volatile UINT8 UartByteCount = 0;       //当前缓冲区剩余待取字节数
  140. volatile UINT8 USBByteCount = 0;        //代表USB端点接收到的数据
  141. volatile UINT8 USBBufOutPoint = 0;      //取数据指针
  142. volatile UINT8 UpPoint2_Busy  = 0;      //上传端点是否忙标志

  143. const UINT8 *pDescr;

  144. /* Endpoint Buffer */
  145. __attribute__ ((aligned(4))) UINT8 EP0_Databuf[64];     //ep0(64)
  146. __attribute__ ((aligned(4))) UINT8 EP1_Databuf[64+64];  //ep1_out(64)+ep1_in(64)
  147. __attribute__ ((aligned(4))) UINT8 EP2_Databuf[64+64];  //ep2_out(64)+ep2_in(64)

  148. void USBHD_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

  149. /*******************************************************************************
  150. * Function Name  : Set_USBConfig
  151. * Description    : Set USB clock.
  152. * Input          : None
  153. * Return         : None
  154. *******************************************************************************/
  155. void USBHD_ClockCmd(UINT32 RCC_USBCLKSource,FunctionalState NewState)
  156. {
  157.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, NewState);
  158.     EXTEN->EXTEN_CTR |= EXTEN_USBHD_IO_EN;
  159.     RCC_USBCLKConfig(RCC_USBCLKSource);             //USBclk=PLLclk/1.5=48Mhz
  160.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBHD,NewState);
  161. }

  162. /*******************************************************************************
  163. * Function Name  : USB_DevTransProcess
  164. * Description    : USB device transfer process.
  165. * Input          : None
  166. * Return         : None
  167. *******************************************************************************/
  168. void USB_DevTransProcess( void )
  169. {
  170.     UINT8  len, chtype,i;
  171.     UINT8  intflag, errflag = 0;

  172.     intflag = R8_USB_INT_FG;         //USB中断标志寄存器

  173.     if( intflag & RB_UIF_TRANSFER )  //USB传输完成中断标志位
  174.     {
  175.         //R8_USB_INT_ST:USB中断状态寄存器   MASK_UIS_TOKEN:设备模式下,当前USB传输事务的令牌PID标识   MASK_UIS_ENDP:设备模式下,当前USB传输事务的端点号
  176.         switch ( R8_USB_INT_ST & ( MASK_UIS_TOKEN | MASK_UIS_ENDP ) )
  177.         {
  178.             //前面描述符配置中数据接口使用端点2进行数据输入输出
  179.             case UIS_TOKEN_OUT | 2:
  180.                 if (R8_USB_INT_FG & RB_U_TOG_OK)                                    //不同步的数据包将丢弃,RB_U_TOG_OK:当前USB传输DATA0/1同步标志匹配状态位
  181.                 {
  182.                     USBByteCount = R8_USB_RX_LEN;                                   //R8_USB_RX_LEN:当前USB端点接收的数据字节数
  183.                     for(i=0; i<USBByteCount; i++)
  184.                     {
  185.                         pEP2_IN_DataBuf[i] = pEP2_OUT_DataBuf[i];
  186.                     }
  187.                     R8_UEP2_T_LEN = USBByteCount;                                   //R8_UEP2_T_LEN:端点2发送长度
  188.                     R8_UEP2_CTRL = (R8_UEP2_CTRL & ~MASK_UEP_T_RES)| UEP_T_RES_ACK; //MASK_UEP_T_RES:端点2的发送器对IN事务的响应控制
  189.                     R8_USB_INT_FG = RB_UIF_TRANSFER;                                //USB传输完成中断标志位,写 1 清零
  190.                 }
  191.                 break;

  192.             case UIS_TOKEN_IN | 2:
  193.                 R8_UEP2_CTRL = (R8_UEP2_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
  194.                 R8_USB_INT_FG = RB_UIF_TRANSFER;
  195.                 break;
  196.             case UIS_TOKEN_SETUP:
  197.                 R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_NAK;
  198.                 len = R8_USB_RX_LEN;

  199.                 //获取一系列描述符
  200.                 if ( len == sizeof( USB_SETUP_REQ ) )
  201.                 {
  202.                     SetupReqLen = pSetupReqPak->wLength;
  203.                     SetupReqCode = pSetupReqPak->bRequest;
  204.                     chtype = pSetupReqPak->bRequestType;

  205.                     len = 0;
  206.                     errflag = 0;
  207.                     if ( ( pSetupReqPak->bRequestType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )  //判断是否为标准请求
  208.                     {
  209.                         //若不是标准请求
  210.                         switch(SetupReqCode)
  211.                         {
  212.                             case GET_LINE_CODING:         //currently configured
  213.                                 pDescr = LineCoding;
  214.                                 len = sizeof(LineCoding);
  215.                                 len = SetupReqLen >= DEFAULT_ENDP0_SIZE ? DEFAULT_ENDP0_SIZE : SetupReqLen;  // 本次传输长度
  216.                                 memcpy(pEP0_DataBuf,pDescr,len);
  217.                                 pDescr += len;
  218.                                 break;
  219.                             case SET_CONTROL_LINE_STATE:  //0x22  generates RS-232/V.24 style control signals
  220.                                 break;
  221.                             case SET_LINE_CODING:         //0x20  Configure
  222.                                 break;
  223.                             default:
  224.                                 errflag = 0xFF;
  225.                         }
  226.                     }
  227.                     else
  228.                     {
  229.                         //若是标准请求
  230.                         switch( SetupReqCode )
  231.                         {
  232.                             case USB_GET_DESCRIPTOR:                   //获取描述符
  233.                             {
  234.                                 switch( ((pSetupReqPak->wValue)>>8) )
  235.                                 {
  236.                                     case USB_DESCR_TYP_DEVICE:         //设备描述符
  237.                                         pDescr = MyDevDescr;
  238.                                         len = MyDevDescr[0];
  239.                                         break;

  240.                                     case USB_DESCR_TYP_CONFIG:         //配置描述符
  241.                                         pDescr = MyCfgDescr;
  242.                                         len = MyCfgDescr[2];
  243.                                         break;

  244.                                     case USB_DESCR_TYP_STRING:         //字符串描述符
  245.                                         switch( (pSetupReqPak->wValue)&0xff )
  246.                                         {
  247.                                             case 1:
  248.                                                 pDescr = MyManuInfo;   //厂商信息
  249.                                                 len = MyManuInfo[0];
  250.                                                 break;

  251.                                             case 2:
  252.                                                 pDescr = MyProdInfo;   //产品信息
  253.                                                 len = MyProdInfo[0];
  254.                                                 break;

  255.                                             case 0:
  256.                                                 pDescr = MyLangDescr;  //语言信息
  257.                                                 len = MyLangDescr[0];
  258.                                                 break;

  259.                                             case 3:
  260.                                                 pDescr = (PUINT8)( &MyProductIDInfo[0] ); //产品序列号
  261.                                                 len = sizeof( MyProductIDInfo );
  262.                                                 break;

  263.                                             default:
  264.                                                 errflag = 0xFF;
  265.                                                 break;
  266.                                         }
  267.                                         break;

  268.                                     default :
  269.                                         errflag = 0xff;
  270.                                         break;
  271.                                 }

  272.                                 if( SetupReqLen>len )   SetupReqLen = len;
  273.                                 len = (SetupReqLen >= DevEP0SIZE) ? DevEP0SIZE : SetupReqLen;
  274.                                 memcpy( pEP0_DataBuf, pDescr, len );
  275.                                 pDescr += len;
  276.                             }
  277.                                 break;

  278.                             case USB_SET_ADDRESS:
  279.                                 SetupReqLen = (pSetupReqPak->wValue)&0xff;
  280.                                 break;

  281.                             case USB_GET_CONFIGURATION:
  282.                                 pEP0_DataBuf[0] = UsbConfig;
  283.                                 if ( SetupReqLen > 1 ) SetupReqLen = 1;
  284.                                 break;

  285.                             case USB_SET_CONFIGURATION:
  286.                                 UsbConfig = (pSetupReqPak->wValue)&0xff;
  287.                                 break;

  288.                             case USB_CLEAR_FEATURE:
  289.                                 if( ( pSetupReqPak->bRequestType & 0x1F ) == USB_REQ_RECIP_DEVICE )  /* 清除设备 */
  290.                                 {
  291.                                     if((pSetupReqPak->wValue) == 0x01 )
  292.                                     {
  293.                                        if( MyCfgDescr[ 7 ] & 0x20 )
  294.                                        {
  295.                                            /* 唤醒 */
  296.                                        }
  297.                                        else
  298.                                        {
  299.                                            errflag = 0xFF;                                           /* 操作失败 */
  300.                                        }
  301.                                     }
  302.                                     else
  303.                                     {
  304.                                         errflag = 0xFF;                                              /* 操作失败 */
  305.                                      }
  306.                                 }
  307.                                 else if ( ( pSetupReqPak->bRequestType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )
  308.                                 {
  309.                                     switch( (pSetupReqPak->wIndex)&0xff )
  310.                                     {
  311.                                         case 0x82:
  312.                                             R8_UEP2_CTRL = (R8_UEP2_CTRL & ~( RB_UEP_T_TOG|MASK_UEP_T_RES )) | UEP_T_RES_NAK;
  313.                                             break;

  314.                                         case 0x02:
  315.                                             R8_UEP2_CTRL = (R8_UEP2_CTRL & ~( RB_UEP_R_TOG|MASK_UEP_R_RES )) | UEP_R_RES_ACK;
  316.                                             break;

  317.                                         case 0x81:
  318.                                             R8_UEP1_CTRL = (R8_UEP1_CTRL & ~( RB_UEP_T_TOG|MASK_UEP_T_RES )) | UEP_T_RES_NAK;
  319.                                             break;

  320.                                         case 0x01:
  321.                                             R8_UEP1_CTRL = (R8_UEP1_CTRL & ~( RB_UEP_R_TOG|MASK_UEP_R_RES )) | UEP_R_RES_ACK;
  322.                                             break;

  323.                                         default:
  324.                                             errflag = 0xFF;
  325.                                             break;

  326.                                     }
  327.                                 }
  328.                                 else    errflag = 0xFF;
  329.                                 break;

  330.                             case USB_SET_FEATURE:                                          /* Set Feature */
  331.                                 if( ( pSetupReqPak->bRequestType & 0x1F ) == USB_REQ_RECIP_DEVICE )                  /* 设置设备 */
  332.                                 {
  333.                                     if(( pSetupReqPak->wValue) == 0x01 )
  334.                                     {
  335.                                         if( MyCfgDescr[ 7 ] & 0x20 )
  336.                                         {
  337.                                             ;
  338.                                         }
  339.                                         else
  340.                                         {
  341.                                             errflag = 0xFF;                                        /* 操作失败 */
  342.                                         }
  343.                                      }
  344.                                     else
  345.                                      {
  346.                                          errflag = 0xFF;                                           /* 操作失败 */
  347.                                      }
  348.                                 }
  349.                                 else if( ( pSetupReqPak->bRequestType & 0x1F ) == USB_REQ_RECIP_ENDP )                /* 设置端点 */
  350.                                 {
  351.                                     if(( pSetupReqPak->wValue) == 0x00 )
  352.                                     {
  353.                                         switch(pSetupReqPak->wIndex)
  354.                                         {
  355.                                             case 0x82:
  356.                                                     R8_UEP2_CTRL = (R8_UEP2_CTRL & (~RB_UEP_R_TOG)) | UEP_T_RES_STALL;/* 设置端点2 IN STALL */
  357.                                                     break;
  358.                                             case 0x02:
  359.                                                     R8_UEP2_CTRL = (R8_UEP2_CTRL & (~RB_UEP_R_TOG)) | UEP_R_RES_STALL;/* 设置端点2 OUT Stall */
  360.                                                     break;
  361.                                             case 0x81:
  362.                                                     R8_UEP1_CTRL = (R8_UEP1_CTRL & (~RB_UEP_R_TOG)) | UEP_T_RES_STALL;/* 设置端点1 IN STALL */
  363.                                                     break;
  364.                                             case 0x01:
  365.                                                     R8_UEP1_CTRL = (R8_UEP1_CTRL & (~RB_UEP_R_TOG)) | UEP_R_RES_STALL;/* 设置端点1 OUT Stall */
  366.                                                     break;
  367.                                             default:
  368.                                                 errflag = 0xFF;                              /* 操作失败 */
  369.                                                 break;
  370.                                         }
  371.                                     }
  372.                                     else
  373.                                     {
  374.                                         errflag = 0xFF;                                      /* 操作失败 */
  375.                                     }
  376.                                 }
  377.                                 else
  378.                                 {
  379.                                     errflag = 0xFF;                                          /* 操作失败 */
  380.                                 }
  381.                                 break;

  382.                             case USB_GET_INTERFACE:
  383.                                 pEP0_DataBuf[0] = 0x00;
  384.                                 if ( SetupReqLen > 1 ) SetupReqLen = 1;
  385.                                 break;

  386.                             case USB_GET_STATUS:
  387.                                 pEP0_DataBuf[0] = 0x00;
  388.                                 pEP0_DataBuf[1] = 0x00;
  389.                                 if ( SetupReqLen > 2 ) SetupReqLen = 2;
  390.                                 break;

  391.                             default:
  392.                                 errflag = 0xff;
  393.                                 break;
  394.                         }
  395.                     }
  396.                 }
  397.                 else    errflag = 0xff;

  398.                 if( errflag == 0xff)
  399.                 {
  400.                     R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL;
  401.                 }
  402.                 else
  403.                 {
  404.                     if( chtype & 0x80 )
  405.                     {
  406.                         len = (SetupReqLen>DevEP0SIZE) ? DevEP0SIZE : SetupReqLen;
  407.                         SetupReqLen -= len;
  408.                     }
  409.                     else  len = 0;

  410.                     R8_UEP0_T_LEN = len;
  411.                     R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;
  412.                 }
  413.                 break;

  414.             case UIS_TOKEN_IN:
  415.                 switch( SetupReqCode )
  416.                 {
  417.                     case USB_GET_DESCRIPTOR:
  418.                         len = SetupReqLen >= DevEP0SIZE ? DevEP0SIZE : SetupReqLen;
  419.                         memcpy( pEP0_DataBuf, pDescr, len );
  420.                         SetupReqLen -= len;
  421.                         pDescr += len;
  422.                         R8_UEP0_T_LEN = len;
  423.                         R8_UEP0_CTRL ^= RB_UEP_T_TOG;
  424.                         break;

  425.                     case USB_SET_ADDRESS:
  426.                         R8_USB_DEV_AD = (R8_USB_DEV_AD&RB_UDA_GP_BIT) | SetupReqLen;
  427.                         R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
  428.                         break;

  429.                     default:
  430.                         R8_UEP0_T_LEN = 0;
  431.                         R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
  432.                         break;

  433.                 }
  434.                 break;

  435.             case UIS_TOKEN_OUT:
  436.                 if(SetupReqCode ==SET_LINE_CODING)                      //设置串口属性
  437.                 {
  438.                     if (R8_USB_INT_FG & RB_U_TOG_OK)
  439.                     {
  440.                         R8_UEP0_T_LEN = 0;
  441.                         R8_UEP0_CTRL |= UEP_R_RES_ACK | UEP_T_RES_ACK;  // 准备上传0包
  442.                     }
  443.                 }
  444.                 else
  445.                 {
  446.                         R8_UEP0_T_LEN = 0;
  447.                         R8_UEP0_CTRL |= UEP_R_RES_ACK | UEP_T_RES_NAK;  //状态阶段,对IN响应NAK
  448.                 }
  449.                 break;

  450.             case UIS_TOKEN_OUT | 1:
  451.                 break;

  452.             case UIS_TOKEN_IN | 1:
  453.                 R8_UEP1_T_LEN = 0;
  454.                 R8_UEP1_CTRL = (R8_UEP1_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
  455.                 break;

  456.             default :
  457.                 break;
  458.         }
  459.         R8_USB_INT_FG = RB_UIF_TRANSFER;
  460.     }
  461.     else if( intflag & RB_UIF_BUS_RST )
  462.     {
  463.         R8_USB_DEV_AD = 0;
  464.         R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
  465.         R8_UEP1_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
  466.         R8_UEP2_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
  467.         R8_USB_INT_FG |= RB_UIF_BUS_RST;
  468.     }
  469.     else if( intflag & RB_UIF_SUSPEND )
  470.     {
  471.         if ( R8_USB_MIS_ST & RB_UMS_SUSPEND ) {;}
  472.         else{;}
  473.         R8_USB_INT_FG = RB_UIF_SUSPEND;
  474.     }
  475.     else
  476.     {
  477.         R8_USB_INT_FG = intflag;
  478.     }
  479. }

  480. /*******************************************************************************
  481. * Function Name  : main
  482. * Description    : Main program.
  483. * Input          : None
  484. * Return         : None
  485. *******************************************************************************/
  486. int main(void)
  487. {
  488.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  489.     Delay_Init();
  490.     USART_Printf_Init(115200);

  491.     printf("SystemClk:%d\r\n",SystemCoreClock);
  492.     printf("USBHD Device Test\r\n");

  493.     pEP0_RAM_Addr = EP0_Databuf;
  494.     pEP1_RAM_Addr = EP1_Databuf;
  495.     pEP2_RAM_Addr = EP2_Databuf;

  496.     USBHD_ClockCmd(RCC_USBCLKSource_PLLCLK_1Div5,ENABLE);
  497.     USB_DeviceInit();
  498.     NVIC_EnableIRQ( USBHD_IRQn );

  499.     while(1)
  500.     {
  501.         ;
  502.     }
  503. }

  504. /*******************************************************************************
  505. * Function Name  : DevEP1_OUT_Deal
  506. * Description    : Deal device Endpoint 1 OUT.
  507. * Input          : l: Data length.
  508. * Return         : None
  509. *******************************************************************************/
  510. void DevEP1_OUT_Deal( UINT8 l )
  511. {
  512.     ;
  513. }

  514. /*******************************************************************************
  515. * Function Name  : DevEP2_OUT_Deal
  516. * Description    : Deal device Endpoint 2 OUT.
  517. * Input          : l: Data length.
  518. * Return         : None
  519. *******************************************************************************/
  520. void DevEP2_OUT_Deal( UINT8 l )
  521. {
  522.     ;
  523. }

  524. /*******************************************************************************
  525. * Function Name  : USB_IRQHandler
  526. * Description    : This function handles USB exception.
  527. * Input          : None
  528. * Return         : None
  529. *******************************************************************************/
  530. void USBHD_IRQHandler (void)
  531. {
  532.     USB_DevTransProcess();
  533. }
复制代码
main.c文件中本人对各种描述符都进行了注释,便于大家理解,有不懂地方可以参考《圈圈教你玩USB》。关于USB设备传输过程,可结合应用手册关于USB寄存器介绍进行理解,因为本人也在学习中,很多地方不能解释很透彻,一知半解,就不一一注释了,本教程也仅供大家参考学习。

4下载验证
将编译好的程序下载到开发板并复位,打开串口调试助手,串口打印如下:
图片1.png
使用公对公USB线将开发板和电脑连接起来,打开设备管理器可以看到端口中多了一个COM口,如图所示:
图片2.png
串口调试助手选择COM10,即可进行数据收发,具体如下:
图片3.png






  

CH32V103 USB模拟CDC.rar

486.34 KB, 下载次数: 3

使用特权

评论回复

相关帖子

| 2021-3-16 14:24 | 显示全部楼层
很棒很全面的应用教程,棒

使用特权

评论回复
扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

我要发帖 我要提问 投诉建议 申请版主

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式

论坛热帖

在线客服 快速回复 返回顶部 返回列表