开始打算做一个关于USB设备共享的机器,多台电脑共享一个鼠标键盘;

模拟鼠标或者键盘,必须使用外部固件模式,内置固件只负责信息数据的传输,所以不得不选择并口控制或者SPI的方式,接下来就是了解基本的USB协议的尝试,懂得USB设备与PC机进行信息握手的过程,懂得什么是SETUP,什么是设备描述符,什么是配置描述符,

以下是部分关于CH372模拟HID鼠标的程序:使用STM32

static void CH376_DATA_DIR_IN( );

BOOLEAN  CH375ACT;
BOOLEAN CH375FLAGERR; //错误清0
BOOLEAN CH375CONFLAG;

BOOLEAN IsBusying;

unsigned char buf[64];
typedef union _REQUEST_PACK{
unsigned char  buffer[8];
struct{
unsigned char bmReuestType;     //标准请求字
unsigned char bRequest;   //请求代码
unsigned int     wValue; //特性选择高
unsigned int     wIndx; //索引
unsigned int     wLength; //数据长度
}r;
} mREQUEST_PACKET, *mpREQUEST_PACKET;
//设备的描述符包含设备描述符、配置描述符、字符描述符;识别描述符的类型就是根据它的第二个字节值来识别;
//一般情况下设备描述符不需要用户去配置,因为可以直接用软件从现有的设备中读取;同种设备的描述符都相同;如优盘描述符都一样
/*以下是设备描述符,(为什么是这些数值,可查阅USB协议书籍)*/
unsigned char DevDes[]={
0x12, //描述符长度,长度1个字节,值18
    0x01, //描述符类型,长度1个字节,值:1-设备描述符,2-配置描述符,3-字符串描述符,4-接口描述符,5-端点描述符
    0x10, //USB规范版本信息,长度2个字节,BCD码:USB1.1-0110、USB2.0-0200
    0x01,
    0x00, //类别码,长度1个字节,数值0X01~0XFE为USB定义的类,如打印机等;00-USB设备的各个接口属于不同的类,由接口描述符提供类的值;02-通信类;03-HID类;09-集线器类;
               //DC-用于诊断用途的设备类;e0-无线通信设备类;XFF是由厂商定义的设备的类别;
    0x00,            //子类别码,长度1个字节,类别码为0,则也必须为0;USB协会指定;0xff-厂商自定义
0x00,            //协议代码,长度1个字节,USB协会指定;0-不使用任何设备类协议,类别码为0时,必须为0;0xff-厂商自定义
    0x08, //端点0的最大信息包大小,长度1字节,低速设备-8,全速设备-8/16/32/64,高速设备-64
    0x87, //厂商ID,VID长度2字节,USB协会分配给不同的厂商,操作系统会根据VID和PID加载驱动
    0x88,
    0x11, //产品ID,PID长度2字节,厂商定义,操作系统加载设备驱动与其有关
    0x00,
    0x00, //设备版本信息,长度2字节,厂商定义,操作系统加载驱动与其有关
    0x01,
    0x01, //描述厂商的字符串描述符的索引值,长度1字节,0-没有厂商字符串;主机获取设备描述符时将其放入WVALUE中,以选择不同的字符串;具体字符串内容在字符串描述符中定义
    0x02,            //描述产品的字符串描述符的索引值,长度1字节,0-没有产品字符串;第一次插入USB设备时,在系统桌面右下角弹出的提示信息就是产品字符串
    0x03,            //描述设备的序列号的字符串描述符的索引值,长度1字节,0-没有序列号描述符
    0x01, //设备支持的配置的数目,长度1字节,一个设备可能有多种配置,每种配置有一个配置描述符,主机通过发送设备配置来选择某一配置
};
//配置描述符;包括配置描述符、接口描述符、端点描述符,HID设备还包括HID描述符;
unsigned char   ConDes[]={
//配置描述符
0x09, //描述符大小
    0x02, //描述符类型02-配置描述符
    0x22, //此配置传回所有数据大小,包括配置描述符、接口描述符、类描述符、端点描述符
    0x00, //
    0x01, //接口数
    0x01, //配置值
    0x00, //描述改配置的字符串的索引,0-没有配置描述字符串
    0x80, //设备属性D7保留位 1,D6:0-总线供电 D5:1-支持远程唤醒 D4-D0:保留位 0000
    0x40, //设备需要的电流,单位为2ma
//接口描述符
    0x09, //描述符大小
    0x04, //描述符类型04-接口描述符
    0x00, //接口编号
    0x00, //接口备用编号
    0x01, //支持的端点数 0-没有非零端点 使用默认控制端点
    0x03, //类别码
    0x01, //子类别码 0-无引导的HID设备 1-有引导的HID设备
    0x02, //协议码子类别码为0时必须也为0 子类别吗为1时 1-键盘 2-鼠标
    0x00, //描述该接口的字符串的索引,0-没有
//HID描述符
0x09,    //描述符长度
0x21,    //描述符类型 0x21-HID
0x10,    //HID协议版本
0x01,
0x21,    //国家码,美式键盘33
0x01,    //下级描述符数量,至少为1,下级描述符即报告描述符或物理描述符
0x22,    //下级描述符类型,0x22-报告描述符 0x23-物理描述符
0x34,    //下级描述符长度,2字节,
0x00,
//端点描述符
    0x07,    //描述符长度
    0x05,    //描述符类型 5-端点描述符
    0x81,    //端点地址,D7-传输方向 1-IN 0-OUT,D3-D0:端点号,D6-D4:保留值
    0x03,    //端点类型;D1-D0:0-控制传输 1-等时传输 2-批量传输 3-中断传输;非等时传输D7-D2保留值 0,等时传输D7-D6保留,D5-D4用途 0-数据端点 1反馈端点 2-暗含反馈的数据端点 D3-D2同步类型0 无同步1-异步 2适配 3 同步
    0x10,    //最大数据包长度
    0x00,    //
    0x0a,    //查询间隔
};
//字符串描述符,报表描述符;
//作键盘设备时,报表描述符描述了数据格式;如键盘,则必须发送8个字节的数据;其中第3个字节是要在
//各种文本里显示的数据(如WORD文挡);其余字节全为0;
unsigned char Hid_des[]={
0x05, 0x01, //全局项目,表示用途页为桌面设备
0x09, 0x02,  //局部项目,表示用途为鼠标
0xa1, 0x01,  //开集合,主项目,应用集合
    0x09, 0x01,  //局部项目,指针设备
    0xa1, 0x00,  //开集合,主项目,物理集合
        0x05, 0x09, //全局项目,用途为按键
        0x19, 0x01, //局部项目,用途最小值为1,鼠标左键
        0x29, 0x03, //局部项目,用途最大值为3,鼠标中键
        0x15, 0x00, //全局项目,返回数据的逻辑值的最小值为0
        0x25, 0x01, //全局项目,返回数据的逻辑值的最大值为1
        
0x95, 0x03, //全局项目,返回值的数据域数量有3个
        0x75, 0x01, //全局项目,返回值每个数据域长度1位
        0x81, 0x02, //主项目,说明有3个长度为1的数据域做输入,属性为DATA VAR ABS,ADAT表示数据可变动,VAR表示这些数据域是独立的变量,即每个数据域表示一个意思,ABS表示他们是绝对值。长度由前述的两个全局项目定义,
        
0x95, 0x01, //全局项目,数据域数量有1个
        0x75, 0x05, //全局项目,数据域长度为5位
        0x81, 0x03, //主项目,说明有一个长度为5位的数据域做输入,属性为CNST VAR ABS,CNST表示常量,目的是补齐8位,因为前面只有3位
        
0x05, 0x01, //全局项目,用途是通用桌面
        0x09, 0x30, //局部项目,用途X轴
        0x09, 0x31, //局部项目,用途Y轴
        0x09, 0x38, //局部项目,用途为滚轮,即中键

0x15, 0x81, //全局项目,返回值的逻辑值的最大和最小值分别为-127和127;
        0x25, 0x7f,
       
0x75, 0x08, //全局项目,每个数据域的长度为8位
        0x95, 0x03, //全局项目,数据域的个数为3个
        0x81, 0x06, //全局项目,说明前述的3个数据域为输入,属性为DATA VAR REL,DATA、VAR前面已经讲过,REL表示这些值是相对值,即鼠标移动时,发送的只是变化量
    0xc0, //关闭集合
0xc0 //关闭集合
         };
 
