📄 ch374_hid.c
字号:
/* 设定全速USB设备运行环境 */
void HostSetFullSpeed( void )
{
Write374Byte( REG_USB_SETUP, Read374Byte( REG_USB_SETUP ) & ~ BIT_SETP_USB_SPEED | BIT_SETP_AUTO_SOF ); // 全速且发SOF
mDelaymS( 1 );
}
/* 设定低速USB设备运行环境 */
void HostSetLowSpeed( void )
{
Write374Byte( REG_USB_SETUP, Read374Byte( REG_USB_SETUP ) | BIT_SETP_USB_SPEED | BIT_SETP_AUTO_SOF ); // 低速且发SOF
mDelaymS( 1 );
}
/* 初始化USB主机 */
void Init374Host( void )
{
Write374Byte( REG_USB_SETUP, 0x00 );
SetHostUsbAddr( 0x00 );
Write374Byte( REG_USB_H_CTRL, 0x00 );
Write374Byte( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_INTER_FLAG ); // 清所有中断标志
// Write374Byte( REG_INTER_EN, BIT_IE_TRANSFER ); // 允许传输完成中断,因为本程序使用查询方式检测USB设备插拔,所以无需USB设备检测中断
Write374Byte( REG_INTER_EN, BIT_IE_TRANSFER | BIT_IE_DEV_DETECT ); // 允许传输完成中断和USB设备检测中断
Write374Byte( REG_SYS_CTRL, BIT_CTRL_OE_POLAR ); // 对于CH374T或者UEN引脚悬空的CH374S必须置BIT_CTRL_OE_POLAR为1
HostSetBusFree( ); // USB总线空闲
}
/* 获取设备描述符 */
UINT8 GetDeviceDescr( PUINT8 buf )
{
UINT8 s, len;
s = HostCtrlTransfer374( SetupGetDevDescr, buf, &len ); // 执行控制传输
if ( s == USB_INT_SUCCESS ) {
UsbDevEndpSize = ( (PUSB_DEV_DESCR)buf ) -> bMaxPacketSize0; // 端点0最大包长度,这是简化处理,正常应该先获取前8字节后立即更新UsbDevEndpSize再继续
if ( len < ( (PUSB_SETUP_REQ)SetupGetDevDescr ) -> wLengthL ) s = USB_INT_BUF_OVER; // 描述符长度错误
}
return( s );
}
/* 获取配置描述符 */
UINT8 GetConfigDescr( PUINT8 buf )
{
UINT8 s, len,i,c,j;
UINT8 BufLogDescr[ sizeof( SetupGetCfgDescr ) ] ;
s = HostCtrlTransfer374( SetupGetCfgDescr, buf, &len ); // 执行控制传输
if ( s == USB_INT_SUCCESS )
{
for(i=0;i!=len;i++)
printf("%02x ",(unsigned short)buf[i]);
printf("\n");
if ( len < ( (PUSB_SETUP_REQ)SetupGetCfgDescr ) -> wLengthL ) s = USB_INT_BUF_OVER; // 返回长度错误
else
{
memcpy ( BufLogDescr, SetupGetCfgDescr, sizeof( SetupGetCfgDescr ) );
( (PUSB_SETUP_REQ)BufLogDescr ) -> wLengthL = ( (PUSB_CFG_DESCR)buf ) -> wTotalLengthL; // 完整配置描述符的总长度
s = HostCtrlTransfer374( BufLogDescr, buf, &len ); // 执行控制传输
if ( s == USB_INT_SUCCESS )
{
//简单分析配置描述符,获取端点地址,这里只处理一个端点的情况
for ( i = 0; i < ( (PUSB_CFG_DESCR)buf ) -> wTotalLengthL; i ++ ) printf( "%02X ", (UINT16)( buf[i] ) ); //配置描述符
printf( "\n" );
for(i=0;i<( (PUSB_CFG_DESCR)buf ) -> wTotalLengthL;i++)
{
if((buf[i]==0x09)&&(buf[i+1]==0x21)&&(buf[i+6]==0x22)) hid_des_leng=buf[i+7]; //获取报告描述符的长度
}
printf("hid_des_leng=%02x\n",(unsigned short)hid_des_leng);
endp_out_addr=endp_in_addr=0;endp_num=0;
for(i=0;i<( (PUSB_CFG_DESCR)buf ) -> wTotalLengthL;i++)
{
if((buf[i]==0x09)&&(buf[i+1]==0x04)&&(buf[i+5]==0x03)&&(buf[i+7]==0x01)||(buf[i+7]==0x02)) //接口描述符为HID的鼠标、键盘
{
for(j=0;j<( (PUSB_CFG_DESCR)buf ) -> wTotalLengthL-i;j++)
{
if((buf[i+j]==0x07)&&(buf[i+j+1]==0x05)&&(buf[i+j+3]==0x03)) c=buf[i+j+2]; //判断是否为中断端点
if ( c&0x80 ) endp_in_addr=c&0x0f; // IN端点的地址
else // OUT端点
{
endp_out_addr=c&0x0f;
}
if((endp_out_addr!=0)||(endp_in_addr!=0)) break;
}
}
if((endp_out_addr!=0)||(endp_in_addr!=0)) break;
}
printf("endp_in_addr=%02x\n",(unsigned short)endp_in_addr);
printf("endp_out_addr=%02x\n",(unsigned short)endp_out_addr);
}
}
}
return( s );
}
/* 设置USB设备地址 */
UINT8 SetUsbAddress( UINT8 addr )
{
UINT8 s;
UINT8 BufSetAddr[ sizeof( SetupSetUsbAddr ) ] ;
memcpy ( BufSetAddr, SetupSetUsbAddr, sizeof( SetupSetUsbAddr ) );
( (PUSB_SETUP_REQ)BufSetAddr ) -> wValueL = addr; // USB设备地址
s = HostCtrlTransfer374( BufSetAddr, NULL, NULL ); // 执行控制传输
if ( s == USB_INT_SUCCESS ) {
SetHostUsbAddr( addr ); // 设置USB主机当前操作的USB设备地址
}
mDelaymS( 3 ); // 等待USB设备完成操作
return( s );
}
/* 设置USB设备配置 */
UINT8 SetUsbConfig( UINT8 cfg )
{
UINT8 BufSetCfg[ sizeof( SetupSetUsbConfig ) ] ;
memcpy ( BufSetCfg, SetupSetUsbConfig, sizeof( SetupSetUsbConfig ) );
( (PUSB_SETUP_REQ)BufSetCfg ) -> wValueL = cfg; // USB设备配置
return( HostCtrlTransfer374( BufSetCfg, NULL, NULL ) ); // 执行控制传输
}
/* 设置Idle */
UINT8 Set_Idle( )
{
UINT8 s;
s=HostCtrlTransfer374(SetupSetidle,NULL,NULL);
return s;
}
/* 获取报表描述符 */
unsigned char Get_Hid_Des(unsigned char *p)//获取报表描述符
{
unsigned char s;
// leng=SetupGetHidDes[0x06]-0x40;//报表描述符的长度在发送数据长度的基础上减去0X40
unsigned char buffer[8];
memcpy ( buffer, SetupGetHidDes, 8 );
buffer[0x06] = hid_des_leng+0x40;
s=HostCtrlTransfer374(buffer,p,&buffer[0x06]);
return s;
}
/* 设置报表 */
UINT8 Set_Report(unsigned char *p)
{
UINT8 s,l=1;
s=HostCtrlTransfer374(SetupSetReport,p,&l); //实际的数据可以写别的数据,这个你可以用计算机抓下数据在发下去
return s;
}
/* 为printf和getkey输入输出初始化串口 */
void mInitSTDIO( )
{
SCON = 0x50;
PCON = 0x80;
TMOD = 0x20;
TH1 = 0xf3; //24MHZ, 9600
TR1 = 1;
TI = 1;
}
int main( void )
{
UINT8 i, s,close_bit_flag=0;
UINT8 idata buf[80]; //由于报告描述符大小不定,缓冲区的大小最好定义大些
// P1&=0xF8; // 如果在U盘文件读写模块上试用本程序必须加上本行
AUXR |= 0x02;
mDelaymS( 50 ); // 等待CH374复位完成
CH374_PORT_INIT( ); // CH374接口初始化
mInitSTDIO( ); // 为了让计算机通过串口监控演示过程
for(i=0;i!=64;i++)
{
s=Read374Byte(i);
printf("%02x ",(unsigned short)s);
}
printf("\n");
printf( "Start CH374 Host\n" );
Init374Host( ); // 初始化USB主机
while ( 1 )
{
HostSetBusFree( ); // 设定USB主机空闲
while ( 1 )
{
if ( Query374Interrupt( ) ) HostDetectInterrupt( ); // 如果有USB主机中断则处理
if ( Query374DeviceIn( ) ) break; // 有USB设备
}
mDelaymS( 250 ); // 由于USB设备刚插入尚未稳定,故等待USB设备数百毫秒,消除插拔抖动
if ( Query374Interrupt( ) ) HostDetectInterrupt( ); // 如果有USB主机中断则处理
printf( "Reset Device\n" );
HostSetBusReset( ); // USB总线复位
for ( i = 0; i < 100; i ++ ) // 等待USB设备复位后重新连接
{
if ( Query374DeviceIn( ) ) break; // 有USB设备
mDelaymS( 1 );
}
if ( Query374Interrupt( ) ) HostDetectInterrupt( ); // 如果有USB主机中断则处理
if ( Query374DeviceIn( ) ) // 有USB设备
{
if ( Query374DevFullSpeed( ) )
{
printf( "Start Full-Speed Device\n" );
HostSetFullSpeed( ); // 检测到全速USB设备
}
else
{
printf( "Start Low-Speed Device\n" );
HostSetLowSpeed( ); // 检测到低速USB设备
LOW_SPEED_BIT=1;
}
}
else
{
continue; // 设备已经断开,继续等待
}
mDelaymS( 50 );
close_bit_flag=0;
printf( "GetDeviceDescr: " );
s = GetDeviceDescr( buf ); // 获取设备描述符
printf("device_status=%02x \n",(unsigned short)s);
if ( s != USB_INT_SUCCESS )
{
goto WaitDeviceOut; // 终止操作,等待USB设备拔出
}
for ( i = 0; i < ( (PUSB_SETUP_REQ)SetupGetDevDescr ) -> wLengthL; i ++ ) printf( "%02X ", (UINT16)( buf[i] ) );
printf( "\n" );
s = SetUsbAddress( 0x02 ); // 设置USB设备地址
printf("address_status=%02x\n",(unsigned short)s);
if ( s != USB_INT_SUCCESS )
{
goto WaitDeviceOut; // 终止操作,等待USB设备拔出
}
s = GetConfigDescr( buf ); // 获取配置描述符
printf("config_status=%02x\n",(unsigned short)s);
if ( s != USB_INT_SUCCESS )
{
goto WaitDeviceOut; // 终止操作,等待USB设备拔出
}
// 分析配置描述符,获取端点数据/各端点地址/各端点大小等,更新变量endp_addr和endp_size等
s = SetUsbConfig( ( (PUSB_CFG_DESCR)buf ) -> bConfigurationValue ); // 设置USB设备配置
if ( s != USB_INT_SUCCESS )
{
// printf( "ERROR = %02X\n", (UINT16)s );
goto WaitDeviceOut; // 终止操作,等待USB设备拔出
}
else printf( "SetUsbConfig_success\n" );
//-------------------------以下进行HID类的简单操作-----------------------------------------------------------
printf("Set_Idle\n");
s=Set_Idle( ); //设置IDLE,这个步骤是按照HID类的协议来做的
if(s!=USB_INT_SUCCESS)
{
printf("Set_Idle_Err=%02x\n",(unsigned short)s);
if(s&0x0f==USB_INT_RET_STALL) goto next_operate1; //返回STALL可能本身不支持
}
else printf("Set_idle success\n");
next_operate1:
printf("Get_Hid_Des\n");
s=Get_Hid_Des(buf); // 获取报表描述符描述符
if(s==USB_INT_SUCCESS)
{
printf("HID_Desc: ");
for(i=0;i!=hid_des_leng;i++) printf("%02x ",(unsigned short)buf[i]);
printf("\n");
}
else
{
goto WaitDeviceOut; //出错退出
}
printf("Set_Report \n"); //对于键盘发Set_Report来点亮灯,对于鼠标则不需要这一步
buf[0]=0x01;
s=Set_Report(buf); //设置报表
if(s==USB_INT_SUCCESS)
{
printf("Set_Report success\n");
}
else
{
printf("Set_Report Err=%02x\n",(unsigned short)s); //设置报告出错
if(s&0x0f==USB_INT_RET_STALL) goto next_operate2; //返回STALL可能本身不支持
}
next_operate2:
// 下面开始读取数据 ( 实际在读取数据的时候,要先发送中断端点的令牌来读取数据,接着才能获取到数据 )
tog1=FALSE; //开始取DATA0
while(1)
{
s=Interrupt_Data_Trans(buf);
// printf("s:%x \n",(unsigned short)s);
if(s==USB_INT_SUCCESS)
{
for(i=0;i!=8;i++) printf("%02x ",(unsigned short)buf[i]);
printf("\n");
}
else if(s==USB_INT_DISCONNECT) // 这个是为了知道设备拔出产生的中断状态
{
close_bit_flag=1;
break;
}
}
WaitDeviceOut: // 等待USB设备拔出
printf( "Wait Device Out\n" );
if(close_bit_flag==0){
while ( 1 )
{
if ( Query374Interrupt( ) ) HostDetectInterrupt( ); // 如果有USB主机中断则处理
if ( Query374DeviceIn( ) == FALSE ) break; // 没有USB设备
}
}
mDelaymS( 100 ); // 等待设备完全断开,消除插拔抖动
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -