天天看點

學習筆記四.基于HAL庫的stm32f103硬體讀寫EEPROM(CUBEMX)

基于cubemx的stm32f103硬體讀寫EEPROM

今天介紹一種可擦除存儲器.

EEPROM (Electrically Erasable Programmable read only memory)是指帶電可擦可程式設計隻讀存儲器。是一種掉電後資料不丢失的存儲晶片。EEPROM 可以在電腦上或專用裝置上擦除已有資訊,重新程式設計。一般用在即插即用。(百度百科)

一般正常單片機的EEPROM是AT24C02

(AT24C02是一個2K位串行CMOS E2PROM, 内部含有256個8位位元組,CATALYST公司的先進CMOS技術實質上減少了器件的功耗。AT24C02有一個16位元組頁寫緩沖器。該器件通過IIC總線接口進行操作,有一個專門的寫保護功能。【百度百科】)

學習筆記四.基于HAL庫的stm32f103硬體讀寫EEPROM(CUBEMX)

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)

參數解釋

學習筆記四.基于HAL庫的stm32f103硬體讀寫EEPROM(CUBEMX)

對這句函數做一下小的封裝,就可以寫入位元組,和頁寫入。寫之前要注意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");
	}
}
           

直接将函數放在主函數裡面調用,序列槽列印資料

學習筆記四.基于HAL庫的stm32f103硬體讀寫EEPROM(CUBEMX)

函數中5ms的延時很重要,如果沒有延時,資料寫會失敗

學習筆記四.基于HAL庫的stm32f103硬體讀寫EEPROM(CUBEMX)

這是單個位元組寫入。一位元組寫一位元組寫很麻煩,是以我們繼續封裝,編寫頁寫入函數。

首先我們知道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);
			}
		}
	}
}
           
學習筆記四.基于HAL庫的stm32f103硬體讀寫EEPROM(CUBEMX)
學習筆記四.基于HAL庫的stm32f103硬體讀寫EEPROM(CUBEMX)
學習筆記四.基于HAL庫的stm32f103硬體讀寫EEPROM(CUBEMX)

可見讀取正确,頁寫入成功。

早睡不掉頭發,祝大家多喝水(手動狗頭)