unsigned char LangDes[]={0x04,0x03,0x09,0x04}; //语言描述符
unsigned char SerDes[] ={0x16,0x03,0xDD,0x84,0xD7,0x65,0x4C,0x5D,0x65,0x51,0x0F,0x5F,0x48,0x00,0x49,0x00,
0x44,0x00,0x20,0x9F,0x07,0x68};

unsigned char  Chan[]={0x16,0x03,0x32,0x00,0x30,0x00,0x30,0x00,0x31,0x00,0x2d,0x00,0x30,0x00,0x37,0x00,0x2d,0x00,0x30,0x00,0x31,0x00};
unsigned char  Chang[] ={0x14,0x03,'L',0,'E',0,'N',0,'C',0,'H',0,'I',0,'M',0,'C',0,'U',0};

unsigned char mVarSetupRequest; // ;USB请求码
unsigned char mVarSetupLength; // ;后续数据长度
unsigned char * VarSetupDescr;// ;描述符偏移地址
unsigned char buf1[8];
unsigned char VarUsbAddress ; //
unsigned  char  Report_ID=0X01;

unsigned char  UPDATA_FLAG;
mREQUEST_PACKET  request;

void sys_DATA_IoInit(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);

GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Pin = WR_PIN ;
    GPIO_Init(WR_PORT, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = A0_PIN ;
    GPIO_Init(A0_PORT, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = RD_PIN ;
    GPIO_Init(RD_PORT, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = CS_PIN ;
    GPIO_Init(CS_PORT, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin =   CH376_INT1_PIN;
GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_IN_FLOATING;
GPIO_Init(CH376_INT1_PORT , &GPIO_InitStructure);
    
     GPIO_SetBits(CS_PORT,CS_PIN);           // CH376_CS = 1;
     GPIO_SetBits(WR_PORT,WR_PIN);           // CH376_WR = 1;
     GPIO_SetBits(RD_PORT,RD_PIN);           // CH376_RD = 1;
     GPIO_ResetBits(A0_PORT,A0_PIN);         // CH376_A0 = 0;
     CH376_DATA_DIR_IN();

}

/***********************************************************************************
****函数名称:不准确的延时20US的函数
****函数作用:
****函数描述:
************************************************************************************/
static void delay20us(void)
{
// unsigned char i;
// for(i=0;i<20;i++);
}
/***********************************************************************************
****函数名称:不准确的延时1mS的函数
****函数作用:
****函数描述:
************************************************************************************/
static void delay1ms(void)
{
// unsigned char m,n;
// for(m=0;m<200;m++)
// for(n=0;n<50;n++);
}
/***********************************************************************************
****函数名称:不准确的延时50mS的函数
****函数作用:
****函数描述:
************************************************************************************/
static void delay50ms(void)
{
// unsigned char m,n;
// for(m=0;m<200;m++)
// for(n=0;n<250;n++);
}

static void CH376_DATA_DIR_IN( )

{
    GPIO_InitTypeDef GPIO_InitStructure;

GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);

GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Pin =   D0_PIN|D1_PIN|D2_PIN|D3_PIN|D4_PIN|D5_PIN|D6_PIN|D7_PIN;  //OE0:PA7 OE1:PA15  OE2:PA8
    GPIO_Init(D0_PORT, &GPIO_InitStructure);
    
}

static void CH376_DATA_DIR_OUT( )

{
    
    GPIO_InitTypeDef GPIO_InitStructure;
    
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);

GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Pin =   D0_PIN| D1_PIN|D2_PIN|D3_PIN|D4_PIN|D5_PIN|D6_PIN|D7_PIN;  //OE0:PA7 OE1:PA15  OE2:PA8
    GPIO_Init(D0_PORT, &GPIO_InitStructure);

}

static uint8_t  CH376_DATA_DAT_IN(void)
{
    u16 cmd1;  uint8_t cmd;  
    cmd1=GPIO_ReadInputData(D0_PORT);    
    cmd=(GPIO_ReadInputData(D0_PORT)&0xff00)>>8;    
delay50ms();
    return(cmd);
    
    
    
}

static void  CH376_DATA_DAT_OUT(u16 cmd)
{

u16 Temp;   
    Temp=GPIO_ReadOutputData(D0_PORT);  
delay50ms();    
    GPIO_Write(D0_PORT,(Temp&0x00ff)|(((u16)cmd)<<8));

}

/*******************************************************************************
* Function Name  : CH376_WR_CMD_PORT  串口发送命令前需要发送57 ab同步码
* Description    : 写CH376命令子函数
* Input          : - cmd: 8位命令码
* Output         : None
* Return         : None
* Attention : None
*******************************************************************************/

void CH376_WR_CMD_PORT( u16  cmd )
{

delay20us();
    CH376_DATA_DIR_OUT( );

CH376_DATA_DAT_OUT(cmd);

GPIO_SetBits(A0_PORT,A0_PIN);         // CH376_A0 = 1;
     GPIO_SetBits(RD_PORT,RD_PIN);           // CH376_RD =1;

GPIO_ResetBits(CS_PORT,CS_PIN);           // CH376_CS = 0;

GPIO_ResetBits(WR_PORT,WR_PIN);           // CH376_WR = 0;

GPIO_ResetBits(CS_PORT,CS_PIN);           // CH376_CS = 0;
    delay50ms();

GPIO_SetBits(WR_PORT,WR_PIN);           // CH376_WR =1;

GPIO_SetBits(CS_PORT,CS_PIN);           // CH376_CS = 1;

GPIO_ResetBits(A0_PORT,A0_PIN);         // CH376_A0 = 0;

CH376_DATA_DAT_OUT(0xffff);
}

/*******************************************************************************
* Function Name  : CH376_WR_DAT_PORT
* Description    : 写CH376数据子函数
* Input          : - dat: 8位数据
* Output         : None
* Return         : None
* Attention : None
*******************************************************************************/
void CH376_WR_DAT_PORT( u16 dat )
{
    CH376_DATA_DIR_OUT( );  /* 设置并口方向为输出 */
delay20us();
    CH376_DATA_DAT_OUT( dat );  /* 向CH376的并口输出数据 */

GPIO_ResetBits(A0_PORT,A0_PIN);            // CH376_A0 = 0;

GPIO_ResetBits(CS_PORT,CS_PIN);           // CH376_CS = 0;

GPIO_ResetBits(WR_PORT,WR_PIN);           // CH376_WR = 0;

delay20us();
    GPIO_ResetBits(CS_PORT,CS_PIN);           // CH376_CS = 0;
delay20us();
    GPIO_SetBits(WR_PORT,WR_PIN);           // CH376_WR =1;

GPIO_SetBits(CS_PORT,CS_PIN);           // CH376_CS = 1;

CH376_DATA_DAT_OUT(0xffff);  /* 禁止数据输出 */

}

/*******************************************************************************
* Function Name  : CH376_RD_DAT_PORT
* Description    : 读CH376数据子函数
* Input          : None
* Output         : None
* Return         : 8位数据
* Attention : 等待读到数据
*******************************************************************************/
uint8_t CH376_RD_DAT_PORT( void )
{
    
    
    uint8_t mData;
    // mDelay0_5uS( );  /* 确保读写周期大于0.6uS */
    
     CH376_DATA_DIR_OUT( );  /* 设置并口方向为输出 */
    CH376_DATA_DAT_OUT(0xffff);  /* 禁止数据输出 */
    GPIO_ResetBits(A0_PORT,A0_PIN);            // CH376_A0 = 0;
    
    CH376_DATA_DIR_IN( );  /* 设置并口方向为输入 */
    CH376_DATA_DAT_OUT(0x0000);  /* 禁止数据输出 */

GPIO_ResetBits(CS_PORT,CS_PIN);           // CH376_CS = 0;

GPIO_ResetBits(RD_PORT,RD_PIN);           // CH376_WR = 0;

GPIO_ResetBits(CS_PORT,CS_PIN);           // CH376_CS = 0;
delay50ms();
delay20us();
    mData = CH376_DATA_DAT_IN( );  /* 从CH376的并口输入数据 */

GPIO_SetBits(RD_PORT,RD_PIN);           // CH376_RD =1;
delay50ms();
    GPIO_SetBits(CS_PORT,CS_PIN);           // CH376_CS = 1;
         CH376_DATA_DIR_OUT( );  /* 设置并口方向为输出 */
    CH376_DATA_DAT_OUT(0xffff);  /* 禁止数据输出 */

return( mData );
    
    
}

void device_376(void)
{
    
    sys_DATA_IoInit();
    sysReset();
        CH376_WR_CMD_PORT( CMD_SET_USB_MODE );
CH376_WR_DAT_PORT( 0);  
    delay50ms();
    CH376_WR_CMD_PORT( CMD_SET_USB_MODE );
CH376_WR_DAT_PORT( 1);   /* 设置为使用内置固件的USB设备方式 */
for ( ;; ) {   /* 等待操作成功,通常需要等待10uS-20uS */
if ( CH376_RD_DAT_PORT( )==CMD_RET_SUCCESS ) break;
}

}

void IO_cfg()            //GPIO初始化
{
   GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;     //选择引脚2 3 5 作为中断信号输入端
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;                   //选择输入模式为浮空输入
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                       //输出频率最大50MHz
   GPIO_Init(GPIOA,&GPIO_InitStructure);                                   //设置PA.2 /PA.3 /PA.5
}

void EXTIX_Init(void)
{

NVIC_InitTypeDef NVIC_InitStructure;     //定义结构体变量

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);    //选择中断分组2,3个中断源,需2bit进行优先级设置
                                                      //高两位用于设置抢占式 优先级;
     //低两位用于设置响应式 优先级
   
   NVIC_InitStructure.NVIC_IRQChannel = EXTI_Line0;     //选择中断通道2
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //抢占式中断优先级设置为0
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;         //响应式中断优先级设置为0
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //使能中断

NVIC_Init(&NVIC_InitStructure);

}

