新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 51單片機實現對24C02進行頁寫、順序讀取并顯示驗證

        51單片機實現對24C02進行頁寫、順序讀取并顯示驗證

        作者: 時間:2016-11-19 來源:網絡 收藏
        //*************************************************************************************
        //**程序名稱:51單片機實現對24C02進行頁寫順序讀取顯示驗證//**編寫人:**** //**修改人:****//**程序目的:熟悉I2C總線協議,實現51模擬I2C時序和24C02通信//**功能描述:51單片機將8個字節數據寫入24C02的一頁中,然后順序讀出,每隔1秒送P0口LED顯示//**其他說明:本程序是采用某51開發板,若在其他地方驗證可更改相關端口及延時程序等。//** 程序編寫前曾參考過多個教程,最終自己編程通過,并詳加注釋。//** 可供初學者參考,并不對程序的可靠性等作保證。//**開發工具:keil 7.50 (C51) //**日期://*************************************************************************************#include #include     //因為用到_nop_();typedef unsigned char uchar;sbit SCL = P3^3;        //注意P1、P2、P3口有內部上拉電阻,可直接連SDA和SCL,若想用P0需外接上拉電阻,否則連上無法輸出高電平!sbit SDA = P3^4;uchar j;                //用于計數50ms的個數的全局變量uchar code ToSDAdataBuffer[8] = {0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80,0x00}; //寫入24C02的一組數據,8個字節對應24C02的一頁(共32頁),這里把這些要驗證的常數放到程序存儲區uchar ReceivedData[8];    //用于存儲接收的8個字節數據(1頁)的數組//本例51為單主機,24C02為從機,不需要總線裁決//延時5us子程序void delay5us(void){_nop_(); //時序圖要求開始建立時間tSU.STA大于4.7us,開始保持時間tHD.STA大于4us。51中每個_nop_();延時1個CPU cycle,即1us。_nop_(); //如考慮不同CPU頻率不同,可用帶參數的延時,參數在前面宏定義。_nop_();_nop_();_nop_();}//50ms定時器0中斷函數void timer0() interrupt 1         //j是個全局變量,不是返回值,所以這里還是void。{TH0 = (65536-46080)/256;    //11.0592MHz時每50ms一次定時器中斷TL0 = (65536-46080)%256;j++;                         //也可以把判斷j到20,并給P0口送顯示數據的程序放在中斷里處理}//延時1秒的子程序,用于將讀取的數據每隔一秒顯示在LED上void delay1s(void){j = 0;TMOD = 0x01;                 //方式1的16位計數器TH0 = (65536-46080)/256;TL0 = (65536-46080)%256;EA = 1;ET0 = 1;TR0 = 1;                     //啟動定時器0工作while(j < 20)                //j達到20之前空操作,達到20時說明已到1s,下面關中斷和定時器0;EA = 0;ET0 = 0;TR0 = 0;}//約2ms的延時void delay(uchar t){uchar x,y;for(x=0;xd address,即寫到哪個存儲單元(24C02有2kbits,所以數據字有2048/8=256個,故地址線有8位)if(!ChkAck()){for(i = 0; i < 8; i++){WriteI2CByte(ToSDAdataBuffer[i]);if(ChkAck()){//這里可添加錯誤處理代碼。如用幾個LED的亮滅組合表示此I2C器件有問題,類似主板錯誤提示。return 1;//一般返回1表示異常,且遇到return就退出整個子程序。}}StopI2C(); //寫完發送結束信號。return 0; //一般返回0表示程序正常}else{return 1; //之前可添加錯誤處理代碼。}}else{return 1;}}//不能用Current Address Read,因為那是24C02數據字地址計數器上次操作后加1的值;而SEQUENTIAL_READ如果不給一個要讀取的開始地址,會從頭輸出,//所以需要Random Read的開始部分,但不要停止信號。bit SequentialRead(uchar WordAddress){uchar i;StartI2C();WriteI2CByte(0xa0);if (!ChkAck()){WriteI2CByte(WordAddress);if (!ChkAck()){StartI2C();             //the microcontroller must generate another start conditionWriteI2CByte(0xa1);     //Device Address后緊跟的那一位R/W^是1說明是讀,24C02內部就是根據最后這位來判斷是從SDA上讀數,還是往SDA上送數//之所以設為1是讀,是因為根據WriteI2CByte子程序,最后給SDA賦1,P3^4就維持1,這樣24C02內部Dout為高就將SDA拉低;//如果最后一位是0,24C02沒能力拉高!if (!ChkAck()){for(i = 0;i < 8;i++){ReceivedData[i] = ReadI2CByte();AckAsMaster(0); //51此時接收數據,調用應答的函數(置SDA為0)}AckAsMaster(1);     //NO ACK.The microcontroller does not respond with a zero but doesgenerate a following stop condition.StopI2C();return 0;}else{return 1;             //之前可添加錯誤處理代碼。}}else{return 1;}}else{return 1;}}int main(void){uchar i;P0 = 0xff;InitI2C();//注意在24C02中用到的頁寫和順序讀的地址是同一個,且必須是8的整數倍,即每頁的首地址才行,如0x08,0x20等。因為24C02頁寫時后三位地址自動加1,//When the word address,internally generated, reaches the page boundary, the following byte is placed at the beginning of the same page.//而順序讀時只有在達到整個存儲區邊界時才會roll over。所以,如讀寫都用0x32這個地址,由于不是8的整數倍,只有前6個數顯示是正確的,最后兩個數//雖然又從頭寫在了該頁的前面,但SequentialRead確讀到了該頁之外的兩個存儲單元,造成錯誤。if (PageWrite(0x08,ToSDAdataBuffer) == 0) { //先執行頁寫操作,設從地址00開始,沒問題就延遲一下再從同一地址讀回來。delay(100); //等待24C02頁寫操作完畢if(SequentialRead(0x08) == 0){ //如果順序讀操作成功,則每隔1秒送P0口顯示一個字節for(i = 0; i < 8; i++){P0 = ReceivedData[i];delay1s();}}}while(1);return 0;}//往I2C總線寫一個字節的數據(即將一個字節的數據發送到SDA上)void WriteI2CByte(uchar ByteData){uchar i,temp;temp = ByteData;// (StartI2C()最后已經先將SCL變0了):for(i=0;i<8;i++){temp <<= 1;     //左移一位,I2C要求由MSB最高位開始,移出的CY即要發送到SDA上的數據。下面考慮時序:SDA = CY;       //此時SCL已為低,每次移一位送出去(下次進循環后SDA還保持著上次發出去的數據)delay5us();     //SDA IN數據變化中點SCL上升沿中點的一段時間是tSU.DAT,即數據建立時間Data In Setup Time,需大于200ns,多延無所謂SCL = 1;delay5us();     //tHIGH即Clock Pulse Width High,最小4usSCL = 0;delay5us();     //tLOW即Clock Pulse Width Low,最小4.7us}}//讀取I2C總線一個字節的數據uchar ReadI2CByte()      //串行總線,51一位位接收從機發送到SDA上的數據,這里只考慮數據已在SDA上時如何存下來這幾位,組成一個字節{uchar i,ByteData;SDA = 1;             //SCL在ChkAck中已經置0了。注意SCL時序仍然由主機控制!24C02只能將SDA由高拉低,象橡皮筋松手又恢復高,而下面只是讀SDA,沒賦值            //其實程序中多處給SDA置1都可省,因為檢查應答時為0就正常,無所謂,寫字節時也無所謂,就是在讀之前要保證SDA為1!            //因之前有WriteI2CByte(0xa1); 其實這句也可省略。delay5us();      //24C02作為發送方在第9個時鐘的negative edge clocks data out of each device,所以現在SDA上為新數據for(i=0;i<8;i++){SCL = 1;         //置時鐘線為高使數據線上數據有效delay5us();ByteData = (ByteData<<1)SDA; //SDA上已是新數據了,讀之。data不管以前多少,左移后最右邊為0,和SDA“按位或”后MLB就是SDASCL = 0;delay5us();}return ByteData;}


        評論


        技術專區

        關閉
        主站蜘蛛池模板: 沂水县| 霍州市| 贺兰县| 钦州市| 格尔木市| 青神县| 庆安县| 商洛市| 无棣县| 陵水| 上高县| 衡阳市| 班玛县| 尼勒克县| 潼关县| 上饶县| 加查县| 平阳县| 青铜峡市| 青河县| 边坝县| 石阡县| 青海省| 大安市| 齐齐哈尔市| 铅山县| 皮山县| 电白县| 临江市| 固原市| 商河县| 南木林县| 普陀区| 陇南市| 肇源县| 邛崃市| 霍城县| 土默特左旗| 崇信县| 河北省| 普洱|