一、前言
书包里面背着CH572的板子,一直想玩玩USB,一直没时间,最近试了一下(对USB并不熟悉),这里选个简单的HID程序来测测
二、准备
- 硬件,CH554 EVK 我这里焊了CH552
三、程序
-
List item准备一下测试工具
工具下载链接 ST论坛分享的工具
-
测试程序地址 CH552\EVT\EXAM\USB\Device\CompatibilityHID.C
-
程序就不贴了,记录一些点(就算不太懂HID的流程,也OK)
描述符
/*设备描述符*/
UINT8C DevDesc[18] = {0x12,0x01,0x10,0x01,0x00,0x00,0x00,THIS_ENDP0_SIZE,
0x31,0x51,0x07,0x20,0x02,0x01,0x00,0x00,
0x00,0x01
};
UINT8C CfgDesc[41] =
{
0x09,0x02,0x29,0x00,0x01,0x01,0x04,0xA0,0x23, //配置描述符
0x09,0x04,0x00,0x00,0x02,0x03,0x00,0x00,0x05, //接口描述符
0x09,0x21,0x00,0x01,0x00,0x01,0x22,0x22,0x00, //HID类描述符
#ifdef Fullspeed
0x07,0x05,0x82,0x03,THIS_ENDP0_SIZE,0x00,0x01, //端点描述符(全速间隔时间改成1ms)
0x07,0x05,0x02,0x03,THIS_ENDP0_SIZE,0x00,0x01, //端点描述符
#else
0x07,0x05,0x82,0x03,THIS_ENDP0_SIZE,0x00,0x0A, //端点描述符(低速间隔时间最小10ms)
0x07,0x05,0x02,0x03,THIS_ENDP0_SIZE,0x00,0x0A, //端点描述符
#endif
};
对应就是VID 和 PID
端点描述符 ,这里用的都是端点2 BIT0代表端点号,BIT7代表IN OUT,这里INT和OUT都用的端点2
数据的发送,是通过DMA数据拷贝完成的
这里的 UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK; 意思就是要回复ACK的意思,先用 &~MASK 让用到的位值清0,再给对应的位域值
/*******************************************************************************
* Function Name : Enp2BlukIn()
* Description : USB设备模式端点2的批量上传
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void Enp2BlukIn( )
{
memcpy( Ep2Buffer+MAX_PACKET_SIZE, UserEp2Buf, sizeof(UserEp2Buf)); //加载上传数据
UEP2_T_LEN = THIS_ENDP0_SIZE; //上传最大包长度
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK; //有数据时上传数据并应答ACK
}
这里看看main,先将UserEp2Buf数据给到0-63,之后Ep2InKey按下了(P15),就上报64字节数据
main()
{
UINT8 i;
CfgFsys( ); //CH559时钟选择配置
mDelaymS(5); //修改主频等待内部晶振稳定,必加
mInitSTDIO( ); //串口0初始化
#ifdef DE_PRINTF
printf("start ...\n");
#endif
for(i=0; i<64; i++) //准备演示数据
{
UserEp2Buf[i] = i;
}
USBDeviceInit(); //USB设备模式初始化
EA = 1; //允许单片机中断
UEP1_T_LEN = 0; //预使用发送长度一定要清空
UEP2_T_LEN = 0; //预使用发送长度一定要清空
FLAG = 0;
Ready = 0;
while(1)
{
if(Ready && (Ep2InKey==0))
{
while( Endp2Busy ); //如果忙(上一包数据没有传上去),则等待。
Endp2Busy = 1; //设置为忙状态
Enp2BlukIn( );
mDelaymS( 100 );
}
mDelaymS( 10 ); //模拟单片机做其它事
}
}
P1.5接地后,上位机收到的数据:
收数据部分,这里 UIS_TOKEN_OUT | 2 代表是收到下发的数据(对于主机 OUT是给从机),并且是端点2
这里令牌PID用于标识是 OUT 还是 IN 包,最后 0-3对应的是端点号
这里收到数据后取反,然后发回到上位机
void DeviceInterrupt( void ) interrupt INT_NO_USB using 1 //USB中断服务程序,使用寄存器组1
{
UINT8 len,i;
if(UIF_TRANSFER) //USB传输完成标志
{
switch (USB_INT_ST & (MASK_UIS_TOKEN | MASK_UIS_ENDP))
{
case UIS_TOKEN_IN | 2: //endpoint 2# 端点批量上传
UEP2_T_LEN = 0; //预使用发送长度一定要清空
// UEP1_CTRL ^= bUEP_T_TOG; //如果不设置自动翻转则需要手动翻转
Endp2Busy = 0 ;
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK; //默认应答NAK
break;
case UIS_TOKEN_OUT | 2: //endpoint 2# 端点批量下传
if ( U_TOG_OK ) // 不同步的数据包将丢弃
{
len = USB_RX_LEN; //接收数据长度,数据从Ep2Buffer首地址开始存放
for ( i = 0; i < len; i ++ )
{
Ep2Buffer[MAX_PACKET_SIZE+i] = Ep2Buffer[i] ^ 0xFF; // OUT数据取反到IN由计算机验证
}
UEP2_T_LEN = len;
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK; // 允许上传
}
break;
发送数据测试,上位机收到返回的数据: