CH372 HID类键盘的连续上传数据的问题

/*;CH372/CH375 USB device mode & external firmware ; U2(AT89C51) Program ; ; Website: http://winchiphead.com ; Email: 个人信息保护,已隐藏 ; Author: W.ch 2003.12, 2005.03 ; ;**************************************************************************** 关于程序的说明: 模拟键盘程序,主机枚举好后,发送K,可以在TXT文档中显示出来。作为演示,需要其他键值可以自己修改,如果不是连续发数据的 话,一般发送完毕键值后发送一包00,主机认为发送结束 */

/* MCS-51单片机C语言的示例程序 */ #include #include "CH375INC.H"

unsigned char idata buf[8]; 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;

//设备描述符 unsigned char code DevDes[]={ 0x12 //描述符大小 , 0x01 //常数DEVICE , 0x10 //USB规范版本信息 , 0x01 , 0x00 //类别码, , 0x00 //子类别码 , 0x00 //协议码 , 0x08 //端点0的最大信息包大小 , 0x3c //厂商ID , 0x41 , 0x03 //产品ID , 0x20 , 0x00 //设备版本信息 , 0x02 , 0x01 //索引值 , 0x02 , 0x00 , 0x01 //可能配置的数目 }; //配置描述符 unsigned char code ConDes[]={ //配置描述符 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x04, 0xa0, 0x23,//配置描述符 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x01, 0x01, 0x05,//接口描述符 0x09, 0x21, 0x10, 0x01, 0x00, 0x01, 0x22, 0x41, 0x00,//HID类描述符 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x18 //端点描述符,只配置了输入端点,输出端点用0端点 }; //配置描述符

/*报表描述符*/ unsigned char code Hid_des[]={0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x05, 0x07, 0x19, 0xe0, 0x29, 0xe7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, 0x95, 0x03, 0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x03, 0x91, 0x02, 0x95, 0x01, 0x75, 0x05, 0x91, 0x01, 0x95, 0x06, 0x75, 0x08, 0x15, 0x00, 0x26, 0xff, 0x00, 0x05, 0x07, 0x19, 0x00, 0x2a, 0xff, 0x00, 0x81, 0x00, 0xc0 }; /*关于全局变量的定义*/ unsigned char mVarSetupRequest; // ;USB请求码 unsigned char mVarSetupLength; // 后续数据长度 unsigned char code * VarSetupDescr; //描述符偏移地址 unsigned char VarUsbAddress ; sbit CH375_INT_WIRE = 0xB0^2; //P3.2, INT0, 连接CH375的INT#引脚,用于查询中断状态 */ sbit CH375ACT = P1^4; bit CH375FLAGERR; //错误清0 bit CH375CONFLAG; unsigned char idata UPDATA_FLAG; mREQUEST_PACKET request;

/*硬件定义,根据硬件修改*/ unsigned char volatile xdata CH375_CMD_PORT _at_ 0xBDF1; /* CH375命令端口的I/O地址 */ unsigned char volatile xdata CH375_DAT_PORT _at_ 0xBCF0; /* CH375数据端口的I/O地址 */

/* 延时2微秒,不精确 */ void Delay1us() { ; }

