热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

STM32(三)ENC28J60以太网(二)

3寄存器操作实现ENC28j60的寄存器操作分为222部分,分别为写寄存器和读寄存器部分,读缓冲区和写缓冲区部分,写PHY寄存器和读PH

3 寄存器操作实现

ENC28j60的寄存器操作分为2+2+2部分,分别为写寄存器和读寄存器部分,读缓冲区和写缓冲区部分,写PHY寄存器和读PHY寄存器部分。

3.1 读写寄存器

读或写寄存器的函数如下:

unsigned char enc28j60Read(unsigned char address)
{/* 设定寄存器地址区域 */enc28j60SetBank(address);/* 读取寄存器值 发送读寄存器命令和地址 */return enc28j60ReadOp(ENC28J60_READ_CTRL_REG, address);
}
void enc28j60Write(unsigned char address, unsigned char data)
{/* 设定寄存器地址区域 */enc28j60SetBank(address);/* 写寄存器值 发送写寄存器命令和地址 */enc28j60WriteOp(ENC28J60_WRITE_CTRL_REG, address, data);
}

读写寄存器的分为两步,第一步为选定寄存器的BANK编号,第二步使用写命令或读命令,操作指定地址的寄存器。在ENC28J60中,由ECON1中的低两位(BIT1-BIT1)保存BANK编号,ECON1是比较特殊的控制寄存器, 4个BANK均具有该寄存器且该寄存器的地址相同。Enc28j60Bank为全局变量,用于保存当前的BANK编号,如果两次操作控制寄存器在同一个BANK时,该变量保持不变,若两次操作的控制寄存器位于不同的BANK,那么BANK的值会变为新的BANK编号。

void enc28j60SetBank(unsigned char address)
{/* 计算本次寄存器地址在存取区域的位置 */if((address & BANK_MASK) != Enc28j60Bank){/* 清除ECON1的BSEL1 BSEL0 详见数据手册15页 */enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0));/* 请注意寄存器地址的宏定义,bit6 bit5代码寄存器存储区域位置 */enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5);/* 重新确定当前寄存器存储区域 */Enc28j60Bank = (address & BANK_MASK);}
}unsigned char enc28j60ReadOp(unsigned char op, unsigned char address)
{unsigned char dat = 0;/* CS拉低 使能ENC28J60 */ENC28J60_CSL();/* 操作码和地址 */dat = op | (address & ADDR_MASK);/* 通过SPI写数据*/spi_sendbyte(dat);/* 通过SPI读出数据 */dat = spi_sendbyte(0xFF);/* 如果是MAC和MII寄存器,第一个读取的字节无效,该信息包含在地址的最高位 */if(address & 0x80){/* 再次通过SPI读取数据 */dat = spi_sendbyte(0xFF);}/* CS拉高 禁止ENC28J60 */ENC28J60_CSH();/* 返回数据 */return dat;
}

读控制寄存器实际上就是严格遵守数据手册的操作要求。由于读MAC和MII寄存器时,第一个接收到的字节为无效字节,第二个字节才为有效字节。程序通过寄存器地址的最高位来判断是否为MAC或MII寄存器。写寄存器函数较为简单,第一次字节包括操作码和寄存器地址,第二个字节为数据。在这两个函数中参数op为ENC28J60的指令,或称之为操作码,该指令占据SPI首字节的前3位,参数address为寄存器地址,参数data为寄存器的具体值。
ENC28J60_CSL()和ENC28J60_CSH()为操作CS端口的操作宏,而spi_sendbyte()可通过SPI发送一个字节。修改这些函数即可在其他平台上操作ENC28J60。不过请特别注意,在使用其他开发板时由于SPI总线上可能挂载多个设备,单独使用ENC28J60时需要把其他设备的CS端口拉高,或安装一个上拉电阻。

unsigned char enc28j60ReadOp(unsigned char op, unsigned char address)
{unsigned char dat = 0;/* CS拉低 使能ENC28J60 */ENC28J60_CSL();/* 操作码和地址 */dat = op | (address & ADDR_MASK);/* 通过SPI写数据*/spi_sendbyte(dat);/* 通过SPI读出数据 */dat = spi_sendbyte(0xFF);/* 如果是MAC和MII寄存器,第一个读取的字节无效,该信息包含在地址的最高位 */if(address & 0x80){/* 再次通过SPI读取数据 */dat = spi_sendbyte(0xFF);}/* CS拉高 禁止ENC28J60 */ENC28J60_CSH();/* 返回数据 */return dat;
}
void enc28j60WriteOp(unsigned char op, unsigned char address, unsigned char data)
{unsigned char dat = 0;/* 使能ENC28J60 */ ENC28J60_CSL(); /* 通过SPI发送 操作码和寄存器地址 */ dat = op | (address & ADDR_MASK);/* 通过SPI1发送数据 */spi_sendbyte(dat);/* 准备寄存器数值 */ dat = data;/* 通过SPI发送数据 */spi_sendbyte(dat);/* 禁止ENC28J60 */ ENC28J60_CSH();
}

 

3.2 读写缓冲区

读写缓冲区的操作也易于理解的。需要说明的是,两个函数具有相同的输入参数,参数len代表被操作数据的长度,pdata为被操作数据的指针。和寄存器读写函数相似,发送或接收数据之前需要发送特定的操作码。

void enc28j60ReadBuffer(unsigned int len, unsigned char* pdata)
{/* 使能ENC28J60 */ENC28J60_CSL();/* 通过SPI发送读取缓冲区命令*/spi_sendbyte(ENC28J60_READ_BUF_MEM);/* 循环读取 */while(len){len--;/* 读取数据 */*pdata = (unsigned char)spi_sendbyte(0);/* 地址指针累加 */pdata++;}/* 禁止ENC28J60 */ENC28J60_CSH();
}
void enc28j60WriteBuffer(unsigned int len, unsigned char* pdata)
{/* 使能ENC28J60 */ENC28J60_CSL();/* 通过SPI发送写取缓冲区命令*/spi_sendbyte(ENC28J60_WRITE_BUF_MEM);/* 循环发送 */while(len){len--;/* 发送数据 */spi_sendbyte(*pdata);/* 地址指针累加 */pdata++;}/* 禁止ENC28J60 */ENC28J60_CSH();
}

3.3 读写PHY寄存器

PHY寄存器和被ENC28J60控制的LED指示灯有关,控制该寄存器可以控制LED驱动方式和发生相应事件时LED显示方式。一般情况下,一个LED指示灯用于指示网络状态(常亮可理解为网络接通),另一个LED指示灯显示接收活动,有数据输入时产生一个点亮脉冲。PHY是比较特殊的寄存器,先要想一个控制寄存器写入PHY寄存器的地址,再向两个控制寄存器依次写入PHY寄存器的具体数据的高8位和低8位,最后等待PHY寄存器操作完成。

void enc28j60PhyWrite(unsigned char address, unsigned int data)
{/* 向MIREGADR写入地址 详见数据手册19页*/enc28j60Write(MIREGADR, address);/* 写入低8位数据 */enc28j60Write(MIWRL, data);/* 写入高8位数据 */enc28j60Write(MIWRH, data>>8);/* 等待PHY寄存器写入完成 */while(enc28j60Read(MISTAT) & MISTAT_BUSY);
}

转自 https://blog.csdn.net/xukai871105/article/details/14092167


推荐阅读
  • 本文介绍了一个项目中如何在Windows平台上实现多声道音频数据的采集,特别是针对DANTE音频接口的8路立体声音频通道。文章详细描述了使用Windows底层音频API进行音频采集的方法,并提供了一个具体的实现示例。 ... [详细]
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • Linux环境下C语言实现定时向文件写入当前时间
    本文介绍如何在Linux系统中使用C语言编程,实现在每秒钟向指定文件中写入当前时间戳。通过此示例,读者可以了解基本的文件操作、时间处理以及循环控制。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 深入解析ESFramework中的AgileTcp组件
    本文详细介绍了ESFramework框架中AgileTcp组件的设计与实现。AgileTcp是ESFramework提供的ITcp接口的高效实现,旨在优化TCP通信的性能和结构清晰度。 ... [详细]
  • 本文详细探讨了Java中的ClassLoader类加载器的工作原理,包括其如何将class文件加载至JVM中,以及JVM启动时的动态加载策略。文章还介绍了JVM内置的三种类加载器及其工作方式,并解释了类加载器的继承关系和双亲委托机制。 ... [详细]
  • 本文介绍了如何通过ARM编译器组件重定向标准C运行时库的I/O函数,以适应不同的硬件平台。原文链接:https://www.keil.com/pack/doc/compiler/RetargetIO/html/retarget_overview.html ... [详细]
  • Java实现文本到图片转换,支持自动换行、字体自定义及图像优化
    本文详细介绍了如何使用Java实现将文本转换为图片的功能,包括自动换行、自定义字体加载、抗锯齿优化以及图片压缩等技术细节。 ... [详细]
  • ElasticSearch 集群监控与优化
    本文详细介绍了如何有效地监控 ElasticSearch 集群,涵盖了关键性能指标、集群健康状况、统计信息以及内存和垃圾回收的监控方法。 ... [详细]
  • 本文探讨了仅对图像文件的内容进行加密的方法,而不加密整个文件。通过这种方式,可以保护图像中的敏感信息,同时保持文件的其他部分不受影响。 ... [详细]
  • 本文探讨了如何在Classic ASP中实现与PHP的hash_hmac('SHA256', $message, pack('H*', $secret))函数等效的哈希生成方法。通过分析不同实现方式及其产生的差异,提供了一种使用Microsoft .NET Framework的解决方案。 ... [详细]
  • 本文深入探讨了UNIX/Linux系统中的进程间通信(IPC)机制,包括消息传递、同步和共享内存等。详细介绍了管道(Pipe)、有名管道(FIFO)、Posix和System V消息队列、互斥锁与条件变量、读写锁、信号量以及共享内存的使用方法和应用场景。 ... [详细]
  • 本文详细介绍了JSP(Java Server Pages)的九大内置对象及其功能,探讨了JSP与Servlet之间的关系及差异,并提供了实际编码示例。此外,还讨论了网页开发中常见的编码转换问题以及JSP的两种页面跳转方式。 ... [详细]
  • Description“第一分钟,X说,要有矩阵,于是便有了一个里面写满了\(0\)的\(n\timesm\)矩阵。第二分钟,L说,要能修改,于是便有了将左上角为\((a,b)\) ... [详细]
  • 本文介绍了如何计算给定数组中所有非质数元素的总和,并提供了多种编程语言的实现示例。 ... [详细]
author-avatar
低调的小男2502928607
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有