ENC28J60读操作
读操作要略比写操作复杂。写操作时每次总是从硬件发送缓冲区的起始地址开始操作,而读操作时需要不断修改接收缓冲区的读指针地址,该参数需要通过NextPacketPtr完成,该变量为长度为16的全局变量。读操作时,先通过寄存器查看是否存在以太网数据包,读EPKTCNT寄存器便可返回以太网数据包的个数;若存在以太网数据包则设定读指针的地址,执行读缓冲区操作,ENC28J60的以太网数据包中前两个字节为下一个以太网数据包的起始地址,立即保存该参数至NextPacketPtr全局变量中;以太网数据包中的后两个字节为该数据包的长度,该长度只从目标MAC地址开始的数据包的长度,进行处理时还应该舍弃最后的4字节CRC校验结果;最重要的事情便是通过读缓冲区操作码把len长度的以太网数据读出,读出的目标应为软件缓冲区,例如定义在程序中的rxtx_buf。最后根据NextPacketPtr移动读指针以便下次操作,并通过操作ECON2的ECON2_PKTDEC位递减了以太网数据包。
<font size="3">unsigned int enc28j60PacketReceive(unsigned int maxlen, unsigned char* packet)
{
unsigned int rxstat;
unsigned int len;
/* 是否收到以太网数据包 */
if( enc28j60Read(EPKTCNT) == 0 )
{
return(0);
}
/* 设置接收缓冲器读指针 */
enc28j60Write(ERDPTL, (NextPacketPtr));
enc28j60Write(ERDPTH, (NextPacketPtr)>>8);
/* 接收数据包结构示例 数据手册43页 */
/* 读下一个包的指针 */
NextPacketPtr = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
NextPacketPtr |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
/* 读包的长度 */
len = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
len |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
/* 去除CRC校验部分 */
len-= 4;
/* 读取接收状态 */
rxstat = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
rxstat |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0) << 8;
/* 限制检索的长度 */
if (len > maxlen-1)
{
len = maxlen-1;
}
/* 检查CRC和符号错误 */
/* ERXFCON.CRCEN是默认设置。通常我们不需要检查 */
if ((rxstat & 0x80)==0)
{
//无效的
len = 0;
}
else
{
/* 从接收缓冲器中复制数据包 */
enc28j60ReadBuffer(len, packet);
}
/* 移动接收缓冲区 读指针*/
enc28j60Write(ERXRDPTL, (NextPacketPtr));
enc28j60Write(ERXRDPTH, (NextPacketPtr)>>8);
/* 数据包递减 */
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
/* 返回长度 */
return(len);
}</font>
复制代码转载
|