基于cubemx的stm32f103硬體讀寫EEPROM
今天介紹一種可擦除存儲器.
EEPROM (Electrically Erasable Programmable read only memory)是指帶電可擦可程式設計隻讀存儲器。是一種掉電後資料不丢失的存儲晶片。EEPROM 可以在電腦上或專用裝置上擦除已有資訊,重新程式設計。一般用在即插即用。(百度百科)
一般正常單片機的EEPROM是AT24C02
(AT24C02是一個2K位串行CMOS E2PROM, 内部含有256個8位位元組,CATALYST公司的先進CMOS技術實質上減少了器件的功耗。AT24C02有一個16位元組頁寫緩沖器。該器件通過IIC總線接口進行操作,有一個專門的寫保護功能。【百度百科】)
EEPROM 晶片最常用的通訊方式就是 I2C 協定,在上一篇文章我們介紹了用軟體IIC寫OLED,今天我們采用硬體IIC(因為軟體IIC調試出了問題,還沒解決,解決了補上傳)。
打開cubemx配置硬體IIC,順便配置一下序列槽友善監測資料。
讀寫eeprom主要用這句函數
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)
參數解釋
對這句函數做一下小的封裝,就可以寫入位元組,和頁寫入。寫之前要注意eeprom的寫位址是0XA0,讀位址0XA1。
//隻寫
uint8_t At24c02_Write_Byte(uint16_t addr, uint8_t* data)
{
return HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, addr, I2C_MEMADD_SIZE_8BIT, data, 1, 0xFFFF);
}
//隻讀
uint8_t At24c02_Read_Byte(uint16_t addr, uint8_t* data,uint16_t size)
{
return HAL_I2C_Mem_Read(&hi2c1, AT24C02_ADDR_READ, addr, I2C_MEMADD_SIZE_8BIT, data, size, 0xFFFF);
}
//參數為寫位址,寫的資料(一般可以定義一個數組),讀位址
void eeprom_onebit_rw(uint16_t write_addr, uint8_t* write_dat,uint16_t read_addr)
{
uint8_t recv_buf=0;//讀取資料的數組
if(HAL_OK == HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, write_addr, I2C_MEMADD_SIZE_8BIT, write_dat, 1, 0xFFFF))
{
printf("EEPROM WRITE OK\n");
}
else
{
printf("WRITE FAIL\n");
}
HAL_Delay(5); //5毫秒延時
if(HAL_OK == HAL_I2C_Mem_Read(&hi2c1, AT24C02_ADDR_READ, read_addr, I2C_MEMADD_SIZE_8BIT, &recv_buf, 1, 0xFFFF))
{
printf("Read Ok, recv_data = %d\n ",recv_buf);
}
else
{
printf("Read Fail\n");
}
}
直接将函數放在主函數裡面調用,序列槽列印資料
函數中5ms的延時很重要,如果沒有延時,資料寫會失敗
這是單個位元組寫入。一位元組寫一位元組寫很麻煩,是以我們繼續封裝,編寫頁寫入函數。
首先我們知道eeprom每頁8個位元組,位址從0-255,借鑒野火的頁寫入方法,相應參數移植前做更改,可以自己寫一寫試一下
uint32_t I2C_EE_PageWrite(uint8_t* pBuffer, uint8_t WriteAddr,uint8_t NumByteToWrite)
{
HAL_StatusTypeDef status = HAL_OK;
/* Write EEPROM_PAGESIZE */
status=HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_READ,WriteAddr,I2C_MEMADD_SIZE_8BIT, (uint8_t*)(pBuffer),NumByteToWrite, 100);
while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY){
}
/* Check if the EEPROM is ready for a new operation */
while (HAL_I2C_IsDeviceReady(&hi2c1, AT24C02_ADDR_WRITE,3000, 0xffff) == HAL_TIMEOUT);
/* Wait for the end of the transfer */
while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY) {
}
return status;
}
//void I2C_EE_WaitEepromStandbyState(void); //是等待響應的函數,不再展開
/**
* @brief 将緩沖區中的資料寫到 I2C EEPROM 中
* @param
* @arg pBuffer:緩沖區指針
* @arg WriteAddr:寫位址
* @arg NumByteToWrite:寫的位元組數
* @retval 無
*/
#define I2C_PageSize 8
void I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr,u16 NumByteToWrite)
{
u8 NumOfPage=0,NumOfSingle=0,Addr =0,count=0,temp =0;
/*mod 運算求餘,若 writeAddr 是 I2C_PageSize 整數倍,
運算結果 Addr 值為 0*/
Addr = WriteAddr % I2C_PageSize;
/*差 count 個資料值,剛好可以對齊到頁位址*/
count = I2C_PageSize - Addr;
/*計算出要寫多少整數頁*/
NumOfPage = NumByteToWrite / I2C_PageSize;
/*mod 運算求餘,計算出剩餘不滿一頁的位元組數*/
NumOfSingle = NumByteToWrite % I2C_PageSize;
// Addr=0,則 WriteAddr 剛好按頁對齊 aligned
// 這樣就很簡單了,直接寫就可以,寫完整頁後
// 把剩下的不滿一頁的寫完即可
if (Addr == 0) {
/* 如果 NumByteToWrite < I2C_PageSize */
if (NumOfPage == 0) {
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
//I2C_EE_WaitEepromStandbyState();
// HAL_Delay(50);
}
/* 如果 NumByteToWrite > I2C_PageSize */
else {
/*先把整數頁都寫了*/
while (NumOfPage--) {
I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
// I2C_EE_WaitEepromStandbyState();
// HAL_Delay(50);
WriteAddr += I2C_PageSize;
pBuffer += I2C_PageSize;
}
/*若有多餘的不滿一頁的資料,把它寫完*/
if (NumOfSingle!=0) {
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
// I2C_EE_WaitEepromStandbyState();
// HAL_Delay(50);
}
}
}
// 如果 WriteAddr 不是按 I2C_PageSize 對齊
// 那就算出對齊到頁位址還需要多少個資料,然後
// 先把這幾個資料寫完,剩下開始的位址就已經對齊
// 到頁位址了,代碼重複上面的即可
else {
/* 如果 NumByteToWrite < I2C_PageSize */
if (NumOfPage== 0) {
/*若 NumOfSingle>count,目前面寫不完,要寫到下一頁*/
if (NumOfSingle > count) {
// temp 的資料要寫到寫一頁
temp = NumOfSingle - count;
I2C_EE_PageWrite(pBuffer, WriteAddr, count);
// I2C_EE_WaitEepromStandbyState();
// HAL_Delay(50);
WriteAddr += count;
pBuffer += count;
I2C_EE_PageWrite(pBuffer, WriteAddr, temp);
// I2C_EE_WaitEepromStandbyState();
// HAL_Delay(50);
}
else { /*若 count 比 NumOfSingle 大*/
I2C_EE_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
// I2C_EE_WaitEepromStandbyState();
// HAL_Delay(50);
}
}
/* 如果 NumByteToWrite > I2C_PageSize */
else {
/*位址不對齊多出的 count 分開處理,不加入這個運算*/
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / I2C_PageSize;
NumOfSingle = NumByteToWrite % I2C_PageSize;
/*先把 WriteAddr 所在頁的剩餘位元組寫了*/
if (count != 0) {
I2C_EE_PageWrite(pBuffer, WriteAddr, count);
// I2C_EE_WaitEepromStandbyState();
// HAL_Delay(50);
/*WriteAddr 加上 count 後,位址就對齊到頁了*/
WriteAddr += count;
pBuffer += count;
}
/*把整數頁都寫了*/
while (NumOfPage--) {
I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
// I2C_EE_WaitEepromStandbyState();
// HAL_Delay(50);
WriteAddr += I2C_PageSize;
pBuffer += I2C_PageSize;
}
/*若有多餘的不滿一頁的資料,把它寫完*/
if (NumOfSingle != 0) {
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
// I2C_EE_WaitEepromStandbyState();
// HAL_Delay(50);
}
}
}
}
可見讀取正确,頁寫入成功。
早睡不掉頭發,祝大家多喝水(手動狗頭)