开云十大最新推荐

C51IO口模拟I2C总线驱动AT24C16 (EEPROM部分)

出处:eefocus 引用地址://www.eeworld.com.cn/mcu/2018/i 发布于:2018-07-21 13:57:54

   名称: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);       &nbsp;   //延时一段时间,等待写操作完成

  while(n--)

  {

  ret_val = SendByte_I2C(*p);

  p++;

  if(ret_val != 0)

  return AckError;

  delay_ms(10); &nbsp;         //延时一段时间,等待写操作完成

  }

  //停止I2C通信

  Stop_I2C();

  delay_ms(10); &nbsp;        //延时一段时间,等待写操作完成

  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);     &nbsp;  //重新生成设备地址,这次是读操作

  //发送设备地址

  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);     &nbsp;//高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);         &nbsp;   //数据没接受完,发送应答位

  else

  Ack_I2C(1);       &nbsp;     //数据接受完,发送非应答位

  }

  Stop_I2C();

  return Rev_OK;

  }


关键词:C51,IO口,模拟I2C,总线驱动

版权与免责声明

凡本网注明“出处:维库电子市场网”的所有作品,版权均属于维库电子市场网,转载请必须注明维库电子市场网,//fzqkw.cn,违反者本网将追究相关法律责任。

本网转载并注明自其它出处的作品,目的在于传递更多信息,并不代表本网赞同其观点或证实其内容的真实性,不承担此类作品侵权行为的直接责任及连带责任。其他媒体、网站或个人从本网转载时,必须保留本网注明的作品出处,并自负版权等法律责任。

如涉及作品内容、版权等问题,请在作品发表之日起一周内与本网联系,否则视为放弃相关权利。

相关技术资料
OEM清单文件: OEM清单文件
*公司名:
*联系人:
*手机号码:
QQ:
有效期:

扫码下载APP,
 一键连接广大的电子世界。 

在线人工客服

买家服务:
卖家服务:
技术客服:

0571-85317607

网站技术支持

13606545031

客服在线时间周一至周五
9:00-17:30 

关注官方微信号,
第一时间获取资讯。

建议反馈

联系人:

联系方式:

按住滑块,拖拽到最右边
>>
感谢您向阿库提出的宝贵意见,您的参与是维库提升服务的动力!意见一经采纳,将有感恩红包奉上哦!