📄 ch375prt.c
字号:
}
void toggle_send( BOOL1 tog ) { /* 主机发送同步控制:0=DATA0,1=DATA1 */
CH375_WR_CMD_PORT( CMD_SET_ENDP7 );
CH375_WR_DAT_PORT( tog ? 0xC0 : 0x80 );
delay2us();
}
unsigned char clr_stall( unsigned char endp_addr ) { /* USB通讯失败后,复位设备端的指定端点到DATA0 */
CH375_WR_CMD_PORT( CMD_CLR_STALL );
CH375_WR_DAT_PORT( endp_addr );
return( wait_interrupt() );
}
/* 数据读写, 单片机读写CH375芯片中的数据缓冲区 */
unsigned char rd_usb_data( unsigned char *buf ) { /* 从CH37X读出数据块 */
unsigned char i, len;
CH375_WR_CMD_PORT( CMD_RD_USB_DATA ); /* 从CH375的端点缓冲区读取接收到的数据 */
len=CH375_RD_DAT_PORT(); /* 后续数据长度 */
for ( i=0; i!=len; i++ ) *buf++=CH375_RD_DAT_PORT();
return( len );
}
void wr_usb_data( unsigned char len, unsigned char *buf ) { /* 向CH37X写入数据块 */
CH375_WR_CMD_PORT( CMD_WR_USB_DATA7 ); /* 向CH375的端点缓冲区写入准备发送的数据 */
CH375_WR_DAT_PORT( len ); /* 后续数据长度, len不能大于64 */
while( len-- ) CH375_WR_DAT_PORT( *buf++ );
}
/* 主机操作 */
unsigned char endp_out_addr; /* 打印机数据接收端点的端点地址 */
unsigned char endp_out_size; /* 打印机数据接收端点的端点尺寸 */
BOOL1 tog_send; /* 打印机数据接收端点的同步标志 */
unsigned char endp_in_addr; /* 双向打印机发送端点的端点地址,一般不用 */
BOOL1 tog_recv; /* 双向打印机发送端点的同步标志,一般不用 */
unsigned char issue_token( unsigned char endp_and_pid ) { /* 执行USB事务 */
/* 执行完成后, 将产生中断通知单片机, 如果是USB_INT_SUCCESS就说明操作成功 */
CH375_WR_CMD_PORT( CMD_ISSUE_TOKEN );
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字节 */
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 int len, unsigned char *buf ) { /* 主机发送数据块,一次最多64KB */
unsigned char l, s;
endp_out_size=64;
while( len ) { /* 连续输出数据块给USB打印机 */
toggle_send( tog_send ); /* 数据同步 */
l = len>endp_out_size?endp_out_size:len; /* 单次发送不能超过端点尺寸 */
wr_usb_data( l, buf ); /* 将数据先复制到CH375芯片中 */
s = issue_token( ( endp_out_addr << 4 ) | DEF_USB_PID_OUT ); /* 请求CH375输出数据 */
if ( s==USB_INT_SUCCESS ) { /* CH375成功发出数据 */
tog_send = ~ tog_send; /* 切换DATA0和DATA1进行数据同步 */
len-=l; /* 计数 */
buf+=l; /* 操作成功 */
}
else if ( s==USB_INT_RET_NAK ) { /* USB打印机正忙,如果未执行SET_RETRY命令则CH375自动重试,所以不会返回USB_INT_RET_NAK状态 */
/* USB打印机正忙,正常情况下应该稍后重试 */
// s=get_port_status( ); /*如果有必要,可以检查是什么原因导致打印机忙 */
}
else { /* 操作失败,正常情况下不会失败 */
clr_stall( endp_out_addr ); /* 清除打印机的数据接收端点,或者 soft_reset_print() */
soft_reset_print(); /* 打印机出现意外错误,软复位 */
tog_send = 0; /* 操作失败 */
}
/* 如果数据量较大,可以定期调用get_port_status()检查打印机状态 */
}
}
unsigned char get_port_status( ) { /* 查询打印机端口状态,返回状态码,如果为0FFH则说明操作失败 */
/* 返回状态码中: 位5(Paper Empty)为1说明无纸, 位4(Select)为1说明打印机联机, 位3(Not Error)为0说明打印机出错 */
toggle_send( 0 ); /* 下面通过控制传输获取打印机的状态, 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字节 */
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个字节 */
toggle_send( 1 ); /* STATUS阶段为DATA1 */
wr_usb_data( 0, buffer ); /* 发送0长度的数据说明控制传输成功 */
if ( issue_token( ( 0 << 4 ) | DEF_USB_PID_OUT )==USB_INT_SUCCESS ) return( buffer[0] ); /* 返回状态码 */
}
}
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, i;
status=get_descr(1); /* 获取设备描述符 */
if ( status==USB_INT_SUCCESS ) {
len=rd_usb_data( buffer ); /* 将获取的描述符数据从CH375中读出到单片机的RAM缓冲区中,返回描述符长度 */
for(i=0;i!=len;i++){
}
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规范 */
status=set_addr(3); /* 设置打印机的USB地址 */
if ( status==USB_INT_SUCCESS ) {
if ( status==USB_INT_SUCCESS ) { /* 操作成功则读出描述符并分析 */
endp_out_addr=0x81;
status=set_config( 0x01 ); /* 加载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为超时后的重试次数 */
// printf("set config ok!\n");
/* 如果单片机在打印机忙时并无事可做,建议设置位7为1,使CH375在收到NAK时自动重试直到操作成功或者失败 */
/* 如果希望单片机在打印机忙时能够做其它事,那么应该设置位7为0,使CH375在收到NAK时不重试,
所以在下面的USB通讯过程中,如果USB打印机正忙,issue_token等子程序将得到状态码USB_INT_RET_NAK */
}
}
}
}
return(status);
}
/*********************以下是时钟操作***********************************************/
/*********I2C延时***********/
void I2CWait(void)
{
_nop_();_nop_();_nop_();_nop_();
}
/********开启SD2200的I2C总线********/
bit I2CStart(void)
{
SDA=1;
SCL=1;
I2CWait();
if(!SDA)return false;//SDA线为低电平则总线忙,退出
SDA=0;
I2CWait();
while(SDA)return false;//SDA线为高电平则总线出错,退出
SCL=0;
I2CWait();
return true;
}
/********关闭SD2200的I2C总线*******/
void I2CStop(void)
{
SDA=0;
SCL=0;
I2CWait();
SCL=1;
I2CWait();
SDA=1;
}
/*********发送 ACK*********/
void I2CAck(void)
{
SDA=0;
SCL=0;
I2CWait();
SCL=1;
I2CWait();
SCL=0;
}
/*********发送NO ACK*********/
void I2CNoAck(void)
{
SDA=1;
SCL=0;
I2CWait();
SCL=1;
I2CWait();
SCL=0;
}
/*********读取ACK信号*********/
bit I2CWaitAck(void) //返回为:1=有ACK,0=无ACK
{
UCHAR errtime=255;
SCL=0;
SDA=1;
I2CWait();
SCL=1;
I2CWait();
while(SDA)
{
errtime--;
if(!errtime)
SCL=0;
return false;
}
SCL=0;
return true;
}
/************从SD2200发送一个字节*************/
void I2CSendByte(UCHAR demand,bit order) //order=1,H_L;order=0,L_H
{
UCHAR i=8; //order=1,从HI-->LO发送8bit数据
//order=0,从LO-->HI发送8bit数据
if(order)
{
while(i--)
{
SCL=0;
_nop_();
SDA=(bit)(demand&0x80);
demand<<=1;
I2CWait();
SCL=1;
I2CWait();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -