找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2471|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

硬件和軟件兼容i2c協(xié)議的24Cxx系列EEPROM存儲器

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
#
ID:161768 發(fā)表于 2017-1-14 23:45 | 只看該作者 回帖獎勵 |正序瀏覽 |閱讀模式
硬件上由于24c01的A0A1A2管腳不允許懸空,故暫時的想法是兼容24c02 ---24c16
使用一個dip8封裝的芯片插座,A0 A1 A2管腳都懸空即可,換芯片方便
軟件上24c02地址只有8位,而其他型號是大于8位的,故地址參數(shù)使用16位
256個字節(jié)作為一個大頁,即largePage,測試芯片24c04空間有512字節(jié)

上代碼,求測試和討論
  1. #include "MY51.H"
  2. //轉(zhuǎn)載請注明:  求測試討論
  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_();        //準備狀態(tài)
  22.         scl=1;
  23.         delayus();                //該狀態(tài)穩(wěn)定時間要求保持4us以上
  24.         sda=1;                        //scl高電平期間,sda來一個上升沿
  25.         delayus();                //sda保持4.7us以上,4.34加上函數(shù)返回時間大于4.7us
  26.                                         //注:此時scl和sda都為1        
  27. }

  28. void iic_sendByte(u8 byteData) //mcu發(fā)送一個字節(jié)
  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_();                 //穩(wěn)定一下
  37.                 sda=CY;                         //將待發(fā)送的數(shù)據(jù)一位位的放到sda上
  38.                 _nop_();
  39.                 scl=1;                     //每一個高電平期間,ic器件都會將數(shù)據(jù)取走
  40.                 _nop_();               
  41.         }

  42.         scl=0;                                 //如果寫成scl=1;sda=1就是停止信號,不能這么寫
  43.         _nop_();                                
  44.         sda=1;                                 //釋放總線,數(shù)據(jù)總線不用時要釋放
  45.         _nop_();
  46. }

  47. u8 iic_readByte()                         //讀一個字節(jié)
  48. {
  49.         u8 i,temp;
  50.         scl=0;                                        //準備讀數(shù)據(jù)
  51.         _nop_();
  52.         sda=1;                                        //釋放總線
  53.         _nop_();

  54.         for(i=0;i<8;i++)
  55.         {
  56.                 scl=1;                                //mcu開始取數(shù)據(jù)
  57.                 delayus();                        //scl為高電平后,ic器件就會將1位數(shù)據(jù)送到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()                  //處理應(yīng)答信號
  66. {
  67.         u8 errCounts=255;           //定義超時量為255次
  68.         scl=1;
  69.         _nop_();
  70.         
  71.         while(sda)                          //在一段時間內(nèi)檢測到sda=0的話認為是應(yīng)答信號
  72.         {        
  73.                 if(0==errCounts)
  74.                 {
  75.                         scl=0;                  //鉗住總線
  76.                         _nop_();
  77.                         return FALSE; //沒有應(yīng)答信號
  78.                 }
  79.                 errCounts--;
  80.         }

  81.         scl=0;                             //鉗住總線,為下1次通信做準備
  82.         _nop_();
  83.         return TRUE;             //成功處理應(yīng)答信號
  84. }

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

  91. void iic_sendACK(bool b_ACK)  //發(fā)送應(yīng)答或非應(yīng)答信號
  92. {
  93.         scl=0;                        //準備
  94.         _nop_();

  95.         if(b_ACK)                //ACK        發(fā)送應(yīng)該信號
  96.         {
  97.                 sda=0;
  98.         }
  99.         else                        //unACK        發(fā)送非應(yīng)答信號
  100.         {
  101.                 sda=1;
  102.         }

  103.         _nop_();
  104.         scl=1;
  105.         delayus();                 //大于4us的延時
  106.         scl=0;                    //鉗住scl,以便繼續(xù)接收數(shù)據(jù)        
  107.         _nop_();
  108. }

  109. void AT24Cxx_writeByte(u16 address,u8 dataByte)//向24cxx寫一字節(jié)數(shù)據(jù)
  110. {
  111.         u8 largePage     = address/256;          //24c04是512字節(jié)(尋址范圍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處理應(yīng)答信號
  116.         iic_sendByte(addressOffset);            //指定要寫入的器件內(nèi)地址在        largePage塊中的偏移
  117.         iic_checkACK();
  118.         iic_sendByte(dataByte);                   //寫數(shù)據(jù)
  119.         iic_checkACK();
  120.         iic_stop();
  121.         delayms(2);        
  122.         //按字節(jié)寫入時,24cxx在接收到停止信號后將數(shù)據(jù)擦寫到內(nèi)部,這需要時間
  123.         //并且在這段時間內(nèi)不會響應(yīng)總線上的任何請求,故讓mcu有2毫秒以上的等待        
  124. }

  125. void AT24Cxx_writeData(u16 address,u8 numBytes,u8* buf)//寫入任意長度數(shù)據(jù)(最大256字節(jié))
  126. {
  127.         while(numBytes--)
  128.         {
  129.                 AT24Cxx_writeByte(address++,*buf++);
  130.         }
  131. }

  132. void AT24Cxx_readData(u16 beginAddr,u8 dataSize,u8* buf)//讀取任意長度字節(jié)到緩沖區(qū)buf中
  133. {
  134.         u8 largePage     = beginAddr/256;        //計算largePage,256字節(jié)為一大頁
  135.         u8 addressOffset = beginAddr%256;        //計算相對于largePage的偏移
  136.         iic_start();                                                  //起始信號
  137.         iic_sendByte(0xa0|(largePage<<1));        //控制字,寫
  138.         iic_checkACK();                                                //處理應(yīng)答信號
  139.         iic_sendByte(addressOffset);                //要讀取的目標地址偏移
  140.         iic_checkACK();                                                //處理應(yīng)答信號        
  141.         iic_start();                                                   //發(fā)送起始信號
  142.         iic_sendByte(0xa1|(largePage<<1));        //控制字,讀
  143.         iic_checkACK();                                                //處理應(yīng)答信號
  144.         while(dataSize--)                                        //讀取dataSize個字節(jié),最大256個字節(jié)
  145.         {                                                                        //dataSize用u16類型會暴掉ram的
  146.                 *buf++=iic_readByte();                        //讀取一個個字節(jié)并保存到緩沖區(qū)buf中
  147.                 iic_sendACK(dataSize);                  //發(fā)送應(yīng)答,當dataSize為0時mcu發(fā)送非應(yīng)答
  148.         }
  149.         iic_stop();                                                        //發(fā)送停止信號
  150. }



  151. void main()//測試
  152. {
  153.         u8 buf[3];                                                                                //接受數(shù)據(jù)的緩沖區(qū)
  154.         u8 arr[7]={0x06,1,2,3,4,0x55,0x33};                                //待寫入的數(shù)據(jù)
  155.                                                 
  156.         iic_init();                                                                                //總線初始化
  157.         AT24Cxx_writeData(0x00+256,sizeof(arr),arr);        //向指定地址處開始寫入7字節(jié)的數(shù)據(jù)

  158.         P1=0xff;                                                                                 //調(diào)試代碼,用P1口的led顯示
  159.         delayms(1000);                                                                         //調(diào)試代碼

  160.         AT24Cxx_readData(0x00+256,sizeof(buf),buf);           //從指定地址開始讀3個字節(jié)
  161.         P1=buf[2];        //也就是2                                                                        //led燈顯示數(shù)值
  162.                                                                                        
  163.         while(1)
  164.         {
  165.                 P1=~P1;
  166.                 delayms(500);               
  167.         }
  168. }

復(fù)制代碼

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

  3. #include"mytype.h"

  4. void delayms(u16 ms)     //軟延時函數(shù)
  5. {
  6.         u16 i,j;
  7.         for(i=ms;i>0;i--)
  8.         {
  9.         for(j=113;j>0;j--)
  10.         {}
  11.         }
  12. }
復(fù)制代碼
  1. 對代碼進行了改進
  2. 去掉了在寫數(shù)據(jù)時的
  3. delayms(2);
  4. 這句軟延時代碼低效 ,而且沒有保障

  5. 改成加一個檢測函數(shù)
  6. bool check_icWriteComplete()   //檢測eeprom是否對內(nèi)部擦寫完成
  7. {
  8. iic_start();
  9. iic_sendByte(0xa0);
  10. return iic_checkACK();
  11. }
復(fù)制代碼


分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表