STM32基于HAL工程硬件I2C讀取AT24C02數(shù)據(jù)
- ?申明:本文章僅發(fā)表在CSDN網(wǎng)站,任何其他網(wǎng)站,未注明來源,見此內(nèi)容均為盜鏈和爬取,請多多尊重和支持原創(chuàng)!
- ??對于文中所提供的相關(guān)資源鏈接將作不定期更換。
- 相關(guān)篇針對AT24C32及以上容量《STM32基于STM32-HAL工程硬件I2C讀取AT24Cxx數(shù)據(jù)》
- ??本工程使用STM32F103VE+AT24C02實物驗證沒有問題。由于手上只有AT24C02,沒有對低于AT24C32型號下的其它容量型號進(jìn)行測試。
- ?說明:本庫文件僅支持容量大于4095Bytes(AT24C32)以下型號的讀取。
- ??型號和容量參照:
#define AT24C01 127
#define AT24C02 255
#define AT24C04 511
#define AT24C08 1023
#define AT24C16 2047
#define AT24C32 4095
#define AT24C64 8191
#define AT24C128 16383
#define AT24C256 32767
??AT24C02/C4/C8/C16地址說明
- ??AT24C02/C4/C8/C16的I2C地址取決于引腳A0、A1和A2的電平設(shè)置,可以有8個不同的地址。以下是每個地址對應(yīng)的引腳配置:
0b1010000:A0 = 0,A1 = 0,A2 = 0
0b1010001:A0 = 1,A1 = 0,A2 = 0
0b1010010:A0 = 0,A1 = 1,A2 = 0
0b1010011:A0 = 1,A1 = 1,A2 = 0
0b1010100:A0 = 0,A1 = 0,A2 = 1
0b1010101:A0 = 1,A1 = 0,A2 = 1
0b1010110:A0 = 0,A1 = 1,A2 = 1
0b1010111:A0 = 1,A1 = 1,A2 = 1
- ??如果引腳A0-A1-A2都接地,則AT24Cxx的I2C地址為
0b1010000
(或0x50
)。
?AT24C02/C4/C8/C16讀寫說明
- ??AT24C02是一種2 Kb(256 × 8)串行電子可擦可編程只讀存儲器(EEPROM)芯片,支持標(biāo)準(zhǔn)I2C總線通信協(xié)議。AT24C02的編程操作是以頁為單位完成的,每次最多可編程8個連續(xù)字節(jié)。
具體來說,AT24C02的一頁大小為8個字節(jié),每次寫入數(shù)據(jù)時,需要確保寫入的數(shù)據(jù)不跨頁。因此,如果要在AT24C02中寫入10個字節(jié)的數(shù)據(jù),需要先將前8個字節(jié)寫入一個頁,再將后兩個字節(jié)寫入另一個頁。
- ??AT24C08是一種8 Kb(1024 × 8)串行電子可擦可編程只讀存儲器(EEPROM)芯片,支持標(biāo)準(zhǔn)I2C總線通信協(xié)議。AT24C08的編程操作是以頁為單位完成的,每次最多可編程8個連續(xù)字節(jié)。
具體來說,AT24C08的一頁大小為8個字節(jié),每次寫入數(shù)據(jù)時,需要確保寫入的數(shù)據(jù)不跨頁。因此,如果要在AT24C08中寫入10個字節(jié)的數(shù)據(jù),需要先將前8個字節(jié)寫入一個頁,再將后兩個字節(jié)寫入另一個頁。
- ??在AT24C16中,每個頁大小為16Bytes,因此一次最多可以進(jìn)行編程16個字節(jié)。
具體來說,AT24C016的一頁大小為16個字節(jié),每次寫入數(shù)據(jù)時,需要確保寫入的數(shù)據(jù)不跨頁。因此,如果要在AT24C16中寫入20個字節(jié)的數(shù)據(jù),需要先將前16個字節(jié)寫入一個頁,再將后4個字節(jié)寫入另一個頁。
??使用注意事項
- ??將需要存儲的字符串或數(shù)組長度不要超過16個字符。
- ??如果需要存儲超過16個字節(jié)長度的數(shù)據(jù)最好截斷,分段存儲。
- ??讀取AT24Cxx的數(shù)據(jù),如果使用數(shù)組接收,不要直接使用
printf
–>%s
來輸出,因為%s
輸出結(jié)尾是以\0
為結(jié)束符,直接使用%s
輸出可能會導(dǎo)致輸出的數(shù)據(jù)重復(fù)輸出。以如下方式輸出:
for(int i=0;i< BufferSize1;i++)
{
HAL_UART_Transmit(&huart1 , &Read_Buffer[i] , 1 , 1000);
}
??STM32CubeMX工程配置
- ??使能一個I2C接口。(如果選擇I2C2,需要在
at24_hal_i2c.c
,修改相關(guān)函數(shù)的形參。) - ??使能一個串口,用于調(diào)試信息輸出。
??時鐘源根據(jù)個人具體的STM32型號自己配置。文章來源:http://www.zghlxwxcb.cn/news/detail-410525.html
??AT24C02/04/08驅(qū)動代碼
-?? at24_hal_i2c.c文件文章來源地址http://www.zghlxwxcb.cn/news/detail-410525.html
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
#include "stm32f1xx_hal_i2c.h"
#include <string.h>
#include <stdio.h>
#include "at24_hal_i2c.h"
/**
* @brief : This function handles Writing Array of Bytes on the specific Address .
* This program have this feature that don't force you to use absolute 16 bytes
* you can use more than 16 bytes buffer.
* @param hi2c : Pointer to a I2C_HandleTypeDef structure that contains
* the configuration information for the specified I2C.
* @param DevAddress : specifies the slave address to be programmed(EEPROM ADDRESS).
* @param MemAddress : Internal memory address (WHERE YOU WANNA WRITE TO)
* @param pData : Pointer to data buffer
* @param TxBufferSize : Amount of data you wanna Write
* @retval
*/
int at24_HAL_WriteBytes(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint8_t *pData, uint16_t TxBufferSize)
{
/*
* program just get the DevAddress of the Slave (not master) and for the next step
* You know that the most of the EEprom address start with 0xA0
* give MemAddress for the location you want to write to
* give Data buffer so it can write Data on this location
*/
//Note that this function works properly to 31 bytes
if (MemAddress + TxBufferSize > 16)
{
//Write to 16bytes
while (HAL_I2C_Mem_Write(hi2c, (uint16_t)DevAddress, (uint16_t)MemAddress, I2C_MEMADD_SIZE_8BIT, pData, (uint16_t)16 - MemAddress, 1000) != HAL_OK);
//write remaining bytes
*pData = *pData + (16 - MemAddress);
while (HAL_I2C_Mem_Write(hi2c, (uint16_t)DevAddress, (uint16_t)16, I2C_MEMADD_SIZE_8BIT, pData, (uint16_t)((MemAddress + TxBufferSize) - 16), 1000) != HAL_OK);
}
else
{
while ((TxBufferSize - 16) > 0)
{
//if your data is more than 16 bytes,you are here
while (HAL_I2C_Mem_Write(hi2c, (uint16_t)DevAddress, (uint16_t)MemAddress, I2C_MEMADD_SIZE_8BIT, pData, (uint16_t)16, 1000) != HAL_OK);
TxBufferSize -= 16;
pData += 16;
MemAddress += 16;
}
//remaining data
while (HAL_I2C_Mem_Write(hi2c, (uint16_t)DevAddress, (uint16_t)MemAddress, I2C_MEMADD_SIZE_8BIT, pData, (uint16_t)TxBufferSize, 1000) != HAL_OK);
}
return 1;
}
int at24_HAL_ReadBytes(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint8_t *pData, uint16_t RxBufferSize)
{
int TimeOut;
/*
* program just get the DevAddress of the Slave (not master) and for the next step
* You know that the most of the EEprom address start with 0xA0
* get the MemAddress for the location you want to write data on it
* get the Data buffer so it can write Data on this location
*/
//Note that this function works properly to 31bytes
while ((RxBufferSize - 16) > 0)
{
//if your data is more than 16 bytes,you are here
TimeOut = 0;
while (HAL_I2C_Mem_Read(hi2c, (uint16_t)DevAddress, (uint16_t)MemAddress, I2C_MEMADD_SIZE_8BIT, pData, (uint16_t)16, 1000) != HAL_OK && TimeOut < 10)
{
TimeOut++;
}
RxBufferSize -= 16;
pData += 16;
MemAddress += 16;
}
// //remaining data
TimeOut = 0;
while (HAL_I2C_Mem_Read(hi2c, (uint16_t)DevAddress, (uint16_t)MemAddress, I2C_MEMADD_SIZE_8BIT, pData, (uint16_t)RxBufferSize, 1000) != HAL_OK && TimeOut < 10)
{
TimeOut++;
}
return 1;
}
/*
* @brief : This function handles Reading Array of Bytes from the specific Address .
* This program have this feature that don't force you to use absolute 16 bytes
* you can use more than 16 bytes buffer.
* @param hi2c : Pointer to a I2C_HandleTypeDef structure that contains
* the configuration information for the specified I2C.
* @param DevAddress : specifies the slave address to be programmed(EEPROM ADDRESS).
* @param MemAddress : Internal memory address (WHERE YOU WANNA READ FROM)
* @param pData : Pointer to data buffer
* @param TxBufferSize : Amount of data to be Read
* @retval
*/
int at24_HAL_SequentialRead(I2C_HandleTypeDef *hi2c , uint8_t DevAddress, uint16_t MemAddress, uint8_t *pData, uint16_t RxBufferSize)
{
/*
* just like WriteByte but get what it want
* but maybe you should know that the Data is location you want to save data
* for future use
*/
while ((RxBufferSize - 16) > 0)
{
while (HAL_I2C_Mem_Read(hi2c, (uint16_t)DevAddress, (uint16_t)MemAddress, I2C_MEMADD_SIZE_8BIT, pData, (uint16_t)16, (uint32_t)1000) != HAL_OK);
RxBufferSize -= 16;
pData += 16;
MemAddress += 16;
}
while (HAL_I2C_Mem_Read(hi2c, (uint16_t)DevAddress, (uint16_t)MemAddress, I2C_MEMADD_SIZE_8BIT, pData, (uint16_t)RxBufferSize, (uint32_t)1000) != HAL_OK) {}
/*
* if DataRecive is 0xFF or 255 ,this means that block was empty
*/
return 1;
}
/*
* @brief : This function handles Erase Full chip.
* @param hi2c : Pointer to a I2C_HandleTypeDef structure that contains
* the configuration information for the specified I2C.
* @retval
*/
int at24_HAL_EraseMemFull(I2C_HandleTypeDef *hi2c)
{
/*
* this may take will don't panic
*/
uint8_t EraseBuf[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
int i;
for (i = 0 ; i < 1024 ; i += 16)
{
/*
* if you know,0xFF means that block is empty
*/
// sdI2C_WriteBytes(&hi2c,0xA0,(uint16_t )i,EraseBuf,16);
at24_HAL_WriteBytes(hi2c, 0xA0, (uint16_t)i, EraseBuf, 16);
}
return 1;
}
/**
* @brief : This function handles Writing String on the specific Address .
* This program have this feature that don't force you to use absolute 16 bytes
* you can use more than 16 bytes buffer.
* @param hi2c : Pointer to a I2C_HandleTypeDef structure that contains
* the configuration information for the specified I2C.
* @param DevAddress : specifies the slave address to be programmed(EEPROM ADDRESS).
* @param MemAddress : Internal memory address (WHERE YOU WANNA Write)
* @param pString : Pointer to data buffer(CHAR DATA)
* @param length : Amount of buffer you wanna Write from
* @retval
*/
int at24_HAL_WriteString(I2C_HandleTypeDef *hi2c, char *pString , uint16_t MemAddress , uint8_t length)
{
uint8_t pData[length];
int i = 0;
while (*pString)
(pData[i++]) = (uint8_t)(*pString++);
// sdI2C_WriteBytes(&hi2c,0xA0,MemAddress,pData,length);
at24_HAL_WriteBytes(hi2c, 0xA0, MemAddress, pData, length);
return 1;
}
/**
* @brief : This function handles Reading String on the specific Address .
* This program have this feature that don't force you to use absolute 16 bytes
* you can use more than 16 bytes buffer.
* @param hi2c : Pointer to a I2C_HandleTypeDef structure that contains
* the configuration information for the specified I2C.
* @param MemAddress : Internal memory address (WHERE YOU WANNA READ)
* @param pString : Pointer to data buffer(CHAR DATA)
* @param length : Amount of buffer you wanna Read from
* @retval
*/
int at24_HAL_ReadString(I2C_HandleTypeDef *hi2c, char *pString, uint16_t MemAddress, uint8_t length)
{
uint8_t pData[length];
int i = 0;
// sdI2C_RandomRead(0xA0,MemAddress,pData,length);
at24_HAL_ReadBytes(hi2c, 0xA0, MemAddress, pData, length);
while (pData[i])
(*pString++) = (char)pData[i++];
return 1;
}
- ??at24_hal_i2c.h文件
#ifndef _AT24_HAL_I2C_H_
#define _AT24_HAL_I2C_H_
#include "stm32f1xx_hal.h"
#include "stm32f1xx_hal_i2c.h"
int at24_HAL_WriteBytes(I2C_HandleTypeDef *hi2c,uint16_t DevAddress,uint16_t MemAddress, uint8_t *pData,uint16_t TxBufferSize);
int at24_HAL_ReadBytes(I2C_HandleTypeDef *hi2c,uint16_t DevAddress,uint16_t MemAddress, uint8_t *pData,uint16_t RxBufferSize);
int at24_HAL_SequentialRead(I2C_HandleTypeDef *hi2c ,uint8_t DevAddress,uint16_t MemAddress,uint8_t *pData,uint16_t RxBufferSize);
int at24_HAL_EraseMemFull(I2C_HandleTypeDef *hi2c);
int at24_HAL_WriteString(I2C_HandleTypeDef *hi2c,char *pString ,uint16_t MemAddress ,uint8_t length);
int at24_HAL_ReadString(I2C_HandleTypeDef *hi2c,char *pString,uint16_t MemAddress,uint8_t length);
#endif /* DRIVERS_MYLIB_AT24_HAL_I2C_H_ */
??main主程序代碼
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
//#include "stdio.h"http://printf函數(shù)啟用
#include <string.h>
#include "at24_hal_i2c.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#define AT24Cxx_ADDRESS ((uint16_t)0xA0)
#define MemAddress ((uint16_t)0x00)
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
uint8_t Buffer[] = "Perseverance";//Hi!STM32F103VE Hello World Perseverance
#define countof(a) (sizeof(a) / sizeof(*(a)))
#define BufferSize1 (countof(Buffer)-1)
uint8_t Read_Buffer[BufferSize1];
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
uint32_t TimerUART = HAL_GetTick();
at24_HAL_WriteBytes(&hi2c1, AT24Cxx_ADDRESS, MemAddress, Buffer, BufferSize1);
// if (BufferSize1 < 9)
// {
// printf("BufferSize=%d \r\n", BufferSize1);
// at24_HAL_WriteBytes(&hi2c1, AT24Cxx_ADDRESS, MemAddress, Buffer, BufferSize1);
// }
// else
// {
// printf("注意:AT24C02一次不能超過8字節(jié) \r\n");
// }
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if ((HAL_GetTick() - TimerUART) > 2500)
{
at24_HAL_SequentialRead(&hi2c1,AT24Cxx_ADDRESS,MemAddress, Read_Buffer, BufferSize1);//連續(xù)讀16字節(jié)數(shù)據(jù)
// at24_HAL_ReadBytes(&hi2c1, AT24Cxx_ADDRESS, MemAddress, Read_Buffer, BufferSize1);
for(int i=0;i< BufferSize1;i++)
{
HAL_UART_Transmit(&huart1 , &Read_Buffer[i] , 1 , 1000);
}
// printf("Read_Date=%s \r\n", Read_Buffer);//數(shù)組不要使用printf->%s輸出
TimerUART = HAL_GetTick();
HAL_GPIO_TogglePin(GPIOE, LED_Pin);
}
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
??工程源碼
- ?申明:本文章僅發(fā)表在CSDN網(wǎng)站,任何其他網(wǎng)站,未注明來源,見此內(nèi)容均為盜鏈和爬取,請多多尊重和支持原創(chuàng)!
- ??對于文中所提供的相關(guān)資源鏈接將作不定期更換。
鏈接: https://pan.baidu.com/s/1dxbnFDVQ3yJPxMlpESfSzA
提取碼: fc33
到了這里,關(guān)于STM32基于HAL工程硬件I2C讀寫AT24C02/04/08數(shù)據(jù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!