⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch372.txt

📁 应用ch372作为USB接口芯片
💻 TXT
字号:
CH375的slaver的程序(C51) 
 
 
发表时间:2005-08-23 18:03:17 浏览人数:534 发布者:administrator 
CH375做slaver的程序
/***************************************
** USB 1.1 Slaver for CH375     **
** 单片机用89C2051             **
****************************************/
#include <INTRINS.H>
#include "REG2051.H"
#include "CH375INC.H"

#define DELAY_START_value 1   /* 根据单片机的时钟选择延时初值 */
#define MY_USB_VENDOR_ID 0x4348 /* 厂商ID */
#define MY_USB_DEVICE_ID 0x5537 /* 设备ID */

unsigned char RECV_LEN;     /* 刚接收到的数据的长度 */
unsigned char idata RECV_BUFFER[ CH375_MAX_DATA_LEN ]; /* 数据缓冲区,用于保存接收到的下传数据,长度为0到64字节 */
unsigned char idata *cmd_buf;
unsigned char idata *ret_buf;

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
,0x00 //类别码,
,0x00 //子类别码
,0x37 //协议码
,0x08 //端点0的最大信息包大小
,0x48 //厂商ID
,0x43
,0x37 //产品ID
,0x55
,0x00 //设备版本信息
,0x01
,0x00 //索引值
,0x00
,0x00
,0x01 //可能配置的数目
,0x00 //无意义
,0x00
,0x00
,0x00
,0x00
,0x00
};
//配置描述符
unsigned char   code ConDes[]={ //配置描述符
0x09 //描述符大小
,0x02 //常数CONFIG
,0x27 //此配置传回所有数据大小
,0x00 //
,0x01 //接口数
,0x01 //配置值
,0x00 //索引
,0x80 //电源设置
,0x40 //需要总线电源
//接口描述符
,0x09 //描述符大小
,0x04 //常数INTERFACE
,0x00 //识别码
,0x00 //代替数值
,0x03 //支持的端点数
,0x08 //类别码
,0x08 //子类别码
,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; //配置标志

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时写命令,A0=0时读写数据 */
sbit CH375_RD = P3^5; /* CH375读选通输入,低电平有效 */
sbit CH375_WR = P3^4; /* CH375写选通输入,低电平有效 */
sbit led = P3^3; /* 指示灯 */
sbit CH375_INT_WIRE = P3^2; /* CH375中断请求输出,低电平有效 */

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有关的基本I/O操作 */
/* 向CH375的命令端口写入命令,周期不小于4uS,如果单片机较快则延时 */
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的数据端口写入数据,周期不小于1.5uS,如果单片机较快则延时 */
void CH375_WR_DAT_PORT( unsigned char dat )
{
_nop_();
CH375_CMD_DAT = 0; /* 数据 */
CH375_DATA_PORT = dat;
CH375_RD = 1;
CH375_WR = 0;
_nop_();
CH375_WR = 1;
CH375_DATA_PORT = 0xFF;
}

/* 从CH375的数据端口读出数据,周期不小于1.5uS,如果单片机较快则延时 */
unsigned char CH375_RD_DAT_PORT(void)
{
unsigned char rev_data;

CH375_DATA_PORT = 0xFF;
CH375_CMD_DAT = 0; /* 数据 */
CH375_WR = 1;
CH375_RD = 0;
_nop_();
rev_data = CH375_DATA_PORT;
CH375_RD = 1;

return( rev_data );
}

/* 设置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-- )   /* 等待设置模式操作完成,不超过30uS */
{
RD_Data=CH375_RD_DAT_PORT();
if( RD_Data == CMD_RET_SUCCESS )
return; /* 成功 */
}

while(1)
{
flash_led(); /* CH375出错 */
}
}

/* 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;

/* 测试CH375是否正常工作 */
for( k=100; k!=0; k-- )
{
CH375_WR_CMD_PORT( CMD_CHECK_EXIST ); /* 测试CH375是否正常工作 */

i = 0x5A;
CH375_WR_DAT_PORT( i ); /* 写入测试数据 */
i = ~i; /* 返回数据应该是测试数据取反 */
RD_Data = CH375_RD_DAT_PORT();
if ( RD_Data != i )   /* CH375不正常 */
{
for ( i=5; i!=0; i-- )
{
CH375_WR_CMD_PORT( CMD_RESET_ALL ); /* 多次重复发命令,执行硬件复位 */
}
delay50ms(); /* 延时50ms */
}
else
break;
}
if( k==0 )
{
while(1)
{
flash_led(); /* CH375出错 */
}
}
/*
#ifdef MY_USB_VENDOR_ID
#ifdef MY_USB_DEVICE_ID
// 设置外部自定义的USB设备VID和PID,可选操作,不执行该命令则使用默认的VID和PID,
// 如果设置使用自定义的ID,那么计算机端驱动程序INF安装文件中的"USB\VID_4348&PID_5537"需要进行类似修改
CH375_WR_CMD_PORT( CMD_SET_USB_ID ); // 设置外部自定义的USB设备VID和PID,可选操作
CH375_WR_DAT_PORT( (unsigned char)MY_USB_VENDOR_ID ); // 写入厂商ID的低字节
CH375_WR_DAT_PORT( (unsigned char)(MY_USB_VENDOR_ID>>8) ); // 写入厂商ID的高字节
CH375_WR_DAT_PORT( (unsigned char)MY_USB_DEVICE_ID ); // 写入设备ID的低字节
CH375_WR_DAT_PORT( (unsigned char)(MY_USB_DEVICE_ID>>8) ); // 写入设备ID的高字节
#endif
#endif
*/
/* 设置USB工作模式, 必要操作 */
// set_usb_mode( 1 ); //外部固件模式
set_usb_mode( 2 ); //内部固件模式

}

