查看: 1779|回复: 0
收起左侧

第八十二章:CH32V103应用教程——USB模拟CDC

[复制链接]

  离线 

  • TA的每日心情
    慵懒
    2021-7-23 17:16
  • 签到天数: 17 天

    [LV.4]

    发表于 2021-5-1 16:11:20 | 显示全部楼层 |阅读模式

    有人预言,RISC-V或将是继Intel和Arm之后的第三大主流处理器体系。欢迎访问全球首家只专注于RISC-V单片机行业应用的中文网站

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    本帖最后由 草帽王子 于 2021-9-10 18:19 编辑

    本章教程主要使用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、下载验证

    将编译好的程序下载到开发板并复位,打开串口调试助手,串口打印如下:
    CH32V CH573单片机芯片-第八十二章:CH32V103应用教程——USB模拟CDCrisc-v单片机中文社区(1)
    使用公对公USB线将开发板和电脑连接起来,打开设备管理器可以看到端口中多了一个COM口,如图所示:
    CH32V CH573单片机芯片-第八十二章:CH32V103应用教程——USB模拟CDCrisc-v单片机中文社区(2)
    串口调试助手选择COM10,即可进行数据收发,具体如下:
    CH32V CH573单片机芯片-第八十二章:CH32V103应用教程——USB模拟CDCrisc-v单片机中文社区(3)

    CH32V103 USB模拟CDC.rar
    CH32V CH573单片机芯片-第八十二章:CH32V103应用教程——USB模拟CDCrisc-v单片机中文社区(4) CH32V103 USB模拟CDC.rar (486.34 KB, 下载次数: 15)
    链接:https://pan.baidu.com/s/1VEXG5NRResTQveWXBW_L9g
    提取码:k0wp
    复制这段内容后打开百度网盘手机App,操作更方便哦







    上一篇:第八十一章:CH32V103应用教程——中断嵌套
    下一篇:第八十三章:CH32V103应用教程——USB模拟鼠标键盘设备
    RISCV作者优文
    全球首家只专注于RISC-V单片机行业应用的中文网站
    回复

    使用道具 举报

    高级模式
    B Color Image Link Quote Code Smilies

    本版积分规则

    关闭

    RISC-V单片机中文网上一条 /2 下一条



    版权及免责声明|RISC-V单片机中文网 |网站地图

    GMT+8, 2024-3-28 22:18 , Processed in 0.471136 second(s), 48 queries .

    快速回复 返回顶部 返回列表