简介
MCU : STM32F103C8T6
库: HAL库裸机开发
EEPROM : AT24C02, 256Byte容量,I2C接口
电路图
AT24C02 电路图
电路图引用
裸机直接读写
// 写入数据到 EEPROM
HAL_StatusTypeDef EEPROM_WriteByte(uint16_t MemAddress, uint8_t Data)
{// 发送数据uint8_t dataToSend[2] = { (uint8_t)(MemAddress & 0xFF), Data };return HAL_I2C_Master_Transmit(&hi2c1, (EEPROM_I2C_ADDRESS << 1), dataToSend, 2, 100);
}// 读取数据从 EEPROM
HAL_StatusTypeDef EEPROM_ReadByte(uint16_t MemAddress, uint8_t *Data)
{// 发送存储地址uint8_t addressToSend = (uint8_t)(MemAddress & 0xFF);if (HAL_I2C_Master_Transmit(&hi2c1, (EEPROM_I2C_ADDRESS << 1), &addressToSend, 1, 100) != HAL_OK){return HAL_ERROR;}// 读取数据return HAL_I2C_Master_Receive(&hi2c1, (EEPROM_I2C_ADDRESS << 1), Data, 1, 100);
}// 调用
uint8_t dat = 100;EEPROM_WriteByte(0, dat);
HAL_Delay(10);
EEPROM_ReadByte(0, &dat);
移植第三方AT24Cxx库
引用库
AT24CXX库源码
AT24CXX系列读写算法
修改库
只需要 _24cxx_dev.c 和 _24cxx_dev.h即可
-
将代码中的地址修改如下
slave_addr = pdev->slave_addr | (addr>>8);
改为
slave_addr = pdev->slave_addr << 1; -
增加写pageBuffer
/*24cxx eeprom devcie struct*/
typedef struct
{int (*i2c_send_thend_recv)(uint8_t slave_addr, const void *send_buff, /* i2c bus fun */uint32_t send_size, void *recv_buff, uint32_t recv_size);int (*i2c_send_thend_send)(uint8_t slave_addr, const void *send_buff1, /* i2c bus fun */uint32_t send_size1,const void *send_buff2, uint32_t send_size2);uint8_t slave_addr; /*eeprom i2c addr*///uint8_t type; /*eeprom type, 0:eeprom;1:fram*/_24_model_t model; /*eeprom model*/void(*wp)(uint8_t ctrl); /*protect of write function*/void(*page_write_delay)(void); /*there is a delay in continuous writin for EEPROM,FRAM not need*/uint8_t *pageBuffer;
}_24cxx_dev_t;/*extern function*/
extern void __24cxx_dev_init(_24cxx_dev_t *pdev) ;
- pageBuffer 初始化
void __24cxx_dev_init(_24cxx_dev_t *pdev)
{uint16_t ee_page_size = get_eeprom_pagesize(pdev->model);if (pdev->model > _24C16_E)pdev->pageBuffer = (uint8_t*)malloc(ee_page_size+2);elsepdev->pageBuffer = (uint8_t*)malloc(ee_page_size+1);
}
- 将写的部分合并之后发送
写时序的问题,不合并无法正常写
/*** @brief write one page. * @param pdev pointer to the eeprom device struct.* @param addr the address of write to.* @param pbuf the data to write.* @param size number of bytes to write..* @retval return 0 if 0k,anything else is considered an error.*/
static int16_t _24cxx_write_page(_24cxx_dev_t *pdev, uint32_t addr, uint8_t *pbuf, uint32_t size)
{
// uint8_t buf[2];
// uint8_t buf_size = 0;uint8_t slave_addr = 0;uint16_t ee_page_size = 0;int16_t ret = 0;if (pdev == 0){return _24CXX_ERR_DEV_NONE;}ee_page_size = get_eeprom_pagesize(pdev->model); if (((addr % ee_page_size) + size) > ee_page_size) /*the over flow of page size*/{return _24CXX_ERR_PAGE_SIZE;}if (pdev->model > _24C16_E){/*24c32-24c1024*/slave_addr = pdev->slave_addr;
// buf[0] = (addr >>8)& 0xff;
// buf[1] = addr & 0xff;pdev->pageBuffer[0] = (addr >>8)& 0xff;pdev->pageBuffer[1] = addr & 0xff;memcpy(&pdev->pageBuffer[2], pbuf, size);size += 2;}else{/*24c01-24c16*/slave_addr = pdev->slave_addr << 1;
// buf[0] = addr & 0xff;pdev->pageBuffer[0] = addr & 0xff;memcpy(&pdev->pageBuffer[1], pbuf, size);size += 1;}if (pdev->wp) /*release write protect*/{pdev->wp(0);}// ret = pdev->i2c_send_thend_send(slave_addr, buf, buf_size, pbuf, size);ret = pdev->i2c_send_thend_send(slave_addr, pdev->pageBuffer, size, 0, 0);if (pdev->wp){pdev->wp(1); /*write protect*/}return ret;
}
- 新增
.h 中新增
extern uint16_t _24cxx_pages(_24cxx_dev_t *pdev); // 设备有多少页
extern int16_t _24cxx_erase_page(_24cxx_dev_t *pdev, uint16_t pageNum, uint8_t val); // 按页擦除, val是写入值
extern int16_t _24cxx_erase(_24cxx_dev_t *pdev, uint8_t val); // 全部擦除int16_t _24cxx_erase(_24cxx_dev_t *pdev, uint8_t val)
{uint16_t pages = 0;int16_t ret = 0;if (pdev == 0){return _24CXX_ERR_DEV_NONE;}pages = _24cxx_pages(pdev);for (int i = 0; i < pages; ++i){ret = _24cxx_erase_page(pdev, i, val);if (_24CXX_OK != ret)break ;if (pdev->page_write_delay){pdev->page_write_delay(); /*eeprom need wait*/}}return ret;
}
int16_t _24cxx_erase_page(_24cxx_dev_t *pdev, uint16_t pageNum, uint8_t val)
{uint16_t pages = 0;uint16_t page_size = 0;int16_t ret = 0;uint16_t slave_addr = 0;uint32_t addr = 0;uint32_t size = 0;if (pdev == 0){return _24CXX_ERR_DEV_NONE;}pages = _24cxx_pages(pdev);page_size = get_eeprom_pagesize(pdev->model);addr = pageNum * page_size;size = page_size;if (pages <= pageNum){return _24CXX_ERR_CHIP_SIZE;}if (pdev->model > _24C16_E){/*24c32-24c1024*/slave_addr = pdev->slave_addr;size += 2;memset(pdev->pageBuffer, val, size);pdev->pageBuffer[0] = (addr >>8)& 0xff;pdev->pageBuffer[1] = addr & 0xff;}else{/*24c01-24c16*/slave_addr = pdev->slave_addr << 1;size += 1;memset(pdev->pageBuffer, val, size);pdev->pageBuffer[0] = addr & 0xff;}ret = pdev->i2c_send_thend_send(slave_addr, pdev->pageBuffer, size, 0, 0);return ret;
}
- 代码使用
int hw_i2c_send_then_recv(uint8_t slave_addr, const void *send_buff, uint32_t send_size, void *recv_buff, uint32_t recv_size)
{// 发送数据if (HAL_OK != HAL_I2C_Master_Transmit(&hi2c1, slave_addr, (uint8_t*)send_buff, send_size, 10)){return _24CXX_ERR_I2C_WR; }if (HAL_OK != HAL_I2C_Master_Receive(&hi2c1, slave_addr, (uint8_t*)recv_buff, recv_size, 1000)){return _24CXX_ERR_I2C_WR; }return _24CXX_OK;
}int hw_i2c_send_then_send(uint8_t slave_addr, const void *send_buff1, uint32_t send_size1,const void *send_buff2, uint32_t send_size2)
{if (HAL_OK != HAL_I2C_Master_Transmit(&hi2c1, slave_addr, (uint8_t*)send_buff1, send_size1, 2000)){return _24CXX_ERR_I2C_WR; }if (0 != send_size2){if (HAL_OK != HAL_I2C_Master_Transmit(&hi2c1, slave_addr, (uint8_t*)send_buff2, send_size2, 1000)){return _24CXX_ERR_I2C_WR; }}return _24CXX_OK;
}static void page_write_delay(void)
{uint16_t i;i = 0xFFFF;while(i--);
}_24cxx_dev_t at24cxx_dev =
{.i2c_send_thend_recv=hw_i2c_send_then_recv,.i2c_send_thend_send=hw_i2c_send_then_send,.slave_addr=0x51, /* eeprom address */.model=_24C02_E, .wp=0, /* no write protect */.page_write_delay=page_write_delay,
};uint8_t buffer[256];
uint16_t size = 0;
uint8_t readBuffer[256];
uint16_t readSize = 256;
void readWriteBufferInit()
{int writeSize = 256;for (int i = 0; i < writeSize; ++i){buffer[i] = 255-i;}size = readSize = writeSize;memset(readBuffer, 0, sizeof(readBuffer));
}/* USER CODE END 0 *//*** @brief The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 */static int ret = _24CXX_OK;/* 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();__24cxx_dev_init(&at24cxx_dev);/* USER CODE BEGIN 2 */readWriteBufferInit();ret = _24cxx_write(&at24cxx_dev, 0, (uint8_t*)buffer, size); if (ret != _24CXX_OK){}else{}HAL_Delay(100);ret = _24cxx_read(&at24cxx_dev, 0, (uint8_t*)readBuffer, readSize); if (ret != _24CXX_OK){}else{}
//for (int i = 0; i < size; ++i)
//{
// ret = EEPROM_WriteByte(i, buffer[i]);
// HAL_Delay(5);
//}
// HAL_Delay(50);
//for (int i = 0; i < size; ++i)
//{
// ret = EEPROM_ReadByte(i, &readBuffer[i]);
// HAL_Delay(5);
//}/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}
注意
1. HAL函数
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
及
HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
中的Timeout需要根据你的Tick时间来设置, 系统默认是1ms, 但是你如果修改了就需要重新设置;
2. 关于读写的Timeout
- 按照数据手册, 写是按字节写/按页写, 所以超时时间按照页进行设置, 5+(写周期时间)~10ms;
- 读是可以连续读的,所以需要按照需求进行设置,如果一次性读取太多设置的Timeout少的话,导致接收超时, 会失败, 这里需要注意;