STM32MX配置EEPROM(AT24C02)------保姆级教程
————————————————————————————————————
⏩ 大家好哇!我是小光,嵌入式爱好者,一个想要成为系统架构师的大三学生。
⏩最近在开发一个STM32H723ZGT6的板子,使用STM32CUBEMX做了很多驱动,包括ADC、UART、RS485、EEPROM(IIC)、FLASH(SPI)等等。
⏩本篇文章对STM32CUBEMX配置RRPROM(AT24C02)做一个详细的使用教程。
⏩感谢你的阅读,不对的地方欢迎指正。
————————————————————————————————————
EEPROM
- AT24C02工作原理
- 实验环境
- MX配置
- 驱动代码
- 测试结果
AT24C02工作原理
引脚封装

SCL 串行时钟
AT24C02串行时钟输入管脚用于产生器件所有数据发送或接收的时钟,这是一个输入管脚。
SDA 串行数据/地址
AT24C02 双向串行数据/地址管脚用于器件所有数据的发送或接收,SDA 是一个开漏输出管脚,可与其它开漏输出或集电极开路输出进行线或(wire-OR)。
A0、A1、A2 器件地址输入端
这些输入脚用于多个器件级联时设置器件地址,当这些脚悬空时默认值为0。当使用AT24C02 时最大可级联8个器件。如果只有一个AT24C02被总线寻址,这三个地址输入脚(A0、A1、A2 )可悬空或连接到Vss or GND。
WP 写保护
如果WP管脚连接到Vcc,所有的内容都被写保护只能读。当WP管脚连接到Vss or GND 或悬空允许器件进行正常的读/写操作。
具体原理可以参考
AT24C02芯片使用介绍
实验环境
- USB转串口
- AT24C02
- STM32H723ZGT6开发板
硬件连接:

我这里接的是PB8和PB9
MX配置
板子、时钟、调试之类的配置就不说了,具体可以看看这篇:
STM32CUBEMX配置ADC(多通道轮询)(STM32H7)–保姆级教程
这里只说一下IIC的具体配置
根据你的连接自己配置

我的引脚是PB8,PB9

