日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【51单片机快速入门指南】4.1: I2C 与 AT24C02 (EEPROM) 的跨页连续读写

發(fā)布時間:2023/12/9 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【51单片机快速入门指南】4.1: I2C 与 AT24C02 (EEPROM) 的跨页连续读写 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

目錄

  • 硬知識
    • AT24Cxx 介紹
      • 引腳排列
      • 引腳說明
      • 存儲結構
      • 器件尋址
      • 器件操作
        • 待機模式
        • 存儲復位
        • 寫操作
          • 字節(jié)寫
          • 頁寫
          • 應答查詢
        • 讀操作
          • 當前地址讀
          • 隨機讀
          • 順序讀
  • 示例程序
    • 24C02.c
    • 24C02.h
    • 測試程序
      • main.c
      • 實驗現(xiàn)象
      • 通訊波形
        • 寫入部分
        • 讀取部分

普中51-單核-A2
STC89C52
Keil uVision V5.29.0.0
PK51 Prof.Developers Kit Version:9.60.0.0


硬知識

???????摘自《普中 51 單片機開發(fā)攻略》、《24C02/24C04/24C08/24C16/24C32/24C64芯片手冊》

AT24Cxx 介紹

???????AT24C01/02/04/08/16…是一個1K/2K/4K/8K/16K 位串行 CMOS,內部含有 128/256/512/1024/2048 個 8 位字節(jié),AT24C01 有一個 8 字節(jié)頁寫緩沖器, AT24C02/04/08/16 有一個 16 字節(jié)頁寫緩沖器。該器件通過 I2C 總線接口進行操作,它有一個專門的寫保護功能。開發(fā)板上使用的是 AT24C02(EEPROM)芯片,此芯片具有 I2C 通信接口,芯片內保存的數(shù)據在掉電情況下都不丟失, 所以通常用于存放一些比較重要的數(shù)據等。

引腳排列

AT24Cxx 芯片管腳如下圖所示:

引腳說明

存儲結構

器件尋址

???????起始條件使能芯片讀寫操作后,EEPROM都要求有8位的器件地址信息。
???????器件地址信息由"1"、“0"序列組成,前4位如圖中所示,對于所有串行EEPROM都是一樣的。對于24C02/32/64,隨后3位A2,A1和A0為器件地址位,必須與硬件輸入引腳保持一致。
???????對于24C04,隨后2位A2和A1為器件地址位,另1位為頁地址位。A2和A1必須與硬件輸入引腳保持一致,而A0是空腳。
???????對于24C08,隨后1位A2為器件地址位,另2位為頁地址位。A2必須與硬件輸入引腳保持一致,而A1和A0是空腳。
???????對于24C16,無器件地址位,3位都為頁地址位,而A2,A1和A0是空腳。
???????器件地址信息的LSB為讀/寫操作選擇位,高為讀操作,低為寫操作。
???????若比較器件地址一致,EEPROM將輸出應答"0”,如果不一致,則返回到待機狀態(tài)。

器件操作

待機模式

