CH375B作主机键盘反应慢问题[原创][求助]

CH375DS2下载地址:http://www.wch.cn/download/list.asp?id=14


TO:gig: endp_in_addr=08 这个不对啊.是该是0X01,你检查一下获取配置描述符部分,或者强制的该为endp_in_addr=01 因为端点不对,所以返回一种错误.


TO luomingde: 请问你用的是什么模块?模块名称.是在我们公司购买的吗?如果是的话我们应该会给您一张光盘,光盘里面会有的


在程式中加了一句:endp_in_addr=0x01;//------------------加上去的,见下面 //------------------ /* 获取配置描述符 */ UINT8 GetConfigDescr( PUINT8 buf ) { UINT8 s, len,i,c,j; UINT8 BufLogDescr[ sizeof( SetupGetCfgDescr ) ] ;

s = HostCtrlTransfer374( SetupGetCfgDescr, buf, &len ); // 执行控制传输 if ( s == USB_INT_SUCCESS ) { for(i=0;i!=len;i++)printf("%02x ",(unsigned short)buf[i]); printf("\n"); if ( len < ( (PUSB_SETUP_REQ)SetupGetCfgDescr ) -> wLengthL ) s = USB_INT_BUF_OVER; // 返回长度错误 else { memcpy ( BufLogDescr, SetupGetCfgDescr, sizeof( SetupGetCfgDescr ) ); ( (PUSB_SETUP_REQ)BufLogDescr ) -> wLengthL = ( (PUSB_CFG_DESCR)buf ) -> wTotalLengthL; // 完整配置描述符的总长度 s = HostCtrlTransfer374( BufLogDescr, buf, &len ); // 执行控制传输 if ( s == USB_INT_SUCCESS ) { //简单分析配置描述符,获取端点地址,这里只处理一个端点的情况 for ( i = 0; i < ( (PUSB_CFG_DESCR)buf ) -> wTotalLengthL; i ++ ) printf( "%02X ", (UINT16)( buf[i] ) ); //配置描述符 printf( "\n" ); for(i=0;i<( (PUSB_CFG_DESCR)buf ) -> wTotalLengthL;i++) { if((buf[i]==0x09)&&(buf[i+1]==0x21)&&(buf[i+6]==0x22))hid_des_leng=buf[i+7]; //获取报告描述符的长度 } printf("hid_des_leng=%02x\n",(unsigned short)hid_des_leng); endp_out_addr=endp_in_addr=0;endp_num=0; for(i=0;i<( (PUSB_CFG_DESCR)buf ) -> wTotalLengthL;i++) { if((buf[i]==0x09)&&(buf[i+1]==0x04)&&(buf[i+5]==0x03)&&(buf[i+7]==0x01)||(buf[i+7]==0x02)) //接口描述符为HID的鼠标、键盘 { for(j=0;j<( (PUSB_CFG_DESCR)buf ) -> wTotalLengthL-i;j++) { if((buf[i+j]==0x07)&&(buf[i+j+1]==0x05)&&(buf[i+j+3]==0x03))c=buf[i+j+2]; //判断是否为中断端点 if ( c&0x80 )endp_in_addr=c&0x0f; // IN端点的地址 else{endp_out_addr=c&0x0f;} // OUT端点 if((endp_out_addr!=0)||(endp_in_addr!=0)) break; } } if((endp_out_addr!=0)||(endp_in_addr!=0))break; } endp_in_addr=0x01;//------------------加上去的 printf("endp_in_addr=%02x\n",(unsigned short)endp_in_addr); printf("endp_out_addr=%02x\n",(unsigned short)endp_out_addr); } } } return( s ); }

