?? ch375prt.c
字號:
unsigned char endp_in_addr; /* 雙向打印機發(fā)送端點的端點地址,一般不用 */
BOOL1 tog_recv; /* 雙向打印機發(fā)送端點的同步標志,一般不用 */
unsigned char issue_token( unsigned char endp_and_pid ) { /* 執(zhí)行USB事務 */
/* 執(zhí)行完成后, 將產生中斷通知單片機, 如果是USB_INT_SUCCESS就說明操作成功 */
CH375_WR_CMD_PORT( CMD_ISSUE_TOKEN );
CH375_WR_DAT_PORT( endp_and_pid ); /* 高4位目的端點號, 低4位令牌PID */
return( wait_interrupt() ); /* 等待CH375操作完成 */
}
unsigned char issue_token_X( unsigned char endp_and_pid, unsigned char tog ) { /* 執(zhí)行USB事務,適用于CH375A */
/* 執(zhí)行完成后, 將產生中斷通知單片機, 如果是USB_INT_SUCCESS就說明操作成功 */
CH375_WR_CMD_PORT( CMD_ISSUE_TKN_X );
CH375_WR_DAT_PORT( tog ); /* 同步標志的位7為主機端點IN的同步觸發(fā)位, 位6為主機端點OUT的同步觸發(fā)位, 位5~位0必須為0 */
CH375_WR_DAT_PORT( endp_and_pid ); /* 高4位目的端點號, 低4位令牌PID */
return( wait_interrupt() ); /* 等待CH375操作完成 */
}
void soft_reset_print( ) { /* 控制傳輸:軟復位打印機 */
tog_send=tog_recv=0; /* 復位USB數據同步標志 */
toggle_send( 0 ); /* SETUP階段為DATA0 */
buffer[0]=0x21; buffer[1]=2; buffer[2]=buffer[3]=buffer[4]=buffer[5]=buffer[6]=buffer[7]=0; /* SETUP數據,SOFT_RESET */
wr_usb_data( 8, buffer ); /* SETUP數據總是8字節(jié) */
if ( issue_token( ( 0 << 4 ) | DEF_USB_PID_SETUP )==USB_INT_SUCCESS ) { /* SETUP階段操作成功 */
toggle_recv( 1 ); /* STATUS階段,準備接收DATA1 */
if ( issue_token( ( 0 << 4 ) | DEF_USB_PID_IN )==USB_INT_SUCCESS ) return; /* STATUS階段操作成功,操作成功返回 */
}
}
#define USB_INT_RET_NAK 0x2A /* 00101010B,返回NAK */
void send_data( unsigned short len, unsigned char *buf ) { /* 主機發(fā)送數據塊,一次最多64KB */
unsigned char l, s;
while( len ) { /* 連續(xù)輸出數據塊給USB打印機 */
toggle_send( tog_send ); /* 數據同步 */
l = len>endp_out_size?endp_out_size:len; /* 單次發(fā)送不能超過端點尺寸 */
wr_usb_data( l, buf ); /* 將數據先復制到CH375芯片中 */
s = issue_token( ( endp_out_addr << 4 ) | DEF_USB_PID_OUT ); /* 請求CH375輸出數據 */
if ( s==USB_INT_SUCCESS ) { /* CH375成功發(fā)出數據 */
tog_send = ~ tog_send; /* 切換DATA0和DATA1進行數據同步 */
len-=l; /* 計數 */
buf+=l; /* 操作成功 */
}
else if ( s==USB_INT_RET_NAK ) { /* USB打印機正忙,如果未執(zhí)行SET_RETRY命令則CH375自動重試,所以不會返回USB_INT_RET_NAK狀態(tài) */
/* USB打印機正忙,正常情況下應該稍后重試 */
/* s=get_port_status( ); 如果有必要,可以檢查是什么原因導致打印機忙 */
}
else { /* 操作失敗,正常情況下不會失敗 */
clr_stall( endp_out_addr ); /* 清除打印機的數據接收端點,或者 soft_reset_print() */
/* soft_reset_print(); 打印機出現(xiàn)意外錯誤,軟復位 */
tog_send = 0; /* 操作失敗 */
}
/* 如果數據量較大,可以定期調用get_port_status()檢查打印機狀態(tài) */
}
}
unsigned char get_port_status( ) { /* 查詢打印機端口狀態(tài),返回狀態(tài)碼,如果為0FFH則說明操作失敗 */
/* 返回狀態(tài)碼中: 位5(Paper Empty)為1說明無紙, 位4(Select)為1說明打印機聯(lián)機, 位3(Not Error)為0說明打印機出錯 */
toggle_send( 0 ); /* 下面通過控制傳輸獲取打印機的狀態(tài), SETUP階段為DATA0 */
buffer[0]=0xA1; buffer[1]=1; buffer[2]=buffer[3]=buffer[4]=buffer[5]=0; buffer[6]=1; buffer[7]=0; /* SETUP數據,GET_PORT_STATUS */
wr_usb_data( 8, buffer ); /* SETUP數據總是8字節(jié) */
if ( issue_token( ( 0 << 4 ) | DEF_USB_PID_SETUP )==USB_INT_SUCCESS ) { /* SETUP階段操作成功 */
toggle_recv( 1 ); /* DATA階段,準備接收DATA1 */
if ( issue_token( ( 0 << 4 ) | DEF_USB_PID_IN )==USB_INT_SUCCESS ) { /* DATA階段操作成功 */
rd_usb_data( buffer ); /* 讀出接收到的數據,通常只有1個字節(jié) */
toggle_send( 1 ); /* STATUS階段為DATA1 */
wr_usb_data( 0, buffer ); /* 發(fā)送0長度的數據說明控制傳輸成功 */
if ( issue_token( ( 0 << 4 ) | DEF_USB_PID_OUT )==USB_INT_SUCCESS ) return( buffer[0] ); /* 返回狀態(tài)碼 */
}
}
return( 0xFF ); /* 返回操作失敗 */
}
unsigned char get_port_status_X( ) { /* 查詢打印機端口狀態(tài),返回狀態(tài)碼,如果為0FFH則說明操作失敗,適用于CH375A */
/* 返回狀態(tài)碼中: 位5(Paper Empty)為1說明無紙, 位4(Select)為1說明打印機聯(lián)機, 位3(Not Error)為0說明打印機出錯 */
buffer[0]=0xA1; buffer[1]=1; buffer[2]=buffer[3]=buffer[4]=buffer[5]=0; buffer[6]=1; buffer[7]=0; /* 控制傳輸獲取打印機狀態(tài),SETUP數據 */
wr_usb_data( 8, buffer ); /* SETUP數據總是8字節(jié) */
if ( issue_token_X( ( 0 << 4 ) | DEF_USB_PID_SETUP, 0x00 )==USB_INT_SUCCESS ) { /* SETUP階段DATA0操作成功 */
if ( issue_token_X( ( 0 << 4 ) | DEF_USB_PID_IN, 0x80 )==USB_INT_SUCCESS ) { /* DATA階段DATA1接收操作成功 */
rd_usb_data( buffer ); /* 讀出接收到的數據,通常只有1個字節(jié) */
wr_usb_data( 0, buffer ); /* 發(fā)送0長度的數據DATA1說明控制傳輸成功 */
if ( issue_token_X( ( 0 << 4 ) | DEF_USB_PID_OUT, 0x40 )==USB_INT_SUCCESS ) return( buffer[0] ); /* STATUS階段操作成功,返回狀態(tài)碼 */
}
}
return( 0xFF ); /* 返回操作失敗 */
}
unsigned char get_descr( unsigned char type ) { /* 從設備端獲取描述符 */
CH375_WR_CMD_PORT( CMD_GET_DESCR );
CH375_WR_DAT_PORT( type ); /* 描述符類型, 只支持1(設備)或者2(配置) */
return( wait_interrupt() ); /* 等待CH375操作完成 */
}
unsigned char set_addr( unsigned char addr ) { /* 設置設備端的USB地址 */
unsigned char status;
CH375_WR_CMD_PORT( CMD_SET_ADDRESS ); /* 設置USB設備端的USB地址 */
CH375_WR_DAT_PORT( addr ); /* 地址, 從1到127之間的任意值, 常用2到20 */
status=wait_interrupt(); /* 等待CH375操作完成 */
if ( status==USB_INT_SUCCESS ) { /* 操作成功 */
CH375_WR_CMD_PORT( CMD_SET_USB_ADDR ); /* 設置USB主機端的USB地址 */
CH375_WR_DAT_PORT( addr ); /* 當目標USB設備的地址成功修改后,應該同步修改主機端的USB地址 */
}
mDelaymS( 5 );
return( status );
}
unsigned char set_config( unsigned char cfg ) { /* 設置設備端的USB配置 */
tog_send=tog_recv=0; /* 復位USB數據同步標志 */
CH375_WR_CMD_PORT( CMD_SET_CONFIG ); /* 設置USB設備端的配置值 */
CH375_WR_DAT_PORT( cfg ); /* 此值取自USB設備的配置描述符中 */
return( wait_interrupt() ); /* 等待CH375操作完成 */
}
#define UNKNOWN_USB_DEVICE 0xF1
#define UNKNOWN_USB_PRINT 0xF2
unsigned char init_print() { /* 初始化USB打印機,完成打印機枚舉 */
#define p_dev_descr ((PUSB_DEV_DESCR)buffer)
#define p_cfg_descr ((PUSB_CFG_DESCR_LONG)buffer)
unsigned char status, len, c;
status=get_descr(1); /* 獲取設備描述符 */
if ( status==USB_INT_SUCCESS ) {
len=rd_usb_data( buffer ); /* 將獲取的描述符數據從CH375中讀出到單片機的RAM緩沖區(qū)中,返回描述符長度 */
if ( len<18 || p_dev_descr->bDescriptorType!=1 ) return( UNKNOWN_USB_DEVICE ); /* 意外錯誤:描述符長度錯誤或者類型錯誤 */
if ( p_dev_descr->bDeviceClass!=0 ) return( UNKNOWN_USB_DEVICE ); /* 連接的USB設備不是USB打印機,或者不符合USB規(guī)范 */
status=set_addr(3); /* 設置打印機的USB地址 */
if ( status==USB_INT_SUCCESS ) {
status=get_descr(2); /* 獲取配置描述符 */
if ( status==USB_INT_SUCCESS ) { /* 操作成功則讀出描述符并分析 */
len=rd_usb_data( buffer ); /* 將獲取的描述符數據從CH375中讀出到單片機的RAM緩沖區(qū)中,返回描述符長度 */
if ( p_cfg_descr->itf_descr.bInterfaceClass!=7 || p_cfg_descr->itf_descr.bInterfaceSubClass!=1 ) return( UNKNOWN_USB_PRINT ); /* 不是USB打印機或者不符合USB規(guī)范 */
endp_out_addr=endp_in_addr=0;
c=p_cfg_descr->endp_descr[0].bEndpointAddress; /* 第一個端點的地址 */
if ( c&0x80 ) endp_in_addr=c&0x0f; /* IN端點的地址 */
else { /* OUT端點 */
endp_out_addr=c&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 ) { /* 端點描述符 */
c=p_cfg_descr->endp_descr[1].bEndpointAddress; /* 第二個端點的地址 */
if ( c&0x80 ) endp_in_addr=c&0x0f; /* IN端點 */
else { /* OUT端點 */
endp_out_addr=c&0x0f;
endp_out_size=p_cfg_descr->endp_descr[1].wMaxPacketSize;
}
}
}
if ( p_cfg_descr->itf_descr.bInterfaceProtocol<=1 ) endp_in_addr=0; /* 單向接口不需要IN端點 */
if ( endp_out_addr==0 ) return( UNKNOWN_USB_PRINT ); /* 不是USB打印機或者不符合USB規(guī)范 */
status=set_config( p_cfg_descr->cfg_descr.bConfigurationValue ); /* 加載USB配置值 */
if ( status==USB_INT_SUCCESS ) {
CH375_WR_CMD_PORT( CMD_SET_RETRY ); /* 設置USB事務操作的重試次數 */
CH375_WR_DAT_PORT( 0x25 );
CH375_WR_DAT_PORT( 0x89 ); /* 位7為1則收到NAK時無限重試, 位3~位0為超時后的重試次數 */
/* 如果單片機在打印機忙時并無事可做,建議設置位7為1,使CH375在收到NAK時自動重試直到操作成功或者失敗 */
/* 如果希望單片機在打印機忙時能夠做其它事,那么應該設置位7為0,使CH375在收到NAK時不重試,
所以在下面的USB通訊過程中,如果USB打印機正忙,issue_token等子程序將得到狀態(tài)碼USB_INT_RET_NAK */
}
}
}
}
return(status);
}
/* 主機端的主程序簡單示例 */
main() {
unsigned char xdata data_to_send[200]; /* 緩沖區(qū) */
unsigned char str_to_print[]="OK, support text print\n";
unsigned char s;
mDelaymS( 200 );
set_usb_mode( 6 ); /* 設置USB主機模式 */
while ( wait_interrupt()!=USB_INT_CONNECT ); /* 等待USB打印機連接上來 */
/* 如果設備端是CH341轉打印口或者是CH37X,那么以下步驟是可選的,如果是其它USB芯片,那么可能需要執(zhí)行以下步驟 */
#define USB_RESET_FIRST 1 /* USB規(guī)范中未要求在USB設備插入后必須復位該設備,但是計算機的WINDOWS總是這樣做,所以有些USB設備也要求在插入后必須先復位才能工作 */
#ifdef USB_RESET_FIRST
set_usb_mode( 7 ); /* 復位USB設備,CH375向USB信號線的D+和D-輸出低電平 */
/* 如果單片機對CH375的INT#引腳采用中斷方式而不是查詢方式,那么應該在復制USB設備期間禁止CH375中斷,在USB設備復位完成后清除CH375中斷標志再允許中斷 */
mDelaymS( 10 ); /* 復位時間不少于1mS,建議為10mS */
set_usb_mode( 6 ); /* 結束復位 */
mDelaymS( 100 );
while ( wait_interrupt()!=USB_INT_CONNECT ); /* 等待復位之后的設備端再次連接上來 */
#endif
mDelaymS( 200 ); /* 有些USB設備要等待數百毫秒才能正常工作 */
if ( init_print()!=USB_INT_SUCCESS ) while(1); /* 錯誤 */
while ( 1 ) {
s = get_port_status( );
if ( s!=0xFF ) {
/* if ( s&0x20 ) printf("No paper!\n");
if ( (s&0x08) == 0 ) printf("Print ERROR!\n");*/
}
send_data( strlen(str_to_print), str_to_print ); /* 輸出數據給打印機,與通過并口方式輸出一樣 */
send_data( sizeof(data_to_send), data_to_send ); /* 輸出的數據必須按照打印機的格式要求或者遵循打印描述語言 */
/* 可以再次繼續(xù)發(fā)送數據或者接收數據 */
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -