?? usbex.c
字號:
/*;CH372/CH375 USB device mode & external firmware
; U2(AT89C51) Program
;
; Website: http://winchiphead.com
; Email: tech@winchiphead.com
; Author: W.ch 2003.12, 2005.03
;
;****************************************************************************
CH375 外部固件方式范例
這里僅處理標準請求和端點2的簡單讀寫
*/
/* MCS-51單片機C語言的示例程序 */
#pragma NOAREGS
#include <reg52.h>
#include "CH375INC.H"
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
, 0xFF //類別碼,
, 0x80 //子類別碼
, 0x37 //協議碼
, 0x08 //端點0的最大信息包大小
, 0x48 //廠商ID
, 0x43
, 0x37 //產品ID
, 0x55
, 0x00 //設備版本信息
, 0x01
, 0x00 //索引值
, 0x00
, 0x00
, 0x01 //可能配置的數目
, 00 //無意義
, 00
, 00
, 00
, 00
, 00
};
//配置描述符
unsigned char code ConDes[]={ //配置描述符
0x09 //描述符大小
, 0x02 //常數CONFIG
, 0x27 //此配置傳回所有數據大小
, 0x00 //
, 0x01 //接口數
, 0x01 //配置值
, 0x00 //索引
, 0x80 //電源設置
, 0x40 //需要總線電源
//接口描述符
, 0x09 //描述符大小
, 0x04 //常數INTERFACE
, 0x00 //識別碼
, 0x00 //代替數值
, 0x03 //支持的端點數
, 0xFF //類別碼
, 0x80 //子類別碼
, 0x37 //協議碼
, 0x00 //索引
//端點描述符
, 0x07 //述符大小
, 0x05 //常數ENDPOINT
, 0x82 //端點數目及方向
, 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請求碼
unsigned char mVarSetupLength; // ;后續數據長度
unsigned char code * VarSetupDescr; // ;描述符偏移地址
unsigned char VarUsbAddress ; //
bit CH375FLAGERR; //錯誤清0
bit CH375CONFLAG;
//配置標志
unsigned char volatile xdata CH375_CMD_PORT _at_ 0x7fff; /* CH375命令端口的I/O地址 */
unsigned char volatile xdata CH375_DAT_PORT _at_ 0x3fff; /* CH375數據端口的I/O地址 */
mREQUEST_PACKET request;
sbit CH375ACT = P1^0;
/* 延時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-- );
}
/* 將PC機的低字節在前的16位字數據轉換為C51的高字節在前的數據 */
//unsigned int BIG_ENDIAN( unsigned int value )
//{
// unsigned int in, out;
// in = value;
// ((unsigned char *)&out)[1] = ((unsigned char *)&in)[0];
// ((unsigned char *)&out)[0] = ((unsigned char *)&in)[1];
// return( out );
//}
void CH375_WR_CMD_PORT( unsigned char cmd ) { /* 向CH375的命令端口寫入命令,周期不小于4uS,如果單片機較快則延時 */
//delay2us();
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;
}
/* 下述啟用中斷,假定CH375連接在INT0 */
IT0 = 0; /* 置外部信號為低電平觸發 */
IE0 = 0; /* 清中斷標志 */
EX0 = 1; /* 允許CH375中斷 */
}
//*********************************************************
//*********************************************************
//端點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++;
}
}
/* CH375中斷服務程序INT0,使用寄存器組1 */
void mCH375Interrupt( ) interrupt 0 using 1
{
unsigned char InterruptStatus;
unsigned char length, c1, len;
unsigned char *pBuf;
unsigned char mBuf[64];
CH375_WR_CMD_PORT(CMD_GET_STATUS); /* 獲取中斷狀態并取消中斷請求 */
InterruptStatus =CH375_RD_DAT_PORT(); /* 獲取中斷狀態 */
IE0 = 0; /* 清中斷標志,對應于INT0中斷 */
switch(InterruptStatus){ // 分析中斷狀態
case USB_INT_EP2_OUT: // 批量端點下傳成功
pBuf=mBuf; //數據未處理
CH375_WR_CMD_PORT(CMD_RD_USB_DATA); //發出讀數據命令
length=CH375_RD_DAT_PORT(); //首先讀出的是長度
for(len=0;len!=length;len++,pBuf++)*pBuf=CH375_RD_DAT_PORT(); //將數據讀入到緩沖區
pBuf=mBuf;
// 演示回傳
CH375_WR_CMD_PORT(CMD_WR_USB_DATA7); //發出寫上傳端點命令
CH375_WR_DAT_PORT(length);
for(len=0;len!=length;len++,pBuf++)CH375_WR_DAT_PORT(*pBuf); //將數據寫入上傳端點
break;
case USB_INT_EP2_IN: //批量端點上傳成功,未處理
CH375_WR_CMD_PORT (CMD_UNLOCK_USB); //釋放緩沖區
break;
case USB_INT_EP1_IN: //中斷端點上傳成功,未處理
CH375_WR_CMD_PORT (CMD_UNLOCK_USB); //釋放緩沖區
break;
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(); //取出下傳數據
}
// CH375_WR_CMD_PORT (CMD_UNLOCK_USB); //釋放緩沖區,如果前面沒有CMD_RD_USB_DATA命令則使用本命令
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]&0x7f; //控制傳輸數據長度最大設置為128
if((c1=request.r.bmReuestType)&0x40){ //廠商請求,未處理
}
if((c1=request.r.bmReuestType)&0x20){ //類請求,未處理
}
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: //設置地址
VarUsbAddress=request.buffer[2]; //暫存USB主機發來的地址
break;
case DEF_USB_GET_DESCR: //獲得描述符
if(request.buffer[3]==1) //設備描述符上傳
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; //已經配置則傳1;這是在描述符里規定的
break;
case DEF_USB_SET_CONFIG: //設置配置
CH375CONFLAG=0;
CH375ACT=1;
if ( request.buffer[2] != 0 ) {
CH375CONFLAG=1; //設置配置標志
CH375ACT=0; //輸出配置完成信號
}
break;
case DEF_USB_GET_INTERF: //得到接口
request.buffer[0]=1; //上傳接口數,本事例只支持一個接口
break;
default :
CH375FLAGERR=1; //不支持的標準請求
break;
}
}
}
else { //不支持的控制傳輸,不是8字節的控制傳輸
CH375FLAGERR=1;
}
if(!CH375FLAGERR) mCh375Ep0Up(); //沒有錯誤/調用數據上傳,,長度為0上傳為狀態
else {
CH375_WR_CMD_PORT(CMD_SET_ENDP3); //設置端點1為STALL,指示一個錯誤
CH375_WR_DAT_PORT(0x0F);
}
break;
case USB_INT_EP0_IN: //控制端點上傳成功
if(mVarSetupRequest==DEF_USB_GET_DESCR){ //描述符上傳
mCh375DesUp();
mCh375Ep0Up();
}
else if(mVarSetupRequest==DEF_USB_SET_ADDRESS){ //設置地址
CH375_WR_CMD_PORT(CMD_SET_USB_ADDR);
CH375_WR_DAT_PORT(VarUsbAddress); //設置USB地址,設置下次事務的USB地址
}
CH375_WR_CMD_PORT (CMD_UNLOCK_USB); //釋放緩沖區
break;
case USB_INT_EP0_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;
default:
if((InterruptStatus&0x03)==0x03){ //總線復位
CH375FLAGERR=0; //錯誤清0
CH375CONFLAG=0; //配置清0
mVarSetupLength=0;
CH375ACT=1; //清配置完成輸出
}
else{ //命令不支持
;
}
CH375_WR_CMD_PORT (CMD_UNLOCK_USB); //釋放緩沖區
break;
}
}
main( ) {
Delay50ms( ); /* 延時等待CH375初始化完成,如果單片機由CH375提供復位信號則不必延時 */
CH375_WR_CMD_PORT( CMD_RESET_ALL ); //似乎是他模擬了一次插拔
Delay50ms( );Delay50ms( );Delay50ms( );Delay50ms( );Delay50ms( );
CH375_Init( ); /* 初始化CH375 */
EA=1;
while(1); /* 主程序 */
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -