請(qǐng)hcn幫忙看段程序

hcn您好: 我的USB設(shè)備是掃描槍,對(duì)它的初始化程序,我參考了打印機(jī)例程那部分。不同的是,例子里是把數(shù)據(jù)傳送給打印機(jī),而我這里是從掃描槍接收采集的數(shù)據(jù),所以對(duì)于USB初始化這部分要作修改。 但對(duì)于例程里的該部分程序有的地方看不明白,修改起來挺費(fèi)勁的,而且也出了很多錯(cuò)誤,請(qǐng)hcn幫忙看一下我修改的,給出指正,謝謝! 其實(shí),我基本沒修改什么地方,因?yàn)橛械牡胤奖旧砭筒幻靼住?/p>

下面是打印機(jī)例程里USB初始化部分: /* 初始化USB設(shè)備,完成設(shè)備枚舉 */ unsigned char init_USB_device(void) { unsigned char address; unsigned char status; unsigned char length;

status = get_descr(1); /* 獲取設(shè)備描述符(1表示設(shè)備,2表示配置) */ if( status == USB_INT_SUCCESS ) { length = rd_usb_data( RECV_BUFFER ); /* 將獲取的描述符數(shù)據(jù)從CH375中讀出到單片機(jī)的RAM緩沖區(qū)中,返回描述符長(zhǎng)度 */ if( length<18 || p_dev_descr->bDescriptorType!=1 ) return( UNKNOWN_USB_DEVICE ); /* 意外錯(cuò)誤:描述符長(zhǎng)度錯(cuò)誤或者類型錯(cuò)誤;0XF1 */ if( p_dev_descr->bDeviceClass!=0 ) return( UNKNOWN_USB_DEVICE ); /* 連接的USB設(shè)備不符合USB規(guī)范 */ status = set_addr(2); /* 設(shè)置USB設(shè)備的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 ); /* 將獲取的描述符數(shù)據(jù)從CH375中讀出到單片機(jī)的RAM緩沖區(qū)中,返回描述符長(zhǎng)度 */ if( p_cfg_descr->itf_descr.bInterfaceClass!=7 || p_cfg_descr->itf_descr.bInterfaceSubClass!=1 ) return( UNKNOWN_USB_DEVICE ); /* 不符合USB規(guī)范 */ endp_out_addr=endp_in_addr=0; /* USB數(shù)據(jù)接收端點(diǎn)地址與USB狀態(tài)發(fā)送端點(diǎn)的端點(diǎn)地址(單向) */ address = p_cfg_descr->endp_descr[0].bEndpointAddress; /* 第一個(gè)端點(diǎn)的地址 */ if( address&0x80 ) endp_in_addr = address&0x0f; /* IN端點(diǎn)的地址 */ else { /* OUT端點(diǎn) */ endp_out_addr = address&0x0f; endp_out_size = p_cfg_descr->endp_descr[0].wMaxPacketSize; /* 數(shù)據(jù)接收端點(diǎn)的最大包長(zhǎng)度 */ if( endp_out_size == 0 || endp_out_size > 64 ) endp_out_size = 64; } if( p_cfg_descr->itf_descr.bNumEndpoints>=2 ) /* 接口有兩個(gè)以上的端點(diǎn) */ { if( p_cfg_descr->endp_descr[1].bDescriptorType==5 ) /* 端點(diǎn)描述符 */ { address = p_cfg_descr->endp_descr[1].bEndpointAddress; /* 第二個(gè)端點(diǎn)的地址 */ if( address&0x80 ) endp_in_addr = address&0x0f; /* IN端點(diǎn) */ else {/* OUT端點(diǎn) */ 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端點(diǎn) */ if( endp_out_addr==0 ) return( UNKNOWN_USB_DEVICE ); /* 不符合USB規(guī)范 */ status = set_config( p_cfg_descr- >cfg_descr.bConfigurationValue ); /* 加載USB配置值 */ if( status == USB_INT_SUCCESS ) { /* 如果單片機(jī)在USB設(shè)備忙時(shí)并無事可做,建議設(shè)置位7為1,使CH375在收到NAK時(shí)自動(dòng)重試直到操作成功或者失敗 */ /* 如果希望單片機(jī)在USB設(shè)備忙時(shí)能夠做其它事,那么應(yīng)該設(shè)置位7為0,使CH375在收到NAK時(shí)不重試, 所以在下面的USB通訊過程中,如果USB設(shè)備正忙,issue_token等子程序?qū)⒌玫綘顟B(tài)碼USB_INT_RET_NAK */ CH375_WR_CMD_PORT( CMD_SET_RETRY ); // 設(shè)置USB事務(wù)操作的重試次數(shù) CH375_WR_DAT_PORT( 0x25 ); CH375_WR_DAT_PORT( 0x85 ); // 位7為1則收到NAK時(shí)無限重試, 位3~位0為超時(shí)后的重試次數(shù) } } } } return(status); }

下面是針對(duì)我的開發(fā)修改后的:

unsigned char buffer[64]; /* 公用緩沖區(qū) */ #define UNKNOWN_USB_DEVICE 0xF1 #define p_dev_descr ((PUSB_DEV_DESCR)buffer) // 強(qiáng)制類型轉(zhuǎn)換,把buffer變成_USB_DEVICE_DESCRIPTOR結(jié)構(gòu)體類型 #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); }

請(qǐng)幫忙批評(píng)指正,謝謝!

掃描槍是低速設(shè)備,所以你在獲取描述符的前面應(yīng)該將375的主頻將為1。5M,同時(shí)將375的D+和D-連接相對(duì)調(diào),也就是將375的D+和掃描槍的D-相連接,將375的D-和掃描槍的D+相連接,這是鍵盤的例子程序,你可以參考。UploadImages/hcn0012006629174851.rar


請(qǐng)問hcn: 除了能下到的CH375中文資料外,是否還有關(guān)于CH375芯片更詳細(xì)的資料呢?能否提供一下呢?

另:您的意思是說將CH375的12MHz晶振改為1.5MHz么?


你可以下載CH375DS1和CH375DS2,上面有關(guān)于外置固件的一些介紹,更詳細(xì)的你只能參考USB協(xié)議了,你的掃描槍應(yīng)該是低速設(shè)備,那么你應(yīng)該看下關(guān)于HID的協(xié)議,關(guān)于例子你只要參考我給你的鍵盤的例子就可以了,你只要在那個(gè)基礎(chǔ)上面做局部的修改就可以了,這個(gè)例子全是外置固件寫的例子程序。 不需要將375的頻率改為1。5M,因?yàn)槲覀冇幸粋€(gè)命令是將12M的頻率降為1。5M,你可以參考例子,上面都有說明


謝謝hcn的指導(dǎo)! 我去弄弄。


謝謝hcn的指導(dǎo)! 我去弄弄。


hcn: 你給的那個(gè)例子里好像沒有將12M的頻率降為1.5M的這樣一個(gè)命令啊。 還有,我覺得這個(gè)例子挺亂的,有拼湊的痕跡,是否有一個(gè)更簡(jiǎn)練的程序呢? 你給的例程中有: 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); }

該子函數(shù)中的tog_send=tog_recv=0;是什么意思呢?除了對(duì)其有個(gè)定義外,好像在其他地方根本沒有用到? 不知道該怎么解釋?

麻煩hcn給解答一下,謝謝!


這個(gè)例子程序是在CH375HST。C的例子程序上面修改成低速設(shè)備來操作鍵盤的例子 CH375_WR_CMD_PORT( CMD_SET_SYS_FREQ );//降主頻 CH375_WR_DAT_PORT( 0x01 ); 這個(gè)命令就是將主頻降為1。5M,這兩個(gè)定義不矛盾??! tog_send=tog_recv=0是同步的一個(gè)標(biāo)志,在程序一開始的時(shí)候都為0,是進(jìn)行同步碼切換用的,我們?cè)诟倪@個(gè)例子的時(shí)候沒用到這個(gè),我們直接定義了一個(gè)變量進(jìn)行切換的。


hcn: 在你給我的USB鍵盤例程中,有幾個(gè)地方我不大明白,特提出來請(qǐng)給予解答,謝謝!

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階段,準(zhǔn)備接收DATA1 */ tb=1; } if ( issue_token( ( 0 << 4 ) | DEF_USB_PID_IN )==USB_INT_SUCCESS ) { /* SETUP階段操作成功 */ i=rd_usb_data(buffer); // i:描述符長(zhǎng)度 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);/*狀態(tài)階段*/ wr_usb_data(0,buffer); issue_token((0<<4)|DEF_USB_PID_OUT); }

這個(gè)子函數(shù)中,關(guān)于flag,我不大明白。flag只是在前面給了定義,但卻沒交代它的作用。 對(duì)于下面部分代碼很茫然: 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就以上兩個(gè)問題給予作答,謝謝!


1,flag=0說明接收到的前8個(gè)字節(jié)是設(shè)備描述符,描述符的長(zhǎng)度為接收到的8字節(jié)的第一個(gè)字節(jié)的數(shù)據(jù)減去收到的8個(gè)字節(jié)(實(shí)際應(yīng)該是18-8=10),而flag=1則說明的接收到的數(shù)據(jù)是配置描述符,數(shù)據(jù)的長(zhǎng)度是接收前8字節(jié)數(shù)據(jù)長(zhǎng)度的第3個(gè)字節(jié)(詳細(xì)可以參考USB協(xié)議,里面有詳細(xì)的介紹)。這兩個(gè)全局變量在主程序獲取設(shè)備描述符和配置描述符的時(shí)候都應(yīng)該有用到。 2,0<<4只是為了說明高4位為設(shè)備的目的端點(diǎn)號(hào),實(shí)際上應(yīng)該是0X80<<4,而在端點(diǎn)2傳輸數(shù)據(jù)的時(shí)候?qū)τ谖覀?75來說,目的端點(diǎn)號(hào)就應(yīng)該是0X82<<4(這個(gè)值要從配置描述符里面的端點(diǎn)描述符里面取得)。


hcn:你是說下面的i應(yīng)該是8對(duì)嗎?可為什么呢?全局?jǐn)?shù)組變量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應(yīng)該是8對(duì)嗎?可為什么呢?全局?jǐn)?shù)組變量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( )函數(shù)返回的數(shù)據(jù)是什么?應(yīng)該是返回的讀取數(shù)據(jù)的長(zhǎng)度,定義的緩沖區(qū)是48,但是不一定要把數(shù)據(jù)接收滿了。按照USB協(xié)議的控制傳輸?shù)膮f(xié)議,一次控制傳輸?shù)拈L(zhǎng)度應(yīng)該是8字節(jié),而后面的處理只是為了分別區(qū)分讀的數(shù)據(jù)是設(shè)備描述符還是配置描述符,仔細(xì)看下USB協(xié)議,你實(shí)際在讀的時(shí)候并不知道讀到的數(shù)據(jù)是設(shè)備描述符還是配置描述符,你只能通過你發(fā)送命令來判斷是讀取設(shè)備描述符還是讀取配置描述符,還有就是你說的直接在后面減8也在BUFFER-8嗎?但是有一種可能就是你獲取的數(shù)據(jù)小于8的話那就會(huì)出問題了,所以用上面的那種方法的話也許好一點(diǎn)