void EXTI_cfg()      //将相应的IO口与中断线路进行连接
{
   EXTI_InitTypeDef EXTI_InitStructure;      //定义结构体变量

EXTI_ClearITPendingBit(EXTI_Line0);      //清空中断标志   PA.2 中断口

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);  //选择中断管脚PA.2 PA.3 PA.5

EXTI_InitStructure.EXTI_Line = EXTI_Line0;  //选择中断线路2 3 5
   EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;                   //设置为中断请求,非事件请求
   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;    //设置中断触发方式为上下降沿触发
   EXTI_InitStructure.EXTI_LineCmd = ENABLE;                         //外部中断使能

EXTI_Init(&EXTI_InitStructure);
}

void ioInterruptSet(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;

EXTI_ClearITPendingBit(EXTI_Line0);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;         
  GPIO_Init(GPIOA,&GPIO_InitStructure);

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);  // 
EXTI_InitStructure.EXTI_Line = EXTI_Line0;                   //选择中断线路0
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;          //设置为中断请求,非事件请求
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;      //下降沿触发
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;                    //外部中断使能
  EXTI_Init(&EXTI_InitStructure);

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);           //选择中断分组2
  NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;          //选择中断通道2
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占式中断优先级设置为0
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //响应式中断优先级设置为0
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           //使能中断
  NVIC_Init(&NVIC_InitStructure);
}

