找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

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

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

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

上代碼,求測(cè)試和討論
  1. #include "MY51.H"
  2. //轉(zhuǎn)載請(qǐng)注明:  求測(cè)試討論
  3. //stc89c52rc,11.0592MHz晶振
  4. sbit sda=P2^0;                //總線連接口定義
  5. sbit scl=P2^1;                //總線連接口定義

  6. void delayus()                 //需要4個(gè)機(jī)器周期,大概4.34us
  7. {
  8.         ;                                //晶振頻率11.0592M,機(jī)器周期為1.085微秒
  9. }

  10. void iic_start()          //啟動(dòng)信號(hào)
  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()                //停止信號(hào)
  20. {
  21.         sda=0;_nop_();        //準(zhǔn)備狀態(tài)
  22.         scl=1;
  23.         delayus();                //該狀態(tài)穩(wěn)定時(shí)間要求保持4us以上
  24.         sda=1;                        //scl高電平期間,sda來(lái)一個(gè)上升沿
  25.         delayus();                //sda保持4.7us以上,4.34加上函數(shù)返回時(shí)間大于4.7us
  26.                                         //注:此時(shí)scl和sda都為1        
  27. }

  28. void iic_sendByte(u8 byteData) //mcu發(fā)送一個(gè)字節(jié)
  29. {
  30.         u8 i;
  31.         u8 temp=byteData;
  32.         for(i=0;i<8;i++)
  33.         {
  34.                 temp=temp<<1;    //移動(dòng)后最高位到了PSW寄存器的CY位中
  35.                 scl=0;                         //準(zhǔn)備
  36.                 _nop_();                 //穩(wěn)定一下
  37.                 sda=CY;                         //將待發(fā)送的數(shù)據(jù)一位位的放到sda上
  38.                 _nop_();
  39.                 scl=1;                     //每一個(gè)高電平期間,ic器件都會(huì)將數(shù)據(jù)取走
  40.                 _nop_();               
  41.         }

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

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

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

  81.         scl=0;                             //鉗住總線,為下1次通信做準(zhǔn)備
  82.         _nop_();
  83.         return TRUE;             //成功處理應(yīng)答信號(hào)
  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)答信號(hào)
  92. {
  93.         scl=0;                        //準(zhǔn)備
  94.         _nop_();

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

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

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

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



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

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

  160.         AT24Cxx_readData(0x00+256,sizeof(buf),buf);           //從指定地址開(kāi)始讀3個(gè)字節(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í)函數(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. 對(duì)代碼進(jìn)行了改進(jìn)
  2. 去掉了在寫(xiě)數(shù)據(jù)時(shí)的
  3. delayms(2);
  4. 這句軟延時(shí)代碼低效 ,而且沒(méi)有保障

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


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

使用道具 舉報(bào)

本版積分規(guī)則

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

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

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