CH375B操作USB键盘问题

前段时间向贵公司申请了两片CH375B,想用它做主机来和USB键盘通信,单片机用的是MSP430,

程序是参考的论坛里提供的CH375B操作HID设备的例程,开始程序在执行设置CH375工作模式时中断返

回正常,但在等待设备连接时中断返回的却是错误的,本来按照贵公司提供的头文件CH375INC.H如果

连接正常,则应返回0x15,但我的返回时0x95,硬件应该没问题,因为我仔细检查过了,并且前面的

模式设置时中断返回正常,请问这会是什么原因呢? 附上相关代码: #define CH375_INT_WIRE P1IN&0x80 //P1.7 连接CH375的INT#引脚,用于查询中断状态 /************************************* //函数名称:Wait_Interrupt //函数功能:主机端等待操作完成, 返回操作状态 //入口:无 //出口:Intout--状态返回 //备注: ***************************************/ INT8U Wait_Interrupt(void) { while( CH375_INT_WIRE ); //查询等待CH375操作完成中断(INT#低电平) Ch375_Wr_Cmd_Port( CMD_GET_STATUS ); // 产生操作完成中断, 获取中断状态 //return( Ch375_Rd_Dat_Port() ); Intout = Ch375_Rd_Dat_Port(); //此处仅仅为了测试,否者应打开被屏蔽的语句 return (Intout); }