EEPROM具有低功耗待機的特點,條件為:

  • 電源上電;
  • 接收停止條件及完成任何內部操作后。
  • 存儲復位

    當協(xié)議中產生中斷、掉電或系統(tǒng)復位后,I2C總線可通過以下步驟復位:

  • 產生9個時鐘周期。
  • 當SCL為高時,SDA也為高。
  • 產生一個起始條件。
  • 寫操作

    字節(jié)寫

    ???????寫操作要求在接收器件地址和ACK應答后,接收8位的字地址。接收到這個地址后EEPROM應答"0",然后是一個8位數(shù)據。在接收8位數(shù)據后,EEPROM應答"0",接著必須由主器件發(fā)送停止條件來終止寫序列。
    ???????此時EEPROM進入內部寫周期tWRt_{WR}tWR?,數(shù)據寫入非易失性存儲器中,在此期間所有輸入都無效。
    ???????直到寫周期完成,EEPROM才會有應答。

    頁寫

    ???????24C02器件按8字節(jié)/頁執(zhí)行頁寫,24C04/08/16器件按16字節(jié)/頁執(zhí)行頁寫,24C32/64器件按32字節(jié)/頁執(zhí)行頁寫。
    ???????頁寫初始化與字節(jié)寫相同,只是主器件不會在第一個數(shù)據后發(fā)送停止條件,而是在EEPROM的ACK以后,接著發(fā)送7個(24C02)或15個(24C04/08/16)或31個(24C32/64)數(shù)據。
    ???????EEPROM收到每個數(shù)據后都應答"0",最后仍需由主器件發(fā)送停止條件,終止寫序列接收到每個數(shù)據后,字地址的低3位(24C02)或4位(24C04/08/16)或5位(24C32/64)內部自動加1,高位地址位不變,維持在當前頁內。當內部產生的字地址達到該頁邊界地址時,隨后的數(shù)據將寫入該頁的頁首。如果超過8個(24C02)或16個(24C04/08/16)或32個24C32/64)數(shù)據傳送給了EEPROM,字地址將回轉到該頁的首字節(jié),先前的字節(jié)將會被覆蓋。

    應答查詢

    ???????一旦內部寫周期啟動,EEPROM輸入無效,此時即可啟動應答查詢:發(fā)送起始條件和器件地址(讀/寫位為期望的操作)。只有內部寫周期完成,EEPROM才應答"0",之后可繼續(xù)讀/寫操作。

    讀操作

    ???????讀操作與寫操作初始化相同,只是器件地址中的讀/寫選擇位應為"1",有三種不同的讀操作方式:當前地址讀,隨機讀和順序讀。

    當前地址讀

    ???????內部地址計數(shù)器保存著上次訪問時最后一個地址加1的值。只要芯片有電,該地址就一直保存。當讀到最后頁的最后字節(jié),地址會回轉到0;當寫到某頁尾的最后一個字節(jié),地址會回轉到該頁的首字節(jié)。
    ???????接收器件地址(讀/寫選擇位為"1")、EEPROM應答ACK后,當前地址的數(shù)據就隨時鐘送出。
    ???????主器件無需應答"0",但需發(fā)送停止條件。

    隨機讀

    ???????隨機讀需先寫一個目標字地址,一旦EEPROM接收器件地址和字地址并應答了ACK,主器件就產生一個重復的起始條件。
    ???????然后,主器件發(fā)送器件地址(讀/寫選擇位為"1"),EEPROM應答ACK,并隨時鐘送出數(shù)據。主器件無需應答"0",但需發(fā)送停止條件。

    順序讀

    ???????順序讀可以通過“當前地址讀”或"隨機讀”啟動。主器件接收到一個數(shù)據后,應答ACK,只要EEPROM接收到ACK,將自動增加字地址并繼續(xù)隨時鐘發(fā)送后面的數(shù)據。若達到存儲器地址末尾,地址自動回轉到0,仍可繼續(xù)順序讀取數(shù)據。
    ???????主器件不應答"0",而發(fā)送停止條件,即可結束順序讀操作。

    示例程序

    ???????stdint.h見【51單片機快速入門指南】1:基礎知識和工程創(chuàng)建
    ???????軟件I2C程序見【51單片機快速入門指南】4: 軟件 I2C

    ???????由原理圖,此24C02的地址為1010 000,即 0x50

    24C02.c

    #include "24C02.h"/******************************************************************************* * 函 數(shù) 名 : at24c02_delay_1ms 移植時需修改 * 函數(shù)功能 : 延時1ms * 輸 入 : 無 * 輸 出 : 無 *******************************************************************************/ void at24c02_delay_1ms() //@11.0592MHz {unsigned char i, j;_nop_();i = 2;j = 199;do{while (--j);} while (--i); }void at24c02_delay_ms(int i) {while(i--)at24c02_delay_1ms(); }/******************************************************************************* * 函 數(shù) 名 : at24c02_write_one_byte * 函數(shù)功能 : 在AT24CXX指定地址寫入一個數(shù)據 * 輸 入 : addr:寫入數(shù)據的目的地址 dat:要寫入的數(shù)據 * 輸 出 : 無 *******************************************************************************/ void at24c02_write_one_byte(uint8_t addr,uint8_t dat) { i2c_mem_write(ADDR_24C02, addr, &dat, 1);at24c02_delay_ms(10); }/******************************************************************************* * 函 數(shù) 名 : at24c02_read_one_byte * 函數(shù)功能 : 在AT24CXX指定地址讀出一個數(shù)據 * 輸 入 : addr:開始讀數(shù)的地址 * 輸 出 : 讀到的數(shù)據 *******************************************************************************/ uint8_t at24c02_read_one_byte(uint8_t addr) { uint8_t temp = 0; i2c_mem_read(ADDR_24C02, addr, &temp, 1);return temp; //返回讀取的數(shù)據 }/******************************************************************************* * 函 數(shù) 名 : at24c02_read_one_page * 函數(shù)功能 : 在AT24CXX指定地址讀出一頁數(shù)據 * 輸 入 : addr:寫入數(shù)據的目的地址 pbuffer:要寫入的緩沖區(qū)首地址Len:數(shù)據長度 * 輸 出 : 無 *******************************************************************************/ void at24c02_read_one_page(uint8_t addr, uint8_t *pbuffer) { i2c_mem_read(ADDR_24C02, addr, pbuffer, 8); }/******************************************************************************* * 函 數(shù) 名 : at24c02_write_one_page * 函數(shù)功能 : 在AT24CXX指定頁寫入一頁數(shù)據 * 輸 入 : addr:寫入數(shù)據的目的地址 dat:要寫入的數(shù)據 * 輸 出 : 無 *******************************************************************************/ void at24c02_write_one_page(uint8_t addr, uint8_t *dat) { i2c_mem_write(ADDR_24C02, addr, dat, 8);at24c02_delay_ms(10); }/******************************************************************************* * 函 數(shù) 名 : at24c02_read_bytes * 函數(shù)功能 : 在AT24CXX指定地址讀出一段數(shù)據 * 輸 入 : addr:寫入數(shù)據的目的地址 pbuffer:要寫入的緩沖區(qū)首地址Len:數(shù)據長度 * 輸 出 : 無 *******************************************************************************/ void at24c02_read_bytes(uint8_t addr, uint8_t* pbuffer, uint8_t Len) { uint8_t pdat_id_S = addr % 8;uint8_t i, pages;if(pdat_id_S){for(i = pdat_id_S; i < 8; ++i){*pbuffer++ = at24c02_read_one_byte(addr++);--Len;if(!Len)return;}}pages = Len / 8;for (i = 0; i < pages; ++i){at24c02_read_one_page(addr, pbuffer);addr += 8;pbuffer += 8;Len -= 8;}if(!Len)return;i2c_mem_read(ADDR_24C02, addr, pbuffer, Len);pbuffer += Len;*pbuffer = '\0'; }/******************************************************************************* * 函 數(shù) 名 : at24c02_write_bytes * 函數(shù)功能 : 在AT24CXX指定地址寫入一段數(shù)據 * 輸 入 : addr:寫入數(shù)據的目的地址 pdat:要寫入的數(shù)據首地址Len:數(shù)據長度 * 輸 出 : 無 *******************************************************************************/ void at24c02_write_bytes(uint8_t addr, uint8_t* pdat, uint8_t Len) { uint8_t Temp[8];uint8_t pdat_id_S = addr % 8;uint8_t i, pages;if(pdat_id_S){for(i = 0; i < pdat_id_S; ++i)Temp[i] = at24c02_read_one_byte(addr - pdat_id_S + i);for (; i < 8; ++i){Temp[i] = *pdat;++pdat;--Len;if(!Len){at24c02_write_one_page(addr - pdat_id_S, Temp);return;}}at24c02_write_one_page(addr - pdat_id_S, Temp);addr = addr + 8 - pdat_id_S;}pages = Len / 8;for (i = 0; i < pages; ++i){at24c02_write_one_page(addr, pdat);addr += 8;pdat += 8;Len -= 8;}if(!Len)return;for (i = 0; i < Len; ++i){Temp[i] = *pdat;++pdat;}for(; i < 8; ++i){Temp[i] = at24c02_read_one_byte(addr + i);}at24c02_write_one_page(addr, Temp); }

    24C02.h

    #ifndef _24C02_H_ #define _24C02_H_#include "stdint.h" #include "intrins.h" #include "Software_I2C.h"#define ADDR_24C02 0x50 //24C02的7位地址void at24c02_write_one_byte(uint8_t addr,uint8_t dat); uint8_t at24c02_read_one_byte(uint8_t addr); void at24c02_write_one_page(uint8_t addr,uint8_t *dat); void at24c02_read_one_page(uint8_t addr, uint8_t *pbuffer);void at24c02_write_bytes(uint8_t addr, uint8_t *pdat, uint8_t Len); void at24c02_read_bytes(uint8_t addr, uint8_t *pbuffer, uint8_t Len);#endif

    測試程序

    串口程序見【51單片機快速入門指南】3.3:USART 串口通信

    main.c

    ???????在地址0x06處連續(xù)寫入
    ???????“123456789098765432123456789012345678909876543212345678901234567890987654321234567890”
    ???????讀取后通過串口返回,波特率為57600,晶振頻率為11.0592MHz。

    #include <STC89C5xRC.H> #include "intrins.h" #include "stdint.h" #include "USART.h" #include "24C02.h"void Delay1ms() //@11.0592MHz {unsigned char i, j;_nop_();i = 2;j = 199;do{while (--j);} while (--i); }void Delay_ms(int i) {while(i--)Delay1ms(); }void main(void) {char Input[] = "123456789098765432123456789012345678909876543212345678901234567890987654321234567890";char Str[sizeof(Input)];USART_Init(USART_MODE_1, Rx_ENABLE, STC_USART_Priority_Lowest, 11059200, 57600, DOUBLE_BAUD_ENABLE, USART_TIMER_1);at24c02_write_bytes(6, Input, sizeof(Input)-1);while(1){Delay_ms(500);at24c02_read_bytes(6, Str, sizeof(Input)-1);printf("%s\r\n", Str);} }

    實驗現(xiàn)象

    如圖,成功讀取

    通訊波形

    寫入部分

    未對齊部分先讀取之前的字節(jié),在對齊順序寫入,并自動換頁



    末尾未對齊部分先讀取后面的字節(jié),再連同要寫入的數(shù)據順序寫入

    讀取部分

    未8位對齊部分為隨機單字節(jié)讀取

    對齊后進行順序讀取,并自動換頁

    末尾未對齊部分也進行順序讀取

    總結

    以上是生活随笔為你收集整理的【51单片机快速入门指南】4.1: I2C 与 AT24C02 (EEPROM) 的跨页连续读写的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。