/* 串行口通讯子程序 */
/* 串行口初始化 */
void ComInit(void)
{
  TMOD = 0x20;       /*T1为方式2 */
  TH1 = 0xFE;       /*计数常数0xFE,波特率:14400 晶振:11.0592MHz */
  TL1 = 0xFE;
  PCON = PCON & 0x7f; /* SMOD=0 */
  SCON = 0x50;       /* 串行口工作在方式3 */
  TR1 = 1;
}

/* 发送数据 */
void SendChar(unsigned char buff)
{
  SBUF = buff;
  while( !TI );
  TI=0;
}

//端点0数据上传
void mCh375Ep0Up(void)
{
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 );           //循环写入数据
  }
else
{
CH375_WR_CMD_PORT( CMD_WR_USB_DATA3 ); //发出写端点0的命令
CH375_WR_DAT_PORT( 0 );               //上传0长度数据,这是一个状态阶段
}
}

//复制描述符以便上传
void mCh375DesUp(void)
{
unsigned char k;
for (k=0; k!=8; k++ )
{
      request.buffer[k]=*VarSetupDescr;   //依次复制8个描述符,
      VarSetupDescr++;
  }
}

/* CH375数据接收程序 */
void mCh375Interrupt(void)
{
unsigned char InterruptStatus;
unsigned char length, len;

CH375_WR_CMD_PORT(CMD_GET_STATUS);   /* 获取中断状态并取消中断请求 */
InterruptStatus = CH375_RD_DAT_PORT();   /* 获取中断状态 */
RECV_LEN=0;
switch( InterruptStatus ) // 分析中断状态
{
case USB_INT_EP2_OUT:   // 批量端点下传成功
CH375_WR_CMD_PORT( CMD_RD_USB_DATA ); /* 从当前USB中断的端点缓冲区读取数据块,并释放缓冲区 */
length = CH375_RD_DAT_PORT(); /* 首先读取后续数据长度 */
if ( length != 0 )   /* 如果长度为0则不处理 */
{
RECV_LEN = length; /* 命令包的数据长度 */
ret_buf = RECV_BUFFER; /* 接收缓冲区 */
while ( length -- )
{
*ret_buf = CH375_RD_DAT_PORT();
ret_buf++;
}
}
break;
case   USB_INT_EP2_IN: //批量端点上传成功,未处理
break;
case   USB_INT_EP1_IN:   //中断端点上传成功,未处理
break;
case   USB_INT_EP1_OUT:   //中断端点下传成功,未处理
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( !(request.r.bmReuestType&0x60) )       //标准请求
{
mVarSetupRequest=request.r.bRequest; //暂存标准请求码
switch( request.r.bRequest ) // 分析标准请求
{
case DEF_USB_CLR_FEATURE: //清除特性
if((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;
if( request.buffer[2] != 0 )
{
CH375CONFLAG=1; //设置配置标志
}
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 );
flash_led();
}
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地址
}
break;
case   USB_INT_EP0_OUT: //控制端点下传成功
CH375_WR_CMD_PORT( CMD_RD_USB_DATA ); //发出读数据命令
length=CH375_RD_DAT_PORT();
if( length>0 ) //长度为0跳出
{
for( len=0;len!=length;len++ )
CH375_RD_DAT_PORT(); //取出下传数据
}
break;
default:
if( InterruptStatus&0x03 ) //总线复位
{
CH375FLAGERR=0; //错误清0
CH375CONFLAG=0; //配置清0
mVarSetupLength=0;
}
else
{ //命令不支持
flash_led();
}
break;
}

CH375_WR_CMD_PORT( CMD_UNLOCK_USB ); //释放缓冲区
led=0;
}

/*串行数据接收程序*/
void receive(void)
{
  unsigned int count;
unsigned char buf;

RECV_LEN=0;
cmd_buf = RECV_BUFFER; /* 接收缓冲区 */
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(); /* 延时等待CH375初始化完成,如果单片机由CH375提供复位信号则不必延时 */
CH375_Init( ); /* 初始化CH375 */
ComInit();
led = 0;

while ( 1 )
{
if( RI==1 ) /* 从串口接收到的数据 */
{
led=1;
receive();
led=0;

/* 将从串口接收到的数据发送到USB设备 */
ret_buf = RECV_BUFFER; /* 接收缓冲区 */
length = RECV_LEN; /* 刚接收到的数据长度 */
if( length!=0 )
{
CH375_WR_CMD_PORT( CMD_WR_USB_DATA7 ); /* 向USB端点2的发送缓冲区写入数据块 */
CH375_WR_DAT_PORT( length ); /* 首先写入后续数据长度 */
while( length-- )
{
CH375_WR_DAT_PORT( *ret_buf ); /* 数据 */
ret_buf++;
}
}
}

CH375_INT_WIRE=1;
if( CH375_INT_WIRE==0 ) /* 从USB设备接收到数据 */
{
mCh375Interrupt();

/* 将从USB设备接收到的数据发送到串口 */
ret_buf = RECV_BUFFER; /* 接收缓冲区 */
length = RECV_LEN; /* 刚接收到的数据长度 */
while( length-- )
{
SendChar( *ret_buf );
ret_buf++;
}
}
}
}
 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -