C51IO口模拟I2C总线驱动AT24C16 (EEPROM部分)
2018-03-27 11:57
471 查看
/*
名称:C51IO口模拟I2C总线驱动AT24C16
说明:关于EEPROM,即这里的AT24C16是一个特殊形式的FLASH存储器,不过其容量一般较少。比较适合于存储少量的数据。
AT24C16的通信接口是标准的I2C通信,即我们需要根据I2C通信协议来操纵EEPROM设备。 关于AT24C16的的各种操作,这里就不细讲了,简单介绍一下。
(1)、主机向AT24C16写一个字节:首先需要发送设备地址,然后发送需要访问的存储器地址。然后在发送要写入的数据。这里省略了开始、结束和确认等信号的产生。
(2)、指定页写入n个字节:和(1)的基本操作很类似。不同的是可以连续写入n个数据。这里要小注意一点的就是,写入的数据如果到达页边界(即n超过16字节)就会产生回滚,也就是重新从页的开始处写入,这样的话可能会覆盖到原来的数据。 本程序的指定页的实现是从页开始处写入的,当然也可以从任何地址开始写入数据,不过还是要注意页边界的问题。
(3)、主机随机从AT24C16读一个字节:这里的操作步骤先是主机向AT24C16写入设备地址和要访问的存储器地址(这个也叫作哑写操作:为了AT24C16装载随机的地址)。然后重新发起读操作,最后从主机接收AT24C16传送的指定地址上的数据
(4)、指定地址顺序读n个字节:这里的操作和(3)中也是差不多,不同的是再读出的时候可以同时读出n个数据。
在这里需要注意一点:在本人的实验中,连续读出n个数据并不会产生到达页边界就会回滚的现象,这里的n可以大于页大小。也就是说,连续读操作地址会自动跨越页边界。但是如果到达地址的边界,应该就会重新回滚了。(关于这点我也并不是很确定,一般的资料上显示的是到达页边界也就产生回滚了,但是我的实验在连续读时确实是没有产生回滚)。
最后这里说一点,AT24C16存储器是128页(页面数)*16字节(页大小)。所以其设备地址结构中1-3位也作为页面地址的高3位,然后存储器地址的高4位作为页面地址的低4位,合起来正好7位,可以访问128个页面。然后存储器地址的低4位作为页偏移,可以访问16个字节的内容。
*/
具体的完整驱动程序源代码:可以驱动程序下载地址进行下载
名称:C51IO口模拟I2C总线驱动AT24C16
说明:关于EEPROM,即这里的AT24C16是一个特殊形式的FLASH存储器,不过其容量一般较少。比较适合于存储少量的数据。
AT24C16的通信接口是标准的I2C通信,即我们需要根据I2C通信协议来操纵EEPROM设备。 关于AT24C16的的各种操作,这里就不细讲了,简单介绍一下。
(1)、主机向AT24C16写一个字节:首先需要发送设备地址,然后发送需要访问的存储器地址。然后在发送要写入的数据。这里省略了开始、结束和确认等信号的产生。
(2)、指定页写入n个字节:和(1)的基本操作很类似。不同的是可以连续写入n个数据。这里要小注意一点的就是,写入的数据如果到达页边界(即n超过16字节)就会产生回滚,也就是重新从页的开始处写入,这样的话可能会覆盖到原来的数据。 本程序的指定页的实现是从页开始处写入的,当然也可以从任何地址开始写入数据,不过还是要注意页边界的问题。
(3)、主机随机从AT24C16读一个字节:这里的操作步骤先是主机向AT24C16写入设备地址和要访问的存储器地址(这个也叫作哑写操作:为了AT24C16装载随机的地址)。然后重新发起读操作,最后从主机接收AT24C16传送的指定地址上的数据
(4)、指定地址顺序读n个字节:这里的操作和(3)中也是差不多,不同的是再读出的时候可以同时读出n个数据。
在这里需要注意一点:在本人的实验中,连续读出n个数据并不会产生到达页边界就会回滚的现象,这里的n可以大于页大小。也就是说,连续读操作地址会自动跨越页边界。但是如果到达地址的边界,应该就会重新回滚了。(关于这点我也并不是很确定,一般的资料上显示的是到达页边界也就产生回滚了,但是我的实验在连续读时确实是没有产生回滚)。
最后这里说一点,AT24C16存储器是128页(页面数)*16字节(页大小)。所以其设备地址结构中1-3位也作为页面地址的高3位,然后存储器地址的高4位作为页面地址的低4位,合起来正好7位,可以访问128个页面。然后存储器地址的低4位作为页偏移,可以访问16个字节的内容。
*/
//AT24C16写一个字节(keil中int是2个字节,在这里只有11位有效数据位) int AT24C16_ByteWrite(unsigned int addr,uchar _data) { bit ret_val = 0; uchar high_addr = (uchar)(addr>>8); //高8位地址 uchar low_addr =(uchar)addr; //低8位地址 uchar dev_addr = 0xA0 | ((high_addr&0x0F)<<1); //组成设备地址,其中包括4-6位是页面地址, if(addr > ADDRMAX) { return OutOfAddr; } //开启I2C通信 Start_I2C(); //发送设备地址 ret_val = SendByte_I2C(dev_addr); if(ret_val != 0) return AckError; //发送要访问的地址 ret_val = SendByte_I2C(low_addr); if(ret_val != 0) return AckError; //发送要访问的地址 ret_val = SendByte_I2C(_data); if(ret_val != 0) return AckError; //停止总线 Stop_I2C(); delay_ms(10); //延时一段时间,等待写操作完成 return Send_OK; } //指定页写入n个字节数据(n<16) int AT24C16_PageWrite(uchar page,uchar* p,uchar n) { uchar dev_addr; //设备地址 uchar low_addr; uchar high_addr; uchar tmp = 0; bit ret_val; if((n > 16)|(page > 128)) //根据读写的设备而变更为适合的页数和每页字节数 { return OutOfRang ; } high_addr = (page) >> 4; //得出页首地址 low_addr = ((page & 0x0F)<<4) ; //得出后四位页地址,组成存储地址的高四位 dev_addr = 0xa0 | ((high_addr & 0x0F) << 1); //开启I2C通信 Start_I2C(); //发送设备地址 ret_val = SendByte_I2C(dev_addr); if(ret_val != 0) return AckError; //发送存储地址,从页首开始 ret_val = SendByte_I2C(low_addr); if(ret_val != 0) return AckError; delay_ms(10); //延时一段时间,等待写操作完成 while(n--) { ret_val = SendByte_I2C(*p); p++; if(ret_val != 0) return AckError; delay_ms(10); //延时一段时间,等待写操作完成 } //停止I2C通信 Stop_I2C(); delay_ms(10); //延时一段时间,等待写操作完成 return Send_OK; } //AT24C16随机读一个字节 uchar AT24C16_RandomRead(unsigned int addr) { uchar dev_addr; //设备地址 uchar low_addr; uchar high_addr; uchar tmp = 0; bit ret_val = 0; low_addr = (uchar)addr; high_addr = (uchar)(addr>>8); dev_addr = 0xA0 | ((high_addr&0x0F)<<1); if(addr > ADDRMAX) { return OutOfAddr; } //开启I2C通信 Start_I2C(); //发送设备地址 ret_val = SendByte_I2C(dev_addr); if(ret_val != 0) return AckError; //发送存储器地址 ret_val = SendByte_I2C(low_addr); if(ret_val != 0) return AckError; //重新开启I2C通信 Start_I2C(); dev_addr = 0xA1 | ((high_addr&0x0F)<<1); //重新生成设备地址,这次是读操作 //发送设备地址 ret_val = SendByte_I2C(dev_addr); if(ret_val != 0) return AckError; //从I2C读取一个字节 tmp = RecByte_I2C(); Ack_I2C(1); //发送非应答位 //发送停止位 Stop_I2C(); return tmp; } //指定地址顺序读出n个字节:(注意可能会到达最终的地址边界,产生回滚) int AT24C16_SequentialRead(unsigned int addr,int n,uchar * p) { uchar dev_addr; //设备地址 uchar low_addr; uchar high_addr; uchar tmp = 0; bit ret_val = 0; if((addr > ADDRMAX)) //根据读写的设备而变更为适合的页数和每页字节数 { return OutOfAddr ; } high_addr = (uchar)(addr>>8); //高8位地址 low_addr =(uchar)addr; //低8位地址 dev_addr = 0xA0 | ((high_addr&0x0F)<<1); //组成设备地址,其中包括4-6位是页面地址, //开启I2C通信 Start_I2C(); //哑写操作,让存储器加载设备地址和存储地址 //发送设备地址 ret_val = SendByte_I2C(dev_addr); if(ret_val != 0) return AckError; //发送存储地址,从页首开始 ret_val = SendByte_I2C(low_addr); if(ret_val != 0) return AckError; //重新开启I2C通信 Start_I2C(); dev_addr = 0xA1 | ((high_addr&0x0F)<<1); //组成设备地址,其中包括4-6位是页面地址, //重新发送设备地址,这次的目的是读操作 ret_val = SendByte_I2C(dev_addr); if(ret_val != 0) return AckError; //开始读操作 while(n--) { *p = RecByte_I2C(); p++; if(n>0) Ack_I2C(0); //数据没接受完,发送应答位 else Ack_I2C(1); //数据接受完,发送非应答位 } Stop_I2C(); return Rev_OK; }
具体的完整驱动程序源代码:可以驱动程序下载地址进行下载
相关文章推荐
- C51IO口模拟I2C总线驱动AT24C16 (I2C协议部分)
- S5PV210 Linux -- IO口模拟I2C总线驱动
- 普通IO模拟i2c总线
- PIC单片机-普通IO口模拟I2C总线对24C02进行读写操作
- RS232模拟I2C总线驱动DS1621测温
- iic驱动(IO口模拟)
- 普通IO模拟i2c总线
- spi驱动--IO模拟
- 基于S5pv210--IO口模拟I2C总线Linux系统下驱动设计
- Qemu模拟IO和半虚拟化Virtio的区别以及I/O半虚拟化驱动介绍
- LPC1788-IO模拟SPI--驱动AD7708--寄存器操作
- stm32驱动3.2寸触摸屏(包括IO模拟,SPI硬件接口)
- STM32 IO口模拟I2C+驱动MPU6050
- C51用IO口模拟SPI
- Z-STACK中按键KEY驱动流程-修改到任意IO口
- <36>python学习笔记——论事件驱动与异步IO
- 【Java部分源码分析之io篇】7.FileReader
- 驱动中实现模拟键盘按键
- 关于Android电池管理系统(一)Linux驱动部分
- Icesword 驱动部分分析