当前位置: 首页 > news >正文

AT24Cxx移植第三方库到裸机中使用

简介

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即可

  1. 将代码中的地址修改如下
    slave_addr = pdev->slave_addr | (addr>>8);
    改为
    slave_addr = pdev->slave_addr << 1;

  2. 增加写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) ;
  1. 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);
}
  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;
}
  1. 新增
.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;
}
  1. 代码使用
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

  1. 按照数据手册, 写是按字节写/按页写, 所以超时时间按照页进行设置, 5+(写周期时间)~10ms;
  2. 读是可以连续读的,所以需要按照需求进行设置,如果一次性读取太多设置的Timeout少的话,导致接收超时, 会失败, 这里需要注意;
原文地址:https://blog.csdn.net/halo_hsuh/article/details/146704129
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mrgr.cn/news/96416.html

相关文章:

  • 实战篇Redis
  • [c++项目]基于微服务的聊天室服务端测试
  • SQL语句及其应用(中)(DQL语句之单表查询)
  • MySQL数据库和表的操作之SQL语句
  • 【Qt】三种操作sqlite3的方式及其三种多表连接
  • 归档重做日志archived log (明显) 比redo log重做日志文件小
  • Binlog、Redo log、Undo log的区别
  • 【Qt】游戏场景和图元
  • RK3588,V4l2 读取Gmsl相机, Rga yuv422转换rgb (mmap)
  • Python3基础库入门(个人学习用)
  • 图解AUTOSAR_SWS_SynchronizedTimeBaseManager
  • 链表(C++)
  • 通信协议之串口
  • Java - 2. 面向对象编程
  • openwrt24.10.0版本上安装istoreOS的屏幕监控插件
  • SpringBoot (一) 自动配置原理
  • pyinstaller 对 pyexecjs模块打包老会有终端框闪烁
  • MySQL多表查询实验
  • GHCTF-web-wp
  • Linux进程管理之子进程的创建(fork函数)、子进程与线程的区别、fork函数的简单使用例子、子进程的典型应用场景、父进程等待子进程结束后自己再结束