EEPROM (Electrically Erasable Programmable read only memory)是指帶電可擦可編程只讀存儲器。是一種掉電后數據不丟失的存儲芯片。EEPROM 可以在電腦上或專用設備上擦除已有信息,重新編程。一般用在即插即用。AT24C02是一個2K位串行CMOS E2PROM, 內部含有256個8位字節,CATALYST公司的先進CMOS技術實質上減少了器件的功耗。AT24C02有一個16字節頁寫緩沖器。該器件通過IIC總線接口進行操作,有一個專門的寫保護功能。
一、模塊來源
模塊實物展示:
二、規格參數
工作電壓:1.8V-5.5V
工作電流:最大3mA
通信接口:IIC
內存:2048位
時鐘速度:5V時最大1000Khz,其余為400Khz
以上信息見廠家資料文件
三、移植過程
我們的目標是將例程移植至CW32F030C8T6開發板上【能夠播報語音的功能】。首先要獲取資料,查看數據手冊應如何實現讀取數據,再移植至我們的工程。
3.1查看資料
上圖是AT24CXX的設備地址(第一行的為AT24C02,它的容量為2K),我們發現AT24CXX整個系列芯片的地址高四位都相同,都是1010,這四位是由生產商固化在芯片內部,無法改變。
AT24C02地址的低三位(不包括讀寫位)對應芯片的三個引腳,也就是說這三位是可以人為設定的,23=8,所以一條I2C總線上可以掛載8個AT24C02。
AT24C02的地址為7位二進制數,下圖中最后一位是讀寫位(數據方向位),1 表示讀數據,0 表示寫數據。
這樣,7位設備地址加1位讀寫位,構成I2C的尋址數據。I2C 總線的尋址過程中,通常在起始條件后的第一個字節決定了主機選擇哪一個從機,該字節的最后一位決定數據傳輸方向。
AT24C02讀寫:AT24C02的存儲空間為2K位(256字節),在對其進行寫數據時,最小寫入單位為字節(Byte),最大寫入單位為頁(Page),AT24C02頁大小為 16 Byte。
字節寫
在字節寫模式下,主器件發送起始信號和從器件地址信息(R/W 位置零)給從器件,在從器件送回應答信號后,主器件發送 AT24WC01/02/04/08/16 的字節地址,主器件在收到從器件的應答信號后,再發送數據到被尋址的存儲單元。AT24WC01/02/04/08/16 再次應答,并在主器件產生停止信號后開始內部數據的擦寫,在內部擦寫過程中,AT24WC01/02/04/08/16 不再應答主器件的任何請求。
頁寫
用頁寫,AT24WC01 可一次寫入 8 個字節數據,AT24WC02/04/08/16 可以一次寫入 16 個字節的數據,頁寫操作的啟動和字節寫一樣,不同在于傳送了一字節數據后并不產生停止信號,主器件被允許發送 P(AT24WC01 P=7;AT24WC02/04/08/16 P=15)個額外的字節。每發送一個字節數據后 AT24WC01/02/04/08/16 產生一個應答位并將字節地址低位加 1,高位保持不變。
如果在發送停止信號之前主器件發送超過P+1個字節,地址計數器將自動翻轉,先前寫入的數據被覆蓋。
接收到P+1字節數據和主器件發送的停止信號后,AT24CXXX啟動內部寫周期將數據寫到數據區,所有接收的數據在一個寫周期內寫入AT24WC01/02/04/08/16。
當前地址讀
AT24WC01/02/04/08/16 的地址計數器內容為最后操作字節的地址加 1。也就是說 如果上次讀/寫的操作地址為 N,則立即讀的地址從地址 N+1 開始。如果 N=E(這里對 24WC01 E=127;對 24WC02 E=255;對 24WC04 E=511;對 24WC08 E=1023;對 24WC16 E=2047)則計數器將翻轉到 0 且繼續輸出數據。AT24WC01/02/04/08/16 接收到從器件地址信號后(R/W 位置 1),它首先發送一個應答信號,然后發送一個 8 位字節數據。主器件不需發送一個應答信號,但要產生一個停止信號。
選擇讀(隨機讀)
選擇性讀操作允許主器件對寄存器的任意字節進行讀操作,主器件首先通過發送起始信號、從器件地址和它想讀取的字節數據的地址執行一個偽寫操作。在 AT24WC01/02/04/08/16 應答之后,主器件重新發送起始信號和從器件地址,此時 R/W 位置 1,AT24WC01/02/04/08/16 響應并發送應答信號,然后輸出所要求的一個 8 位字節數據,主器件不發送應答信號但產生一個停止信號。
連續讀
連續讀操作可通過立即讀或選擇性讀操作啟動。在 AT24WC01/02/04/08/16 發送完一個 8 位字節數據后,主器件產生一個應答信號來響應,告知 AT24WC01/02/04/08/16 主器件要求更多的數據,對應每個主機產生的應答信號 AT24WC01/02/04/08/16 將發送一個 8 位數據字節。當主器件不發送應答信號而發送停止位時結束此操作。
從 AT24WC01/02/04/08/16 輸出的數據按順序由 N 到 N+1 輸出。讀操作時地址計數器在 AT24WC01/02/04/08/16 整個地址內增加,這樣整個寄存器區域在可在一個讀操作內全部讀出。當讀取的字節超過 E(對于 24WC01 E=127;對 24WC02 E=255; 對 24WC04 E=511;對 24WC08 E=1023;對 24WC16 E=2047)計數器將翻轉到零并繼續輸出數據字節。
3.2引腳選擇
模塊接線圖
3.3移植至工程
移植步驟中的導入.c和.h文件與【CW32模塊使用】DHT11溫濕度傳感器相同,只是將.c和.h文件更改為bsp_at24c02.c與bsp_at24c02.h。這里不再過多講述,移植完成后面修改相關代碼。
在文件bsp_at24c02.c中,編寫如下代碼。
/* * Change Logs: * Date Author Notes * 2024-06-25 LCKFB-LP first version */ #include "bsp_at24c02.h" #include "stdio.h" // SLAVE ADDRESS+W為0xA0,SLAVE ADDRESS+R為0xA1 #define AT24C02_ADDRESS_READ 0xA0 #define AT24C02_ADDRESS_WRITE 0xA1 /****************************************************************** * 函 數 名 稱:AT24C02_GPIO_Init * 函 數 說 明:AT24C02的引腳初始化 * 函 數 形 參:無 * 函 數 返 回:無 * 作 者:LC * 備 注:無 ******************************************************************/ void AT24C02_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; // GPIO初始化結構體 RCC_AT24C02_GPIO_ENABLE(); // 使能GPIO時鐘 GPIO_InitStruct.Pins = GPIO_SDA|GPIO_SCL; // GPIO引腳 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; // 開漏輸出 GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; // 輸出速度高 GPIO_Init(PORT_AT24C02, &GPIO_InitStruct); // 初始化 } /****************************************************************** * 函 數 名 稱:IIC_Start * 函 數 說 明:IIC起始時序 * 函 數 形 參:無 * 函 數 返 回:無 * 作 者:LC * 備 注:無 ******************************************************************/ void IIC_Start(void) { SDA_OUT(); SDA(1); delay_us(5); SCL(1); delay_us(5); SDA(0); delay_us(5); SCL(0); delay_us(5); } /****************************************************************** * 函 數 名 稱:IIC_Stop * 函 數 說 明:IIC停止信號 * 函 數 形 參:無 * 函 數 返 回:無 * 作 者:LC * 備 注:無 ******************************************************************/ void IIC_Stop(void) { SDA_OUT(); SCL(0); SDA(0); SCL(1); delay_us(5); SDA(1); delay_us(5); } /****************************************************************** * 函 數 名 稱:IIC_Send_Ack * 函 數 說 明:主機發送應答或者非應答信號 * 函 數 形 參:0發送應答 1發送非應答 * 函 數 返 回:無 * 作 者:LC * 備 注:無 ******************************************************************/ void IIC_Send_Ack(unsigned char ack) { SDA_OUT(); SCL(0); SDA(0); delay_us(5); if(!ack) SDA(0); else SDA(1); SCL(1); delay_us(5); SCL(0); SDA(1); } /****************************************************************** * 函 數 名 稱:I2C_WaitAck * 函 數 說 明:等待從機應答 * 函 數 形 參:無 * 函 數 返 回:0有應答 1超時無應答 * 作 者:LC * 備 注:無 ******************************************************************/ unsigned char I2C_WaitAck(void) { char ack = 0; unsigned char ack_flag = 10; SCL(0); SDA(1); SDA_IN(); delay_us(5); SCL(1); delay_us(5); while( (SDA_GET()==1) && ( ack_flag ) ) { ack_flag--; delay_us(5); } if( ack_flag <= 0 ) { IIC_Stop(); return 1; } else { SCL(0); SDA_OUT(); } return ack; } /****************************************************************** * 函 數 名 稱:Send_Byte * 函 數 說 明:寫入一個字節 * 函 數 形 參:dat要寫入的數據 * 函 數 返 回:無 * 作 者:LC * 備 注:無 ******************************************************************/ void Send_Byte(uint8_t dat) { int i = 0; SDA_OUT(); SCL(0);//拉低時鐘開始數據傳輸 for( i = 0; i < 8; i++ ) { SDA( (dat & 0x80) >> 7 ); delay_us(1); SCL(1); delay_us(5); SCL(0); delay_us(5); dat<=1; } } /****************************************************************** * 函 數 名 稱:Read_Byte * 函 數 說 明:IIC讀時序 * 函 數 形 參:無 * 函 數 返 回:讀到的數據 * 作 者:LC * 備 注:無 ******************************************************************/ unsigned char Read_Byte(void) { unsigned char i,receive=0; SDA_IN();//SDA設置為輸入 for(i=0;i8;i++ ) { SCL(0); delay_us(5); SCL(1); delay_us(5); receive<=1; if( SDA_GET() ) { receive|=1; } delay_us(5); } SCL(0); return receive; } /****************************************************************** * 函 數 名 稱:AT24C02_WriteByte * 函 數 說 明:AT24C02寫入一個字節 * 函 數 形 參:WordAddress 要寫入字節的地址 Data 要寫入的數據 * 函 數 返 回:無 * 作 者:LC * 備 注:無 ******************************************************************/ void AT24C02_WriteByte(unsigned char WordAddress,unsigned char Data) { IIC_Start(); Send_Byte(AT24C02_ADDRESS_READ); I2C_WaitAck(); Send_Byte(WordAddress); I2C_WaitAck(); Send_Byte(Data); I2C_WaitAck(); IIC_Stop(); } /****************************************************************** * 函 數 名 稱:AT24C02_ReadByte * 函 數 說 明:AT24C02讀取一個字節 * 函 數 形 參:WordAddress 要讀出字節的地址 * 函 數 返 回:讀出的數據 * 作 者:LC * 備 注:無 ******************************************************************/ unsigned char AT24C02_ReadByte(unsigned char WordAddress) { unsigned char Data; IIC_Start(); Send_Byte(AT24C02_ADDRESS_READ); I2C_WaitAck(); Send_Byte(WordAddress); I2C_WaitAck(); IIC_Start(); Send_Byte(AT24C02_ADDRESS_WRITE); I2C_WaitAck(); Data=Read_Byte(); IIC_Send_Ack(1); IIC_Stop(); return Data; }
在文件bsp_at24c02.h中,編寫如下代碼。
/* * Change Logs: * Date Author Notes * 2024-06-25 LCKFB-LP first version */ #ifndef _BSP_AT24C02_H_ #define _BSP_AT24C02_H_ #include "board.h" //端口移植 #define RCC_AT24C02_GPIO_ENABLE() __RCC_GPIOB_CLK_ENABLE() #define PORT_AT24C02 CW_GPIOB #define GPIO_SDA GPIO_PIN_8 #define GPIO_SCL GPIO_PIN_9 //設置SDA輸出模式 #define SDA_OUT() { GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Pins = GPIO_SDA; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; GPIO_Init(PORT_AT24C02, &GPIO_InitStruct); } //設置SDA輸入模式 #define SDA_IN() { GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Pins = GPIO_SDA; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; GPIO_Init(PORT_AT24C02, &GPIO_InitStruct); } //獲取SDA引腳的電平變化 #define SDA_GET() GPIO_ReadPin(PORT_AT24C02, GPIO_SDA) //SDA與SCL輸出 #define SDA(x) GPIO_WritePin(PORT_AT24C02, GPIO_SDA, (x?GPIO_Pin_SET:GPIO_Pin_RESET) ) #define SCL(x) GPIO_WritePin(PORT_AT24C02, GPIO_SCL, (x?GPIO_Pin_SET:GPIO_Pin_RESET) ) void AT24C02_GPIO_Init(void); void AT24C02_WriteByte(unsigned char WordAddress,unsigned char Data); unsigned char AT24C02_ReadByte(unsigned char WordAddress); #endif
四、移植驗證
在自己工程中的main主函數中,編寫如下。
/* * Change Logs: * Date Author Notes * 2024-06-25 LCKFB-LP first version */ #include "board.h" #include "stdio.h" #include "bsp_uart.h" #include "bsp_at24c02.h" int32_t main(void) { unsigned char dat1 = 0; unsigned char dat2 = 0; board_init(); uart1_init(115200U); AT24C02_GPIO_Init(); printf("startrn"); //向0地址寫入數據48 AT24C02_WriteByte(0,48); delay_ms(5); //向8地址寫入數據48 AT24C02_WriteByte(8,66); delay_ms(5); //從0地址讀取數據到dat1 dat1 = AT24C02_ReadByte(0); delay_ms(5); //從8地址讀取數據到dat2 dat2 = AT24C02_ReadByte(8); delay_ms(5); delay_ms(50); //輸出dat查看數據是否正確 printf("dat1 = %drn",dat1); delay_ms(1); printf("dat2 = %drn",dat2); delay_ms(1); while(1) { } }
移植現象:
向0地址寫入數據48,再讀出查看是否是48。
向8地址寫入數據66,再讀出查看是否是66。
模塊移植成功案例代碼:
鏈接:https://pan.baidu.com/s/1vMkhtubSlSjCLW960FccxQ?pwd=LCKF
提取碼:LCKF
-
存儲器
+關注
關注
38文章
7595瀏覽量
165681 -
EEPROM
+關注
關注
9文章
1060瀏覽量
82872 -
存儲芯片
+關注
關注
11文章
915瀏覽量
43743 -
CW32
+關注
關注
1文章
232瀏覽量
1000
發布評論請先 登錄
相關推薦
STM32基礎知識:IIC總線操作EEPROM存儲模塊AT24C02

使用51單片機和EEPROM存儲器24C02保持保存實現流水燈的程序

使用51單片機進行EEPROM存儲器24C02讀取存儲多字節的程序免費下載

評論