前言:
為了友善檢視部落格,特意申請了一個公衆号,附上二維碼,有興趣的朋友可以關注,和我一起讨論學習,一起享受技術,一起成長。
github:my github
注:部落格所涉及的關于 stm32 的代碼,均在倉庫【stm32f013_study】下,包括底層驅動和應用測試代碼。
本文設計的檔案包含:
(1)drvsfi2c.c:軟體模拟 i2c 驅動實作
(2)app_at24cxx.c:AT24C02 測試實作
(3)頭檔案:
drvsfi2c.h : 軟體模拟I2C;
app_at24cxx.h:AT24C02 應用測試;
1. 概述
MiniSTM32 開發闆闆載的 EEPROM 晶片型号為 24C02。該晶片的總容量是 256個位元組,該晶片通過 I2C 總線與外部連接配接。這裡直接采用原子闆上的 AT24C02 ,主要是軟體程式設計方面的學習。
2. 硬體連接配接
A2、A1、A0 三個引腳直接接地。供電: (VCC = 2.7V to 5.5V)
器件位址設定:
對于AT24C02:Addr—>0xA0(寫)/ 0xA1(讀)。
單位元組寫入:
//--------------------------------------------------------------------------------------------------------------------------
// 函 數 名: ee_at24cxx_write_byte
// 功能說明: eeprom寫一個位元組資料
// 形 參: write_addr:寫入位址
// write_byte:寫入資料
// 返 回 值: 無
// 日 期: 2020-03-22
// 備 注: eeprom小于16K bits
// 作 者: by 霁風AI
//--------------------------------------------------------------------------------------------------------------------------
bool ee_at24cxx_write_byte(uint16_t write_addr, uint8_t write_byte)
{
I2c_Start();
I2c_SendOneByte(AT24CXX_ADDR | ((write_addr / 256) << 1)); //發送裝置位址+資料位址高3位(<16K:1010 + p2p1p0 + r/w)
if (I2c_WaitAck(I2C_WAIT_TIME) == I2C_NACK)
{
return false;
}
I2c_SendOneByte(write_addr % 256); //裝置位址低8位
if (I2c_WaitAck(I2C_WAIT_TIME) == I2C_NACK)
{
return false;
}
I2c_SendOneByte(write_byte); //寫入的資料
if (I2c_WaitAck(I2C_WAIT_TIME) == I2C_NACK)
{
return false;
}
I2c_Stop();
delay_ms(5 ); //寫完一個位元組需要延時重新開啟總線
return true;
}
按頁寫入:
從目前位址讀出資料;
//--------------------------------------------------------------------------------------------------------------------------
// 函 數 名: ee_at24cxx_read_byte
// 功能說明: eeprom讀一個位元組資料
// 形 參: write_addr:讀出位址
// write_byte:讀出資料
// 返 回 值: 無
// 日 期: 2020-03-22
// 備 注: eeprom小于16K bits(先确定讀資料位址,再進行讀資料)
// 作 者: by 霁風AI
//--------------------------------------------------------------------------------------------------------------------------
bool ee_at24cxx_read_byte(uint16_t read_addr)
{
uint8_t ret = 0;
I2c_Start();
I2c_SendOneByte(AT24CXX_ADDR | ((read_addr / 256) << 1)); //發送位址高3位(<16K:1010 + p2p1p0 + r/w)
if (I2c_WaitAck(I2C_WAIT_TIME) == I2C_NACK)
{
return false;
}
I2c_SendOneByte(read_addr % 256);
if (I2c_WaitAck(I2C_WAIT_TIME) == I2C_NACK)
{
return false;
}
I2c_Start();
I2c_SendOneByte(AT24CXX_ADDR | 0x01); //裝置位址 + 讀操作
if (I2c_WaitAck(I2C_WAIT_TIME) == I2C_NACK)
{
return false;
}
ret = I2c_RecvOneByte(I2C_NACK);
I2c_Stop();
return ret;
}
随機讀取:
順序讀出:
3. 例程分析
(一)I2C 部分實作代碼
包括 IIC 的初始化(IO 口)、 IIC 開始、 IIC 結束、 ACK、 IIC 讀寫等功能,在其他函數裡面,隻需要調用相關的 IIC 函數就可以和外部 IIC 器件通信了,這裡并不局限于 24C02,該段代碼可以用在任何 IIC 裝置上。
IIC_SCL 和 IIC_SDA 分别連在 STM32 的 PC12 和 PC11。
I2C 部分的代碼請參看---->STM32 驅動溫濕度傳感器 HTU21D
(二)AT24C02 操作
1. 初始化
//--------------------------------------------------------------------------------------------------------------------------
// 函 數 名: ee_at24cxx_init
// 功能說明: eeprom初始化
// 形 參: 無
// 返 回 值: 無
// 日 期: 2020-03-22
// 備 注: 調用I2c_Init
// 作 者: by 霁風AI
//--------------------------------------------------------------------------------------------------------------------------
void ee_at24cxx_init(void)
{
I2c_Init();
}
2. 在 AT24CXX 指定位址讀出一個資料
//--------------------------------------------------------------------------------------------------------------------------
// 函 數 名: ee_at24cxx_read_byte
// 功能說明: eeprom讀一個位元組資料
// 形 參: write_addr:讀出位址
// write_byte:讀出資料
// 返 回 值: 無
// 日 期: 2020-03-22
// 備 注: eeprom小于16K bits(先确定讀資料位址,再進行讀資料)
// 作 者: by 霁風AI
//--------------------------------------------------------------------------------------------------------------------------
bool ee_at24cxx_read_byte(uint16_t read_addr)
{
uint8_t ret = 0;
I2c_Start();
I2c_SendOneByte(AT24CXX_ADDR | ((read_addr / 256) << 1)); //發送位址高3位(<16K:1010 + p2p1p0 + r/w)
if (I2c_WaitAck(I2C_WAIT_TIME) == I2C_NACK)
{
return false;
}
I2c_SendOneByte(read_addr % 256);
if (I2c_WaitAck(I2C_WAIT_TIME) == I2C_NACK)
{
return false;
}
I2c_Start();
I2c_SendOneByte(AT24CXX_ADDR | 0x01); //裝置位址 + 讀操作
if (I2c_WaitAck(I2C_WAIT_TIME) == I2C_NACK)
{
return false;
}
ret = I2c_RecvOneByte(I2C_NACK);
I2c_Stop();
return ret;
}
3. 在 AT24CXX 指定位址寫入一個資料
//--------------------------------------------------------------------------------------------------------------------------
// 函 數 名: ee_at24cxx_write_byte
// 功能說明: eeprom寫一個位元組資料
// 形 參: write_addr:寫入位址
// write_byte:寫入資料
// 返 回 值: 無
// 日 期: 2020-03-22
// 備 注: eeprom小于16K bits
// 作 者: by 霁風AI
//--------------------------------------------------------------------------------------------------------------------------
bool ee_at24cxx_write_byte(uint16_t write_addr, uint8_t write_byte)
{
I2c_Start();
I2c_SendOneByte(AT24CXX_ADDR | ((write_addr / 256) << 1)); //發送裝置位址+資料位址高3位(<16K:1010 + p2p1p0 + r/w)
if (I2c_WaitAck(I2C_WAIT_TIME) == I2C_NACK)
{
return false;
}
I2c_SendOneByte(write_addr % 256); //裝置位址低8位
if (I2c_WaitAck(I2C_WAIT_TIME) == I2C_NACK)
{
return false;
}
I2c_SendOneByte(write_byte); //寫入的資料
if (I2c_WaitAck(I2C_WAIT_TIME) == I2C_NACK)
{
return false;
}
I2c_Stop();
delay_ms(5 ); //寫完一個位元組需要延時重新開啟總線
return true;
}
4. AT24CXX 裡面的指定位址開始讀出指定個數的資料
//--------------------------------------------------------------------------------------------------------------------------
// 函 數 名: ee_at24cxx_read_some_bytes
// 功能說明: eeprom讀出一些位元組資料
// 形 參: read_addr:讀出裝置位址
// pbdata:讀出資料位址
// read_length:讀出資料長度
// 返 回 值: 無
// 日 期: 2020-03-22
// 備 注: eeprom小于16K bits,循環調用ee_at24cxx_read_byte
// 作 者: by 霁風AI
//--------------------------------------------------------------------------------------------------------------------------
uint16_t ee_at24cxx_read_some_bytes(uint16_t read_addr, uint8_t *pbdata, uint16_t read_length)
{
uint16_t temp = read_length;
while (temp--)
{
*pbdata++ = ee_at24cxx_read_byte(read_addr);
read_addr++; //讀出位址遞增
}
return read_length;
}
5. AT24CXX 裡面的指定位址開始寫入指定個數的資料
//--------------------------------------------------------------------------------------------------------------------------
// 函 數 名: ee_at24cxx_write_some_bytes
// 功能說明: eeprom寫一些位元組資料
// 形 參: write_addr:寫入裝置位址
// pbdata:寫入資料位址
// write_length:寫入資料長度
// 返 回 值: 無
// 日 期: 2020-03-22
// 備 注: eeprom小于16K bits,循環調用ee_at24cxx_write_byte
// 作 者: by 霁風AI
//--------------------------------------------------------------------------------------------------------------------------
void ee_at24cxx_write_some_bytes(uint16_t write_addr, uint8_t *pbdata, uint16_t write_length)
{
for (uint16_t i = 0; i < write_length; i++)
{
ee_at24cxx_write_byte(write_addr, pbdata[i]);
write_addr++; //寫入位址遞增
}
}
6. AT24CXX 讀寫測試
//--------------------------------------------------------------------------------------------------------------------------
// 函 數 名: ee_at24cxx_test
// 功能說明: eeprom測試
// 形 參: 無
// 返 回 值: 無
// 日 期: 2020-03-22
// 備 注: eeprom小于16K bits
// 作 者: by 霁風AI
//--------------------------------------------------------------------------------------------------------------------------
#define AT_TEST_ADDR 0x10
void ee_at24cxx_test(void)
{
uint8_t test_val = 0x55;
uint8_t ret = 0;
uint8_t write_buf[10] = {0xcc, 0xaa, 0x66, 0x5a, 0x77, 0x89, 0x33, 0xbb, 0xac, 0xe9};
uint8_t read_buf[10] = {0};
ee_at24cxx_write_byte(0x00, test_val);
Sys_delay_ms(10);
ret = ee_at24cxx_read_byte(0x00);
printf("ee at24cxx test val :0x%02x \r\n", ret);
ee_at24cxx_write_some_bytes(AT_TEST_ADDR, write_buf, sizeof(write_buf));
Sys_delay_ms(50);
ee_at24cxx_read_some_bytes(AT_TEST_ADDR, read_buf, sizeof(write_buf));
for (uint16_t i = 0; i < sizeof(write_buf); i++)
{
printf("ee test some byte ---> 0x%02x \r\n", read_buf[i]);
}
printf("\r\n");
}
測試結果:
參考:
- 原子 STM32 開發庫函數版本
- STM32 驅動溫濕度傳感器 HTU21D