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;

}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

idea使用Translation插件实现翻译

1.打开idea&#xff0c;settings&#xff0c;选择plugins&#xff0c;搜索插件Translation&#xff0c;安装 2.选择翻译引擎 3.配置引擎&#xff0c;以有道词典为例 3.1 获取应用ID&#xff0c;应用秘钥 3.1.1 创建应用 点击进入有道智云控制台 3.1.2 复制ID和秘钥 3.2 idea设…

【论文精读】LPT: Long-tailed prompt tuning for image classification

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;论文精读_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 摘要 2. …

【SQL Server】解决因使用 varchar 类型存储 Unicode 字符串导致的中文显示乱码问题

问题描述 导入 SQL 到 SQL Server 数据库后&#xff0c;存在部分列的中文显示异常的问题。 原因分析 观察发现显示异常的字段的数据类型是 varchar&#xff0c;而显示正常的字段的数据类型是 nvarchar。 而且&#xff0c;SQL 文件中所有字符串前面都带有 N 的前缀。 在 SQL 中…

dify实战案例分享-基于多模态模型的发票识别

1 什么是dify Dify是一个开源的大语言模型&#xff08;LLM&#xff09;应用开发平台&#xff0c;旨在简化和加速生成式AI应用的创建和部署。它结合了后端即服务&#xff08;Backend as Service, BaaS&#xff09;和LLMOps的理念&#xff0c;使开发者能够快速搭建生产级的AI应用…

电机控制储备知识 一 电机驱动本质分析以及磁相关的使用场景

一&#xff1a;电机旋转的原因 1.电机基本认识 &#xff08;1&#xff09;电机是一种动力装置&#xff0c;能够将电能转换为动能 电机拥有体积小 、动力足&#xff0c;控制精细灵活的特点 完整的电机系统&#xff1a;电机&#xff08;减速器 传感器&#xff09; 电机驱动器&a…

ubuntu交叉编译dbus库给arm平台使用

1.下载dbus库源码 https://www.freedesktop.org/wiki/Software/dbus 克隆源码: https://gitlab.freedesktop.org/dbus/dbus/-/tree/dbus-1.12?ref_type=heads 下载1.12.20版本: 指定pkgconfig环境变量: export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$PWD/../expat-2.3.…

推荐一款音乐神器:想听就听,想下就下~

在这个音乐充斥生活的时代&#xff0c;你是否也曾想过&#xff0c;有一款软件可以随时随地畅听你喜欢的音乐&#xff1f;今天&#xff0c;我要向你推荐一款令人心动的音乐神器——MusicFree&#xff0c;让你真正体验“想听就听&#xff0c;想下就下”的乐趣&#xff01; 那么&a…

aws(学习笔记第十课) 对AWS的EBS如何备份(snapshot)以及使用snapshot恢复数据,AWS实例存储

aws(学习笔记第十课) 对AWS的EBS如何备份&#xff08;snapshot&#xff09;以及使用snapshot&#xff0c;AWS实例存储 学习内容&#xff1a; 对AWS的EBS如何备份AWS实例存储EBS和实例存储的不足 1. 对AWS的EBS如何备份&#xff08;snapshot&#xff09;以及使用snapshot恢复数…

Unity照片墙效果

Unity照片墙效果&#xff0c;如下效果展示 。 工程源码

qt QMenu详解

1、概述 QMenu是Qt框架中的一个类&#xff0c;用于创建和管理菜单。它提供了丰富的接口来添加菜单项&#xff08;通常是QAction对象&#xff09;、子菜单以及分隔符。QMenu可以嵌入到菜单栏&#xff08;QMenuBar&#xff09;中&#xff0c;也可以作为弹出菜单&#xff08;通过…

倍增 st表 RMQ问题

本章我们来谈谈&#xff0c;倍增 && st表 && RMQ问题。 倍增 倍增即成倍增长。是指我们在进行递推时&#xff0c;如果状态空间很大&#xff0c;线性递推无法满足时空要求&#xff0c;此时可以考虑成倍增长的方式&#xff0c;只递推状态空间在2的整数次幂位置上…

51单片机应用开发(进阶)---定时器应用(电子秒表)

实现目标 1、巩固定时器的配置流程&#xff1b; 2、掌握按键、数码管与定时器配合使用&#xff1b; 3、秒表具体实现&#xff1a;&#xff08;1&#xff09;按K1开始计时&#xff0c;再按K1暂停计时.......&#xff1b;&#xff08;2&#xff09;按K2计时清零&#xff1b;&a…

吴恩达深度学习笔记(11)13.

人脸检校&#xff1a;输入某人的照片以及姓名或ID&#xff0c;判断是不是他所说的那个人 人脸识别&#xff1a; 单样本学习&#xff1a; 大多数人脸识别的问题需要在样本中只有一张照片的情况下认出一个人。 相似性函数&#xff1a;利用神经网络训练一个函数&#xff0c;可…

链表详解(三)

目录 链表功能实现链表的查找SLNode* SLFind(SLNode* phead, SLNDataType x)代码 链表任意位置前插入void SLInsert(SLNode**pphead&#xff0c;SLNode* pos, SLNDataType x)代码 链表任意位置前删除void SLErase(SLNode**pphead&#xff0c;SLNode* pos)代码 链表任意位置后插…

《C#语法一篇通》,20万字,48小时阅读,持续完善中。。。

本文摘录了C#语法的主要内容&#xff0c;接近20万字。 所有鸡汤的味道都等于马尿&#xff01; 如果你相信任何所谓的鸡汤文章&#xff0c;智商堪忧。 计算机语言没有”好不好“之说&#xff0c;骗子才会告诉你哪个语言好&#xff0c;学好任何一本基础语言&#xff08;C&#…

HarmonyOS开发 - 餐饮APP中多门店多窗口打开实例补充

specified启动模式为指定实例模式&#xff0c;有一些特殊场景&#xff0c;例如多门店应用中每次打开一个门店都希望能新建一个门店实例&#xff0c;而重复打开同一个门店都是同一门店实例。 此篇为餐饮APP中多门店实例的补充内容&#xff0c;以解决同一门店多次点击重复创建新窗…

【Redis问题】(error) NOAUTH Authentication required.解决方法

问题描述&#xff1a; “(error) NOAUTH Authentication required”&#xff0c;通过ping方法和redis打招呼发现不成功&#xff0c;意思是没有这个权限&#xff08;也就是没有密码&#xff09; 问题解决1&#xff1a; 在命令后面加上密码&#xff08;一般情况下&#xff0c;在…

关于自动化测试用例失败重试的一些思考

自动化测试用例失败重跑有助于提高自动化用例的稳定性&#xff0c;那我们来看一下&#xff0c;python和java生态里都有哪些具体做法&#xff1f; 怎么做 如果是在python生态里&#xff0c;用pytest做测试驱动&#xff0c;那么可以通过pytest的插件pytest-rerunfailures来实现…

Vue Router进阶详解

导航守卫 若依框架登录鉴权详解&#xff08;动态路由&#xff09;_若依鉴权-CSDN博客 完整的导航解析流程 导航被触发&#xff1a; 当用户点击页面中的链接、使用编程式导航&#xff08;如router.push或router.replace&#xff09;或手动输入URL时&#xff0c;导航流程被触发。…

Rust 力扣 - 1984. 学生分数的最小差值

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 原数组 nums 排序&#xff0c;遍历nums中下标为[0, nums.len() - k]的学生分数 假设当前遍历的下标为i则&#xff0c;以 i 下标为最小值的学生分数的最小差值为nums[i k - 1] - nums[i] 取最小差值的最小值即…