///***********************************************************************************
//****函数名称:端点1数据上传函数
//****函数作用:
//****函数描述:
//************************************************************************************/
//void ch372ep1up()
//{
// unsigned char i;
// CH375_WRCMD(CMD_WR_USB_DATA5);
// CH375_WRDAT(0x04);
// for(i=0;i<4;i++)
// CH375_WRDAT(MouseData[i]);
// IsBusying=1;
//
//}
/***********************************************************************************
****函数名称:端点0数据上传函数
****函数作用:
****函数描述:
************************************************************************************/
void mCh375Ep0Up()
{
unsigned char i,len;
if(mVarSetupLength)
{ //长度不为0传输具体长度的数据
if(mVarSetupLength<=8)
{
len=mVarSetupLength;
mVarSetupLength=0;
        } //长度小于8则长输要求的长度
else
{
len=8;
mVarSetupLength-=8;
}                         //长度大于8则传输8个,切总长度减8
   CH376_WR_CMD_PORT(CMD_WR_USB_DATA3); //发出写端点0的命令
        CH376_WR_DAT_PORT(len); //写入长度
    for(i=0;i!=len;i++)
{
CH376_WR_DAT_PORT(request.buffer[i]);               //循环写入数据
}

}
else
{
CH376_WR_CMD_PORT(CMD_WR_USB_DATA3); //发出写端点0的命令
CH376_WR_DAT_PORT(0);                   //上传0长度数据,这是一个状态阶段

}

}
/***********************************************************************************
****函数名称:描述符复制函数
****函数作用:
****函数描述:
************************************************************************************/
void mCh375DesUp()
{
unsigned char k;        
for (k=0; k!=8; k++ ) 
{
         request.buffer[k]=*VarSetupDescr;   //依次复制8个描述符,
         VarSetupDescr++;
    }
}