問一下hcn:為什么打印機(jī)的例程和鍵盤的例程區(qū)別如此之大呢? 好像打印機(jī)的例程里不用考慮的這么細(xì)致。 是全速和低速的差異造成的么? hcn能確定條碼掃描槍一定是低速設(shè)備么?


實(shí)際上給你的例子程序全部都是用外部固件寫的,這不是全速設(shè)備和低速設(shè)備造成的,而是因?yàn)槭遣煌念惗斐傻?,打印機(jī)屬于打印機(jī)類,鍵盤鼠標(biāo)屬于HID類,你可以將你的掃描槍的描述符抓下來看下,你看下設(shè)備描述符里面有沒有HID描述符就可以了啊!


請(qǐng)問hcn: HID描述符有什么特征嗎? 我用一個(gè)軟件抓了掃描槍設(shè)備描述符,好像沒發(fā)現(xiàn)跟HID有什么關(guān)系。 我后來又抓了USB接口鼠標(biāo)設(shè)備描述符,同樣找不到HID描述符。 這是怎么回事呢? 但可以從掃描槍的設(shè)備描述符中看到Speed為Full。 請(qǐng)問您之前所說的“將375的D+和D-連接相對(duì)調(diào),也就是將375的D+和掃描槍的D-相連接,將375的D-和掃描槍的D+相連接”這個(gè)到底根據(jù)什么來調(diào)整呢?是根據(jù)低速?還是根據(jù)HID?


只有登錄才能回復(fù),可以選擇微信賬號(hào)登錄

国产91精品新入口,国产成人综合网在线播放,九热这里只有精品,本道在线观看,美女视频a美女视频,韩国美女激情视频,日本美女pvp视频