STM32Fxx读写eeprom(AT24C16)

一.I2C 协议简介

I2C 通讯协议 (Inter - Integrated Circuit) 是由 Phiilps 公司开发的,由于它引脚少,硬件实现简单,可扩展性强,不需要 USART、CAN 等通讯协议的外部收发设备,现在被广泛地使用在系统内多个集成电路 (IC) 间的通讯。

IIC协议采用半双工(也有资料称其为全双工)工作模式,即在同一时间只能进行单向的数据传输。它由两条信号线组成:一条是数据线SDA(Serial Data Line),用于传输数据;另一条是时钟线SCL(Serial Clock Line),由主设备提供时钟信号,以确保所有连接到总线的设备同步进行数据交换。在I2C总线上,每个从设备都有一个唯一的地址,主设备通过发送这个地址来选择与其通信的目标设备。

STM32 的 I2C 外设可用作通讯的主机及从机,支持 100Kbit/s 和 400Kbit/s 的速率,支持 7 位、10位设备地址,支持 DMA 数据传输,并具有数据校验功能。

二.AT24C16 eeprom读写

1.AT24C16概述

AT24c16 一共16Kbit,也就是2K Byte;每页大小16byte,一共128页。

2.AT24C16读写

(1)AT24C16不用外部硬件引脚控制A2 A1 A0;全部由软件控制

(2)软件内需要设置8个地址,每个地址内可以读写256个byte的数据

3.代码实现如下:

  使用HAL库方式读取。

(1)iic.h

#ifndef __I2C_EE_H

#define __I2C_EE_H

#include "stm32f4xx.h"

/* AT24C04/08A/16A每页有16个字节 */

#define EEPROM_PAGESIZE      16

#define I2C_OWN_ADDRESS7     0X1A   

#define I2Cx                             I2C1

#define I2Cx_CLK_ENABLE()                __HAL_RCC_I2C1_CLK_ENABLE()

#define I2Cx_SDA_GPIO_CLK_ENABLE()       __HAL_RCC_GPIOB_CLK_ENABLE()

#define I2Cx_SCL_GPIO_CLK_ENABLE()       __HAL_RCC_GPIOB_CLK_ENABLE()

#define I2Cx_FORCE_RESET()               __HAL_RCC_I2C1_FORCE_RESET()

#define I2Cx_RELEASE_RESET()             __HAL_RCC_I2C1_RELEASE_RESET()

/* Definition for I2Cx Pins */

#define I2Cx_SCL_PIN                    GPIO_PIN_8

#define I2Cx_SCL_GPIO_PORT              GPIOB

#define I2Cx_SCL_AF                     GPIO_AF4_I2C1

#define I2Cx_SDA_PIN                    GPIO_PIN_9

#define I2Cx_SDA_GPIO_PORT              GPIOB

#define I2Cx_SDA_AF                     GPIO_AF4_I2C1

/*等待超时时间*/

#define I2CT_FLAG_TIMEOUT         ((uint32_t)0x1000)

#define I2CT_LONG_TIMEOUT         ((uint32_t)(10 * I2CT_FLAG_TIMEOUT))

#define I2Cx_TIMEOUT_MAX                300

/* Maximum number of trials for HAL_I2C_IsDeviceReady() function */

#define EEPROM_MAX_TRIALS               300

/*信息输出*/

#define EEPROM_DEBUG_ON         0

#define EEPROM_INFO(fmt,arg...)           printf("<<-EEPROM-INFO->> "fmt"\n",##arg)

#define EEPROM_ERROR(fmt,arg...)          printf("<<-EEPROM-ERROR->> "fmt"\n",##arg)

#define EEPROM_DEBUG(fmt,arg...)          do{\

                                          if(EEPROM_DEBUG_ON)\

                                          printf("<<-EEPROM-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\

                                          }while(0)

/* EEPROM Addresses defines */

#define EEPROM_Block0_ADDRESS 0xA0 /* E2 = 0 */

#define EEPROM_Block1_ADDRESS 0xA2 /* E2 = 0 */

#define EEPROM_Block2_ADDRESS 0xA4 /* E2 = 0 */

#define EEPROM_Block3_ADDRESS 0xA6 /* E2 = 0 */

#define EEPROM_Block4_ADDRESS 0xA8 /* E2 = 0 */

#define EEPROM_Block5_ADDRESS 0xAa /* E2 = 0 */

#define EEPROM_Block6_ADDRESS 0xAc /* E2 = 0 */

#define EEPROM_Block7_ADDRESS 0xAe /* E2 = 0 */

extern uint8_t EEPROM_ADDRESS;   

void I2C_EE_Init(void);

  

void I2C_EE_BufferWrite(uint8_t* pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite);

uint32_t I2C_EE_ByteWrite(uint8_t* pBuffer, uint16_t WriteAddr);

uint32_t I2C_EE_PageWrite(uint8_t* pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite);  

uint32_t I2C_EE_BufferRead(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t NumByteToRead);

(2)iic.c

#include "iic.h"

uint8_t EEPROM_ADDRESS;     

I2C_HandleTypeDef  I2C_Handle;

/**

  * @brief I2C MSP Initialization

  *        This function configures the hardware resources used in this example:

  *           - Peripheral's clock enable

  *           - Peripheral's GPIO Configuration  

  *           - DMA configuration for transmission request by peripheral

  *           - NVIC configuration for DMA interrupt request enable

  * @param hi2c: I2C handle pointer

  * @retval None

  */

void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c)

{  

  GPIO_InitTypeDef  GPIO_InitStruct;

  

  /*##-1- Enable peripherals and GPIO Clocks #################################*/

  /* Enable GPIO TX/RX clock */

  I2Cx_SCL_GPIO_CLK_ENABLE();

  I2Cx_SDA_GPIO_CLK_ENABLE();

  /* Enable I2C1 clock */

  I2Cx_CLK_ENABLE();

  

  /*##-2- Configure peripheral GPIO ##########################################*/  

  /* I2C TX GPIO pin configuration  */

  GPIO_InitStruct.Pin       = I2Cx_SCL_PIN;

  GPIO_InitStruct.Mode      = GPIO_MODE_AF_OD;

  GPIO_InitStruct.Pull      = GPIO_NOPULL;

  GPIO_InitStruct.Speed     = GPIO_SPEED_FAST;

  GPIO_InitStruct.Alternate = I2Cx_SCL_AF;

  

  HAL_GPIO_Init(I2Cx_SCL_GPIO_PORT, &GPIO_InitStruct);

    

  /* I2C RX GPIO pin configuration  */

  GPIO_InitStruct.Pin = I2Cx_SDA_PIN;

  GPIO_InitStruct.Alternate = I2Cx_SDA_AF;

    

  HAL_GPIO_Init(I2Cx_SDA_GPIO_PORT, &GPIO_InitStruct);

  

   /* Force the I2C peripheral clock reset */  

I2Cx_FORCE_RESET() ;

/* Release the I2C peripheral clock reset */  

I2Cx_RELEASE_RESET();

}

/**

  * @brief  I2C 工作模式配置

  * @param  无

  * @retval 无

  */

static void I2C_Mode_Config(void)

{

   

  I2C_Handle.Instance             = I2Cx;

  

  I2C_Handle.Init.AddressingMode  = I2C_ADDRESSINGMODE_7BIT;

  I2C_Handle.Init.ClockSpeed      = 400000;

  I2C_Handle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;

  I2C_Handle.Init.DutyCycle       = I2C_DUTYCYCLE_2;

  I2C_Handle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;

  I2C_Handle.Init.NoStretchMode   = I2C_NOSTRETCH_DISABLE;

  I2C_Handle.Init.OwnAddress1     = I2C_OWN_ADDRESS7 ;

  I2C_Handle.Init.OwnAddress2     = 0;

    /* Init the I2C */

  HAL_I2C_Init(&I2C_Handle);

  HAL_I2CEx_AnalogFilter_Config(&I2C_Handle, I2C_ANALOGFILTER_ENABLE);    

}

/**

  * @brief  I2C 外设(EEPROM)初始化

  * @param  无

  * @retval 无

  */

void I2C_EE_Init(void)

{

I2C_Mode_Config();

EEPROM_ADDRESS =  EEPROM_Block0_ADDRESS;

}

