📄 usbcore.c
字号:
//8位小端格式
const uint8 ManufacturerStringDescriptor[82]={
82, //该描述符的长度为82字节
0x03, //字符串描述符的类型编码为0x03
0x35, 0x75, //电
0x11, 0x81, //脑
0x08, 0x57, //圈
0x08, 0x57, //圈
0x84, 0x76, //的
0x55, 0x00, //U
0x53, 0x00, //S
0x42, 0x00, //B
0x13, 0x4e, //专
0x3a, 0x53, //区
0x20, 0x00, //
0x48, 0x00, //H
0x74, 0x00, //t
0x74, 0x00, //t
0x70, 0x00, //p
0x3a, 0x00, //:
0x2f, 0x00, ///
0x2f, 0x00, ///
0x67, 0x00, //g
0x72, 0x00, //r
0x6f, 0x00, //o
0x75, 0x00, //u
0x70, 0x00, //p
0x2e, 0x00, //.
0x65, 0x00, //e
0x64, 0x00, //d
0x6e, 0x00, //n
0x63, 0x00, //c
0x68, 0x00, //h
0x69, 0x00, //i
0x6e, 0x00, //n
0x61, 0x00, //a
0x2e, 0x00, //.
0x63, 0x00, //c
0x6f, 0x00, //o
0x6d, 0x00, //m
0x2f, 0x00, ///
0x39, 0x00, //9
0x33, 0x00, //3
0x2f, 0x00 ///
};
/////////////////////////厂商字符串结束/////////////////////////////
//字符串“21IC DIY U盘学习板 之USB转串口”的Unicode编码
//8位小端格式
const uint8 ProductStringDescriptor[46]={
46, //该描述符的长度为46字节
0x03, //字符串描述符的类型编码为0x03
0x32, 0x00, //2
0x31, 0x00, //1
0x49, 0x00, //I
0x43, 0x00, //C
0x20, 0x00, //
0x44, 0x00, //D
0x49, 0x00, //I
0x59, 0x00, //Y
0x20, 0x00, //
0x55, 0x00, //U
0xd8, 0x76, //盘
0x66, 0x5b, //学
0x60, 0x4e, //习
0x7f, 0x67, //板
0x20, 0x00, //
0x4b, 0x4e, //之
0x55, 0x00, //U
0x53, 0x00, //S
0x42, 0x00, //B
0x6c, 0x8f, //转
0x32, 0x4e, //串
0xe3, 0x53 //口
};
////////////////////////产品字符串结束////////////////////////////
//字符串“2009-03-10”的Unicode编码
//8位小端格式
const uint8 SerialNumberStringDescriptor[22]={
22, //该描述符的长度为22字节
0x03, //字符串描述符的类型编码为0x03
0x32, 0x00, //2
0x30, 0x00, //0
0x30, 0x00, //0
0x39, 0x00, //9
0x2d, 0x00, //-
0x30, 0x00, //0
0x33, 0x00, //3
0x2d, 0x00, //-
0x31, 0x00, //1
0x30, 0x00 //0
};
//////////////////////产品序列号字符串结束/////////////////////////
/********************************************************************
函数功能:总线挂起中断处理函数。
入口参数:无。
返 回:无。
备 注:无。
********************************************************************/
void UsbBusSuspend(void)
{
#ifdef DEBUG0
Prints("USB总线挂起。\r\n");
#endif
}
////////////////////////End of function//////////////////////////////
/********************************************************************
函数功能:总线复位中断处理函数。
入口参数:无。
返 回:无。
备 注:无。
********************************************************************/
void UsbBusReset(void)
{
#ifdef DEBUG0
Prints("USB总线复位。\r\n");
#endif
UsbChipResetEndpoint(); //复位端点
ConfigValue=0; //配置值初始化为0
UsbChipSetConfig(0); //设置芯片的配置值为0
Ep1InIsBusy=0; //复位后端点1输入缓冲区空闲。
Ep3InIsBusy=0; //复位后端点3输入缓冲区空闲。
}
////////////////////////End of function//////////////////////////////
/********************************************************************
函数功能:根据pData和SendLength将数据发送到端点0的函数。
入口参数:无。
返 回:无。
备 注:无。
********************************************************************/
void UsbEp0SendData(void)
{
//将数据写到端点中去准备发送
//写之前要先判断一下需要发送的数据是否比端点0
//最大长度大,如果超过端点大小,则一次只能发送
//最大包长的数据。端点0的最大包长在DeviceDescriptor[7]
if(SendLength>DeviceDescriptor[7])
{
//按最大包长度发送
UsbChipWriteEndpointBuffer(0,DeviceDescriptor[7],pSendData);
//发送后剩余字节数减少最大包长
SendLength-=DeviceDescriptor[7];
//发送一次后指针位置要调整
pSendData+= DeviceDescriptor[7];
}
else
{
if(SendLength!=0)
{
//不够最大包长,可以直接发送
UsbChipWriteEndpointBuffer(0,SendLength,pSendData);
//发送完毕后,SendLength长度变为0
SendLength=0;
}
else //如果要发送的数据包长度为0
{
if(NeedZeroPacket==1) //如果需要发送0长度数据
{
UsbChipWriteEndpointBuffer(0,0,pSendData); //发送0长度数据包
NeedZeroPacket=0; //清需要发送0长度数据包标志
}
}
}
}
////////////////////////End of function//////////////////////////////
/********************************************************************
函数功能:USB端点0数据过程数据处理函数。
入口参数:无。
返 回:无。
备 注:该函数用来处理0端点控制传输的数据或状态过程。
********************************************************************/
void UsbEp0DataOut(void)
{
//由于本程序中只有一个请求输出数据,所以可以直接使用if语句判断条件,
//如果有很多请求的话,使用if语句就不方便了,而应该使用switch语句散转。
if((bmRequestType==0x21)&&(bRequest==SET_LINE_CODING))
{
uint32 NewBitRate;
uint8 Length;
//读回7字节的LineCoding值
Length=UsbChipReadEndpointBuffer(0,7,LineCoding);
UsbChipClearBuffer(0); //清除缓冲区
if(Length==7) //如果长度正确
{
//从LineCoding计算设置的波特率
NewBitRate=LineCoding[3];
NewBitRate=(NewBitRate<<8)+LineCoding[2];
NewBitRate=(NewBitRate<<8)+LineCoding[1];
NewBitRate=(NewBitRate<<8)+LineCoding[0];
#ifdef DEBUG0
Prints("波特率设置为:");
PrintLongInt(NewBitRate);
Prints("bps\r\n");
#endif
//设置串口的波特率
NewBitRate=UartSetBitRate(NewBitRate);
//将LineCoding的值设置为实际的设置值
LineCoding[0]=NewBitRate&0xFF;
LineCoding[1]=(NewBitRate>>8)&0xFF;
LineCoding[2]=(NewBitRate>>16)&0xFF;
LineCoding[3]=(NewBitRate>>24)&0xFF;
//设置串口的停止位
LineCoding[4]=UartSetStopBits(LineCoding[4]);
LineCoding[5]=0x00; //只支持无校验
LineCoding[6]=UartSetDataBits(LineCoding[6]);
}
//返回0长度的状态数据包。
UsbChipWriteEndpointBuffer(0,1,0);
}
else //其它请求的数据过程或者状态过程
{
UsbChipReadEndpointBuffer(0,16,Buffer);
UsbChipClearBuffer(0);
}
}
////////////////////////End of function//////////////////////////////
/********************************************************************
函数功能:端点0输出中断处理函数。
入口参数:无。
返 回:无。
备 注:无。
********************************************************************/
void UsbEp0Out(void)
{
int32 L;
#ifdef DEBUG0
Prints("USB端点0输出中断。\r\n");
#endif
//判断是否是建立包
if(UsbChipIsSetup(0))
{
L=UsbChipReadEndpointBuffer(0,16,Buffer); //读建立过程数据
UsbChipAcknowledgeSetup(0); //应答建立包
UsbChipClearBuffer(0); //清缓冲区
if(L!=8) //不是8字节的标准请求,直接返回
return;
//将缓冲数据填到设备请求的各字段中
bmRequestType=Buffer[0];
bRequest=Buffer[1];
wValue=Buffer[2]+(((uint16)Buffer[3])<<8);
wIndex=Buffer[4]+(((uint16)Buffer[5])<<8);
wLength=Buffer[6]+(((uint16)Buffer[7])<<8);
//下面的代码判断具体的请求,并根据不同的请求进行相关操作
//如果D7位为1,则说明是输入请求
if((bmRequestType&0x80)==0x80)
{
//根据bmRequestType的D6~5位散转,D6~5位表示请求的类型
//0为标准请求,1为类请求,2为厂商请求。
switch((bmRequestType>>5)&0x03)
{
case 0: //标准请求
#ifdef DEBUG0
Prints("USB标准输入请求:");
#endif
//USB协议定义了几个标准输入请求,我们实现这些标准请求即可
//请求的代码在bRequest中,对不同的请求代码进行散转
//事实上,我们还需要对接收者进行散转,因为不同的请求接收者
//是不一样的。接收者在bmRequestType的D4~D0位中定义。
//我们这里为了简化操作,有些就省略了对接收者的判断。
//例如获取描述符的请求,只根据描述符的类型来区别。
switch(bRequest)
{
case GET_CONFIGURATION: //获取配置
#ifdef DEBUG0
Prints("获取配置。\r\n");
#endif
break;
case GET_DESCRIPTOR: //获取描述符
#ifdef DEBUG0
Prints("获取描述符——");
#endif
//对描述符类型进行散转,对于全速设备,
//标准请求只支持发送到设备的设备、配置、字符串三种描述符
switch((wValue>>8)&0xFF)
{
case DEVICE_DESCRIPTOR: //设备描述符
#ifdef DEBUG0
Prints("设备描述符。\r\n");
#endif
pSendData=(uint8)DeviceDescriptor; //需要发送的数据
//判断请求的字节数是否比实际需要发送的字节数多
//这里请求的是设备描述符,因此数据长度就是
//DeviceDescriptor[0]。如果请求的比实际的长,
//那么只返回实际长度的数据
if(wLength>DeviceDescriptor[0])
{
SendLength=DeviceDescriptor[0];
if(SendLength%DeviceDescriptor[7]==0) //并且刚好是整数个数据包时
{
NeedZeroPacket=1; //需要返回0长度的数据包
}
}
else
{
SendLength=wLength;
}
//将数据通过EP0返回
UsbEp0SendData();
break;
case CONFIGURATION_DESCRIPTOR: //配置描述符
#ifdef DEBUG0
Prints("配置描述符。\r\n");
#endif
pSendData=(uint8 *)ConfigurationDescriptor; //需要发送的数据为配置描述符
//判断请求的字节数是否比实际需要发送的字节数多
//这里请求的是配置描述符集合,因此数据长度就是
//ConfigurationDescriptor[3]*256+ConfigurationDescriptor[2]。
//如果请求的比实际的长,那么只返回实际长度的数据
SendLength=ConfigurationDescriptor[3];
SendLength=SendLength*256+ConfigurationDescriptor[2];
if(wLength>SendLength)
{
if(SendLength%DeviceDescriptor[7]==0) //并且刚好是整数个数据包时
{
NeedZeroPacket=1; //需要返回0长度的数据包
}
}
else
{
SendLength=wLength;
}
//将数据通过EP0返回
UsbEp0SendData();
break;
case STRING_DESCRIPTOR: //字符串描述符
#ifdef DEBUG0
Prints("字符串描述符");
#endif
switch(wValue&0xFF) //根据wValue的低字节(索引值)散转
{
case 0: //获取语言ID
#ifdef DEBUG0
Prints("(语言ID)。\r\n");
#endif
pSendData=(uint8 *)LanguageId;
SendLength=LanguageId[0];
break;
case 1: //厂商字符串的索引值为1,所以这里为厂商字符串
#ifdef DEBUG0
Prints("(厂商描述)。\r\n");
#endif
pSendData=(uint8 *)ManufacturerStringDescriptor;
SendLength=ManufacturerStringDescriptor[0];
break;
case 2: //产品字符串的索引值为2,所以这里为产品字符串
#ifdef DEBUG0
Prints("(产品描述)。\r\n");
#endif
pSendData=(uint8 *)ProductStringDescriptor;
SendLength=ProductStringDescriptor[0];
break;
case 3: //产品序列号的索引值为3,所以这里为序列号
#ifdef DEBUG0
Prints("(产品序列号)。\r\n");
#endif
pSendData=(uint8 *)SerialNumberStringDescriptor;
SendLength=SerialNumberStringDescriptor[0];
break;
default :
#ifdef DEBUG0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -