开发板 :51单片机 + pdiusbd12 芯片
1,数据会存储在缓冲区中,那么就要实现读取缓冲区
1),读最后处理状态寄存器
命令40 45h
数据读1字节
读最后处理状态寄存器命令后跟一个数据返回端点最后处理的状态。该命令同时复位中断寄存器中的
相应位并将状态清零表示已经读取。由于它保留了每次处理的记录,所以该命令在以调试为目的时很有用。
在每次新的处理之后会将原来的状态信息覆盖。
数据接收/发送成功 1表示数据已经成功地接收或发送。
错误代码 见下表
建立信息包 1表示收到的是建立(setup)过程的数据包。
数据0/1包 1表示收到的是DATA1数据包,0表示收到的是DATA0数据包。
前一状态未读 1表示在前一状态没有读取,前面的状态已经被覆盖。

点击(此处)折叠或打开
-
uint8_t read_last_status(uint8_t endpoint)
-
{
-
uint8_t ret = 0;
-
-
write_com(0x40 + endpoint);
-
ret = read_byte();
-
-
return ret;
- }
2)选择端点
选择端点
命令00 05h
数据可选读1字节
选择端点命令将内部指针初始化到选择的缓冲区起始位置。可选的,该命令可跟一个返回的读出字节。

满/空1表示缓冲区已满0表示缓冲区为空。
停止1表示选择的端点处于停止状态。
点击(此处)折叠或打开
-
uint8_t select_endpoint(uint8_t endpoint)
-
{
-
uint8_t ret = 0;
-
-
write_com( 0x00 + endpoint);
-
ret = read_byte();
-
-
return ret;
- }
3)查看端点的状态
选择端点
命令00 05h
数据可选读1字节

点击(此处)折叠或打开
-
uint8_t read_endpoint_status(uint8_t endpoint)
-
{
-
uint8_t ret = 0;
-
-
write_com(0x80 + endpoint);
-
ret = read_byte();
-
-
return ret;
- }
4)读取缓冲区
读缓冲区
命令F0h
数据读多个字节最大130
读缓冲区命令后,返回一系列从选择的端点数据缓冲区读出的数据。每读一个字节,内部缓冲区指针
自动加一。 读缓冲区命令不会将缓冲区指针复位到缓冲区起始端。这意味着可被其它的命令所中断(选择端点命令除外)。
缓冲区数据结构如下
字节1 保留可为任意值
字节2 数据字节的数目/长度
字节3 数据字节1
字节4 数据字节2
……
头两个字节在DMA读操作中可跳过,因此第一个读出的字节是数据字节1 。第二个读出的是数据字
节2 ,等等PDIUSBD12可通过USB信息包的EOP终止来决定包的最后一个字节。
点击(此处)折叠或打开
-
int32_t read_endpoint_buffer(uint8_t endpoint,uint8_t *buffer,uint8_t len)
-
{
-
int32_t ret = 0;
-
uint8_t read_len = 0;
-
int32_t index = 0;
-
-
read_last_status(endpoint); // 复位中断寄存器中的相应位并将状态清零表示已经读取
-
-
/*当一个信息包完全接收之后内部端点缓冲区满标志置位所有后续的包将被返回的NAK拒绝当
-
微控制器已读取数据它应当通过清缓冲区命令来释放缓冲区 当缓冲区清空之后新的信息包就可被接
-
受了*/
-
if(!(select_endpoint(endpoint)&0x01)) // 查看该端点的缓冲区是否满了
-
{// 信息包没有完全接收
-
return -1;
-
}
-
-
// 判断端点的输入输出缓冲区是否都满了
-
if((read_endpoint_status(endpoint)&0x60) != 0x60)
-
{// 没满
-
read_last_status(endpoint); // 复位中断寄存器中的相应位并将状态清零表示已经读取
-
}
-
-
-
write_com(READ_BUFFER);
-
read_byte(); // 忽略第一个读到的字节
-
read_len = read_byte(); // 数据字节的数目/长度
-
if(read_len > len)
-
{
-
read_len = len;
-
}
-
for(index = 0; index < read_len; index++)
-
{
-
buffer[index] = read_byte();
-
}
-
-
return ret;
- }
2,读取缓冲区数据之后的操作
当一个信息包完全接收之后,内部端点缓冲区满标志置位。所有后续的包将被返回的NAK拒绝。当微控制器已读取数据,它应当通过清缓冲区命令来释放缓冲区 。当缓冲区清空之后新的信息包就可被接受了。因此在读取数据之后,要将端点缓冲区清空。
然而对于 pidusbd12 的控制端点,接收到建立包后必须要使用一个特殊的命令,才可以使 Clear buffer 和 Validate Buffer 命令生效,这个命令就是 Acknowledge Setup。这样做的目的是为了保证控制传输建立过程的数据不会丢失,并且接着也不会返回错误的数据,只有等到处理完了这个建立的过程,并发送 Acknowledge Setup 命令之后,才能使用 Clear Buffer 命令和 Validate Buffer 命令。
因此程序首先要判断一下,收到的这个数据包是否为建立过程的数据包,如果是,则要在发送Clear Buffer 命令之前,先发送 Acknowledge Setup 命令。 Acknowledge Setup 命令对控制输出和输入端点都要发送,因为 Clear Buffer 命令式针对输出端点的,而 Validate Buffer 命令式针对输入端点的。
通常是先读取端点缓冲区后再来清除端点缓冲,因此这里的清除端点缓冲区函数并没有在选择端点,避免多余的操作。在调用该函数之前,一定要确保当前所选择的端点是需要清除的目标端点。例如:下面的Acknowledge Setup() 函数就是先对输入端点 0 操作,然后再对输出端点0操作,以保证在后面使用清除缓冲区时当前的目标端点是输出端点0.
1)应答建立(Acknowledge setup)
命令F1h
数据无
一个SETUP信息包的到达将IN缓冲区刷新并禁止对IN和OUT端点的两条命令:使缓冲区有效和清
零缓冲区命令。微控制器需要通过应答建立命令重新使能这些命令。这确保了最后的SETUP包留在缓冲区内,
并且在微控制器看到SETUP包并应答之前,不会有任何包发回主机。微控制器必须将应答建立命令发送到IN和OUT端点。
点击(此处)折叠或打开
-
int32_t ack_setup(uint8_t endpoint)
-
{
-
int32_t ret = 0;
-
-
select_endpoint(endpoint);
-
write_com(ACK_SETUP);
-
-
return ret;
- }
2)清空缓冲区
命令F2h
数据无
当一个信息包完全接收之后,内部端点缓冲区满标志置位。所有后续的包将被返回的NAK拒绝。
当微控制器已读取数据,它应当通过清缓冲区命令来释放缓冲区 。当缓冲区清空之后新的信息包就可被接受了。
点击(此处)折叠或打开
-
int32_t clear_buffer()
-
{
-
int32_t ret = 0;
-
-
write_com(CLEAR_BUFFER);
-
-
return ret;
- }
3,运行结果:



4,测试源码:
mouse.zip5,疑惑:从以上运行结果图中可以看出,已经成功接收了主机发送过来的8个字节数据,在第一次接收到数据之后,会停顿一段时间。这段时间主机一直在请求输入。但是程序程序目前并没有发挥数据,所以pdiusbd12芯片一直在返回 NAK,及没有数据准备好。
那么这8个字节的数据到底是干什么用的呢?主机又在等待什么数据返回呢?
其实这8个字节的数据就是 USB 协议所规定的标准请求,主机在试图获取描述符。
欲知更多内容,请看下回分解。。。