这样加了之后,按键有反应了,是正确的值,但是: 中断脚总是低电平,如果不按任何键,总是有2a,14等出来 还有,如果要将上面的程式理解清楚一些,有没有参考的资料,实在是不想买一大本书去研究USB,没有时间啊! //============================================================================================= 00 00 80 00 d5 00 00 f0 00 04 85 fe 00 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 28 cc 5c 63 62 c0 44 11 0c bb 1a 16 54 78 38 25 68 00 50 58 03 81 57 74 28 f8 04 c4 66 4a 24 58 Start CH374 Host Reset Device Start Low-Speed Device GetDeviceDescr: device_status=14 12 01 00 02 00 00 00 08 F2 04 00 04 44 01 01 02 00 01 address_status=14 09 02 22 00 09 02 22 00 01 01 00 A0 32 09 04 00 00 01 03 01 01 00 09 21 11 01 00 01 22 41 00 07 05 81 03 08 00 0A hid_des_leng=41 endp_in_addr=01 endp_out_addr=00 config_status=14 SetUsbConfig_success Set_Idle Set_idle success Get_Hid_Des HID_Desc: 05 01 09 06 a1 01 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 95 01 75 08 81 01 95 03 75 01 05 08 19 01 29 03 91 02 95 05 75 01 91 01 95 06 75 08 15 00 26 ff 00 05 07 19 00 2a ff 00 81 00 c0 Set_Report Set_Report success s:2a s:2a s:2a s:2a s:2a s:2a s:2a s:2a s:14 s:14 6 00 00 62 00 00 00 00 00 s:14 s:14 6 00 00 00 00 00 00 00 00 s:14 s:14 6 00 00 62 00 00 00 00 00 s:14 s:14 6 00 00 00 00 00 00 00 00 s:14 s:14 6 00 00 62 00 00 00 00 00 s:2a s:2a s:14 s:14 6 00 00 00 00 00 00 00 00 s:2a s:2a s:14 s:14 6 00 00 59 00 00 00 00 00 s:14 s:14 6 00 00 00 00 00 00 00 00 s:2a s:2a s:2a s:2a


在程式中加了一句:endp_in_addr=0x01;//------------------加上去的,见下面 //------------------ /* 获取配置描述符 */ UINT8 GetConfigDescr( PUINT8 buf ) { UINT8 s, len,i,c,j; UINT8 BufLogDescr[ sizeof( SetupGetCfgDescr ) ] ;

s = HostCtrlTransfer374( SetupGetCfgDescr, buf, &len ); // 执行控制传输 if ( s == USB_INT_SUCCESS ) { for(i=0;i!=len;i++)printf("%02x ",(unsigned short)buf[i]); printf("\n"); if ( len < ( (PUSB_SETUP_REQ)SetupGetCfgDescr ) -> wLengthL ) s = USB_INT_BUF_OVER; // 返回长度错误 else { memcpy ( BufLogDescr, SetupGetCfgDescr, sizeof( SetupGetCfgDescr ) ); ( (PUSB_SETUP_REQ)BufLogDescr ) -> wLengthL = ( (PUSB_CFG_DESCR)buf ) -> wTotalLengthL; // 完整配置描述符的总长度 s = HostCtrlTransfer374( BufLogDescr, buf, &len ); // 执行控制传输 if ( s == USB_INT_SUCCESS ) { //简单分析配置描述符,获取端点地址,这里只处理一个端点的情况 for ( i = 0; i < ( (PUSB_CFG_DESCR)buf ) -> wTotalLengthL; i ++ ) printf( "%02X ", (UINT16)( buf[i] ) ); //配置描述符 printf( "\n" ); for(i=0;i<( (PUSB_CFG_DESCR)buf ) -> wTotalLengthL;i++) { if((buf[i]==0x09)&&(buf[i+1]==0x21)&&(buf[i+6]==0x22))hid_des_leng=buf[i+7]; //获取报告描述符的长度 } printf("hid_des_leng=%02x\n",(unsigned short)hid_des_leng); endp_out_addr=endp_in_addr=0;endp_num=0; for(i=0;i<( (PUSB_CFG_DESCR)buf ) -> wTotalLengthL;i++) { if((buf[i]==0x09)&&(buf[i+1]==0x04)&&(buf[i+5]==0x03)&&(buf[i+7]==0x01)||(buf[i+7]==0x02)) //接口描述符为HID的鼠标、键盘 { for(j=0;j<( (PUSB_CFG_DESCR)buf ) -> wTotalLengthL-i;j++) { if((buf[i+j]==0x07)&&(buf[i+j+1]==0x05)&&(buf[i+j+3]==0x03))c=buf[i+j+2]; //判断是否为中断端点 if ( c&0x80 )endp_in_addr=c&0x0f; // IN端点的地址 else{endp_out_addr=c&0x0f;} // OUT端点 if((endp_out_addr!=0)||(endp_in_addr!=0)) break; } } if((endp_out_addr!=0)||(endp_in_addr!=0))break; } endp_in_addr=0x01;//------------------加上去的 printf("endp_in_addr=%02x\n",(unsigned short)endp_in_addr); printf("endp_out_addr=%02x\n",(unsigned short)endp_out_addr); } } } return( s ); }

这样加了之后,按键有反应了,是正确的值,但是: 中断脚总是低电平,如果不按任何键,总是有2a,14等出来 还有,如果要将上面的程式理解清楚一些,有没有参考的资料,实在是不想买一大本书去研究USB,没有时间啊! //============================================================================================= 00 00 80 00 d5 00 00 f0 00 04 85 fe 00 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 28 cc 5c 63 62 c0 44 11 0c bb 1a 16 54 78 38 25 68 00 50 58 03 81 57 74 28 f8 04 c4 66 4a 24 58 Start CH374 Host Reset Device Start Low-Speed Device GetDeviceDescr: device_status=14 12 01 00 02 00 00 00 08 F2 04 00 04 44 01 01 02 00 01 address_status=14 09 02 22 00 09 02 22 00 01 01 00 A0 32 09 04 00 00 01 03 01 01 00 09 21 11 01 00 01 22 41 00 07 05 81 03 08 00 0A hid_des_leng=41 endp_in_addr=01 endp_out_addr=00 config_status=14 SetUsbConfig_success Set_Idle Set_idle success Get_Hid_Des HID_Desc: 05 01 09 06 a1 01 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 95 01 75 08 81 01 95 03 75 01 05 08 19 01 29 03 91 02 95 05 75 01 91 01 95 06 75 08 15 00 26 ff 00 05 07 19 00 2a ff 00 81 00 c0 Set_Report Set_Report success s:2a s:2a s:2a s:2a s:2a s:2a s:2a s:2a s:14 s:14 6 00 00 62 00 00 00 00 00 s:14 s:14 6 00 00 00 00 00 00 00 00 s:14 s:14 6 00 00 62 00 00 00 00 00 s:14 s:14 6 00 00 00 00 00 00 00 00 s:14 s:14 6 00 00 62 00 00 00 00 00 s:2a s:2a s:14 s:14 6 00 00 00 00 00 00 00 00 s:2a s:2a s:14 s:14 6 00 00 59 00 00 00 00 00 s:14 s:14 6 00 00 00 00 00 00 00 00 s:2a s:2a s:2a s:2a


你把S打印去掉不就可以了吗.因为你一直在循环查询USB键盘是否有数据.所以会有中断的.


多谢红桃六,感觉到已调的差不多了,现在还是有一个问题没有搞定: 当开机后,刚开始正常,过不了多长时间(有时几秒,有时几十秒),中断指示灯就会不停的闪动(我在中断引脚到电源间接了一个LED),再按键盘上的按键就没有作用了,在下面的程式中增加一条S的打印指令,发现其值为20H,而不是成功之后的14H,将下面的程式中的延时的程式mDelaymS(5)改成mDelaymS(100)灯闪的会变慢,说明一直在这里循环,不清楚S=20H是什么意思?(CH374DS2的资料还在申请中,方便的话就将我的权限马上开通,谢谢) //================================ /*通过中断端点获取鼠标、键盘上传的数据 */ unsigned char Interrupt_Data_Trans(unsigned char *p) { UINT8 s,count; s = WaitHostTransact374( endp_in_addr, DEF_USB_PID_IN, tog1, 1000 ); // IN数据 printf("s:%x \n",(unsigned short)s); if(s!=USB_INT_SUCCESS ){mDelaymS(100); return s;} //5 else { count = Read374Byte( REG_USB_LENGTH ); Read374Block( RAM_HOST_RECV, count, p ); tog1 = tog1 ? FALSE : TRUE; } return s; } //=============================== 用串口监查到的值: 00 00 80 00 c5 00 00 f0 00 04 8f ff 00 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 28 cc 5c 67 62 c8 44 91 14 bb 12 56 54 68 38 25 68 00 54 58 03 81 57 74 28 b8 04 c4 66 4a 2c 5a Start CH374 Host Reset Device Start Low-Speed Device GetDeviceDescr: device_status=14 12 01 10 01 00 00 00 08 D9 04 27 A0 10 01 01 02 00 01 address_status=14 09 02 3b 00 09 02 3B 00 02 01 00 A0 32 09 04 00 00 01 03 01 01 00 09 21 10 01 00 01 22 3E 00 07 05 81 03 08 00 0A 09 04 01 00 01 03 00 00 00 09 21 10 01 00 01 22 6A 00 07 05 82 03 08 00 0A hid_des_leng=6a endp_in_addr=01 endp_out_addr=00 config_status=14 SetUsbConfig_success Set_Idle Set_idle success Get_Hid_Des HID_Desc: 05 01 09 06 a1 01 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 95 01 75 08 81 01 95 03 75 01 05 08 19 01 29 03 91 02 95 05 75 01 91 01 95 06 75 08 26 ff 00 05 07 19 00 29 91 81 00 c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 08 b5 09 38 09 01 03 0c 10 02 1c 4a 1c a9 f3 71 65 e9 b4 8f be af 5e e7 2e Set_Report Set_Report success s:14 00 00 25 00 00 00 00 00 s:14 00 00 00 00 00 00 00 00 s:14 00 00 25 00 00 00 00 00 s:20 s:20 s:20 s:20


下面给您贴一个兼容比较好的函数,您去替换一下相应的函数: UINT8 HostTransact374( UINT8 endp_addr, UINT8 pid, BOOL tog ) { // 本子程序着重于易理解,而在实际应用中,为了提供运行速度,应该对本子程序代码进行优化 UINT8 retry; UINT8 s, r, u; for ( retry = 0; retry < 3; retry ++ ) { Write374Byte( REG_USB_H_PID, M_MK_HOST_PID_ENDP( pid, endp_addr ) ); // 指定令牌PID和目的端点号 // Write374Byte( REG_USB_H_CTRL, BIT_HOST_START | ( tog ? ( BIT_HOST_TRAN_TOG | BIT_HOST_RECV_TOG ) : 0x00 ) ); // 设置同步标志并启动传输 Write374Byte( REG_USB_H_CTRL, ( tog ? ( BIT_HOST_START | BIT_HOST_TRAN_TOG | BIT_HOST_RECV_TOG ) : BIT_HOST_START ) ); // 设置同步标志并启动传输 // Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE ); // 取消暂停 mDelayuS( 200 ); s = Wait374Interrupt( ); if ( s == ERR_USB_UNKNOWN ) return( s ); // 中断超时,可能是硬件异常 // mDelayuS( 200 ); s = Read374Byte( REG_INTER_FLAG ); // 获取中断状态 if ( s & BIT_IF_DEV_DETECT ) { // USB设备插拔事件 mDelayuS( 200 ); Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_DEV_DETECT | BIT_IF_TRANSFER ); // 清中断标志 if ( s & BIT_IF_DEV_ATTACH ) { // USB设备连接事件 u = Read374Byte( REG_USB_SETUP ); if ( s & BIT_IF_USB_DX_IN ) { // 速度匹配,不需要切换速度 if ( u & BIT_SETP_USB_SPEED ) return( USB_INT_CONNECT_LS ); // 低速USB设备 return( USB_INT_CONNECT ); // 全速USB设备 } else { // 速度失配,需要切换速度 if ( u & BIT_SETP_USB_SPEED ) return( USB_INT_CONNECT ); // 全速USB设备 return( USB_INT_CONNECT_LS ); // 低速USB设备 } } else return( USB_INT_DISCONNECT ); // USB设备断开事件 } else if ( s & BIT_IF_TRANSFER ) { // 传输完成 mDelayuS( 100 ); Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_TRANSFER ); // 清中断标志 s = Read374Byte( REG_USB_STATUS ); // USB状态 // printf(" %02x ",(unsigned short )s); r = s & BIT_STAT_DEV_RESP; // USB设备应答状态 switch ( pid ) { case DEF_USB_PID_SETUP: case DEF_USB_PID_OUT: if ( r == DEF_USB_PID_ACK ) return( USB_INT_SUCCESS ); else if ( r == DEF_USB_PID_STALL || r == DEF_USB_PID_NAK ) return( r | 0x20 ); else if ( ! M_IS_HOST_TIMEOUT( s ) ) return( r | 0x20 ); // 不是超时/出错,意外应答 break; case DEF_USB_PID_IN: if ( M_IS_HOST_IN_DATA( s ) ) { // DEF_USB_PID_DATA0 or DEF_USB_PID_DATA1 if ( s & BIT_STAT_TOG_MATCH ) return( USB_INT_SUCCESS ); // 不同步则需丢弃后重试 } else if ( r == DEF_USB_PID_STALL || r == DEF_USB_PID_NAK ) return( r | 0x20 ); else if ( ! M_IS_HOST_TIMEOUT( s ) ) return( r | 0x20 ); // 不是超时/出错,意外应答 break; default: return( ERR_USB_UNKNOWN ); // 不可能的情况 break; } } else { // 其它中断,不应该发生的情况 mDelayuS( 200 ); // 等待传输完成 Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_INTER_FLAG ); /* 清中断标志 */ if ( retry ) return( ERR_USB_UNKNOWN ); // 不是第一次检测到则返回错误 } } return( 0x20 ); // 应答超时 }

获取数据的函数,速度尽可能快: /*通过中断端点获取鼠标、键盘上传的数据 */ unsigned char Interrupt_Data_Trans( ) { UINT8 s,count,i; UINT8 buf1[8]; s = WaitHostTransact374( endp_in_addr, DEF_USB_PID_IN, tog1, 1000 ); // IN数据 if ( s != USB_INT_SUCCESS ){ TI = 0; SBUF = s; while( TI == 0 );

mDelaymS( 5 ); return s; } else { count = Read374Byte( REG_USB_LENGTH ); Read374Block( RAM_HOST_RECV, count, buf1 ); for(i=0;i!=count;i++){ TI = 0; SBUF = buf1[i]; while( TI == 0 ); } tog1 = tog1 ? FALSE : TRUE; } return s; }


To: 红桃六 我使用的模块是在别人那买的,之后我才知道了南京沁恒电子及这个论坛,其实就只有一颗IC CH375B和转DIP的一个板子及晶振,线路和手册上的那部分相同,单片机是AT89S52我自己加的,从你发表的程序可以看出要使用一个128*64的LCD吧,这个我也可以加上去的。但从评估板上看没有使用LCD,那是用的PC上的串口调试器吗? 如果使用P1口和P3口的话,CH375B的片选CS连接到哪呢?谢谢指点。


TO: luomingde (1)用串口调试 (2)用P1口和P3口的话,那么是模拟I/O操作375了,CS可以任意接,只要不与其他的冲突即可 另,程序中CH375的CS、A0、RD、WR、INT,数据口需要按照你的硬件连接重新定义


用上面的程式之后,将print全部去掉,将中断的指示灯也去掉之后还是同前面一样的问题,返回的值还是20H,这个20H代表的是什么意义呢?(波特率也调高到了115200)


这个程序是我们测试兼容效果还不错的,如果你很多键盘都产生这个现象 的话就太不正常了.这样,你把程序发到我们技术支持邮箱里,我们看一下. 另外你检查你的硬件,USB外壳有没有接地?374工作在几V?9脚的接法是否正确?


中断INT0为何没有被拉低?我在串口测试中的信息如下: Start Please Insert USB Device... 设备描述符是:12 01 10 01 00 00 00 08 6d 04 0f c3 00 23 01 02 00 01 device 12 01 10 01 00 00 00 08 6d 04 0f c3 00 23 01 02 00 01 配置描述符是:09 02 3b 00 02 01 00 a0 32 09 04 00 00 01 03 01 01 00 09 21 10 01 0 0 01 22 40 00 07 05 81 03 08 00 0a 09 04 01 00 01 03 00 00 00 09 21 10 01 00 01 22 90 00 07 05 82 03 08 00 20 config 09 02 3b 00 02 01 00 a0 32 config 2 09 02 3b 00 02 01 00 a0 32 09 04 00 00 01 03 01 01 00 09 21 10 01 00 01 22 40 00 07 05 81 03 08 00 0a 09 04 01 00 01 03 00 00 00 09 21 10 01 00 01 22 90 00 07 0 5 82 03 08 00 20 set config set idle report 05 01 09 06 a1 01 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 95 01 75 08 81 01 95 05 75 01 05 08 19 01 29 05 91 02 95 01 75 03 91 01 95 06 75 08 15 00 26 a 4 00 05 07 19 00 29 a4 81 00 c0 set report

是USB的键盘,中断程序没有执行,键盘无效,收不到任何字节。谢谢了!


不知道你是如何监视中断引脚没有产生,如果不产生中断的话那么你上述的描述符也是无法获取到的. 你这个键盘比较特殊是一个复合设备.需要更改程序后才能支持,你看一下有两个接口,你插在PC上肯定是两个设备.其他键盘是否也是相同情况?键盘无效,收不到任何字节。


等输出set report后就没有反应了,键盘上的Nun Lock灯点亮了, 我想是中断没有起作用,用示波器测试到INT0上一直是高电平。在输出set report之前测试到INT0的电平还会被拉低。换个键盘,鼠标都没有反应,将PC上的USB键盘也去掉了。收不到任何字节。谢谢了!


只有登录才能回复,可以选择微信账号登录