请hcn帮忙看段程序

hcn您好: 我的USB设备是扫描枪,对它的初始化程序,我参考了打印机例程那部分。不同的是,例子里是把数据传送给打印机,而我这里是从扫描枪接收采集的数据,所以对于USB初始化这部分要作修改。 但对于例程里的该部分程序有的地方看不明白,修改起来挺费劲的,而且也出了很多错误,请hcn帮忙看一下我修改的,给出指正,谢谢! 其实,我基本没修改什么地方,因为有的地方本身就不明白。

下面是打印机例程里USB初始化部分: /* 初始化USB设备,完成设备枚举 */ unsigned char init_USB_device(void) { unsigned char address; unsigned char status; unsigned char length;

status = get_descr(1); /* 获取设备描述符(1表示设备,2表示配置) */ if( status == USB_INT_SUCCESS ) { length = rd_usb_data( RECV_BUFFER ); /* 将获取的描述符数据从CH375中读出到单片机的RAM缓冲区中,返回描述符长度 */ if( length<18 || p_dev_descr->bDescriptorType!=1 ) return( UNKNOWN_USB_DEVICE ); /* 意外错误:描述符长度错误或者类型错误;0XF1 */ if( p_dev_descr->bDeviceClass!=0 ) return( UNKNOWN_USB_DEVICE ); /* 连接的USB设备不符合USB规范 */ status = set_addr(2); /* 设置USB设备的USB地址;1到128都可以,常用2到20 */ if( status == USB_INT_SUCCESS ) { status = get_descr(2); /* 获取配置描述符 */ if( status == USB_INT_SUCCESS ) /* 操作成功则读出描述符并分析 */ { length = rd_usb_data( RECV_BUFFER ); /* 将获取的描述符数据从CH375中读出到单片机的RAM缓冲区中,返回描述符长度 */ if( p_cfg_descr->itf_descr.bInterfaceClass!=7 || p_cfg_descr->itf_descr.bInterfaceSubClass!=1 ) return( UNKNOWN_USB_DEVICE ); /* 不符合USB规范 */ endp_out_addr=endp_in_addr=0; /* USB数据接收端点地址与USB状态发送端点的端点地址(单向) */ address = p_cfg_descr->endp_descr[0].bEndpointAddress; /* 第一个端点的地址 */ if( address&0x80 ) endp_in_addr = address&0x0f; /* IN端点的地址 */ else { /* OUT端点 */ endp_out_addr = address&0x0f; endp_out_size = p_cfg_descr->endp_descr[0].wMaxPacketSize; /* 数据接收端点的最大包长度 */ if( endp_out_size == 0 || endp_out_size > 64 ) endp_out_size = 64; } if( p_cfg_descr->itf_descr.bNumEndpoints>=2 ) /* 接口有两个以上的端点 */ { if( p_cfg_descr->endp_descr[1].bDescriptorType==5 ) /* 端点描述符 */ { address = p_cfg_descr->endp_descr[1].bEndpointAddress; /* 第二个端点的地址 */ if( address&0x80 ) endp_in_addr = address&0x0f; /* IN端点 */ else {/* OUT端点 */ endp_out_addr = address&0x0f; endp_out_size = p_cfg_descr->endp_descr[1].wMaxPacketSize; if( endp_out_size == 0 || endp_out_size > 64 ) endp_out_size = 64; } } } if( p_cfg_descr->itf_descr.bInterfaceProtocol==1 ) endp_in_addr=0; /* 单向接口不需要IN端点 */ if( endp_out_addr==0 ) return( UNKNOWN_USB_DEVICE ); /* 不符合USB规范 */ status = set_config( p_cfg_descr- >cfg_descr.bConfigurationValue ); /* 加载USB配置值 */ if( status == USB_INT_SUCCESS ) { /* 如果单片机在USB设备忙时并无事可做,建议设置位7为1,使CH375在收到NAK时自动重试直到操作成功或者失败 */ /* 如果希望单片机在USB设备忙时能够做其它事,那么应该设置位7为0,使CH375在收到NAK时不重试, 所以在下面的USB通讯过程中,如果USB设备正忙,issue_token等子程序将得到状态码USB_INT_RET_NAK */ CH375_WR_CMD_PORT( CMD_SET_RETRY ); // 设置USB事务操作的重试次数 CH375_WR_DAT_PORT( 0x25 ); CH375_WR_DAT_PORT( 0x85 ); // 位7为1则收到NAK时无限重试, 位3~位0为超时后的重试次数 } } } } return(status); }

下面是针对我的开发修改后的:

unsigned char buffer[64]; /* 公用缓冲区 */ #define UNKNOWN_USB_DEVICE 0xF1 #define p_dev_descr ((PUSB_DEV_DESCR)buffer) // 强制类型转换,把buffer变成_USB_DEVICE_DESCRIPTOR结构体类型 #define p_cfg_descr ((PUSB_CFG_DESCR_LONG)buffer) unsigned char status1=0,status2=0,status3=0,status4=0; unsigned char length1=0,length2=0; unsigned char address1=0,address2=0; unsigned char init_USB_device() { status1=get_descr(1); if(status1==USB_INT_SUCCESS) { length1=rd_usb_data(buffer); //if(length1<18||p_dev_descr->bDescriptorType!=1) return(UNKNOWN_USB_DEVICE); status2=set_addr(2); if(status2==USB_INT_SUCCESS) { status3=get_descr(2); if(status3==USB_INT_SUCCESS) { length2=rd_usb_data(buffer); endp_out_addr=endp_in_addr=0; address1=p_cfg_descr->endp_descr[0].bEndpointAddress; if(address1&0x80) endp_in_addr=address1&0x0f; else { endp_out_addr=address1&0x0f; endp_out_size=p_cfg_descr->endp_descr[0].wMaxPacketSize; } if(p_cfg_descr->itf_descr.bNumEndpoints>=2) { if(p_cfg_descr->endp_descr[1].bDescriptorType==5) { address2=p_cfg_descr->endp_descr[1].bEndpointAddress; if(address2&0x80) endp_in_addr=address2&0x0f; else { endp_out_addr=address2&0x0f; endp_out_size=p_cfg_descr->endp_descr[1].wMaxPacketSize; } } } if(p_cfg_descr->itf_descr.bInterfaceProtocol==1) endp_out_addr=0; if(endp_in_addr==0) return(UNKNOWN_USB_DEVICE); status4=set_config(p_cfg_descr->cfg_descr.bConfigurationValue); } } } return(status4); }

请帮忙批评指正,谢谢!

扫描枪是低速设备,所以你在获取描述符的前面应该将375的主频将为1。5M,同时将375的D+和D-连接相对调,也就是将375的D+和扫描枪的D-相连接,将375的D-和扫描枪的D+相连接,这是键盘的例子程序,你可以参考。UploadImages/hcn0012006629174851.rar


请问hcn: 除了能下到的CH375中文资料外,是否还有关于CH375芯片更详细的资料呢?能否提供一下呢?

另:您的意思是说将CH375的12MHz晶振改为1.5MHz么?


你可以下载CH375DS1和CH375DS2,上面有关于外置固件的一些介绍,更详细的你只能参考USB协议了,你的扫描枪应该是低速设备,那么你应该看下关于HID的协议,关于例子你只要参考我给你的键盘的例子就可以了,你只要在那个基础上面做局部的修改就可以了,这个例子全是外置固件写的例子程序。 不需要将375的频率改为1。5M,因为我们有一个命令是将12M的频率降为1。5M,你可以参考例子,上面都有说明


谢谢hcn的指导! 我去弄弄。


谢谢hcn的指导! 我去弄弄。


hcn: 你给的那个例子里好像没有将12M的频率降为1.5M的这样一个命令啊。 还有,我觉得这个例子挺乱的,有拼凑的痕迹,是否有一个更简练的程序呢? 你给的例程中有: typedef unsigned char BOOL1; ... typedef unsigned char UCHAR; 这两者是不是矛盾的?

unsigned char set_config(unsigned char cfg) { tog_send=tog_recv=0; CH375_WR_CMD_PORT(CMD_SET_CONFIG); CH375_WR_DAT_PORT(cfg); return(wait_interrupt); }

该子函数中的tog_send=tog_recv=0;是什么意思呢?除了对其有个定义外,好像在其他地方根本没有用到? 不知道该怎么解释?

麻烦hcn给解答一下,谢谢!


这个例子程序是在CH375HST。C的例子程序上面修改成低速设备来操作键盘的例子 CH375_WR_CMD_PORT( CMD_SET_SYS_FREQ );//降主频 CH375_WR_DAT_PORT( 0x01 ); 这个命令就是将主频降为1。5M,这两个定义不矛盾啊! tog_send=tog_recv=0是同步的一个标志,在程序一开始的时候都为0,是进行同步码切换用的,我们在改这个例子的时候没用到这个,我们直接定义了一个变量进行切换的。


hcn: 在你给我的USB键盘例程中,有几个地方我不大明白,特提出来请给予解答,谢谢!

void get_device_desc() { unsigned char len,tb,l,i,j; unsigned char *p=buffer; toggle_send(0);//同步 wr_usb_data(8,request.buffer); if ( issue_token( ( 0 << 4 ) | DEF_USB_PID_SETUP )==USB_INT_SUCCESS ){ toggle_recv( 1 ); /* DATA阶段,准备接收DATA1 */ tb=1; } if ( issue_token( ( 0 << 4 ) | DEF_USB_PID_IN )==USB_INT_SUCCESS ) { /* SETUP阶段操作成功 */ i=rd_usb_data(buffer); // i:描述符长度 if(flag==0) len=buffer[0]-i; else if(flag==1) len=buffer[2]-i; j=len+8; while(len){ tb=((~tb)&0x01); // ~:按位取反;&:按位与 p+=0x08; toggle_recv( tb ); /* DATA阶段 */ _nop_(); _nop_(); if ( issue_token( ( 0 << 4 ) | DEF_USB_PID_IN )==USB_INT_SUCCESS ) { /* SETUP阶段操作成功 */ l=rd_usb_data(p); len=len-l; } } } toggle_recv(1);/*状态阶段*/ wr_usb_data(0,buffer); issue_token((0<<4)|DEF_USB_PID_OUT); }

这个子函数中,关于flag,我不大明白。flag只是在前面给了定义,但却没交代它的作用。 对于下面部分代码很茫然: if(flag==0) len=buffer[0]-i; else if(flag==1) len=buffer[2]-i; j=len+8;

还有在下面的语句中,0<<4不就是0么?为什么不直接写0得了? if ( issue_token( ( 0 << 4 ) | DEF_USB_PID_IN )==USB_INT_SUCCESS )

麻烦hcn就以上两个问题给予作答,谢谢!


1,flag=0说明接收到的前8个字节是设备描述符,描述符的长度为接收到的8字节的第一个字节的数据减去收到的8个字节(实际应该是18-8=10),而flag=1则说明的接收到的数据是配置描述符,数据的长度是接收前8字节数据长度的第3个字节(详细可以参考USB协议,里面有详细的介绍)。这两个全局变量在主程序获取设备描述符和配置描述符的时候都应该有用到。 2,0<<4只是为了说明高4位为设备的目的端点号,实际上应该是0X80<<4,而在端点2传输数据的时候对于我们375来说,目的端点号就应该是0X82<<4(这个值要从配置描述符里面的端点描述符里面取得)。


hcn:你是说下面的i应该是8对吗?可为什么呢?全局数组变量buffer的大小是48啊?如果真那样的话,完全可以直接在后面减8啊。??? i=rd_usb_data(buffer); if(flag==0) len=buffer[0]-i; else if(flag==1) len=buffer[2]-i; j=len+8;


hcn:你是说下面的i应该是8对吗?可为什么呢?全局数组变量buffer的大小是48啊?如果真那样的话,完全可以直接在后面减8啊。??? i=rd_usb_data(buffer); if(flag==0) len=buffer[0]-i; else if(flag==1) len=buffer[2]-i; j=len+8;


你看下rd_usb_data( )函数返回的数据是什么?应该是返回的读取数据的长度,定义的缓冲区是48,但是不一定要把数据接收满了。按照USB协议的控制传输的协议,一次控制传输的长度应该是8字节,而后面的处理只是为了分别区分读的数据是设备描述符还是配置描述符,仔细看下USB协议,你实际在读的时候并不知道读到的数据是设备描述符还是配置描述符,你只能通过你发送命令来判断是读取设备描述符还是读取配置描述符,还有就是你说的直接在后面减8也在BUFFER-8吗?但是有一种可能就是你获取的数据小于8的话那就会出问题了,所以用上面的那种方法的话也许好一点


问一下hcn:为什么打印机的例程和键盘的例程区别如此之大呢? 好像打印机的例程里不用考虑的这么细致。 是全速和低速的差异造成的么? hcn能确定条码扫描枪一定是低速设备么?


实际上给你的例子程序全部都是用外部固件写的,这不是全速设备和低速设备造成的,而是因为是不同的类而造成的,打印机属于打印机类,键盘鼠标属于HID类,你可以将你的扫描枪的描述符抓下来看下,你看下设备描述符里面有没有HID描述符就可以了啊!


请问hcn: HID描述符有什么特征吗? 我用一个软件抓了扫描枪设备描述符,好像没发现跟HID有什么关系。 我后来又抓了USB接口鼠标设备描述符,同样找不到HID描述符。 这是怎么回事呢? 但可以从扫描枪的设备描述符中看到Speed为Full。 请问您之前所说的“将375的D+和D-连接相对调,也就是将375的D+和扫描枪的D-相连接,将375的D-和扫描枪的D+相连接”这个到底根据什么来调整呢?是根据低速?还是根据HID?


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