/***********************************************************************************
****函数名称:外部中断0的响应函数
****函数作用:通过判断375的终端类型值进行相应的处理
****函数描述:
************************************************************************************/
void EXTI0_IRQHandler(void)
{
unsigned char i,temp,length,len;
unsigned char c1;
   // ;//SendStr("......进入中断......\r\n");
//unsigned char   *pBuf;
//unsigned char   mBuf[64];
    EXTI_ClearITPendingBit(EXTI_Line0);  //清空中断标志位,防止持续进入中断
CH376_WR_CMD_PORT(CMD_GET_STATUS);  /* 向CH375芯片发送获取中断状态的命令;CMD_GET_STATUS为命令码,数值大小在CH375INC.H 头文件中*/
temp =CH376_RD_DAT_PORT();   /* 读取中断状态 */

switch(temp)                                  //判断中断类型(状态),具体区分请见375头文件中的定义
{
   case USB_INT_EP0_SETUP:
;//SendStr("......接收到SETUP......\r\n");
CH376_WR_CMD_PORT(CMD_RD_USB_DATA);
length=CH376_RD_DAT_PORT();
for(i=0;i<length;i++)
{
request.buffer[i]=CH376_RD_DAT_PORT();
//SendHex(request.buffer[i]);
;//SendStr("\r\n");
}
if(length==8)//如果长度是8
{
mVarSetupLength=request.buffer[6]&0x7f;//控制传输的数据长度最长是128字节
if(request.r.bmReuestType&0x40)//6-5=10厂商请求
;//SendStr("......厂商请求......\r\n");
if(request.r.bmReuestType&0x20)//6-5=01类请求
;//SendStr("......类请求......\r\n");
if(!(request.r.bmReuestType&0x60))//6-5=00标准请求,一共11中标准请求
{
mVarSetupRequest=request.r.bRequest;//将标准请求保存
   switch(request.r.bRequest)//判断标准请求
   {
   case DEF_USB_GET_CONFIG://获取配置
    ;//SendStr("......获取配置......\r\n");
   break;
   case DEF_USB_GET_DESCR://获取描述符
   ;//SendStr("......获取描述符......\r\n");
   switch(request.buffer[3])//判断描述符的类型
   {
   case 1://设备描述符
   ;//SendStr("......请求设备描述符......\r\n");
   VarSetupDescr=DevDes;
   break;
   case 2://配置描述符
   ;//SendStr("......请求配置描述符......\r\n");
VarSetupDescr=ConDes;
   break;
   case 3://字数串描述符
    ;//SendStr("......请求字符串描述符......\r\n");
//VarSetupDescr=
if(request.buffer[4]==0)
{
;//SendStr("......请求语言描述符......\r\n");
VarSetupDescr=LangDes;
mVarSetupLength=4;
           }
if(request.buffer[2]==1)
{
;//SendStr("......请求厂商字符串......\r\n");
VarSetupDescr=Chang;
mVarSetupLength=0x14;
}
if (request.buffer[2]==2)
{
;//SendStr("......请求产品字符串......\r\n");
VarSetupDescr=SerDes;
mVarSetupLength=0x16;
}
if(request.buffer[2]==3)
{
;//SendStr("......请求产品序列号......\r\n");
VarSetupDescr=Chan;
mVarSetupLength=0x16;
}
   break;
   case 4://接口描述符
    ;//SendStr("......请求接口描述符......\r\n");
    break;
   case 5://端点描述符
    ;//SendStr("......请求端点描述符......\r\n");
    break;
case 0x22://获取HID报告描述符
;//SendStr("......请求HID......\r\n");
VarSetupDescr=Hid_des;
mVarSetupLength=0x34;
break;
default://没有定义
   ;//SendStr("......不支持的描述符请求......\r\n");
   break;
    }
   mCh375DesUp();
   break;
    case DEF_USB_GET_INTERF://获取接口
   ;//SendStr("......获取接口......\r\n");
   break;
    case DEF_USB_GET_STATUS://获取状态
    ;//SendStr("......获取状态......\r\n");
    break;
   case DEF_USB_SYNC_FRAME://同步帧
   ;//SendStr("......同步帧......\r\n");
   break;
case DEF_USB_CLR_FEATURE://清除特性
;//SendStr("......清除特性......\r\n");
break;
case DEF_USB_SET_ADDRESS://设置地址
;//SendStr("......设置地址......\r\n");
VarUsbAddress=request.buffer[2];
break;
case DEF_USB_SET_CONFIG://设置配置
;//SendStr("......设置配置......\r\n");
break;
case DEF_USB_SET_DESCR://设置描述
;//SendStr("......设置描述......\r\n");
CH375CONFLAG=0;
if(request.buffer[2]!=0)
{
CH375CONFLAG=1;
}
break;
case DEF_USB_SET_FEATURE://设置特性
;//SendStr("......设置特性......\r\n");
break;
case DEF_USB_SET_INTERF://设置接口
;//SendStr("......设置接口......\r\n");
break;
   default :
   ;//SendStr("......不支持的标准请求......\r\n");
   CH376_WR_CMD_PORT (CMD_UNLOCK_USB); //释放缓冲区
   break;
   }
}

}
mCh375Ep0Up();
break;
case USB_INT_EP0_OUT:
CH376_WR_CMD_PORT(CMD_RD_USB_DATA); //发出读数据命令
if(length=CH376_RD_DAT_PORT())
{ //长度为0跳出
for(len=0;len!=length;len++)
c1=CH376_RD_DAT_PORT(); //取出下传数据
}
break;
case USB_INT_EP0_IN:
;//SendStr("......端点0IN......\r\n");
if(mVarSetupRequest==DEF_USB_GET_DESCR)
{
mCh375DesUp();
mCh375Ep0Up();
;//SendStr("......描述符上传成功......\r\n");
}
else 
if(mVarSetupRequest==DEF_USB_SET_ADDRESS)
   { //设置地址
   CH376_WR_CMD_PORT(CMD_SET_USB_ADDR);
   CH376_WR_DAT_PORT(VarUsbAddress); //设置USB地址,设置下次事务的USB地址
   }
CH376_WR_CMD_PORT(CMD_UNLOCK_USB); //释放缓冲区
break;
case USB_INT_EP1_OUT:
;//SendStr("......端点1OUT......\r\n");
break;
case USB_INT_EP1_IN:
;//SendStr("......端点1IN......\r\n");
CH376_WR_CMD_PORT(CMD_UNLOCK_USB);
IsBusying=0;
break;
case USB_INT_EP2_OUT:
;//SendStr("......端点2OUT......\r\n");
break;
case USB_INT_EP2_IN:
;//SendStr("......端点2IN......\r\n");
break;
case USB_INT_USB_SUSPEND:
;//SendStr("......USB挂起......\r\n");
break;
default:
;//SendStr("......总线复位......\r\n");
if((temp&0x03)==0x03)
{ //总线复位
CH375FLAGERR=0;             //错误清0
CH375CONFLAG=0;         //配置清0
mVarSetupLength=0;
}
CH376_WR_CMD_PORT (CMD_UNLOCK_USB); //释放缓冲区
break;
break;

}
}