驱动代码
at24C02.h
我使用两个共用体去存储浮点型和整形的数据,这是最简单的方法。
#ifndef AT24C02_H_
#define AT24C02_H_#include "stm32H7xx_hal.h" //HAL库文件声明#define AT24C02_ADDR_WRITE 0xA0 // 写命令
#define AT24C02_ADDR_READ 0xA1 // 读命令#define ADDR_24LCxx_Write 0xA0 //AT24C02写地址
#define ADDR_24LCxx_Read 0xA1 //AT24C02读地址
#define BufferSize 256 //读写缓冲区大小union float_union{float float_write_dat; // 浮点数占4个字节double double_write_dat; // 双精度浮点数占8个字节uint8_t buf[8]; // 定义 8个字节 的空间
};
union int_union{int int_dat; //整型数占四个字节uint8_t buf[4]; //定义4个字节的空间
};uint8_t At24c02_Write_Byte(uint16_t addr, uint8_t* dat); //AT24C02任意地址写一个字节数据
uint8_t At24c02_Read_Byte(uint16_t addr, uint8_t* read_buf);//AT24C02任意地址读一个字节数据
uint8_t At24c02_Write_Amount_Byte(uint16_t addr, uint8_t* dat, uint16_t size);// AT24C02任意地址连续写多个字节数据
uint8_t At24c02_Read_Amount_Byte(uint16_t addr, uint8_t* recv_buf, uint16_t size);//AT24C02任意地址连续读多个字节数据
#endif
at24c02.c
#include "at24c02.h"
#include "i2c.h"
/*** @brief AT24C02任意地址写一个字节数据* @param addr —— 写数据的地址(0-255)* @param dat —— 存放写入数据的地址* @retval 成功 —— HAL_OK
*/
uint8_t At24c02_Write_Byte(uint16_t addr, uint8_t* dat)
{HAL_StatusTypeDef result;result = HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, addr, I2C_MEMADD_SIZE_8BIT, dat, 1, 0xFFFF);HAL_Delay(5); // 写一个字节,延迟一段时间,不能连续写return result;
}/*** @brief AT24C02任意地址读一个字节数据* @param addr —— 读数据的地址(0-255)* @param read_buf —— 存放读取数据的地址* @retval 成功 —— HAL_OK
*/
uint8_t At24c02_Read_Byte(uint16_t addr, uint8_t* read_buf)
{return HAL_I2C_Mem_Read(&hi2c1, AT24C02_ADDR_READ, addr, I2C_MEMADD_SIZE_8BIT, read_buf, 1, 0xFFFF);
}/*** @brief AT24C02任意地址连续写多个字节数据* @param addr —— 写数据的地址(0-255)* @param dat —— 存放写入数据的地址* @retval 成功 —— HAL_OK
*/
uint8_t At24c02_Write_Amount_Byte(uint16_t addr, uint8_t* dat, uint16_t size)
{uint8_t i = 0;uint16_t cnt = 0; // 写入字节计数HAL_StatusTypeDef result; // 返回是否写入成功/* 对于起始地址,有两种情况,分别判断 */if(0 == addr % 8){/* 起始地址刚好是页开始地址 *//* 对于写入的字节数,有两种情况,分别判断 */if(size <= 8){// 写入的字节数不大于一页,直接写入result = HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, addr, I2C_MEMADD_SIZE_8BIT, dat, size, 0xFFFF);HAL_Delay(20); // 写完八个字节(最多八个字节),延迟久一点return result;}else{// 写入的字节数大于一页,先将整页循环写入for(i = 0; i < size/8; i++){HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, addr, I2C_MEMADD_SIZE_8BIT, &dat[cnt], 8, 0xFFFF);// 一次写入了八个字节,延迟久一点HAL_Delay(20); // 写完八个字节,延迟久一点addr += 8;cnt += 8;}// 将剩余的字节写入result = HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, addr, I2C_MEMADD_SIZE_8BIT, &dat[cnt], size - cnt, 0xFFFF);HAL_Delay(20); // 写完八个字节(最多八个字节),延迟久一点return result;}}else{/* 起始地址偏离页开始地址 *//* 对于写入的字节数,有两种情况,分别判断 */if(size <= (8 - addr%8)){/* 在该页可以写完 */result = HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, addr, I2C_MEMADD_SIZE_8BIT, dat, size, 0xFFFF);HAL_Delay(20); // 写完八个字节(最多八个字节),延迟久一点return result;}else{/* 该页写不完 */// 先将该页写完cnt += 8 - addr%8;HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, addr, I2C_MEMADD_SIZE_8BIT, dat, cnt, 0xFFFF);HAL_Delay(20); // 写完八个字节(最多八个字节),延迟久一点addr += cnt;// 循环写整页数据for(i = 0;i < (size - cnt)/8; i++){HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, addr, I2C_MEMADD_SIZE_8BIT, &dat[cnt], 8, 0xFFFF);HAL_Delay(20); // 写完八个字节,延迟久一点addr += 8;cnt += 8;}// 将剩下的字节写入result = HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, addr, I2C_MEMADD_SIZE_8BIT, &dat[cnt], size - cnt, 0xFFFF);HAL_Delay(20); // 写完八个字节(最多八个字节),延迟久一点return result;} }
}/*** @brief AT24C02任意地址连续读多个字节数据* @param addr —— 读数据的地址(0-255)* @param dat —— 存放读出数据的地址* @retval 成功 —— HAL_OK
*/
uint8_t At24c02_Read_Amount_Byte(uint16_t addr, uint8_t* recv_buf, uint16_t size)
{return HAL_I2C_Mem_Read(&hi2c1, AT24C02_ADDR_READ, addr, I2C_MEMADD_SIZE_8BIT, recv_buf, size, 0xFFFF);
}
main.c
//AT24C02
uint8_t WriteBuffer[BufferSize] = {0};//AT24C02写缓冲区
uint8_t ReadBuffer[BufferSize] = {0}; //AT24C02读缓冲区//测试// 单个字节 读写测试uint8_t simple_write_dat = 0xa5; // 一个字节uint8_t simple_recv_buf = 0;if(HAL_OK == At24c02_Write_Byte(10, &simple_write_dat)){printf("Simple data write success \r\n");} else {printf("Simple data write fail \r\n");}HAL_Delay(50); // 写一次和读一次之间需要短暂的延时if(HAL_OK == At24c02_Read_Byte(10, &simple_recv_buf)){printf("Simple data read success, recv_buf = 0x%02X \r\n", simple_recv_buf);} else {printf("Simple data read fail \r\n");}printf("--------------------- \r\n");// 单个字节读写 测试结束// 浮点数 读写测试union float_union send_float_data; // 用来发送union float_union rev_float_data; // 用来接收union int_union send_int_data; //发送union int_union rev_int_data; //接收// 先测试第一个 浮点数send_float_data.float_write_dat = 3.1415f;if(HAL_OK == At24c02_Write_Amount_Byte(20, send_float_data.buf, 4)){printf("Float data write success \r\n");} else {printf("Float data write fail \r\n");}HAL_Delay(50);if(HAL_OK == At24c02_Read_Amount_Byte(20, rev_float_data.buf, 4)){// 默认输出六位小数printf("Float data read success, recv_buf = %f \r\n", rev_float_data.float_write_dat);} else {printf("Float data read fail \r\n");}// 测试第二个 双精度浮点数send_float_data.double_write_dat = 3.1415f;if(HAL_OK == At24c02_Write_Amount_Byte(20, send_float_data.buf, 8)){printf("Double data write success \r\n");} else {printf("Double data write fail \r\n");}HAL_Delay(50);if(HAL_OK == At24c02_Read_Amount_Byte(20, rev_float_data.buf, 8)){// 最多15位小数printf("Double data read success, recv_buf = %.15f \r\n", rev_float_data.double_write_dat);} else {printf("Double data read fail \r\n");}printf("--------------------- \r\n");// 浮点数读写测试 测试结束// 测试第三个 整形数send_int_data.int_dat = 2147483647;if(HAL_OK == At24c02_Write_Amount_Byte(30,send_int_data.buf, 4)){printf("int data write success \r\n");} else {printf("int data write fail \r\n");}HAL_Delay(50);if(HAL_OK == At24c02_Read_Amount_Byte(30, rev_int_data.buf, 4)){printf("int data read success, recv_buf = %d \r\n", rev_int_data.int_dat);} else {printf("int data read fail \r\n");}printf("--------------------- \r\n");// 整型数读写测试 测试结束// 连续数据读写测试uint8_t write_dat[22] = {0}; // 22个字节uint8_t recv_buf[22] = {0};printf("正在往数组中填充数据... \r\n");for(int i = 0; i < 22; i++){write_dat[i] = i;printf("%02X ", write_dat[i]);}printf("\r\n 数组中数据填充完毕... \r\n");if(HAL_OK == At24c02_Write_Amount_Byte(0, write_dat, 22)){printf("24c02 write success \r\n");} else {printf("24c02 write fail \r\n");}HAL_Delay(50); // 写一次和读一次之间需要短暂的延时if(HAL_OK == At24c02_Read_Amount_Byte(0, recv_buf, 22)){printf("read success \r\n");for(int i = 0; i < 22; i++) {printf("0x%02X ", recv_buf[i]);}} else {printf("read fail\r\n");}// 连续数据读写 测试结束
测试结果

