STM32MX配置EEPROM(AT24C02)------保姆级教程

news2024/12/25 9:00:03

————————————————————————————————————
⏩ 大家好哇!我是小光,嵌入式爱好者,一个想要成为系统架构师的大三学生。
⏩最近在开发一个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");
    }
    // 连续数据读写 测试结束


测试结果

在这里插入图片描述
可以看到存取单个字节、多个字节、浮点数、双精度浮点数、整型数都没有问题。

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

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

相关文章

临床检验系统LIS

临床检验系统(Laboratory Information System)是一个能实现检验信息电子化、检验信息管理自动化的网络系统&#xff0c;其主要功能是将检验的实验仪器传出的检验数据经分析后&#xff0c;生成检验报告&#xff0c;通过网络存储在数据库中&#xff0c;使医生能够方便、及时的看到…

助力中小企业数字化改造 象过河把中小企业老板当成“自己人”

燥热的夏日午后&#xff0c;在郑州市国家大学科技园附近的一家咖啡店里约见了象过河软件研发的总负责人象海先生。 温文儒雅、润物无声的象海先生自信豁达、成熟冷静。软件开发技术出身的他&#xff0c;善于通过软件开发定制来帮助中小企业解决各种错综复杂的业务、仓储以及财…

Could not resolve placeholder

本质原因&#xff1a;项目启动未扫描到该配置&#xff0c;一般来说是配置不对 检查方向 1、检查编译后的target包里是否有该配置所在的文件 如果不在就clear&#xff0c;重新编译启动再去检查 2、检查启动的环境是否匹配 编译后的target包下的配置文件名称是否跟启动类的环境…

app流量变现流量分发策略——waterfall技术

waterfall&#xff0c;中文翻译为“瀑布流”&#xff0c;字面意思理解就是“从上往下流”&#xff0c;但“从上到下”这四个字该如何理解&#xff1f; 在广告行业中&#xff0c;waterfall指的是“在无法实时评估每次流量的价值时&#xff0c;基于历史eCPM数据&#xff0c;从上…

Docker OOM处理方式

优质博文&#xff1a;IT-BLOG-CN cicode xxx k8s docker events oom occured告警原因 特别需要注意的是&#xff1a;docker events oom的处理方法不同于java.lang.OutOfMemoryError。 当我们在PAAS/Captain上申请容器实例时&#xff0c;会设置内存Limit。比如容器Flavor为2C4…

【Nodejs】npm的使用

1.包和npm 1.1 什么是包 由于 Node 是一套轻内核的平台&#xff0c;虽然提供了一系列的内置模块&#xff0c;但是不足以满足开发者的需求&#xff0c;于是乎出现了包&#xff08;package&#xff09;的概念&#xff1a; 与核心模块类似&#xff0c;就是将一些预先设计好的功能…

20.0 HTTP通信

1. web开发 1.1 web开发介绍 Web指的是World Wide Web(万维网), 是一种基于互联网的信息系统. 万维网由一系列通过超文本链接相互连接的页面组成, 这些页面中包含了文本, 图像, 音频, 视频等多媒体内容. 用户可以通过浏览器访问万维网上的网页, 并通过超链接在不同页面之间导…

网页布局元素填充思路 ———— 先布局,再局部

【引言】 今天来分享一下在JS练习项目中学习到的网页布局思路&#xff0c;适合刚接触JS的小白在做练习项目&#xff0c;不知所措的时候看喔~ 简单来说就是 ———— 先布局&#xff0c;再局部。 在初次做练习项目的时候&#xff0c;大多都会先仿照一个网站先进行一个试练&…

商城后台系统的多规格

