找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1958|回复: 0
打印 上一主题 下一主题
收起左侧

硬件和软件兼容i2c协议的24Cxx系列EEPROM存储器

[复制链接]
跳转到指定楼层
楼主
ID:161768 发表于 2017-1-14 23:45 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
硬件上由于24c01的A0A1A2管脚不允许悬空,故暂时的想法是兼容24c02 ---24c16
使用一个dip8封装的芯片插座,A0 A1 A2管脚都悬空即可,换芯片方便
软件上24c02地址只有8位,而其他型号是大于8位的,故地址参数使用16位
256个字节作为一个大页,即largePage,测试芯片24c04空间有512字节

上代码,求测试和讨论
  1. #include "MY51.H"
  2. //转载请注明:  求测试讨论
  3. //stc89c52rc,11.0592MHz晶振
  4. sbit sda=P2^0;                //总线连接口定义
  5. sbit scl=P2^1;                //总线连接口定义

  6. void delayus()                 //需要4个机器周期,大概4.34us
  7. {
  8.         ;                                //晶振频率11.0592M,机器周期为1.085微秒
  9. }

  10. void iic_start()          //启动信号
  11. {
  12.         sda=1;
  13.         scl=1;
  14.         delayus();                //sda和scl同为高电平保持4.7us以上
  15.         _nop_();                //1.085us,共5.78us
  16.         sda=0;                         //下降沿
  17.         delayus();                //sda低电平保持4us以上        ,这里是4.34us满足要求
  18. }

  19. void iic_stop()                //停止信号
  20. {
  21.         sda=0;_nop_();        //准备状态
  22.         scl=1;
  23.         delayus();                //该状态稳定时间要求保持4us以上
  24.         sda=1;                        //scl高电平期间,sda来一个上升沿
  25.         delayus();                //sda保持4.7us以上,4.34加上函数返回时间大于4.7us
  26.                                         //注:此时scl和sda都为1        
  27. }

  28. void iic_sendByte(u8 byteData) //mcu发送一个字节
  29. {
  30.         u8 i;
  31.         u8 temp=byteData;
  32.         for(i=0;i<8;i++)
  33.         {
  34.                 temp=temp<<1;    //移动后最高位到了PSW寄存器的CY位中
  35.                 scl=0;                         //准备
  36.                 _nop_();                 //稳定一下
  37.                 sda=CY;                         //将待发送的数据一位位的放到sda上
  38.                 _nop_();
  39.                 scl=1;                     //每一个高电平期间,ic器件都会将数据取走
  40.                 _nop_();               
  41.         }

  42.         scl=0;                                 //如果写成scl=1;sda=1就是停止信号,不能这么写
  43.         _nop_();                                
  44.         sda=1;                                 //释放总线,数据总线不用时要释放
  45.         _nop_();
  46. }

  47. u8 iic_readByte()                         //读一个字节
  48. {
  49.         u8 i,temp;
  50.         scl=0;                                        //准备读数据
  51.         _nop_();
  52.         sda=1;                                        //释放总线
  53.         _nop_();

  54.         for(i=0;i<8;i++)
  55.         {
  56.                 scl=1;                                //mcu开始取数据
  57.                 delayus();                        //scl为高电平后,ic器件就会将1位数据送到sda上
  58.                                                         //总共用时不会大于4.34us,然后就可以让mcu读sda了
  59.                 temp=(temp<<1)|sda; //读一位保存到temp中
  60.                 scl=0;
  61.                 delayus();               
  62.         }
  63.         return temp;
  64. }

  65. bool iic_checkACK()                  //处理应答信号
  66. {
  67.         u8 errCounts=255;           //定义超时量为255次
  68.         scl=1;
  69.         _nop_();
  70.         
  71.         while(sda)                          //在一段时间内检测到sda=0的话认为是应答信号
  72.         {        
  73.                 if(0==errCounts)
  74.                 {
  75.                         scl=0;                  //钳住总线
  76.                         _nop_();
  77.                         return FALSE; //没有应答信号
  78.                 }
  79.                 errCounts--;
  80.         }

  81.         scl=0;                             //钳住总线,为下1次通信做准备
  82.         _nop_();
  83.         return TRUE;             //成功处理应答信号
  84. }

  85. void iic_init()                     //总线初始化
  86. {
  87.         scl=1;
  88.         sda=1;
  89.         delayus();
  90. }

  91. void iic_sendACK(bool b_ACK)  //发送应答或非应答信号
  92. {
  93.         scl=0;                        //准备
  94.         _nop_();

  95.         if(b_ACK)                //ACK        发送应该信号
  96.         {
  97.                 sda=0;
  98.         }
  99.         else                        //unACK        发送非应答信号
  100.         {
  101.                 sda=1;
  102.         }

  103.         _nop_();
  104.         scl=1;
  105.         delayus();                 //大于4us的延时
  106.         scl=0;                    //钳住scl,以便继续接收数据        
  107.         _nop_();
  108. }

  109. void AT24Cxx_writeByte(u16 address,u8 dataByte)//向24cxx写一字节数据
  110. {
  111.         u8 largePage     = address/256;          //24c04是512字节(寻址范围0~511),largePage最大值是1
  112.         u8 addressOffset = address%256;   //largePage=0的话地址范围是(0~255)
  113.         iic_start();
  114.         iic_sendByte(0xa0|(largePage<<1));//控制字,前4位固定1010,后三位是器件地址,末位0是写
  115.         iic_checkACK();                                      //mcu处理应答信号
  116.         iic_sendByte(addressOffset);            //指定要写入的器件内地址在        largePage块中的偏移
  117.         iic_checkACK();
  118.         iic_sendByte(dataByte);                   //写数据
  119.         iic_checkACK();
  120.         iic_stop();
  121.         delayms(2);        
  122.         //按字节写入时,24cxx在接收到停止信号后将数据擦写到内部,这需要时间
  123.         //并且在这段时间内不会响应总线上的任何请求,故让mcu有2毫秒以上的等待        
  124. }

  125. void AT24Cxx_writeData(u16 address,u8 numBytes,u8* buf)//写入任意长度数据(最大256字节)
  126. {
  127.         while(numBytes--)
  128.         {
  129.                 AT24Cxx_writeByte(address++,*buf++);
  130.         }
  131. }

  132. void AT24Cxx_readData(u16 beginAddr,u8 dataSize,u8* buf)//读取任意长度字节到缓冲区buf中
  133. {
  134.         u8 largePage     = beginAddr/256;        //计算largePage,256字节为一大页
  135.         u8 addressOffset = beginAddr%256;        //计算相对于largePage的偏移
  136.         iic_start();                                                  //起始信号
  137.         iic_sendByte(0xa0|(largePage<<1));        //控制字,写
  138.         iic_checkACK();                                                //处理应答信号
  139.         iic_sendByte(addressOffset);                //要读取的目标地址偏移
  140.         iic_checkACK();                                                //处理应答信号        
  141.         iic_start();                                                   //发送起始信号
  142.         iic_sendByte(0xa1|(largePage<<1));        //控制字,读
  143.         iic_checkACK();                                                //处理应答信号
  144.         while(dataSize--)                                        //读取dataSize个字节,最大256个字节
  145.         {                                                                        //dataSize用u16类型会暴掉ram的
  146.                 *buf++=iic_readByte();                        //读取一个个字节并保存到缓冲区buf中
  147.                 iic_sendACK(dataSize);                  //发送应答,当dataSize为0时mcu发送非应答
  148.         }
  149.         iic_stop();                                                        //发送停止信号
  150. }



  151. void main()//测试
  152. {
  153.         u8 buf[3];                                                                                //接受数据的缓冲区
  154.         u8 arr[7]={0x06,1,2,3,4,0x55,0x33};                                //待写入的数据
  155.                                                 
  156.         iic_init();                                                                                //总线初始化
  157.         AT24Cxx_writeData(0x00+256,sizeof(arr),arr);        //向指定地址处开始写入7字节的数据

  158.         P1=0xff;                                                                                 //调试代码,用P1口的led显示
  159.         delayms(1000);                                                                         //调试代码

  160.         AT24Cxx_readData(0x00+256,sizeof(buf),buf);           //从指定地址开始读3个字节
  161.         P1=buf[2];        //也就是2                                                                        //led灯显示数值
  162.                                                                                        
  163.         while(1)
  164.         {
  165.                 P1=~P1;
  166.                 delayms(500);               
  167.         }
  168. }

复制代码

  1. //my51.h中主要用到
  2. #include<reg52.h>

  3. #include"mytype.h"

  4. void delayms(u16 ms)     //软延时函数
  5. {
  6.         u16 i,j;
  7.         for(i=ms;i>0;i--)
  8.         {
  9.         for(j=113;j>0;j--)
  10.         {}
  11.         }
  12. }
复制代码
  1. 对代码进行了改进
  2. 去掉了在写数据时的
  3. delayms(2);
  4. 这句软延时代码低效 ,而且没有保障

  5. 改成加一个检测函数
  6. bool check_icWriteComplete()   //检测eeprom是否对内部擦写完成
  7. {
  8. iic_start();
  9. iic_sendByte(0xa0);
  10. return iic_checkACK();
  11. }
复制代码


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表