有人预言,RISC-V或将是继Intel和Arm之后的第三大主流处理器体系。欢迎访问全球首家只专注于RISC-V单片机行业应用的中文网站
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
本帖最后由 草帽王子 于 2021-9-10 18:20 编辑
本章教程主要使用CH32V103 USB模拟鼠标键盘设备。
1、USB简介及相关函数介绍
关于USB具体介绍,可参考前面章节。
2、硬件设计
本章教程主要进行USB模拟鼠标键盘实验,仅需用到开发板USB口。
3、软件设计
本章程序全在主函数中进行,具体程序如下:
main.c文件
- /********************************** (C) COPYRIGHT *******************************
- * File Name : main.c
- * Author : WCH
- * Version : V1.0.0
- * Date : 2019/10/15
- * Description : Main program body.
- *******************************************************************************/
- #include "debug.h"
- #include "usart.h"
- #include "string.h"
- #define DevEP0SIZE 0x40
- /* Device Descriptor */
- const UINT8 MyDevDescr[] =
- {
- 0x12, //设备描述符长度,18字节
- 0x01, //描述符类型,0x01为设备描述符
- 0x10, 0x01, //本设备所使用USB版本协议,因为是小端结构,所以低字节在前,即USB1.1版本为0x10,0x01,USB2.0为0x00,0x02
- 0x00, //类代码,此处不在设备描述符中定义设备类,而在接口描述符中定义设备类。对于大多数标准的USB设备类,该字段通常设置为0,而在接口描述符中的bInterfaceClass中指定接口所实现的功能
- 0x00, //子类代码,当类代码bDeviceClass为0时,下面的子类代码bDeviceSubClass也必须为0。
- 0x00, //设备所使用的协议,协议代码由USB协会规定。当该字段为0时,表示设备不使用类所定义的协议。
- DevEP0SIZE, //端点0的最大包长,可以取值8、16、32、64,此处为64字节
- 0x86, 0x1A, //厂商ID
- 0xe1, 0xe6, //产品设备ID
- 0x00, 0x01, //设备版本号
- 0x01, //描述厂商的字符串索引值。当该值为0时,表示没有厂商字符串
- 0x02, //描述产品的字符串索引值。当该值为0时,表示没有产品字符串
- 0x03, //描述设备的序列号字符串索引值。当该值为0时,表示没有序列号字符串
- 0x01, //可能的配置数,通常为1
- };
- const UINT8 KeyRepDesc[] =
- {
- 0x05, 0x01, // Usage page Generatic Desktop
- 0x09, 0x06, // Usage keyboard
- 0xa1, 0x01, // Collation Application
- 0x05, 0x07, // Usafe page (key code)
- 0x19, 0xe0, // Usage Min ( E0 --> L_CTL)
- 0x29, 0xe7, // Usage MAX ( E7 --> R_GUI )
- 0x15, 0x00, // Logical min
- 0x25, 0x01, // Logical max
- 0x95, 0x08, // Report count ( 8 )
- 0x75, 0x01, // Report size ( 1 )
- 0x81, 0x02, // Input ( Data, Variable, Absolute )
- 0x95, 0x08, // Report count ( 8 )
- 0x75, 0x01, // Report size ( 1 )
- 0x81, 0x01, // Input ( const )
- 0x05, 0x08, // Usage page( LED )
- 0x19, 0x01, // Usage min ( 1 )
- 0x29, 0x03, // Usage max ( 3 )
- 0x95, 0x03, // Report count ( 3 )
- 0x75, 0x01, // Report size ( 1 )
- 0x91, 0x02, // Output ( Data, Variable, Absolute )
- 0x95, 0x01, // Report count ( 1 )
- 0x75, 0x05, // Report size ( 5 )
- 0x91, 0x01, // Output ( const )
- 0x05, 0x07, // Usage page ( key code )
- 0x19, 0x00, // Usage min ( 0H )
- 0x2a, 0xff, 0x00, // Usage max ( FFH )
- 0x15, 0x00, // Logical min ( 0H )
- 0x26, 0xff, 0x00, // Logical max ( FFH )
- 0x95, 0x06, // Report count ( 6 )
- 0x75, 0x08, // Report size ( 8 )
- 0x81, 0x00, // Input ( Data, Array, Absolute )
- 0xc0 // End collection
- };
- const UINT8 MouseRepDesc[]=
- {
- 0x05,0x01,
- 0x09,0x02,
- 0xA1,0x01,
- 0x09,0x01,
- 0xA1,0x00,
- 0x05,0x09,
- 0x19,0x01,
- 0x29,0x03,
- 0x15,0x00,
- 0x25,0x01,
- 0x95,0x03,
- 0x75,0x01,
- 0x81,0x02,
- 0x95,0x01,
- 0x75,0x05,
- 0x81,0x03,
- 0x05,0x01,
- 0x09,0x30,
- 0x09,0x31,
- 0x09,0x38,
- 0x15,0x81,
- 0x25,0x7f,
- 0x75,0x08,
- 0x95,0x03,
- 0x81,0x06,
- 0xC0,
- 0xC0
- };
- /* Configration Descriptor */
- const UINT8 MyCfgDescr[] =
- {
- //配置描述符
- 0x09, //配置描述符长度,标准USB配置描述符长度为9字节
- 0x02, //描述符类型,配置描述符为0x02
- 0x3b, 0x00, //配置描述符集合总长度,59字节
- 0x02, //该配置所支持的接口数,2个接口
- 0x01, //表示该配置的值
- 0x00, //描述该配置的字符串的索引值,0x00表示没有字符串
- 0xA0, //描述设备的一些属性,如供电方式和唤醒等,0xA0表示设备总线供电且支持远程唤醒
- 0x32, //设备需要从总线获取的最大电流量,0x32表示最大电流100ma
- //键盘
- //接口描述符,接口描述符不能单独返回,必须附着在配置描述符后一并返回
- 0x09, //接口描述符长度,标准的USB接口描述符长度为9字节
- 0x04, //描述符类型,接口描述符为0x04
- 0x00, //该接口的编号,从0开始,此处为0x00
- 0x00, //该接口的备用编号,通常设置为0
- 0x01, //该接口所使用的端点数,0x01表示使用1个端点。如果该字段为0,则表示没有非0端点,只使用默认的控制端点
- 0x03, //该接口所使用的类,0x03为HID类
- 0x01, //该接口所使用的子类
- 0x01, //该接口所使用的协议
- 0x00, //该接口的字符串的索引值,0x00表示没有字符串
- //HID类描述符,它是一个类描述符,应该跟在接口描述符后面
- 0x09, //该描述符长度,它的大小与该描述符中下级描述符的个数有关。例如只有一个下级描述符时,总长度为9
- 0x21, //描述符类型,HID描述符为0x21
- 0x10,0x01, //HID协议的版本号,这里参看的HID协议是USB HID1.1协议,因此这里为0x0110
- 0x00, //国家代码,是设备所适用的国家。通常我们的键盘是美式键盘,代码为33,即0x21,但此处设置为0x00
- 0x01, //下级描述符的数量,该值至少为1,即至少要有一个报告描述符。下级描述符可以是报告描述符或物理描述符
- 0x22, //下级描述符的类型,报告描述符的编号为0x22,物理描述符编号为0x23
- sizeof(KeyRepDesc)&0xFF, 0x00, //下级描述符的长度
- //端点描述符,端点描述符不能单独返回,必须附着在配置描述符后一并返回
- 0x07, //端点描述符长度,标准的USB端点描述符长度为7字节
- 0x05, //描述符类型,端点描述符为0x05
- 0x81, //该端点的地址,0x81表示端点1作为输入,最高位D7为该端点的传输方向,1为输入,0为输出。D3-D0为端点号,可设置为0-7,D6-4保留,设为0.
- //关于端点属性,最低两位D1-0表示该端点的传输类型,0为控制传输,1为等时传输,2为批量传输,3为中断传输。
- 0x03, //该端点的属性,此处为中断传输方式
- DevEP0SIZE, 0x00, //该端点支持的最大包长度,此处设置为64字节
- 0x0a, //端点的查询时间。对于中断端点,表示查询的帧间隔数
- //鼠标
- //接口描述符
- 0x09, //接口描述符长度,9字节
- 0x04, //描述符类型,接口描述符为0x04
- 0x01, //该接口的编号,从0开始,此处为0x01
- 0x00, //该接口的备用编号
- 0x01, //该接口所使用的端点数,0x01表示使用1个端点
- 0x03, //该接口所使用的类,0x03为HID类
- 0x01, //该接口所使用的子类
- 0x02, //该接口所使用的协议
- 0x00, //该接口的字符串的索引值,0x00表示没有字符串
- //HID类描述符
- 0x09, //该描述符长度,它的大小与该描述符中下级描述符的个数有关。例如只有一个下级描述符时,总长度为9
- 0x21, //描述符类型,HID描述符为0x21
- 0x10,0x01, //HID协议的版本号,这里参看的HID协议是USB HID1.1协议,因此这里为0x0110
- 0x00, //国家代码,是设备所适用的国家。通常我们的键盘是美式键盘,代码为33,即0x21,但此处设置为0x00
- 0x01, //下级描述符的数量,该值至少为1,即至少要有一个报告描述符。下级描述符可以是报告描述符或物理描述符
- 0x22, //下级描述符的类型,报告描述符的编号为0x22,物理描述符编号为0x23
- sizeof(MouseRepDesc)&0xFF,0x00, //下级描述符的长度
- //端点描述符
- 0x07, //端点描述符长度,7字节
- 0x05, //描述符类型,端点描述符为0x05
- 0x82, //该端点的地址,0x82表示端点2作为输入
- 0x03, //该端点的属性
- DevEP0SIZE, 0x00, //该端点支持的最大包长度,64字节
- 0x0a, //端点的查询时间
- };
- const UINT8 MyProductIDInfo[] = {0x0E,0x03,'K',0,'&',0,'M',0,'1',0,'0',0,'3',0};
- /* Language Descriptor */
- const UINT8 MyLangDescr[] = { 0x04, 0x03, 0x09, 0x04 };
- /* Manufactor Descriptor */
- const UINT8 MyManuInfo[] = { 0x0E, 0x03, 'w', 0, 'c', 0, 'h', 0, '.', 0, 'c', 0, 'n', 0 };
- /* Product Information */
- const UINT8 MyProdInfo[] = { 0x0C, 0x03, 'C', 0, 'H', 0, '5', 0, '5', 0, '9', 0 };
- /**********************************************************/
- volatile UINT8 Ready = 0;
- volatile UINT8 Endp1Busy = 0; //传输完成控制标志位
- volatile UINT8 Endp2Busy = 0;
- UINT8 DevConfig;
- UINT8 SetupReqCode;
- UINT16 SetupReqLen;
- UINT8 HIDKey[8];
- UINT8 HIDMouse[4];
- const UINT8 *pDescr;
- /* Endpoint Buffer */
- __attribute__ ((aligned(4))) UINT8 EP0_Databuf[64]; //ep0(64)
- __attribute__ ((aligned(4))) UINT8 EP1_Databuf[64+64]; //ep1_out(64)+ep1_in(64)
- __attribute__ ((aligned(4))) UINT8 EP2_Databuf[64+64]; //ep2_out(64)+ep2_in(64)
- void USBHD_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
- /*******************************************************************************
- * Function Name : USB_DevTransProcess
- * Description : USB device transfer process.
- * Input : None
- * Return : None
- *******************************************************************************/
- void USB_DevTransProcess( void )
- {
- UINT8 len, chtype;
- UINT8 intflag, errflag = 0;
- intflag = R8_USB_INT_FG;
- if( intflag & RB_UIF_TRANSFER )
- {
- switch ( R8_USB_INT_ST & ( MASK_UIS_TOKEN | MASK_UIS_ENDP ) )
- {
- case UIS_TOKEN_SETUP:
- R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_NAK;
- len = R8_USB_RX_LEN;
- if ( len == sizeof( USB_SETUP_REQ ) )
- {
- SetupReqLen = pSetupReqPak->wLength;
- SetupReqCode = pSetupReqPak->bRequest;
- chtype = pSetupReqPak->bRequestType;
- len = 0;
- errflag = 0;
- if ( ( pSetupReqPak->bRequestType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )
- {
- switch(SetupReqCode)
- {
- case 0x01: //GetReport
- len = 1;
- pEP0_DataBuf[0] = 0xaa;
- break;
- case 0x0a:
- R8_UEP0_T_LEN = 0;
- break; //这个一定要有
- case 0x09:
- Ready = 1;
- break;
- default:
- errflag = 0xFF;
- }
- }
- else
- {
- switch( SetupReqCode )
- {
- case USB_GET_DESCRIPTOR:
- {
- switch( ((pSetupReqPak->wValue)>>8) )
- {
- case USB_DESCR_TYP_DEVICE:
- pDescr = MyDevDescr;
- len = MyDevDescr[0];
- break;
- case USB_DESCR_TYP_CONFIG:
- pDescr = MyCfgDescr;
- len = MyCfgDescr[2];
- break;
- case USB_DESCR_TYP_STRING:
- switch( (pSetupReqPak->wValue)&0xff )
- {
- case 0:
- pDescr = MyLangDescr;
- len = MyLangDescr[0];
- break;
- case 1:
- pDescr = MyManuInfo;
- len = MyManuInfo[0];
- break;
- case 2:
- pDescr = MyProdInfo;
- len = MyProdInfo[0];
- break;
- case 3:
- pDescr = MyProductIDInfo;
- len = MyProductIDInfo[0];
- break;
- default:
- errflag = 0xFF;
- break;
- }
- break;
- case USB_DESCR_TYP_REPORT:
- if(((pSetupReqPak->wIndex)&0xff) == 0) //接口0报表描述符
- {
- pDescr = KeyRepDesc; //数据准备上传
- len = sizeof(KeyRepDesc);
- }
- else if(((pSetupReqPak->wIndex)&0xff) == 1) //接口1报表描述符
- {
- pDescr = MouseRepDesc; //数据准备上传
- len = sizeof(MouseRepDesc);
- Ready = 1; //如果有更多接口,该标准位应该在最后一个接口配置完成后有效
- }
- else len = 0xff; //本程序只有2个接口,这句话正常不可能执行
- break;
- default :
- errflag = 0xff;
- break;
- }
- if( SetupReqLen>len ) SetupReqLen = len;
- len = (SetupReqLen >= DevEP0SIZE) ? DevEP0SIZE : SetupReqLen;
- memcpy( pEP0_DataBuf, pDescr, len );
- pDescr += len;
- }
- break;
- case USB_SET_ADDRESS:
- SetupReqLen = (pSetupReqPak->wValue)&0xff;
- break;
- case USB_GET_CONFIGURATION:
- pEP0_DataBuf[0] = DevConfig;
- if ( SetupReqLen > 1 ) SetupReqLen = 1;
- break;
- case USB_SET_CONFIGURATION:
- DevConfig = (pSetupReqPak->wValue)&0xff;
- break;
- case USB_CLEAR_FEATURE:
- if ( ( pSetupReqPak->bRequestType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )
- {
- switch( (pSetupReqPak->wIndex)&0xff )
- {
- case 0x82:
- R8_UEP2_CTRL = (R8_UEP2_CTRL & ~( RB_UEP_T_TOG|MASK_UEP_T_RES )) | UEP_T_RES_NAK;
- break;
- case 0x02:
- R8_UEP2_CTRL = (R8_UEP2_CTRL & ~( RB_UEP_R_TOG|MASK_UEP_R_RES )) | UEP_R_RES_ACK;
- break;
- case 0x81:
- R8_UEP1_CTRL = (R8_UEP1_CTRL & ~( RB_UEP_T_TOG|MASK_UEP_T_RES )) | UEP_T_RES_NAK;
- break;
- case 0x01:
- R8_UEP1_CTRL = (R8_UEP1_CTRL & ~( RB_UEP_R_TOG|MASK_UEP_R_RES )) | UEP_R_RES_ACK;
- break;
- default:
- errflag = 0xFF;
- break;
- }
- }
- else errflag = 0xFF;
- break;
- case USB_GET_INTERFACE:
- pEP0_DataBuf[0] = 0x00;
- if ( SetupReqLen > 1 ) SetupReqLen = 1;
- break;
- case USB_GET_STATUS:
- pEP0_DataBuf[0] = 0x00;
- pEP0_DataBuf[1] = 0x00;
- if ( SetupReqLen > 2 ) SetupReqLen = 2;
- break;
- default:
- errflag = 0xff;
- break;
- }
- }
- }
- else errflag = 0xff;
- if( errflag == 0xff)
- {
- R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL;
- }
- else
- {
- if( chtype & 0x80 )
- {
- len = (SetupReqLen>DevEP0SIZE) ? DevEP0SIZE : SetupReqLen;
- SetupReqLen -= len;
- }
- else len = 0;
- R8_UEP0_T_LEN = len;
- R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;
- }
- break;
- case UIS_TOKEN_IN:
- switch( SetupReqCode )
- {
- case USB_GET_DESCRIPTOR:
- len = SetupReqLen >= DevEP0SIZE ? DevEP0SIZE : SetupReqLen;
- memcpy( pEP0_DataBuf, pDescr, len );
- SetupReqLen -= len;
- pDescr += len;
- R8_UEP0_T_LEN = len;
- R8_UEP0_CTRL ^= RB_UEP_T_TOG;
- break;
- case USB_SET_ADDRESS:
- R8_USB_DEV_AD = (R8_USB_DEV_AD&RB_UDA_GP_BIT) | SetupReqLen;
- R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
- break;
- default:
- R8_UEP0_T_LEN = 0;
- R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
- break;
- }
- break;
- case UIS_TOKEN_OUT:
- len = R8_USB_RX_LEN;
- break;
- case UIS_TOKEN_OUT | 1:
- if ( R8_USB_INT_ST & RB_UIS_TOG_OK )
- {
- len = R8_USB_RX_LEN;
- DevEP1_OUT_Deal( len );
- }
- break;
- case UIS_TOKEN_IN | 1:
- R8_UEP1_T_LEN = 0;
- Endp1Busy = 0;
- R8_UEP1_CTRL = (R8_UEP1_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
- break;
- case UIS_TOKEN_OUT | 2:
- if ( R8_USB_INT_ST & RB_UIS_TOG_OK )
- {
- len = R8_USB_RX_LEN;
- DevEP2_OUT_Deal( len );
- }
- break;
- case UIS_TOKEN_IN | 2:
- R8_UEP2_T_LEN = 0;
- Endp2Busy = 0;
- R8_UEP2_CTRL = (R8_UEP2_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
- break;
- default :
- break;
- }
- R8_USB_INT_FG = RB_UIF_TRANSFER;
- }
- else if( intflag & RB_UIF_BUS_RST )
- {
- R8_USB_DEV_AD = 0;
- R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
- R8_UEP1_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
- R8_UEP2_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
- R8_USB_INT_FG |= RB_UIF_BUS_RST;
- }
- else if( intflag & RB_UIF_SUSPEND )
- {
- if ( R8_USB_MIS_ST & RB_UMS_SUSPEND ) {;}
- else{;}
- R8_USB_INT_FG = RB_UIF_SUSPEND;
- }
- else
- {
- R8_USB_INT_FG = intflag;
- }
- }
- void HIDValueHandle()
- {
- UINT8 i;
- i = USART_ReceiveData(USART2);
- printf( "%c\n", (UINT8)i );
- switch(i)
- {
- //鼠标数据上传示例
- case 'L': //左键
- HIDMouse[0] = 0x01;
- while( Endp2Busy )
- {
- ; //如果忙(上一包数据没有传上去),则等待。
- }
- Endp2Busy = 1; //设置为忙状态
- memcpy(pEP2_IN_DataBuf, HIDMouse, 4);
- DevEP2_IN_Deal(4);
- HIDMouse[0] = 0; //抬起
- while( Endp2Busy )
- {
- ; //如果忙(上一包数据没有传上去),则等待。
- }
- Endp2Busy = 1; //设置为忙状态
- memcpy(pEP2_IN_DataBuf, HIDMouse, 4);
- DevEP2_IN_Deal(4);
- break;
- case 'R': //右键
- HIDMouse[0] = 0x02;
- while( Endp2Busy )
- {
- ; //如果忙(上一包数据没有传上去),则等待。
- }
- Endp2Busy = 1; //设置为忙状态
- memcpy(pEP2_IN_DataBuf, HIDMouse, 4);
- DevEP2_IN_Deal(4);
- HIDMouse[0] = 0; //抬起
- while( Endp2Busy )
- {
- ; //如果忙(上一包数据没有传上去),则等待。
- }
- Endp2Busy = 1; //设置为忙状态
- memcpy(pEP2_IN_DataBuf, HIDMouse, 4);
- DevEP2_IN_Deal(4);
- break;
- //键盘数据上传示例
- case 'A': //A键
- HIDKey[2] = 0x04; //按键开始
- while( Endp1Busy )
- {
- ; //如果忙(上一包数据没有传上去),则等待。
- }
- Endp1Busy = 1; //设置为忙状态
- memcpy(pEP1_IN_DataBuf, HIDKey, 8);
- DevEP1_IN_Deal(8);
- HIDKey[2] = 0; //按键结束
- while( Endp1Busy )
- {
- ; //如果忙(上一包数据没有传上去),则等待。
- }
- Endp1Busy = 1; //设置为忙状态
- memcpy(pEP1_IN_DataBuf, HIDKey, 8);
- DevEP1_IN_Deal(8);
- break;
- case 'Q': //CAP键
- HIDKey[2] = 0x39;
- while( Endp1Busy )
- {
- ; //如果忙(上一包数据没有传上去),则等待。
- }
- Endp1Busy = 1; //设置为忙状态
- memcpy(pEP1_IN_DataBuf, HIDKey, 8);
- DevEP1_IN_Deal(8);
- HIDKey[2] = 0; //按键结束
- while( Endp1Busy )
- {
- ; //如果忙(上一包数据没有传上去),则等待。
- }
- Endp1Busy = 1; //设置为忙状态
- memcpy(pEP1_IN_DataBuf, HIDKey, 8);
- DevEP1_IN_Deal(8);
- break;
- default: //其他
- break;
- }
- }
- /*******************************************************************************
- * Function Name : Set_USBConfig
- * Description : Set USB clock.
- * Input : None
- * Return : None
- *******************************************************************************/
- void USBHD_ClockCmd(UINT32 RCC_USBCLKSource,FunctionalState NewState)
- {
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, NewState);
- EXTEN->EXTEN_CTR |= EXTEN_USBHD_IO_EN;
- RCC_USBCLKConfig(RCC_USBCLKSource); //USBclk=PLLclk/1.5=48Mhz
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBHD,NewState);
- }
- /*******************************************************************************
- * Function Name : main
- * Description : Main program.
- * Input : None
- * Return : None
- *******************************************************************************/
- int main(void)
- {
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
- Delay_Init();
- USART2_Printf_Init(115200);
- printf("SystemClk:%d\r\n",SystemCoreClock);
- printf("USBHD Device Test\r\n");
- pEP0_RAM_Addr = EP0_Databuf;
- pEP1_RAM_Addr = EP1_Databuf;
- pEP2_RAM_Addr = EP2_Databuf;
- USBHD_ClockCmd(RCC_USBCLKSource_PLLCLK_1Div5,ENABLE);
- USB_DeviceInit();
- NVIC_EnableIRQ( USBHD_IRQn );
- while(1)
- {
- printf("Ready1=%d\n",Ready);
- if(Ready)
- {
- HIDValueHandle();
- }
- Delay_Ms(500);
- }
- }
- /*******************************************************************************
- * Function Name : DevEP1_OUT_Deal
- * Description : Deal device Endpoint 1 OUT.
- * Input : l: Data length.
- * Return : None
- *******************************************************************************/
- void DevEP1_OUT_Deal( UINT8 l )
- {
- ;
- }
- /*******************************************************************************
- * Function Name : DevEP2_OUT_Deal
- * Description : Deal device Endpoint 2 OUT.
- * Input : l: Data length.
- * Return : None
- *******************************************************************************/
- void DevEP2_OUT_Deal( UINT8 l )
- {
- ;
- }
- /*******************************************************************************
- * Function Name : USB_IRQHandler
- * Description : This function handles USB exception.
- * Input : None
- * Return : None
- *******************************************************************************/
- void USBHD_IRQHandler (void)
- {
- USB_DevTransProcess();
- }
复制代码 main.c文件中本人对各种描述符都进行了注释,便于大家理解,有不懂地方可以参考《圈圈教你玩USB》。关于USB设备传输过程,可结合应用手册关于USB寄存器介绍进行理解学习。
4、下载验证
将编译好的程序下载到开发板并复位,打开串口调试助手,串口打印如下:
用公对公USB线将开发板与电脑连接起来,打开设备管理器可以看到端口中多了一个键盘设备和鼠标设备,如图所示:
串口调试助手发送L,显示如下:
CH32V103 USB模拟鼠标键盘设备.rar
CH32V103 USB模拟鼠标键盘设备.rar
(498.8 KB, 下载次数: 18)
链接:https://pan.baidu.com/s/1QrG4lBJM1QqqlidS6LHZ-g
提取码:b571
复制这段内容后打开百度网盘手机App,操作更方便哦
完
|