可以看到存取单个字节、多个字节、浮点数、双精度浮点数、整型数都没有问题。
相关文章:
STM32MX配置EEPROM(AT24C02)------保姆级教程
———————————————————————————————————— ⏩ 大家好哇!我是小光,嵌入式爱好者,一个想要成为系统架构师的大三学生。 ⏩最近在开发一个STM32H723ZGT6的板子,使用STM32CUBEMX做了很多驱动&#x…...
微信小程序 样式和全局配置
WXSS wxss 把屏幕分为750个物理像素,大屏大,小屏小,随着设备不一致自动适配 推荐使用iPhone6作为标准,1个rpx 0.5个px,把px乘以2就是rpx的参数 import 导入外部样式表 import /common/common.wxss 样式 权重一…...
一.初识C语言
一.初识C语言 C语言标准规定: sizeof(long)>sizeof(int)就可以了变量要定义在当前代码块的最前面 #defin _CRT_SECURE_NO_WARNINGS 1#include <stdio.h> //包含一个stdio.h的文件 std-标准standard input outputint main() //主函数-程序的入口-main函数…...
filebeat到kafka示例
docker run -d \ --namefilebeat_7.14_0 \ #filebeat名称 --userroot \ --volume"/data/filebeat/filebeat.yml:/usr/share/filebeat/filebeat.yml" \ #映射filebeat.yml配置 --volume"/data/filebeat/log:/usr/share/filebeat/log" \…...
AlmaLinux系统下的Zabbix汉化
我安装的是zabbix下的虚拟机,安装完成后,直接可以打开网站了,但是界面是英文,看了设置,没有中文选项,就需要在系统中安装中文字符集了。 # locale -a #查看里面没有zh_CN之类的项 # dnf install -…...
【网络编程】(TCP流套接字编程 ServerSocket API Socket API 手写TCP版本的回显服务器 TCP中的长短连接)
文章目录 网络编程TCP流套接字编程ServerSocket APISocket APITCP中的长短连接手写TCP版本的回显服务器 网络编程 TCP流套接字编程 TCP提供的API主要是两个类:ServerSocket 和 Socket . TCP不需要一个类来表示"TCP数据报"因为TCP不是以数据报为单位进行传输的.是以…...
企业级PaaS低代码快开平台源码,基于 Salesforce Platform 的开源替代方案
PaaS低代码快开平台是一种快速开发应用系统的工具,用户通过少量代码甚至不写代码就可以快速构建出各种应用系统。 随着信息化技术的发展,企业对信息化开发的需求正在逐渐改变,传统的定制开发已经无法满足企业需求。低代码开发平台࿰…...
【LeetCode】72.编辑距离
题目 给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。 你可以对一个单词进行如下三种操作: 插入一个字符删除一个字符替换一个字符 示例 1: 输入:word1 "horse", word2 "…...
大模型,开源干不掉闭源
开源大模型对闭源大模型的冲击,变得非常猛烈。 今年3月,Meta发布了Llama(羊驼),很快成为AI社区内最强大的开源大模型,也是许多模型的基座模型。有人戏称,当前的大模型集群,就是一堆各…...
Redis 九种数据类型的基本操作
一、redis9种数据类型的基本操作 ①key操作 #查找所有的key 127.0.0.1:6379> keys * 1) "pop" 2) "mylist" 3) "lpl" 4) "myset" #设置key的过期时间 返回1表示执行成功,0表示失败,出现问题 127.0.0.1:6379…...
爬取微博热搜榜并进行数据分析
设计方案 爬虫爬取的内容 :爬取微博热搜榜数据。 网络爬虫设计方案概述 用requests库访问页面用get方法获取页面资源,登录页面对页面HTML进行分析,用beautifulsoup库获取并提取自己所需要的信息。再讲数据保存到CSV文件中,进行…...
基于深度神经网络的肺炎检测系统实现
一、说在前面 使用AI进行新冠肺炎图像诊断可以加快病例的诊断速度,提高诊断的准确性,并在大规模筛查中发挥重要作用,从而更好地控制和管理这一流行病。然而,需要强调的是,AI技术仅作为辅助手段,最终的诊断决…...
C# LINQ和Lambda表达式对照
C# LINQ和Lambda表达式对照 1. 基本查询语句 Linq语法: var datafrom a in db.Areas select a ; Lamda语法: var datadb.Areas; sql语法: SELECT * FROM Areas2. 简单的WHERE语句 Linq语法: var datafrom a in db.orderI…...
二、SQL-6.DCL-1).用户管理
一、DCL介绍 Data Control Language 数据控制语言 用来管理数据库 用户、控制数据库的 访问权限。 二、语法 1、管理用户 管理用户在系统数据库mysql中的user表中创建、删除一个用户,需要Host(主机名)和User(用户名࿰…...
ElasticSearch学习--数据聚合
介绍 数据聚合可以帮助我们对海量的数据进行统计分析,如果结合kibana,我们还能形成可视化的图形报表。自动补全可以根据用户输入的部分关键字去自动补全和提示。数据同步可以帮助我们解决es和mysql的数据一致性问题。集群可以帮助我们了解结构和不同节点…...
PostMan+Jmeter工具介绍及安装
目录 一、PostMan介绍编辑 二、下载安装 三、Postman与Jmeter的区别 一、开发语言区别: 二、使用范围区别: 三、使用区别: 四、Jmeter安装 附一个详细的Jmeter按照新手使用教程,感谢作者,亲测有效。 五、Jme…...
AutoSAR系列讲解(实践篇)7.4-实验:配置SWCRTE
注意: 实验篇是重点,有条件的同学最好跟着做一遍,然后回头对照着7.1-7.3理解其配置的目的和意义。实验下篇将在7.7节中继续做 一、实验概览 1、实验目的 通过本次实验,主要是让大家对Dev的配置有一个全流程的学习。这里会用到前两节的内容,将其串联起来,让大家能完整的…...
腾讯云内存型CVM服务器MA3、M6、M6ce和M5处理器CPU说明
腾讯云内存型CVM服务器CPU处理器大全,CVM内存型MA3、内存型M6、安全增强内存型M6ce、内存型M6p、内存型M5、MA2、M4、M3、M2、M1处理器主频、CPU性能性能大全说明,腾讯云内存型云服务器具有大内存的特点,适合高性能数据库、分布式内存缓存等需…...
集睿致远推出CS5466多功能拓展坞方案:支持DP1.4、HDMI2.1视频8K输出
ASL新推出的 CS5466是一款Type-C/DP1.4转HDMI2.1的显示协议转换芯片,,它通过类型C/显示端口链路接收视频和音 频流,并转换为支持TMDS或FRL输出信令。DP接收器支持81.Gbp s链路速率。HDMI输出端口可以作为TMDS或FRL发射机工作。FRL发射机符合HDMI 2.1规范…...
SQL中为何时常见到 where 1=1?
你是否曾在 SELECT 查询中看到过 WHERE 11 条件。我在许多不同的查询和许多 SQL 引擎中都有看过。这条件显然意味着 WHERE TRUE,所以它只是返回与没有 WHERE 子句时相同的查询结果。此外,由于查询优化器几乎肯定会删除它,因此对查询执行时间没…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...
