CH375的slaver的程序(C51)
CH375做slaver的程序 /*************************************** ** USB 1.1 Slaver for CH375 ** ** 單片機(jī)用89C2051 ** ****************************************/ #include <INTRINS.H> #include "REG2051.H" #include "CH375INC.H"
#define DELAY_START_value 1 /* 根據(jù)單片機(jī)的時(shí)鐘選擇延時(shí)初值 */ #define MY_USB_VENDOR_ID 0x4348 /* 廠商ID */ #define MY_USB_DEVICE_ID 0x5537 /* 設(shè)備ID */
unsigned char RECV_LEN; /* 剛接收到的數(shù)據(jù)的長(zhǎng)度 */ unsigned char idata RECV_BUFFER[ CH375_MAX_DATA_LEN ]; /* 數(shù)據(jù)緩沖區(qū),用于保存接收到的下傳數(shù)據(jù),長(zhǎng)度為0到64字節(jié) */ unsigned char idata *cmd_buf; unsigned char idata *ret_buf;
typedef union _REQUEST_PACK{ unsigned char buffer[8]; struct{ unsigned char bmReuestType; //標(biāo)準(zhǔn)請(qǐng)求字 unsigned char bRequest; //請(qǐng)求代碼 unsigned int wvalue; //特性選擇高 unsigned int wIndx; //索引 unsigned int wLength; //數(shù)據(jù)長(zhǎng)度 }r; } mREQUEST_PACKET, *mpREQUEST_PACKET;
//設(shè)備描述符 unsigned char code DevDes[]={ 0x12 //描述符大小 ,0x01 //常數(shù)DEVICE ,0x10 //USB規(guī)范版本信息 ,0x01 ,0x00 //類別碼, ,0x00 //子類別碼 ,0x37 //協(xié)議碼 ,0x08 //端點(diǎn)0的最大信息包大小 ,0x48 //廠商ID ,0x43 ,0x37 //產(chǎn)品ID ,0x55 ,0x00 //設(shè)備版本信息 ,0x01 ,0x00 //索引值 ,0x00 ,0x00 ,0x01 //可能配置的數(shù)目 ,0x00 //無意義 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 }; //配置描述符 unsigned char code ConDes[]={ //配置描述符 0x09 //描述符大小 ,0x02 //常數(shù)CONFIG ,0x27 //此配置傳回所有數(shù)據(jù)大小 ,0x00 // ,0x01 //接口數(shù) ,0x01 //配置值 ,0x00 //索引 ,0x80 //電源設(shè)置 ,0x40 //需要總線電源 //接口描述符 ,0x09 //描述符大小 ,0x04 //常數(shù)INTERFACE ,0x00 //識(shí)別碼 ,0x00 //代替數(shù)值 ,0x03 //支持的端點(diǎn)數(shù) ,0x08 //類別碼 ,0x08 //子類別碼 ,0x37 //協(xié)議碼 ,0x00 //索引 //端點(diǎn)描述符 ,0x07 //描述符大小 ,0x05 //常數(shù)ENDPOINT ,0x82 //端點(diǎn)數(shù)目及方向 ,0x02 //支持的傳輸類型 ,0x40 //支持的最大信息包大小 ,0x00 ,0x00 //
,0x07 ,0x05 ,0x02 ,0x02 ,0x40 ,0x00 ,0x00
,0x07 ,0x05 ,0x81 ,0x03 ,0x08 ,0x00 ,0x01 ,0x07 ,0x05 ,0x01 ,0x02 ,0x08 ,0x00 ,0x00 }; //配置描述符 unsigned char code LangDes[]={0x04,0x03,0x09,0x04}; //語言描述符 unsigned char code SerDes[]={0x12,0x03,'C',0,'H',0,'3',0,'7',0,'5',0,'U',0,'S',0,'B',0}; //字符串描述符
unsigned char mVarSetupRequest; // USB請(qǐng)求碼 unsigned char mVarSetupLength; // 后續(xù)數(shù)據(jù)長(zhǎng)度 unsigned char code * VarSetupDescr; // 描述符偏移地址
unsigned char VarUsbAddress ; // bit CH375FLAGERR; //錯(cuò)誤清0 bit CH375CONFLAG; //配置標(biāo)志
mREQUEST_PACKET request;
/* Ch375與51等的連接 CH375 51 D0 P1.0 . . . . . . D7 P1.7 A0 P3.7 RD P3.5 WR P3.4 CS 接地 INT P3.2(int0) */ #define CH375_DATA_PORT P1 /* CH375端口的I/O地址 */ sbit CH375_CMD_DAT = P3^7; /* CH375地址線輸入A0,A0=1時(shí)寫命令,A0=0時(shí)讀寫數(shù)據(jù) */ sbit CH375_RD = P3^5; /* CH375讀選通輸入,低電平有效 */ sbit CH375_WR = P3^4; /* CH375寫選通輸入,低電平有效 */ sbit led = P3^3; /* 指示燈 */ sbit CH375_INT_WIRE = P3^2; /* CH375中斷請(qǐng)求輸出,低電平有效 */
void delay50ms(void); void delay1s(void); void flash_led(void); void CH375_WR_CMD_PORT( unsigned char cmd ); void CH375_WR_DAT_PORT( unsigned char dat ); unsigned char CH375_RD_DAT_PORT(void); void set_usb_mode( unsigned char mode ); void CH375_Init( void ); void ComInit(void); void SendChar(unsigned char buff); void mCh375Ep0Up(void); void mCh375DesUp(void);
void delay50ms(void) { unsigned char i, j; for( i=200; i!=0; i-- ) for( j=250; j!=0; j-- ); }
void delay1s(void) { unsigned char i,j,k;
for( i=10; i!=0; i-- ) for( j=200; j!=0; j-- ) for( k=250; k!=0; k-- ); }
void flash_led(void) { unsigned char i;
for( i=10;i>0;i-- ) { led=!led; delay1s(); } }
/* 與CH372/CH375有關(guān)的基本I/O操作 */ /* 向CH375的命令端口寫入命令,周期不小于4uS,如果單片機(jī)較快則延時(shí) */ void CH375_WR_CMD_PORT( unsigned char cmd ) { _nop_(); _nop_(); CH375_CMD_DAT = 1; /* 命令 */ CH375_DATA_PORT = cmd; CH375_RD = 1; CH375_WR = 0; _nop_(); _nop_(); CH375_WR = 1; CH375_CMD_DAT = 0; CH375_DATA_PORT = 0xFF; }
/* 向CH375的數(shù)據(jù)端口寫入數(shù)據(jù),周期不小于1.5uS,如果單片機(jī)較快則延時(shí) */ void CH375_WR_DAT_PORT( unsigned char dat ) { _nop_(); CH375_CMD_DAT = 0; /* 數(shù)據(jù) */ CH375_DATA_PORT = dat; CH375_RD = 1; CH375_WR = 0; _nop_(); CH375_WR = 1; CH375_DATA_PORT = 0xFF; }
/* 從CH375的數(shù)據(jù)端口讀出數(shù)據(jù),周期不小于1.5uS,如果單片機(jī)較快則延時(shí) */ unsigned char CH375_RD_DAT_PORT(void) { unsigned char rev_data;
CH375_DATA_PORT = 0xFF; CH375_CMD_DAT = 0; /* 數(shù)據(jù) */ CH375_WR = 1; CH375_RD = 0; _nop_(); rev_data = CH375_DATA_PORT; CH375_RD = 1;
return( rev_data ); }
/* 設(shè)置CH37X的工作模式 */ void set_usb_mode( unsigned char mode ) { unsigned char i; unsigned char RD_Data;
CH375_WR_CMD_PORT( CMD_SET_USB_MODE ); CH375_WR_DAT_PORT( mode );
for( i=100; i!=0; i-- ) /* 等待設(shè)置模式操作完成,不超過30uS */ { RD_Data=CH375_RD_DAT_PORT(); if( RD_Data == CMD_RET_SUCCESS ) return; /* 成功 */ }
while(1) { flash_led(); /* CH375出錯(cuò) */ } }
/* CH375初始化子程序 */ void CH375_Init( void ) { unsigned char i, k; unsigned char RD_Data;
CH375_DATA_PORT = 0xFF; CH375_INT_WIRE = 1; CH375_WR = 1; CH375_RD = 1; CH375_CMD_DAT = 0;
/* 測(cè)試CH375是否正常工作 */ for( k=100; k!=0; k-- ) { CH375_WR_CMD_PORT( CMD_CHECK_EXIST ); /* 測(cè)試CH375是否正常工作 */
i = 0x5A; CH375_WR_DAT_PORT( i ); /* 寫入測(cè)試數(shù)據(jù) */ i = ~i; /* 返回?cái)?shù)據(jù)應(yīng)該是測(cè)試數(shù)據(jù)取反 */ RD_Data = CH375_RD_DAT_PORT(); if ( RD_Data != i ) /* CH375不正常 */ { for ( i=5; i!=0; i-- ) { CH375_WR_CMD_PORT( CMD_RESET_ALL ); /* 多次重復(fù)發(fā)命令,執(zhí)行硬件復(fù)位 */ } delay50ms(); /* 延時(shí)50ms */ } else break; } if( k==0 ) { while(1) { flash_led(); /* CH375出錯(cuò) */ } } /* #ifdef MY_USB_VENDOR_ID #ifdef MY_USB_DEVICE_ID // 設(shè)置外部自定義的USB設(shè)備VID和PID,可選操作,不執(zhí)行該命令則使用默認(rèn)的VID和PID, // 如果設(shè)置使用自定義的ID,那么計(jì)算機(jī)端驅(qū)動(dòng)程序INF安裝文件中的"USB\VID_4348&PID_5537"需要進(jìn)行類似修改 CH375_WR_CMD_PORT( CMD_SET_USB_ID ); // 設(shè)置外部自定義的USB設(shè)備VID和PID,可選操作 CH375_WR_DAT_PORT( (unsigned char)MY_USB_VENDOR_ID ); // 寫入廠商ID的低字節(jié) CH375_WR_DAT_PORT( (unsigned char)(MY_USB_VENDOR_ID>>8) ); // 寫入廠商ID的高字節(jié) CH375_WR_DAT_PORT( (unsigned char)MY_USB_DEVICE_ID ); // 寫入設(shè)備ID的低字節(jié) CH375_WR_DAT_PORT( (unsigned char)(MY_USB_DEVICE_ID>>8) ); // 寫入設(shè)備ID的高字節(jié) #endif #endif */ /* 設(shè)置USB工作模式, 必要操作 */ // set_usb_mode( 1 ); //外部固件模式 set_usb_mode( 2 ); //內(nèi)部固件模式
}
/* 串行口通訊子程序 */ /* 串行口初始化 */ void ComInit(void) { TMOD = 0x20; /*T1為方式2 */ TH1 = 0xFE; /*計(jì)數(shù)常數(shù)0xFE,波特率:14400 晶振:11.0592MHz */ TL1 = 0xFE; PCON = PCON & 0x7f; /* SMOD=0 */ SCON = 0x50; /* 串行口工作在方式3 */ TR1 = 1; }
/* 發(fā)送數(shù)據(jù) */ void SendChar(unsigned char buff) { SBUF = buff; while( !TI ); TI=0; }
//端點(diǎn)0數(shù)據(jù)上傳 void mCh375Ep0Up(void) { unsigned char i,len;
if( mVarSetupLength ) //長(zhǎng)度不為0傳輸具體長(zhǎng)度的數(shù)據(jù) { if( mVarSetupLength<=8 ) { len=mVarSetupLength; mVarSetupLength=0; } //長(zhǎng)度小于8則傳輸要求的長(zhǎng)度 else { len=8; mVarSetupLength-=8; } //長(zhǎng)度大于8則傳輸8個(gè),切總長(zhǎng)度減8 CH375_WR_CMD_PORT( CMD_WR_USB_DATA3 ); //發(fā)出寫端點(diǎn)0的命令 CH375_WR_DAT_PORT( len ); //寫入長(zhǎng)度 for( i=0;i!=len;i++ ) CH375_WR_DAT_PORT( request.buffer ); //循環(huán)寫入數(shù)據(jù) } else { CH375_WR_CMD_PORT( CMD_WR_USB_DATA3 ); //發(fā)出寫端點(diǎn)0的命令 CH375_WR_DAT_PORT( 0 ); //上傳0長(zhǎng)度數(shù)據(jù),這是一個(gè)狀態(tài)階段 } }
//復(fù)制描述符以便上傳 void mCh375DesUp(void) { unsigned char k; for (k=0; k!=8; k++ ) { request.buffer[k]=*VarSetupDescr; //依次復(fù)制8個(gè)描述符, VarSetupDescr++; } }
/* CH375數(shù)據(jù)接收程序 */ void mCh375Interrupt(void) { unsigned char InterruptStatus; unsigned char length, len;
CH375_WR_CMD_PORT(CMD_GET_STATUS); /* 獲取中斷狀態(tài)并取消中斷請(qǐng)求 */ InterruptStatus = CH375_RD_DAT_PORT(); /* 獲取中斷狀態(tài) */ RECV_LEN=0; switch( InterruptStatus ) // 分析中斷狀態(tài) { case USB_INT_EP2_OUT: // 批量端點(diǎn)下傳成功 CH375_WR_CMD_PORT( CMD_RD_USB_DATA ); /* 從當(dāng)前USB中斷的端點(diǎn)緩沖區(qū)讀取數(shù)據(jù)塊,并釋放緩沖區(qū) */ length = CH375_RD_DAT_PORT(); /* 首先讀取后續(xù)數(shù)據(jù)長(zhǎng)度 */ if ( length != 0 ) /* 如果長(zhǎng)度為0則不處理 */ { RECV_LEN = length; /* 命令包的數(shù)據(jù)長(zhǎng)度 */ ret_buf = RECV_BUFFER; /* 接收緩沖區(qū) */ while ( length -- ) { *ret_buf = CH375_RD_DAT_PORT(); ret_buf++; } } break; case USB_INT_EP2_IN: //批量端點(diǎn)上傳成功,未處理 break; case USB_INT_EP1_IN: //中斷端點(diǎn)上傳成功,未處理 break; case USB_INT_EP1_OUT: //中斷端點(diǎn)下傳成功,未處理 break; case USB_INT_EP0_SETUP: //控制端點(diǎn)建立成功 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(); // 取出數(shù)據(jù) if( length==0x08 ) { mVarSetupLength=request.buffer[6]&0x7f; //控制傳輸數(shù)據(jù)長(zhǎng)度最大設(shè)置為128 // if((c1=request.r.bmReuestType)&0x40 ) //廠商請(qǐng)求,未處理 // {} // if((c1=request.r.bmReuestType)&0x20) //類請(qǐng)求,未處理 // {} if( !(request.r.bmReuestType&0x60) ) //標(biāo)準(zhǔn)請(qǐng)求 { mVarSetupRequest=request.r.bRequest; //暫存標(biāo)準(zhǔn)請(qǐng)求碼 switch( request.r.bRequest ) // 分析標(biāo)準(zhǔn)請(qǐng)求 { case DEF_USB_CLR_FEATURE: //清除特性 if((request.r.bmReuestType&0x1F)==0x02) //不是端點(diǎn)不支持 { switch( request.buffer[4] ) { case 0x82: CH375_WR_CMD_PORT( CMD_SET_ENDP7 ); //清除端點(diǎn)2上傳 CH375_WR_DAT_PORT( 0x8E ); //發(fā)命令清除端點(diǎn) break; case 0x02: CH375_WR_CMD_PORT( CMD_SET_ENDP6 ); CH375_WR_DAT_PORT( 0x80 ); //清除端點(diǎn)2下傳 break; case 0x81: CH375_WR_CMD_PORT( CMD_SET_ENDP5 ); //清除端點(diǎn)1上傳 CH375_WR_DAT_PORT( 0x8E ); break; case 0x01: CH375_WR_CMD_PORT( CMD_SET_ENDP4 ); //清除端點(diǎn)1下傳 CH375_WR_DAT_PORT( 0x80 ); break; default: break; } } else { CH375FLAGERR=1; //不支持的清除特性,置錯(cuò)誤標(biāo)志 } break; case DEF_USB_GET_STATUS: //獲得狀態(tài) request.buffer[0]=0; request.buffer[1]=0; //上傳狀態(tài) break; case DEF_USB_SET_ADDRESS: //設(shè)置地址 VarUsbAddress=request.buffer[2]; //暫存USB主機(jī)發(fā)來的地址 break; case DEF_USB_GET_DESCR: //獲得描述符 if( request.buffer[3]==1 ) //設(shè)備描述符上傳 VarSetupDescr=DevDes; else if( request.buffer[3]==2 ) //配置描述符上傳 VarSetupDescr=ConDes; else if( request.buffer[3]==3 ) { if( request.buffer[2]== 0 ) VarSetupDescr=LangDes; else VarSetupDescr=SerDes; //做字符串處理 } mCh375DesUp(); //其余描述符不支持 break; case DEF_USB_GET_CONFIG: //獲得配置 request.buffer[0]=0; //沒有配置則傳0 if( CH375CONFLAG ) request.buffer[0]=1; //已經(jīng)配置則傳1;這是在描述符里規(guī)定的 break; case DEF_USB_SET_CONFIG: //設(shè)置配置 CH375CONFLAG=0; if( request.buffer[2] != 0 ) { CH375CONFLAG=1; //設(shè)置配置標(biāo)志 } break; case DEF_USB_GET_INTERF: //得到接口 request.buffer[0]=1; //上傳接口數(shù),本事例只支持一個(gè)接口 break; default : CH375FLAGERR=1; //不支持的標(biāo)準(zhǔn)請(qǐng)求 break; } } } else //不支持的控制傳輸,不是8字節(jié)的控制傳輸 { CH375FLAGERR=1; }
if( !CH375FLAGERR ) mCh375Ep0Up(); //沒有錯(cuò)誤/調(diào)用數(shù)據(jù)上傳,長(zhǎng)度為0上傳為狀態(tài) else { CH375_WR_CMD_PORT( CMD_SET_ENDP3 ); //設(shè)置端點(diǎn)1為STALL,指示一個(gè)錯(cuò)誤 CH375_WR_DAT_PORT( 0x0F ); flash_led(); } break; case USB_INT_EP0_IN: //控制端點(diǎn)上串成功 if( mVarSetupRequest==DEF_USB_GET_DESCR ) //描述符上傳 { mCh375DesUp(); mCh375Ep0Up(); } else if( mVarSetupRequest==DEF_USB_SET_ADDRESS ) //設(shè)置地址 { CH375_WR_CMD_PORT( CMD_SET_USB_ADDR ); CH375_WR_DAT_PORT( VarUsbAddress ); //設(shè)置USB地址,設(shè)置下次事務(wù)的USB地址 } break; case USB_INT_EP0_OUT: //控制端點(diǎn)下傳成功 CH375_WR_CMD_PORT( CMD_RD_USB_DATA ); //發(fā)出讀數(shù)據(jù)命令 length=CH375_RD_DAT_PORT(); if( length>0 ) //長(zhǎng)度為0跳出 { for( len=0;len!=length;len++ ) CH375_RD_DAT_PORT(); //取出下傳數(shù)據(jù) } break; default: if( InterruptStatus&0x03 ) //總線復(fù)位 { CH375FLAGERR=0; //錯(cuò)誤清0 CH375CONFLAG=0; //配置清0 mVarSetupLength=0; } else { //命令不支持 flash_led(); } break; }
CH375_WR_CMD_PORT( CMD_UNLOCK_USB ); //釋放緩沖區(qū) led=0; }
/*串行數(shù)據(jù)接收程序*/ void receive(void) { unsigned int count; unsigned char buf;
RECV_LEN=0; cmd_buf = RECV_BUFFER; /* 接收緩沖區(qū) */ while( 1 ) { RI=0; *cmd_buf = SBUF; cmd_buf++; RECV_LEN++; if( RECV_LEN == 64 ) { while( 1 ) { count=10000; while( RI==0 ) { count--; if( count==0 ) return; } RI=0; buf=SBUF; } } count=10000; while( RI==0 ) { count--; if( count==0 ) return; } } }
void main(void) { unsigned char length;
delay1s(); /* 延時(shí)等待CH375初始化完成,如果單片機(jī)由CH375提供復(fù)位信號(hào)則不必延時(shí) */ CH375_Init( ); /* 初始化CH375 */ ComInit(); led = 0;
while ( 1 ) { if( RI==1 ) /* 從串口接收到的數(shù)據(jù) */ { led=1; receive(); led=0;
/* 將從串口接收到的數(shù)據(jù)發(fā)送到USB設(shè)備 */ ret_buf = RECV_BUFFER; /* 接收緩沖區(qū) */ length = RECV_LEN; /* 剛接收到的數(shù)據(jù)長(zhǎng)度 */ if( length!=0 ) { CH375_WR_CMD_PORT( CMD_WR_USB_DATA7 ); /* 向USB端點(diǎn)2的發(fā)送緩沖區(qū)寫入數(shù)據(jù)塊 */ CH375_WR_DAT_PORT( length ); /* 首先寫入后續(xù)數(shù)據(jù)長(zhǎng)度 */ while( length-- ) { CH375_WR_DAT_PORT( *ret_buf ); /* 數(shù)據(jù) */ ret_buf++; } } }
CH375_INT_WIRE=1; if( CH375_INT_WIRE==0 ) /* 從USB設(shè)備接收到數(shù)據(jù) */ { mCh375Interrupt();
/* 將從USB設(shè)備接收到的數(shù)據(jù)發(fā)送到串口 */ ret_buf = RECV_BUFFER; /* 接收緩沖區(qū) */ length = RECV_LEN; /* 剛接收到的數(shù)據(jù)長(zhǎng)度 */ while( length-- ) { SendChar( *ret_buf ); ret_buf++; } } } }
|
|