|
硬件上由于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è)試和討論
- #include "MY51.H"
- //轉(zhuǎn)載請(qǐng)注明: 求測(cè)試討論
- //stc89c52rc,11.0592MHz晶振
- sbit sda=P2^0; //總線連接口定義
- sbit scl=P2^1; //總線連接口定義
- void delayus() //需要4個(gè)機(jī)器周期,大概4.34us
- {
- ; //晶振頻率11.0592M,機(jī)器周期為1.085微秒
- }
- void iic_start() //啟動(dòng)信號(hào)
- {
- sda=1;
- scl=1;
- delayus(); //sda和scl同為高電平保持4.7us以上
- _nop_(); //1.085us,共5.78us
- sda=0; //下降沿
- delayus(); //sda低電平保持4us以上 ,這里是4.34us滿足要求
- }
- void iic_stop() //停止信號(hào)
- {
- sda=0;_nop_(); //準(zhǔn)備狀態(tài)
- scl=1;
- delayus(); //該狀態(tài)穩(wěn)定時(shí)間要求保持4us以上
- sda=1; //scl高電平期間,sda來(lái)一個(gè)上升沿
- delayus(); //sda保持4.7us以上,4.34加上函數(shù)返回時(shí)間大于4.7us
- //注:此時(shí)scl和sda都為1
- }
- void iic_sendByte(u8 byteData) //mcu發(fā)送一個(gè)字節(jié)
- {
- u8 i;
- u8 temp=byteData;
- for(i=0;i<8;i++)
- {
- temp=temp<<1; //移動(dòng)后最高位到了PSW寄存器的CY位中
- scl=0; //準(zhǔn)備
- _nop_(); //穩(wěn)定一下
- sda=CY; //將待發(fā)送的數(shù)據(jù)一位位的放到sda上
- _nop_();
- scl=1; //每一個(gè)高電平期間,ic器件都會(huì)將數(shù)據(jù)取走
- _nop_();
- }
- scl=0; //如果寫(xiě)成scl=1;sda=1就是停止信號(hào),不能這么寫(xiě)
- _nop_();
- sda=1; //釋放總線,數(shù)據(jù)總線不用時(shí)要釋放
- _nop_();
- }
- u8 iic_readByte() //讀一個(gè)字節(jié)
- {
- u8 i,temp;
- scl=0; //準(zhǔn)備讀數(shù)據(jù)
- _nop_();
- sda=1; //釋放總線
- _nop_();
- for(i=0;i<8;i++)
- {
- scl=1; //mcu開(kāi)始取數(shù)據(jù)
- delayus(); //scl為高電平后,ic器件就會(huì)將1位數(shù)據(jù)送到sda上
- //總共用時(shí)不會(huì)大于4.34us,然后就可以讓mcu讀sda了
- temp=(temp<<1)|sda; //讀一位保存到temp中
- scl=0;
- delayus();
- }
- return temp;
- }
- bool iic_checkACK() //處理應(yīng)答信號(hào)
- {
- u8 errCounts=255; //定義超時(shí)量為255次
- scl=1;
- _nop_();
-
- while(sda) //在一段時(shí)間內(nèi)檢測(cè)到sda=0的話認(rèn)為是應(yīng)答信號(hào)
- {
- if(0==errCounts)
- {
- scl=0; //鉗住總線
- _nop_();
- return FALSE; //沒(méi)有應(yīng)答信號(hào)
- }
- errCounts--;
- }
- scl=0; //鉗住總線,為下1次通信做準(zhǔn)備
- _nop_();
- return TRUE; //成功處理應(yīng)答信號(hào)
- }
- void iic_init() //總線初始化
- {
- scl=1;
- sda=1;
- delayus();
- }
- void iic_sendACK(bool b_ACK) //發(fā)送應(yīng)答或非應(yīng)答信號(hào)
- {
- scl=0; //準(zhǔn)備
- _nop_();
- if(b_ACK) //ACK 發(fā)送應(yīng)該信號(hào)
- {
- sda=0;
- }
- else //unACK 發(fā)送非應(yīng)答信號(hào)
- {
- sda=1;
- }
- _nop_();
- scl=1;
- delayus(); //大于4us的延時(shí)
- scl=0; //鉗住scl,以便繼續(xù)接收數(shù)據(jù)
- _nop_();
- }
- void AT24Cxx_writeByte(u16 address,u8 dataByte)//向24cxx寫(xiě)一字節(jié)數(shù)據(jù)
- {
- u8 largePage = address/256; //24c04是512字節(jié)(尋址范圍0~511),largePage最大值是1
- u8 addressOffset = address%256; //largePage=0的話地址范圍是(0~255)
- iic_start();
- iic_sendByte(0xa0|(largePage<<1));//控制字,前4位固定1010,后三位是器件地址,末位0是寫(xiě)
- iic_checkACK(); //mcu處理應(yīng)答信號(hào)
- iic_sendByte(addressOffset); //指定要寫(xiě)入的器件內(nèi)地址在 largePage塊中的偏移
- iic_checkACK();
- iic_sendByte(dataByte); //寫(xiě)數(shù)據(jù)
- iic_checkACK();
- iic_stop();
- delayms(2);
- //按字節(jié)寫(xiě)入時(shí),24cxx在接收到停止信號(hào)后將數(shù)據(jù)擦寫(xiě)到內(nèi)部,這需要時(shí)間
- //并且在這段時(shí)間內(nèi)不會(huì)響應(yīng)總線上的任何請(qǐng)求,故讓mcu有2毫秒以上的等待
- }
- void AT24Cxx_writeData(u16 address,u8 numBytes,u8* buf)//寫(xiě)入任意長(zhǎng)度數(shù)據(jù)(最大256字節(jié))
- {
- while(numBytes--)
- {
- AT24Cxx_writeByte(address++,*buf++);
- }
- }
- void AT24Cxx_readData(u16 beginAddr,u8 dataSize,u8* buf)//讀取任意長(zhǎng)度字節(jié)到緩沖區(qū)buf中
- {
- u8 largePage = beginAddr/256; //計(jì)算largePage,256字節(jié)為一大頁(yè)
- u8 addressOffset = beginAddr%256; //計(jì)算相對(duì)于largePage的偏移
- iic_start(); //起始信號(hào)
- iic_sendByte(0xa0|(largePage<<1)); //控制字,寫(xiě)
- iic_checkACK(); //處理應(yīng)答信號(hào)
- iic_sendByte(addressOffset); //要讀取的目標(biāo)地址偏移
- iic_checkACK(); //處理應(yīng)答信號(hào)
- iic_start(); //發(fā)送起始信號(hào)
- iic_sendByte(0xa1|(largePage<<1)); //控制字,讀
- iic_checkACK(); //處理應(yīng)答信號(hào)
- while(dataSize--) //讀取dataSize個(gè)字節(jié),最大256個(gè)字節(jié)
- { //dataSize用u16類型會(huì)暴掉ram的
- *buf++=iic_readByte(); //讀取一個(gè)個(gè)字節(jié)并保存到緩沖區(qū)buf中
- iic_sendACK(dataSize); //發(fā)送應(yīng)答,當(dāng)dataSize為0時(shí)mcu發(fā)送非應(yīng)答
- }
- iic_stop(); //發(fā)送停止信號(hào)
- }
- void main()//測(cè)試
- {
- u8 buf[3]; //接受數(shù)據(jù)的緩沖區(qū)
- u8 arr[7]={0x06,1,2,3,4,0x55,0x33}; //待寫(xiě)入的數(shù)據(jù)
-
- iic_init(); //總線初始化
- AT24Cxx_writeData(0x00+256,sizeof(arr),arr); //向指定地址處開(kāi)始寫(xiě)入7字節(jié)的數(shù)據(jù)
- P1=0xff; //調(diào)試代碼,用P1口的led顯示
- delayms(1000); //調(diào)試代碼
- AT24Cxx_readData(0x00+256,sizeof(buf),buf); //從指定地址開(kāi)始讀3個(gè)字節(jié)
- P1=buf[2]; //也就是2 //led燈顯示數(shù)值
-
- while(1)
- {
- P1=~P1;
- delayms(500);
- }
- }
復(fù)制代碼
- //my51.h中主要用到
- #include<reg52.h>
- #include"mytype.h"
- void delayms(u16 ms) //軟延時(shí)函數(shù)
- {
- u16 i,j;
- for(i=ms;i>0;i--)
- {
- for(j=113;j>0;j--)
- {}
- }
- }
復(fù)制代碼- 對(duì)代碼進(jìn)行了改進(jìn)
- 去掉了在寫(xiě)數(shù)據(jù)時(shí)的
- delayms(2);
- 這句軟延時(shí)代碼低效 ,而且沒(méi)有保障
- 改成加一個(gè)檢測(cè)函數(shù)
- bool check_icWriteComplete() //檢測(cè)eeprom是否對(duì)內(nèi)部擦寫(xiě)完成
- {
- iic_start();
- iic_sendByte(0xa0);
- return iic_checkACK();
- }
復(fù)制代碼
|
|