需要添加多规格,并且还要根据算法生成对应的规格列表 1、获取此规格值数据类型 specsList:[{title: "颜色",specsTag:[蓝色,绿色],},{title: "尺码",specsTag:[165*130,L,XL], }] 2、处理数据 let skuList = []for(const { specsTag } of this.specsLi…

StableDiffusion 换脸实现

先看效果&#xff1a; 想要换的脸&#xff1a; 想要把脸放到的目标图片&#xff1a; 实现方案&#xff1a; StableDiffusionroop&#xff08;本次实验基于roopV0.02版本&#xff09; 1/安装SD&#xff0c;模型选择 DreamShaper,Sampler使用 Euler a 2/安装roop插件 roop插…

adnroid 11. 0 Activity启动流程图解

从Launcher到ActivityTaskManager 从ActivityTaskManagerService 到 ApplicationThread 从ApplicationThread到onCreate

CSS实现文字渐变色

css样式 style"background: linear-gradient(to right, red, #FFA387);-webkit-background-clip: text;color: transparent;"效果

结构型设计模式-1.代理设计模式

结构型设计模式-1.代理设计模式 结构型设计模式&#xff1a;利用类与类之间的关系&#xff08;继承、组合&#xff09;&#xff0c;形成一种类与类之间的结构&#xff0c;通过这种结构提高代码的可拓展性、可维护性和可重用性。 一、简介 代理设计模式&#xff08;Proxy Des…

从零开始制作婚礼策划展示小程序

随着移动互联网的发展&#xff0c;小程序已经成为各行各业展示和推广自己的重要工具之一。对于婚礼策划行业来说&#xff0c;制作一个专属的婚礼策划展示小程序&#xff0c;不仅能提升服务的专业性和便利性&#xff0c;还能吸引更多的客户。下面将介绍从零开始制作婚礼策划展示…

【MySQL技术专题】「问题实战系列」深入探索和分析MySQL数据库的数据备份和恢复实战开发指南(系统底层优化篇)

深入探索和分析MySQL数据库的全方位的优化实战开发指南&#xff08;数据库底层优化篇&#xff09; 硬件层面优化数据库物理机分析底层技术优化磁盘性能优化随机IO能力的能力支持 RAID磁盘阵列RAID10RAID10的优势 网卡优化网络设备坑点问题建议 服务器硬件配置调整服务器BIOS调整…

Layout软件中的焊盘的一般命名方法是什么呢?

答&#xff1a;对于不同的焊盘有不同命名方法&#xff0c;这里给大家介绍一下普遍的命名方法&#xff0c;具体如下所示&#xff1a; 贴片类焊盘命名方式&#xff1a; 1&#xff09;圆焊盘circle &#xff1a;SC 直径&#xff0c;如&#xff1a; SC1R00&#xff0c;即直径为1m…

多种语言示例采集数据【淘宝天猫1688拼多多API系列】可高并发线程

长话短说&#xff0c;节约彼此宝贵时间&#xff0c;我们以淘宝商品详情数据为例&#xff1a; 请求方式&#xff1a;HTTPS POST GET 请求地址&#xff1a;https://o0b.cn/anzexi taobao.item_get 公共参数 名称类型必须描述技术交流18179014480keyString是调用key&#xf…

探寻智能化未来:AI与Web3共创金融领域巨大潜力

人工智能&#xff08;AI&#xff09;和Web3技术的迅猛发展为我们带来了许多新的机遇和影响。在数字经济和社会的浪潮中&#xff0c;结合了AI的智能化能力和Web3的去中心化与区块链技术&#xff0c;我们将进入一个智能化的Web3时代。人工智能和Web3技术是开拓生产力极限和重新定…

Docker 数据管理

Docker 数据管理 一、docker数据管理 1.数据卷 数据卷是一个供容器使用的特殊目录&#xff0c;位于容器中。可将宿主机的目录挂载到数据卷上&#xff0c;对数据卷的修改操作立刻可见&#xff0c;并且更新数据不会影响镜像&#xff0c;从而实现数据在宿主机与容器之间的迁移。…

QT构建套件(Kit)黄色感叹号问题解决

构建套件&#xff08;Kit&#xff09;黄色感叹号问题 1:看下面的图出现了黄色警告&#xff0c;此时这个构建套件 就是不允许使用的 2&#xff1a;查看一下MSVC的dedbug调试器(cdb.exe) 如果没有&#xff0c;我们需要下载cdb.exe cdb.exe下载方法 2.1首先我们可以打开我们系…