/**

  * @brief   将缓冲区中的数据写到I2C EEPROM中

  * @param   

  * @arg pBuffer:缓冲区指针

  * @arg WriteAddr:写地址

  *     @arg NumByteToWrite:写的字节数

  * @retval  无

  */

void I2C_EE_BufferWrite(uint8_t* pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite)

{

printf("I2C_EE_BufferWrite   addr: %d\r\n", WriteAddr);

  uint16_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;

  Addr = WriteAddr % EEPROM_PAGESIZE;

  count = EEPROM_PAGESIZE - Addr;

  NumOfPage =  NumByteToWrite / EEPROM_PAGESIZE;

  NumOfSingle = NumByteToWrite % EEPROM_PAGESIZE;

  /* If WriteAddr is I2C_PageSize aligned  */

  if(Addr == 0)

  {

    /* If NumByteToWrite < I2C_PageSize */

    if(NumOfPage == 0)

    {

      I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);

    }

    /* If NumByteToWrite > I2C_PageSize */

    else  

    {

      while(NumOfPage--)

      {

        I2C_EE_PageWrite(pBuffer, WriteAddr, EEPROM_PAGESIZE);

        WriteAddr +=  EEPROM_PAGESIZE;

        pBuffer += EEPROM_PAGESIZE;

      }

      if(NumOfSingle!=0)

      {

        I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);

      }

    }

  }

  /* If WriteAddr is not I2C_PageSize aligned  */

  else

  {

    /* If NumByteToWrite < I2C_PageSize */

    if(NumOfPage== 0)

    {

      I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);

    }

    /* If NumByteToWrite > I2C_PageSize */

    else

    {

      NumByteToWrite -= count;

      NumOfPage =  NumByteToWrite / EEPROM_PAGESIZE;

      NumOfSingle = NumByteToWrite % EEPROM_PAGESIZE;

      

      if(count != 0)

      {  

        I2C_EE_PageWrite(pBuffer, WriteAddr, count);

        WriteAddr += count;

        pBuffer += count;

      }

      

      while(NumOfPage--)

      {

        I2C_EE_PageWrite(pBuffer, WriteAddr, EEPROM_PAGESIZE);

        WriteAddr +=  EEPROM_PAGESIZE;

        pBuffer += EEPROM_PAGESIZE;  

      }

      if(NumOfSingle != 0)

      {

        I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);

      }

    }

  }  

}

/**

  * @brief   写一个字节到I2C EEPROM中

  * @param   

  * @arg pBuffer:缓冲区指针

  * @arg WriteAddr:写地址

  * @retval  无

  */

uint32_t I2C_EE_ByteWrite(uint8_t* pBuffer, uint16_t WriteAddr)

{

HAL_StatusTypeDef status = HAL_OK;

status = HAL_I2C_Mem_Write(&I2C_Handle, g_EEPROM_ADDRESS, (uint16_t)WriteAddr, I2C_MEMADD_SIZE_8BIT, pBuffer, 1, 100);

/* Check the communication status */

if(status != HAL_OK)

{

/* Execute user timeout callback */

//I2Cx_Error(Addr);

}

while (HAL_I2C_GetState(&I2C_Handle) != HAL_I2C_STATE_READY)

{

}

/* Check if the EEPROM is ready for a new operation */

while (HAL_I2C_IsDeviceReady(&I2C_Handle, g_EEPROM_ADDRESS, EEPROM_MAX_TRIALS, I2Cx_TIMEOUT_MAX) == HAL_TIMEOUT);

/* Wait for the end of the transfer */

while (HAL_I2C_GetState(&I2C_Handle) != HAL_I2C_STATE_READY)

{

}

return status;

}

/**

  * @brief   在EEPROM的一个写循环中可以写多个字节,但一次写入的字节数

  *          不能超过EEPROM页的大小,AT24C02每页有8个字节

  * @param   

  * @arg pBuffer:缓冲区指针

  * @arg WriteAddr:写地址

  *     @arg NumByteToWrite:写的字节数

  * @retval  无

  */

uint32_t I2C_EE_PageWrite(uint8_t* pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite)