USB设备,鼠标,键盘使用CH372,CH375,进行模拟的历程相关推荐

  1. 编写一个USB接口程序,模拟计算机启动过程和关闭过程启动过程中要加载鼠标、键盘、麦克风等USB设备,具体要求如下: (1)定义一个接口USB,包含两个抽象方法turnOn()he turnOff(),

    一.好物推荐 给大家推荐三款蓝牙耳机,下面的链接可以直接购买: 1.https://item.taobao.com/item.htm?ft=t&id=643733003968 2.https: ...

  2. python3操作USB设备

    本文以读取USB无线测量设备数据举例说明.需要用到pyusb模块和libusb-1.0.dll,详细说明如下. 一.配置libusb-1.0.dll 下载libusb-1.0.22.7z,根据操作系统 ...

  3. PyMouse模拟鼠标键盘操作

    PyMouse模拟鼠标键盘操作 使用PyMouse实现模拟鼠标键盘操作 -----解决方案1 1)安装[pyMouse]( https://pypi.org/project/PyMouse/) 2)安 ...

  4. 远程桌面鼠标键盘映射问题

    如果在远程桌面使用时需要最小化远程桌面时仍需要使用到鼠标键盘时,可在开启远程桌面的服务机做如下操作:  运行regedit 找到注册表项HKEY_CURRENT_USER\Software\Micro ...

  5. 戴尔服务器鼠标键盘无响应,Windows 10 更新 KB4074588 后,USB 鼠标、键盘和其他设备无响应...

    本文包含有关 Windows 10 更新(KB4074588)后 USB 设备无法响应的信息. USB 设备无响应 运行 Windows 10 的台式机和笔记本电脑可能会使用最近的 Windows 1 ...

  6. 8修改host_正点原子【STM32-F407探索者】第五十九章 USB 鼠标键盘(Host)实验

    1)资料下载:点击资料即可下载 2)对正点原子Linux感兴趣的同学可以加群讨论:935446741 3)关注正点原子公众号,获取最新资料更新 上一章我们向大家介绍了如何利用 STM32F4 的 US ...

  7. 解决 Windows USB 鼠标键盘断连掉线的问题 和 安全删除硬件并弹出媒体图标 没有弹出移动硬盘的选项

    解决 Windows USB 鼠标键盘断连掉线的问题 鼠标键盘在连接到USB集线器后,经常性出现掉线的情况,键盘和数遍经常性的失灵. 在跟换USB集线器和重装官方驱动后无果.更换过新的USB集线器,发 ...

  8. 台式计算机usb口不识别鼠标,如何解决插入鼠标提示无法识别USB设备的问题

    如何解决插入鼠标提示无法识别USB设备的问题 有的小伙伴在使用电脑过程中,为了方便使用鼠标,因此插入了鼠标,但是却看到了无法识别USB设备的提示框,那么如何解决这一问题呢?小编就来为大家介绍一下吧. ...

  9. android usb鼠标,用鼠标键盘控制你的Android手机完整图文教程

    网上大都是91助手for android来连接手机和电脑,我自己比较偏向于豌豆荚,都可以的,下面给出我的步骤及过程中遇到的几个小问题,供大家参考! 一.鼠标键盘控制手机教程 1.在PC上,安装豌豆荚, ...