/************************************* //函数名称:Ch375_Rd_Dat_Port //函数功能:从CH375的数据端口读出数据,周期不小于1.5uS,如果单片机较快则延时 //入口:无 //出口:dout--读得的数据,一个字节 //备注: ***************************************/ INT8U Ch375_Rd_Dat_Port(void) { INT8U dout; CH375_A0_CLR; //A0=1时为写入命令 =0为写入数据 CH375_WR_SET; CH375_RD_CLR; //RD=0时表示读入操作 Delay_X_Us(2);// 因为MSP430单片机较快所以需延时 CH375_DATA_IN; dout= P2IN; Delay_X_Us(1); CH375_RD_SET;//RD=0时表示读入操作 Delay_X_Us(1); return(dout); }

/************************************* //函数名称:Ch375_Wr_Cmd_Port //函数功能:向CH375写命令,周期不小于4uS,如果单片机较快则延时 //入口:cmd--待写命令 //出口:无 //备注: ***************************************/ void Ch375_Wr_Cmd_Port( INT8U cmd ) { CH375_A0_SET;//A0=1时为写入命令 CH375_RD_SET;//RD=0时表示读入操作 CH375_DATA_OUT; P2OUT=cmd; CH375_WR_CLR; Delay_X_Us(2); CH375_WR_SET; Delay_X_Us(2); }

贵公司提供的头文件部分内容如下: /* 以下状态代码1XH用于USB主机方式的操作状态代码, 仅CH375支持 */ #ifndef USB_INT_SUCCESS #define USB_INT_SUCCESS 0x14 /* USB事务或者传输操作成功 */ #define USB_INT_CONNECT 0x15 /* 检测到USB设备连接事件 */ #define USB_INT_DISCONNECT 0x16 /* 检测到USB设备断开事件 */ #define USB_INT_BUF_OVER 0x17 /* USB控制传输的数据太多, 缓冲区

溢出 */ #define USB_INT_USB_READY 0x18 /* USB设备已经被初始化(已分配

USB地址) */ #define USB_INT_DISK_READ 0x1D /* USB存储器读数据块, 请求数据读

出 */ #define USB_INT_DISK_WRITE 0x1E /* USB存储器写数据块, 请求数据写

入 */ #define USB_INT_DISK_ERR 0x1F /* USB存储器操作失败 */ #endif

这个头文件应该没问题吧,它对于键盘设备应该是一样的吧? 谁对这方面比较熟悉请帮我分析一下,先谢谢了!

设置模式不会产生中断,而且模式设置成功应该返回0x51,如果硬件没问题,检查你的操作流程。


1、官方提供的头文件没问题 2、参考手册作2次测试命令,测试数据分别是0x55, 0xAA


谢谢两位的解答,我按照上面的流程试了,测试程序如下: void Usb_Key(void) { INT8U i; Init_Usb_Ports(); //初始化端口 Delay_X_Ms(250); Set_Usb_Mode(7); // 复位USB设备,CH375向USB信号线的D+和D-输出低电平 Delay_X_Ms(10); Set_Usb_Mode( 6 ); // 结束复位 Ch375_Wr_Cmd_Port( CMD_GET_IC_VER ); Ceshi=Ch375_Rd_Dat_Port(); //得到固件版本号,正常为0x0B7 Ch375_Wr_Cmd_Port(CMD_CHECK_EXIST); // 测试工作状态是否正常? Ch375_Wr_Dat_Port(0x55); // 测试数据 Ceshi = Ch375_Rd_Dat_Port(); } 在上面的程序中,如果我不把键盘接上去,则得到的版本号为0x0B7和测试返回数据0xAA,但是当我把键盘接上去后得到的版本号就是0x37和测试返回数据0x2A了,请问这是为什么了?还请高手给予指教!先谢谢了!


Ch375_Wr_Cmd_Port( CMD_GET_IC_VER ); Ceshi=Ch375_Rd_Dat_Port(); //得到固件版本号,正常为0x0B7 Ch375_Wr_Cmd_Port(CMD_CHECK_EXIST); // 测试工作状态是否正常? Ch375_Wr_Dat_Port(0x55); // 测试数据 Ceshi = Ch375_Rd_Dat_Port(); 初始化CH376之前做。


补充一下:刚才又用其他数据进行了测试,发现键盘不连接时,D7始终为高电平;当键盘接上去后,D7始终为低电平;这是硬件的问题吗?


谢谢4楼的解答。 void Usb_Key(void) { INT8U i; Init_Usb_Ports(); //初始化端口 Delay_X_Ms(250); Ch375_Wr_Cmd_Port( CMD_GET_IC_VER ); Ceshi=Ch375_Rd_Dat_Port(); //得到固件版本号,正常为0x0B7 Ch375_Wr_Cmd_Port(CMD_CHECK_EXIST); // 测试工作状态是否正常? Ch375_Wr_Dat_Port(0x55); // 测试数据 Ceshi = Ch375_Rd_Dat_Port(); Ch375_Wr_Cmd_Port(CMD_CHECK_EXIST); // 测试工作状态是否正常? Ch375_Wr_Dat_Port(0xff); // 测试数据 Ceshi = Ch375_Rd_Dat_Port(); } 我在刚才的基础上,去掉了初始化,增加了一个0xff测试数据,结果是无论连接键盘与否,D7都是高电平,即0xff测试数据返回始终是0x80,这说明是我的硬件有问题了吗?


Ch375_Wr_Cmd_Port(CMD_CHECK_EXIST); // 测试工作状态是否正常? Ch375_Wr_Dat_Port(0x55); // 测试数据 Ceshi = Ch375_Rd_Dat_Port();

Ch375_Wr_Cmd_Port(CMD_CHECK_EXIST); // 测试工作状态是否正常? Ch375_Wr_Dat_Port(0xaa); // 测试数据 Ceshi = Ch375_Rd_Dat_Port(); 连续做两次测试,看看数据是否全部正常。 如果D7始终为1,建议检查端口方向是否设置正确,检查外部电路是否虚焊。


谢谢您的解答,我按照您说的测试了,但是还是若不初始化,D7返回始终为1,检查硬件并无虚焊存在,IO口方向设置正确。如果连接上键盘后,用语句Set_Usb_Mode( 6 );设置模式,返回值为0x51,即正常,但若不接,返回为0x0D1,即返回错误,D7始终为1。仅仅把键盘接上去,而不初始化,用数据测试和不接键盘无区别。 补充:我用的是CH375B,接键盘时数据线是不用反接的吧?我目前是没有反接的。 请问如果连接正确,会不会是CH375B本身坏了?谢谢!


芯片坏的可能性很小,先不用测试是否插入USB键盘。按照7楼测试,最终的结果是什么?芯片坏的可能性应该是很小的,还是怀疑IO设置,硬件部分有问题。单片机和CH375之间的通讯和CH375与USB设备的通讯应该是相互独立的。另外仔细检查一下AO线变化是否正确,你没有贴出写数据的函数。


谢谢您的解答,我按照7楼的测试了,结果当测试数据为0x55时,返回为0x0aa;当测试数据为0x0aa时,返回数据为0xD5;当我用0x0ff作为测试数据时,返回值为0x80。 我再把我的相关程序附上: //宏定义 #define DATAIN P2IN #define DATAOUT P2OUT #define CH375_DATA_IN P2DIR = 0x00 //单片机P2口设为输入 #define CH375_DATA_OUT P2DIR = 0xff //单片机P2口设为输出 #define CH375_INT_WIRE P1IN&0x80 //P1.7 连接CH375的INT#引脚,用于查询中断状态 #define CH375_WR_SET P3OUT |= BIT0 //P3.0 写选通(注:BIT0=0x0001) #define CH375_WR_CLR P3OUT &= ~BIT0 #define CH375_RD_SET P3OUT |= BIT1 //P3.1 读选通(注:BIT1=0x0002) #define CH375_RD_CLR P3OUT &= ~BIT1 #define CH375_A0_SET P3OUT |= BIT2 //P3.2 地址线口,若为1,写命令;若为0,读写数据(注:BIT2=0x0004) #define CH375_A0_CLR P3OUT &= ~BIT1 #define CH375_CS_SET P3OUT |= BIT3 //p3.3 片选信号(注:BIT3=0x0008) #define CH375_CS_CLR P3OUT &= ~BIT3

/************************************* //函数名称:Init_Usb_Ports //函数功能:初始化与USB模块相关的引脚 //入口:无 //出口:无 //备注: ***************************************/ void Init_Usb_Ports(void) { P3DIR |= 0x0f; //控制引脚设为输出 P1DIR &= ~BIT7;//USB中断引脚设为输入 P1IFG &= ~BIT7;//清除中断标志0 P1IES |= BIT7;//下降沿中断 P1IE &= ~BIT7;//禁止管脚P1.7中断 CH375_CS_SET; _NOP(); _NOP(); CH375_CS_CLR; _EINT();//使能中断 } //基本读写函数 /************************************* //函数名称:Ch375_Wr_Cmd_Port //函数功能:向CH375写命令,周期不小于4uS,如果单片机较快则延时 //入口:cmd--待写命令 //出口:无 //备注: ***************************************/ void Ch375_Wr_Cmd_Port( INT8U cmd ) { CH375_DATA_OUT;//数据口输出 CH375_A0_SET;//A0=1时为命令 CH375_RD_SET;//RD=1、WR=0时表示写入操作 DATAOUT=cmd; CH375_WR_CLR; Delay_X_Us(4); CH375_WR_SET; Delay_X_Us(2); } /************************************* //函数名称:Ch375_Wr_Dat_Port //函数功能:向CH375写数据,周期不小于1.5uS,如果单片机较快则延时 //入口:dat--待写数据 //出口:无 //备注: ***************************************/ void Ch375_Wr_Dat_Port( INT8U dat ) { CH375_DATA_OUT;//数据口输出 CH375_A0_CLR;//A0=1时为命令 =0为数据 CH375_RD_SET;//RD=1、WR=0时表示写入操作 DATAOUT=dat; CH375_WR_CLR; Delay_X_Us(3); CH375_WR_SET; Delay_X_Us(2); }

/************************************* //函数名称:Ch375_Rd_Dat_Port //函数功能:从CH375的数据端口读出数据,周期不小于1.5uS,如果单片机较快则延时 //入口:无 //出口:dout--读得的数据,一个字节 //备注: ***************************************/ INT8U Ch375_Rd_Dat_Port(void) { INT8U dout; CH375_DATA_IN; //数据口输入 CH375_A0_CLR; //A0=1时为命令 =0为数据 CH375_WR_SET; CH375_RD_CLR; //RD=0、WR=1时表示读入操作 dout= DATAIN; Delay_X_Us(3); CH375_RD_SET; return(dout); } 关于硬件部分,我昨天重新换了一个测试的板子,效果一样,除非我的原理图有错,焊接、连线本身是不存在问题的,由于我的单片机在3.3V工作,所以CH375B也是3.3V供电的的,具体原理图如下: 2010575371843.jpg


原理图我是参考贵公司的《USB 芯片的电路及PCB 设计的重要注意事项》设计的,不知道我的原理图有误没,请您帮忙看看,麻烦您了!


检查D7数据线有没有虚焊,或者短路,用万用表或者示波器测试一下A0信号线,发送命令的时候A0为高,在发送数据的时候A0为低电平


复位电容C26换成0.47UF或者更大点,保证复位的可靠性


非常感谢楼上各位的解答,都怪我粗心,程序的宏定义搞错了,哎,忙了一天!刚才按照楼上两位的意思测了一下,发现问题了!再次深表感谢!谢谢楼上各位热心的帮助!


又遇到新问题了,贵公司提供的代码中在开始得到键盘描述符的时候为什么不直接用下面这个函数: INT8U Get_Descr( INT8U type ) { Status=0xff; Ch375_Wr_Cmd_Port( CMD_GET_DESCR ); Ch375_Wr_Dat_Port( type ); // 描述符类型, 只支持1(设备)或者2(配置) Status=Wait_Interrupt(); // 等待CH375操作完成 if ( Status==USB_INT_SUCCESS ) // 操作成功 { INT8U i, len; len=Rd_Usb_Data( Data_Buf ); //printf( "%s描述符是:", type==1?"设备":"配置" ); for ( i=0; i!=len; i++ ); //printf( "%02x ", (unsigned int)Data_Buf[i] ); //printf( "\n" ); } return( Status ); } 而是采用控制传输的方式通过先设置请求包的各个值, Request.Req.bmRequestType=0x80; //获取设备描述符 Request.Req.bRequest=0x06; Request.Req.wValue=0x0001; Request.Req.wIndex=0x0000; Request.Req.wLength=0x1200; 然后调用下面这个函数呢? INT8U Get_Descr_Ex(void) { INT8U descr_len; INT8U *p=Data_Buf; Endp7_Mode=0x80; Toggle_Send(); Wr_Usb_Data(8,Request.Req_buf); Issue_Token(( 0 << 4 ) | DEF_USB_PID_SETUP); Status=Wait_Interrupt(); if(Status==USB_INT_SUCCESS)// SETUP阶段操作成功 { Endp6_Mode=0xc0; Toggle_Recv(); } else return(0); Issue_Token(( 0 << 4 ) | DEF_USB_PID_IN); Status=Wait_Interrupt(); if(Status==USB_INT_SUCCESS)// DATA阶段操作成功 { if(Flag_Config_2) descr_len=Data_Buf[2]-Rd_Usb_Data(Data_Buf); else descr_len=Data_Buf[0]-Rd_Usb_Data(Data_Buf); while(descr_len>0) { Toggle_Recv(); p+=0x08; Issue_Token(( 0 << 4 ) | DEF_USB_PID_IN); Status=Wait_Interrupt(); if(Status==USB_INT_SUCCESS) // DATA阶段操作成功 descr_len-=Rd_Usb_Data(p); else return(0); } } else return(0); Endp7_Mode=0xc0; Toggle_Send(); Wr_Usb_Data(0,Request.Req_buf); Issue_Token(( 0 << 4 ) | DEF_USB_PID_OUT); Status=Wait_Interrupt(); if(Status==USB_INT_SUCCESS)// 状态阶段操作成功 return(1); else return(0); } 我在调用这个函数的时候,前面的建立阶段返回状态正确,,但是数据阶段返回总是0x2E而不是所想的0x14,这可能是什么原因照成的呢?

另外,在设置CH375B进入低速模式的时候,使用下面这个函数吗? void Set_Freq(void) { Ch375_Wr_Cmd_Port(0x0b); // 切换使375B进入低速模式 Ch375_Wr_Dat_Port(0x17); Ch375_Wr_Dat_Port(0xd8); }

请各位高手给予解答,小弟在这里先谢过了!


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