{

HAL_StatusTypeDef status = HAL_OK;

/* Write EEPROM_PAGESIZE */

status=HAL_I2C_Mem_Write(&I2C_Handle, g_EEPROM_ADDRESS,WriteAddr, I2C_MEMADD_SIZE_8BIT, pBuffer,NumByteToWrite, 100);

while (HAL_I2C_GetState(&I2C_Handle) != HAL_I2C_STATE_READY)

{

}

/* Check if the EEPROM is ready for a new operation */

while (HAL_I2C_IsDeviceReady(&I2C_Handle, g_EEPROM_ADDRESS, EEPROM_MAX_TRIALS, I2Cx_TIMEOUT_MAX) == HAL_TIMEOUT);

/* Wait for the end of the transfer */

while (HAL_I2C_GetState(&I2C_Handle) != HAL_I2C_STATE_READY)

{

}

return status;

}

/**

  * @brief   从EEPROM里面读取一块数据

  * @param   

  * @arg pBuffer:存放从EEPROM读取的数据的缓冲区指针

  * @arg WriteAddr:接收数据的EEPROM的地址

  *     @arg NumByteToWrite:要从EEPROM读取的字节数

  * @retval  无

  */

uint32_t I2C_EE_BufferRead(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t NumByteToRead)

{

HAL_StatusTypeDef status = HAL_OK;

status=HAL_I2C_Mem_Read(&I2C_Handle,g_EEPROM_ADDRESS,ReadAddr, I2C_MEMADD_SIZE_8BIT, (uint8_t *)pBuffer, NumByteToRead,1000);

return status;

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/908580.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙系统的优势 开发 环境搭建 开发小示例

HarmonyOS是面向多智能终端、全场景的分布式操作系统,为消费者提供跨终端的无缝体验.华为开发者联盟从HarmonyOS应用设计、开发、测试、推广变现等环节全方位助力开发者。 开发者可以通过以下步骤学习鸿蒙系统的开发&#xff1a; 基础理论学习&#xff1a; 了解鸿蒙系统概述&a…

「C/C++」C/C++的区别

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「C/C」C/C程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…

Windows部署rabbitmq

本次安装环境&#xff1a; 系统&#xff1a;Windows 11 软件建议版本&#xff1a; erlang OPT 26.0.2rabbitmq 3.12.4 一、下载 1.1 下载erlang 官网下载地址&#xff1a; 1.2 下载rabbitmq 官网下载地址&#xff1a; 建议使用解压版&#xff0c;安装版可能会在安装软件…

el-table 滚动条重置 手动控制滚动条

最近在使用 el-table 的时候&#xff0c;出现一个问题&#xff1a; 表头过长的时候&#xff0c;会有左右滑动的操作&#xff0c;当我们把表格拉到最右侧&#xff0c;这个时候重新请求数据的话&#xff0c;表格位置还是在最右侧&#xff0c;不会恢复原位。 那我们想恢复原位&a…

推荐FileLink数据跨网摆渡系统 — 安全、高效的数据传输解决方案

在数字化转型的浪潮中&#xff0c;企业对于数据传输的需求日益增加&#xff0c;特别是在不同网络环境之间的文件共享和传输。为了满足这一需求&#xff0c;FileLink数据跨网摆渡系统应运而生&#xff0c;为企业提供了一种安全、高效的数据传输解决方案。 安全第一&#xff0c;保…

STl学习-迭代器

1.迭代器种类 这五种迭代器的声明如下&#xff1a; truct output_iterator_tag {};//输出迭代器 truct input_iterator_tag{ };//输入迭代器 truct forward iterator tag : public input iterator tag {};//向前迭代器 truct bidirectional iterator tag :public forward iter…

自适应对话式团队构建,提升语言模型代理的复杂任务解决能力

人工智能咨询培训老师叶梓 转载标明出处 如何有效利用多个大模型&#xff08;LLM&#xff09;代理解决复杂任务一直是一个研究热点。由美国南加州大学、宾夕法尼亚州立大学、华盛顿大学、早稻田大学和谷歌DeepMind的研究人员联合提出了一种新的解决方案——自适应团队构建&…

临街矩阵乘以自己转置的含义

总结: 临街矩阵* 邻接矩阵转置的(i,j) 位置表示有多少种线路从元素A跳转一条边最终落到元素j的路线. 这个也叫1_degree.

JavaEE-多线程初阶(3)

目录 1.线程的状态 1.1 NEW、RUNNABLE、TERMINATED 1.2 TIMED_WAITING 1.3 WAITING 1.4 BLOCKED 2.多线程带来的风险-线程安全&#xff08;重点&#xff09; 2.1 观察线程不安全的现象 2.2 分析产生该现象的原因 2.3 产生线程安全问题的原因 2.3.1 抢占式执行&#x…

江协科技STM32学习- P35 硬件I2C读写MPU6050

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

学习虚幻C++开发日志——定时器

官方文档&#xff1a;虚幻引擎中的Gameplay定时器 | 虚幻引擎 5.5 文档 | Epic Developer Community | Epic Developer Community 定时器 安排在经过一定延迟或一段时间结束后要执行的操作。例如&#xff0c;您可能希望玩家在获取某个能力提升道具后变得无懈可击&#xff0c;…

【简道云 -注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

【表格解决问题】EXCEL行数过多,WPS如何按逐行分别打印多个纸张中

1 问题描述 如图&#xff1a;我的表格行数太多了。打印在一张纸上有点不太好看 2 解决方式 Step01&#xff1a;先选中你需要打印的部分&#xff0c;找到【页面】->【打印区域】->【设置打印区域】 Step02&#xff1a;先选中一行&#xff0c;找到【插入分页符】 Step0…

提高交换网络可靠性之链路聚合

转载请注明出处 该实验为链路聚合的配置实验。 1.改名&#xff0c;分别将交换机1和交换机2改名为S1&#xff0c;S2&#xff0c;然后查看S1&#xff0c;S2的STP信息。以交换机1为例&#x1f447;。 2.交换机S1&#xff0c;S2上创建聚合端口&#xff0c;将端口加入聚合端口。以S…

SpringMVC笔记 一万字

此笔记来自于B站尚硅谷 文章目录 一、SpringMVC 简介1、什么是MVC2、什么是SpringMVC3、SpringMVC的特点 二、HelloWorld1、开发环境2、创建maven工程a>添加web模块b>打包方式&#xff1a;warc>引入依赖 3、配置web.xmla>默认配置方式b>扩展配置方式 4、创建请求…

【Hive sql面试题】找出连续活跃3天及以上的用户

表数据如下&#xff1a; 要求&#xff1a;求出连续活跃三天及以上的用户 建表语句和插入数据如下&#xff1a; create table t_useractive(uid string,dt string );insert into t_useractive values(A,2023-10-01 10:10:20),(A,2023-10-02 10:10:20),(A,2023-10-03 10:16…

livp是什么格式文件?这几款软件可以轻松处理!

今天&#xff0c;我们要探讨的是一种可能相对陌生但又颇具特色的文件格式——LIVP。它通常与某些特定的软件或设备相关联&#xff0c;比如某些品牌的相机或视频编辑软件。LIVP文件往往包含了丰富的图像或视频信息&#xff0c;以及与之相关的元数据&#xff08;如拍摄时间、地点…

贪心算法---java---黑马

贪心算法 1)Greedy algorithm 称之为贪心算法或者贪婪算法&#xff0c;核心思想是 将寻找最优解的问题分为若干个步骤每一步骤都采用贪心原则&#xff0c;选取当前最优解因为未考虑所有可能&#xff0c;局部最优的堆叠不一定得到最终解最优 贪心算法例子 Dijkstra while …

基于vue框架的的留守儿童帮扶管理系统c2691(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;留守儿童,帮扶活动,申请记录,帮扶机构,帮扶进度,帮扶人,申请加入记录,参与帮扶记录,地区信息 开题报告内容 基于Vue框架的留守儿童帮扶管理系统开题报告 一、研究背景与意义 在现代化进程中&#xff0c;随着城乡经济差异的不断扩大&a…

MySQL数据库迁移到DM8数据库

1. 达梦新建zsaqks库 2. 打开DM数据迁移工具 3. 新建工程 4. 迁移 - 右击 - 新建迁移 下一步 5. 选择迁移方式 6. MySQL数据源 请输入MySQL数据库信息 7. DM数据库目的 请输入达梦数据库信息 8. 迁移选项 保持对象名大小写(勾选) 9. 指定模式 指定是从数据源复制对象。 10.…