最新文章

  1. mysql sysdate本周_mysql 查询当天、本周,本月,上一个月的数据
  2. 品牌诞生于两个驱动力
  3. SQL_drop删除表、数据库
  4. python利用函数求20的阶乘_请运用reduce函数,计算20的阶乘,慕课网2-19
  5. OJ 21658::Monthly Expense(二分搜索+最小化最大值)
  6. 模态框 (框架引入出现的问题)
  7. 喵喵玩 v3.8.5
  8. 您尝试安装的Adobe Flash Player版本不是最新版本解决办法
  9. nginx静态资源优化配置方法
  10. 网站的友情链接是什么?
  11. npm WARN unmet dependency错误解决方法
  12. 什么是抖音小店飞鸽3分钟人工回复率?了解客服回复问题以及解决方案
  13. 软考非计算机专业考难吗,非计算机专业考软考初级哪个更容易过
  14. 概率论4.5中心矩与原点矩
  15. IntelliJ IDEA中的神仙插件 写代码必备!
  16. 期货贴水如何交割(期货交割升贴水)
  17. 【学习笔记】无监督行人重识别
  18. 惠普HP Tango X 打印机驱动
  19. 华硕主板使用nt6 oem loader激活之后重启卡在ASUS LOGO位置无法进入BIOS界面
  20. 怎么把一个页面的数据传到另一个页面?

热门文章

  1. 【SemiDrive源码分析】【MailBox核间通信】42 - 基于Mailbox 实现的 mailbox_demo 应用程序(RTOS Android侧通信实现)
  2. 如何提升运行效率(性能优化)
  3. WORD显示Word无法创建工作文件请检查临时环境变量
  4. 照片批量重命名为拍摄日期
  5. VB编写DirectX简明教程
  6. 【专家访谈】测试专家 陈林钧 访谈问题收集中
  7. 小米蒸排骨+炒红萝卜丝+苦瓜炒蛋
  8. FileIterator
  9. 计算机数控系统cnc分类,数控机床系统有几种 数控系统的类型和分类
  10. Java:获取当前日期当前季度、上一季度开始结束日期时间