STM32基礎:IIC總線操作EEPROM存儲模塊AT24C02
參考文檔:AT24C02數據手冊
STM32基礎:IIC概述與軟件模擬IIC一文中,詳細介紹了使用STM32的GPIO口模擬IIC總線的方法,如果讀者對IIC總線還不了解,請先閱讀此文。
本文是IIC總線的實際應用,將帶領讀者一步一步閱讀AT24C02數據手冊,看時序圖了解如何使用IIC接口EEPROM存儲模塊AT24C02,并編寫代碼使用STM32驅動這個模塊。
1 AT24C02概述
1.1 基本描述
《AT24C02數據手冊》P1
從上文可以知道,AT24C02提供2048位串行電可擦除和可編程只讀存儲器(EEPROM),組織256字節。該器件針對許多汽車應用進行了優化,在這些應用中,低功耗和低電壓操作是必不可少的。
AT24C02具有節省空間的8引腳JEDEC SOIC和8引腳TSSOP封裝,可通過 雙線串行接口(即IIC) 訪問。此外,整個系列還提供2.7V (2.7V至5.5V)版本。
1.2 重要特點
AT24C02有如下特點,重點用紅色標出:
《AT24C02數據手冊》P1
- 存儲器內部按組織256字節 × 8位 (2K)組織
- 雙線串行接口(IIC)
- 兼容400kHz通信速率
- 具有硬件數據保護的寫保護引腳
- 8字節/頁寫模式
- 允許部分頁寫入
- 高可靠性:100萬次寫周期,數據保留:100年
1.3 引腳定義
《AT24C02數據手冊》P1
《AT24C02數據手冊》P2
《AT24C02數據手冊》P3
DA、SCL為IIC總線使用引腳不再贅述。從上文可以知道,A2,A1和A0引腳用于AT24C02的設備地址輸入。WP為寫保護引腳,提供硬件數據保護。寫保護引腳在連接到地(GND)時允許正常的讀寫操作。當寫保護引腳接在VCC上時,寫保護功能開啟,操作如下表所示。
《AT24C02數據手冊》P3
在開發板的原理圖上可以看到,設備地址輸入A2、A1、A0都為0,WP已近接在GND上關閉了寫保護,我們可以正常讀寫。
1.4 存儲空間
《AT24C02數據手冊》P4
AT24C02,2K,串行EEPROM內部組織為32頁,每頁8字節,2K需要一個8位的字地址進行隨機字尋址。
1.5 設備地址
《AT24C02數據手冊》P8
2K EEPROM設備都需要一個 8位設備地址字 , 包含一個啟動條件 ,以使芯片能夠進行讀或寫操作。
設備地址字前4位最高有效位為1010。這對所有串行EEPROM設備都是通用的。接下來的3位是1K/2K EEPROM的A2、A1和A0設備地址位。設備地址的第8位是讀寫操作選擇位。如果該位高,則進行讀操作;如果該位低,則進行寫操作。
綜上,如果對AT24C02進行讀操作,則設備地址為10100001B=A1H;如果對AT24C02進行寫操作,則設備地址為10100000B=A0H.
《AT24C02數據手冊》P9
2 AT24C01編程
2.1 寫操作:字編程和頁編程
《AT24C02數據手冊》P8
寫數據有字編程和頁編程兩種方式:
- 字編程:一次寫入一個字節。
- 頁編程:1K/2K EEPROM能夠一次寫入一個8字節的頁。
如果打算寫入數據,則需要知道數據的存儲地址。因為AT24C02的存儲空間為2K(2^11),故尋址空間為02^11-1,即000H7FFH。每頁8字節,故第1頁地址000H,第2頁地址008H,第3頁地址010H,……,第256頁地址7F8H。
下圖描述了字編程寫數據的過程,根據圖中的分析和前文的講述,可以寫出字編程函數:
《AT24C02數據手冊》P10
/**
* @brief AT24C02初始化
*
*/
void AT24C02_Init(void)
{
IIC_Init(); // 初始化IIC總線
}
/**
* @brief AT24C02字節寫入
*
* @param Address: 字節地址
* @param Data: 待寫入的數據
*/
void AT24C02_ByteWrite(uint8_t Address, uint8_t Data)
{
IIC_StartSignal(); // 發送開始信號
// 發送設備地址,寫操作
IIC_SendBytes(0xA0);
if (IIC_WaitACK() == 1) // AT24C02沒應答
{
printf("[AT24C02] Answered the device address: Errorn");
IIC_StopSignal(); // 發送停止信號
}
else
{
printf("[AT24C02] Answered the device address: OKn");
}
// 發送字地址
IIC_SendBytes(Address);
if (IIC_WaitACK() == 1) // AT24C02沒應答
{
printf("[AT24C02] Answered the word address: Errorn");
IIC_StopSignal(); // 發送停止信號
}
else
{
printf("[AT24C02] Answered the word address: OKn");
}
// 發送待寫入的數據
IIC_SendBytes(Data);
if (IIC_WaitACK() == 1) // AT24C02沒應答
{
printf("[AT24C02] Answered the data: Errorn");
IIC_StopSignal(); // 發送停止信號
}
else
{
printf("[AT24C02] Answered the data: OKn");
}
IIC_StopSignal(); // 發送停止信號
}
下圖描述了頁編程寫數據的過程,根據圖中的分析和前文的講述,可以寫出頁編程函數:
《AT24C02數據手冊》P10
/**
* @brief AT24C02頁編程(8字節/頁)
*
* @param Address: 頁地址
* @param buf: 待寫入的數據
* @param DataLen: 待寫入的數據長度
*/
void AT24C02_PageWrite(uint32_t Address, uint8_t *buf, uint8_t DataLen)
{
IIC_StartSignal(); // 發送開始信號
// 發送設備地址,寫操作
IIC_SendBytes(0xA0);
if (IIC_WaitACK() == 1) // AT24C02沒應答
{
printf("[AT24C02] Answered the device address: Errorn");
IIC_StopSignal(); // 發送停止信號
}
else
{
printf("[AT24C02] Answered the device address: OKn");
}
// 發送頁地址
IIC_SendBytes(Address);
if (IIC_WaitACK() == 1) // AT24C02沒應答
{
printf("[AT24C02] Answered the page address: Errorn");
IIC_StopSignal(); // 發送停止信號
}
else
{
printf("[AT24C02] Answered the page address: OKn");
}
// 循環發送數據
while (DataLen--)
{
IIC_SendBytes(*buf++); // 發送數據
if (IIC_WaitACK() == 1) // AT24C02沒應答
{
printf("[AT24C02] Answered the data: Errorn");
IIC_StopSignal(); // 發送停止信號
}
else
{
printf("[AT24C02] Answered the data: OKn");
}
}
IIC_StopSignal(); // 發送停止信號
}
2.2 讀操作:當前地址讀
《AT24C02數據手冊》P19
- 當前地址讀:內部地址計數器保存著上次訪問時最后一個地址加1的值 。(使用”當前地址讀“讀出的數據,其地址為上次訪問的最后一個地址加1。)
- 只要芯片有電,該地址就一直保存,當讀到最后頁的最后字節,地址會回轉到0:
- 當寫到某頁尾的最后一個字節,地址會回轉到該頁的首字節。
- 接收器件地址(讀/寫選擇位為"1")、EEPROM應答ACK后,當前地址的數據就隨時鐘送出。主器件無需應答"0",但需發送停止條件。
《AT24C02數據手冊》P10
根據此圖和前文的講述,編寫當前地址讀函數:
/**
* @brief AT24C02當前地址讀
*
* @return uint8_t 當前地址的數據
*/
uint8_t AT24C02_CurrentAddressRead(void)
{
uint8_t Data;
IIC_StartSignal(); // 發送開始信號
// 發送設備地址,讀操作
IIC_SendBytes(0xA1);
if (IIC_WaitACK() == 1) // AT24C02沒應答
{
printf("[AT24C02] Answered the device address: Errorn");
IIC_StopSignal(); // 發送停止信號
}
else
{
printf("[AT24C02] Answered the device address: OKn");
}
// 讀取1字節數據
Data = IIC_ReadBytes();
// 發送應答信號
IIC_MasterACK(1); // 不應答
IIC_StopSignal(); // 發送停止信號
return Data; // 返回接收到的數據
}
下面我們測試前面寫的四個函數(AT24C02_Init
,AT24C02_ByteWrite
,AT24C02_PageWrite
,AT24C02_CurrentAddressRead
),測試過程為:
- 使用
AT24C02_Init
初始化AT24C02 - 使用
AT24C02_PageWrite
向0x00寫入“0123456” - 使用
AT24C02_ByteWrite
向0x07寫入“7” - 使用
AT24C02_CurrentAddressRead
進行“當前地址讀”
(0x00-0x07已經被寫入“01234567”,即第一頁寫滿了,此時地址會回到該頁首字節,使用“當前地址讀”讀出的應該是該頁第一個字節“0”)
如果輸出的提示信息全部正常且返回值為“0”則說明這四個函數編寫正確。測試效果如下圖,測試成功。
uint8_t data;
AT24C02_Init()
AT24C02_PageWrite(0x00, "0123456", 6);
HAL_Delay(100);
AT24C02_ByteWrite(0x07, '7');
HAL_Delay(100);
data = AT24C02_CurrentAddressRead();
printf("AT24C02_CurrentAddressRead: %c", data);
2.3 讀操作:隨機讀
《AT24C02數據手冊》P9
隨機讀需先寫一個目標字地址 ,一旦EEPROM接收器設備地址(讀/寫選擇位為"0")和字地址并應答了ACK,主機就產生一個重復的起始條件。然后,主器件發送設備地址(讀/寫選擇位為"1"),EEPROM應答ACK,并隨時鐘送出數據。主器件無需應答"0",但需發送停止條件。
《AT24C02數據手冊》P11
根據此圖和前文的講述,編寫隨機讀函數:
/**
* @brief AT24C02隨機讀1字節數據
*
* @param Address: 字地址
* @return uint8_t 讀取到的數據
*/
uint8_t AT24C02_RandomRead(uint8_t Address)
{
uint8_t Data;
IIC_StartSignal(); // 發送開始信號
// 發送設備地址,寫操作
IIC_SendBytes(0xA0);
if (IIC_WaitACK() == 1) // AT24C02沒應答
{
printf("[AT24C02] Answered the device address: Errorn");
IIC_StopSignal(); // 發送停止信號
}
else
{
printf("[AT24C02] Answered the device address: OKn");
}
// 發送字數據的地址
IIC_SendBytes(Address);
if (IIC_WaitACK() == 1) // AT24C02沒應答
{
printf("[AT24C02] Answered the word address: Errorn");
IIC_StopSignal(); // 發送停止信號
}
else
{
printf("[AT24C02] Answered the word address: OKn");
}
IIC_StartSignal(); // 發送開始信號
// 發送設備地址,讀操作
IIC_SendBytes(0xA1);
if (IIC_WaitACK() == 1) // AT24C02沒應答
{
printf("[AT24C02] Answered the device address: Errorn");
IIC_StopSignal(); // 發送停止信號
}
else
{
printf("[AT24C02] Answered the device address: OKn");
}
// 讀取1字節數據
Data = IIC_ReadBytes();
// 發送應答信號
IIC_MasterACK(1); // 不應答
IIC_StopSignal(); // 發送停止信號
return Data; // 返回接收到的數據
}
下面我們測試AT24C02_RandomRead
函數,測試過程為:
- 使用
AT24C02_Init
初始化AT24C02 - 使用
AT24C02_PageWrite
向0x00寫入“01234567” - 使用
AT24C02_RandomRead
讀出0x07處的數據
uint8_t data;
AT24C02_Init();
AT24C02_PageWrite(0x00, "01234567", 7);
HAL_Delay(100);
data = AT24C02_RandomRead(0x07);
printf("AT24C02_RandomRead: %c", data);
如果輸出的提示信息全部正常且返回值為“7”則說明函數編寫正確。測試效果如下圖,測試成功。
如果想要“隨機讀”函數可以一次讀取多個字節,可以修改函數為如下形式:
/**
* @brief AT24C02隨機讀n個字節
*
* @param Address: 字地址
* @param RecvBuf: 接收緩沖區
* @param DataLen: 接收數據長度
*/
void AT24C02_RandomRead(uint8_t Address, uint8_t *RecvBuf, uint8_t DataLen)
{
uint8_t Data;
IIC_StartSignal(); // 發送開始信號
// 發送設備地址,寫操作
IIC_SendBytes(0xA0);
if (IIC_WaitACK() == 1) // AT24C02沒應答
{
printf("[AT24C02] Answered the device address: Errorn");
IIC_StopSignal(); // 發送停止信號
}
else
{
printf("[AT24C02] Answered the device address: OKn");
}
// 發送字數據的地址
IIC_SendBytes(Address);
if (IIC_WaitACK() == 1) // AT24C02沒應答
{
printf("[AT24C02] Answered the word address: Errorn");
IIC_StopSignal(); // 發送停止信號
}
else
{
printf("[AT24C02] Answered the word address: OKn");
}
IIC_StartSignal(); // 發送開始信號
// 發送設備地址,讀操作
IIC_SendBytes(0xA1);
if (IIC_WaitACK() == 1) // AT24C02沒應答
{
printf("[AT24C02] Answered the device address: Errorn");
IIC_StopSignal(); // 發送停止信號
}
else
{
printf("[AT24C02] Answered the device address: OKn");
}
// 讀取n字節數據
DataLen -= 1;
while (DataLen--) // 讀取n-1字節數據,最后1字節數據單獨讀取
{
*RecvBuf++ = IIC_ReadBytes();
// 發送應答信號
IIC_MasterACK(0); // 應答
}
*RecvBuf++ = IIC_ReadBytes(); // 讀取最后1字節數據
// 發送應答信號
IIC_MasterACK(1); // 不應答
IIC_StopSignal(); // 發送停止信號
return Data; // 返回接收到的數據
}
下面我們測試AT24C02_RandomRead
函數,測試過程為:
- 使用
AT24C02_Init
初始化AT24C02 - 使用
AT24C02_PageWrite
向0x00寫入“01234567” - 使用
AT24C02_RandomRead
讀出0x00-0x07處的數據
uint8_t RecvBuf[10] = {0};
AT24C02_Init();
AT24C02_PageWrite(0x00, "01234567", 8);
HAL_Delay(100);
AT24C02_RandomRead(0x00, RecvBuf, 8);
printf("AT24C02_RandomRead: %s", RecvBuf);
如果輸出的提示信息全部正常且返回值為“01234567”則說明函數編寫正確。測試效果如下圖,測試成功。
2.4 讀操作:順序讀
《AT24C02數據手冊》P9
AT24C02還有一種讀操作,就是順序讀取。順序讀取由當前地址讀取或隨機地址讀取啟動。主機接收到一個數據字后,它以確認響應。只要 EEPROM 接收到應答,將自動增加字地址并繼續隨時鐘發送后面的數據。當達到內存地址限制時,地址自動回轉到0,認可繼續順序讀取數據。主機不應答“0”,而發送停止條件,即可結束順序讀操作。
《AT24C02數據手冊》P11
正所謂“紙上得來終覺淺,絕知此事要躬行”。在對順序讀寫略加分析后,順序讀取的代碼這里不再給出,讀者可以結合本文對前面幾種讀寫操作的講解和順序讀操作的流程自行完成。
-
STM32
+關注
關注
2242文章
10680瀏覽量
349251 -
EEPROM
+關注
關注
9文章
928瀏覽量
80466 -
IIC總線
+關注
關注
1文章
65瀏覽量
20181 -
存儲模塊
+關注
關注
0文章
14瀏覽量
8838
發布評論請先 登錄
相關推薦
評論