void Delay2us( ) { unsigned char i; #define DELAY_START_VALUE 1 /* 根据单片机的时钟选择初值,20MHz以下为0,30MHz以上为2 */ for ( i=DELAY_START_VALUE; i!=0; i-- ); }

/* 延时50毫秒,不精确 */ void Delay50ms( ) { unsigned char i, j; for ( i=200; i!=0; i-- ) for ( j=250; j!=0; j-- ); }

void CH375_WR_CMD_PORT( unsigned char cmd ) { /* 向CH375的命令端口写入命令,周期不小于4uS,如果单片机较快则延时 */ CH375_CMD_PORT=cmd; Delay2us( ); }

void CH375_WR_DAT_PORT( unsigned char dat ) { /* 向CH375的数据端口写入数据,周期不小于1.5uS,如果单片机较快则延时 */ CH375_DAT_PORT=dat; Delay1us(); /* 因为MCS51单片机较慢所以实际上无需延时 */ }

unsigned char CH375_RD_DAT_PORT() { /* 从CH375的数据端口读出数据,周期不小于1.5uS,如果单片机较快则延时 */ Delay1us( ); /* 因为MCS51单片机较慢所以实际上无需延时 */ return( CH375_DAT_PORT );

} /* CH375初始化子程序 */ void CH375_Init( ) { /* 设置USB工作模式, 必要操作 */ CH375_WR_CMD_PORT( CMD_SET_USB_MODE ); CH375_WR_DAT_PORT( 1 ); /* 设置为使用内置固件的USB设备方式 */ for ( ;; ) { /* 等待操作成功,通常需要等待10uS-20uS */ if ( CH375_RD_DAT_PORT( )==CMD_RET_SUCCESS ) break; } }

//端点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 CH375_WR_CMD_PORT(CMD_WR_USB_DATA3); //发出写端点0的命令 CH375_WR_DAT_PORT(len); //写入长度 for(i=0;i!=len;i++) CH375_WR_DAT_PORT(request.buffer[i]); //循环写入数据 } else { CH375_WR_CMD_PORT(CMD_WR_USB_DATA3); //发出写端点0的命令 CH375_WR_DAT_PORT(0); //上传0长度数据,这是一个状态阶段 } }

//复制描述符以便上传 void mCh375DesUp() { unsigned char k; for (k=0; k!=8; k++ ) { request.buffer[k]=*VarSetupDescr; //依次复制8个描述符, VarSetupDescr++; } }

/*中断函数,但是本例用的是查询方式,只处理了输入端点1和端点0的事件,其余不处理*/ void mCH375Interrupt( ) { unsigned char InterruptStatus; unsigned char length, c1, len; CH375_WR_CMD_PORT(CMD_GET_STATUS); /* 获取中断状态并取消中断请求 */ InterruptStatus =CH375_RD_DAT_PORT(); /* 获取中断状态 */ switch(InterruptStatus){ // 分析中断状态 case USB_INT_EP1_OUT: //中断端点下传成功,未处理 CH375_WR_CMD_PORT(CMD_RD_USB_DATA); //发出读数据命令 if( length=CH375_RD_DAT_PORT( ) ) { //长度为0跳出 for(len=0;len!=length;len++)c1=CH375_RD_DAT_PORT(); //取出下传数据 } break; case USB_INT_EP0_SETUP: //控制端点建立成功 CH375_WR_CMD_PORT(CMD_RD_USB_DATA); length=CH375_RD_DAT_PORT(); for(len=0;len!=length;len++)request.buffer[len]=CH375_RD_DAT_PORT(); // 取出数据 if(length==0x08){ mVarSetupLength=request.buffer[6]; //控制传输数据长度最大设置为128 if((c1=request.r.bmReuestType)&0x40){ //厂商请求,未处理 } if((c1=request.r.bmReuestType)&0x20) { //类请求,未处理 if(request.buffer[1]==0x0a) { } //SET_IDLE else if(request.buffer[1]==0x09) { UPDATA_FLAG=1; } } if(!((c1=request.r.bmReuestType)&0x60)) { //标准请求 mVarSetupRequest=request.r.bRequest; //暂存标准请求码 switch(request.r.bRequest){ // 分析标准请求 case DEF_USB_CLR_FEATURE: //清除特性 if((c1=request.r.bmReuestType&0x1F)==0X02) { //不是端点不支持 switch(request.buffer[4]) { case 0x82: CH375_WR_CMD_PORT(CMD_SET_ENDP7); //清除端点2上传 CH375_WR_DAT_PORT(0x8E); //发命令清除端点 break; case 0x02: CH375_WR_CMD_PORT(CMD_SET_ENDP6); CH375_WR_DAT_PORT(0x80); //清除端点2下传 break; case 0x81: CH375_WR_CMD_PORT(CMD_SET_ENDP5); //清除端点1上传 CH375_WR_DAT_PORT(0x8E); break; case 0x01: CH375_WR_CMD_PORT(CMD_SET_ENDP4); //清除端点1下传 CH375_WR_DAT_PORT(0x80); break; default: break; } } else { CH375FLAGERR=1; //不支持的清除特性,置错误标志 } break; case DEF_USB_GET_STATUS: //获得状态 request.buffer[0]=0; request.buffer[1]=0; //上传状态 break; case DEF_USB_SET_ADDRESS: //设置地址 Var

//连续发送11个数 Up_Data( 0x62 );//0 Up_Data( 0x5a );//1 Up_Data( 0x5b );//2 Up_Data( 0x5c );//3 Up_Data( 0x5b );//4 Up_Data( 0x5d );//5 Up_Data( 0x5e );//6 Up_Data( 0x5f );//7 Up_Data( 0x60 );//8 Up_Data( 0x61 );//9 Up_Data( 0x58 );//回车 //Up_Data1( 0 ); 这样写是不对的。比如: Up_Data( 0x62 ); 那你必须要等待PC把这个数据取走后你才能发送Up_Data( 0x5a ); 当PC取走后,会产生USB_INT_EP1_IN这个中断,所以发送完毕后,等待USB_INT_EP1_IN中断产生。


按照你的程序来说的话,应该只有回车,因为你最后一次写的数据就是回车键的键值。 正确做法是每次写你要写的键值,等CH372产生中断之后,读取中断状态为“中断端点上传成功”中断之后,在发送下一个键值给中断端点。


case USB_INT_EP1_IN: //PC机取走键值标记, USB_INT_EP1_IN_FLAG=1;//PC机取走数据标志,1表示数据已经取走,可以发送下一个键值 break; default: if( (InterruptStatus&0x03)==0x03 ) { //总线复位 CH375FLAGERR=0; //错误清0 CH375CONFLAG=0; //配置清0 mVarSetupLength=0; CH375ACT=1; //清配置完成输出 }

while(1) { /* 主程序 */ if(CH375_INT_WIRE == 0) { mCH375Interrupt( ); if(UPDATA_FLAG==0x01) {

//Up_Data( 0x0e );//键k //连续发送11个数 Up_Data( 0x62 );//0

if (USB_INT_EP1_IN_FLAG =1) { USB_INT_EP1_IN_FLAG=0; Up_Data( 0x5a );//1 }

/* Up_Data( 0x5b );//2 Up_Data( 0x5c );//3 Up_Data( 0x5b );//4 Up_Data( 0x5d );//5 Up_Data( 0x5e );//6 Up_Data( 0x5f );//7 Up_Data( 0x60 );//8 Up_Data( 0x61 );//9 Up_Data( 0x58 );//回车 */ } } }

等待了也还是不行,还是一直发送最后一个键值


UPDATA_FLAG==0x01一直成立,也就是说一直发送数据(Up_Data( 0x62 )),流程还是不对 另外你的程序看不出来是传不同的数据。


Up_Data( 0x62 );//0 1。先传一个数字0

if (USB_INT_EP1_IN_FLAG ==1) //等待中断 { USB_INT_EP1_IN_FLAG=0; //标记置0 Up_Data( 0x5a );//1 发送数字1 }

UPDATA_FLAG==0x01 一直成立,应该一直发送 01 啊


case USB_INT_EP1_IN: //PC机取走键值标记, USB_INT_EP1_IN_FLAG=1;//PC机取走数据标志,1表示数据已经取走,可以发送下一个键值 break; 上面还需要修改,在发送8个0X00的数据上去告诉计算机此按键释放。完了之后在上传下一个按键。


我也还是没改来这程序 郁闷ING 哪位大侠 指点下嘛


楼主labor能不能加你qq,有几个问题想请教你。我也在做这个,也是再弄这个程序,543131667.


我知道怎么连续发送数据了。把中断查询方式改为中断方式,然后像CH375上传一个数据后,产生中断,进入中断函数,我们在上传端点0下面设一个中断标志flag,并改变flag的值。而主函数中发送完一个数据后马上查询flag,如果flag的值改变了就证明一个数已经发送完毕。不断重复就能连续发送不同的数据了。哈哈。。。

还不明白就看一下程序吧: http://d.download.csdn.net/down/3518670/xiangiscoming


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