STM32CUBEMX+STM32F405RGT6+I2C+AT24C02学习应用

news2025/1/11 6:12:23
I2C 通讯 机制 较为 繁琐 但是I2C的速率比较低,而且EEPROM的容量不大,比如AT24C02的容量 只有 2Kb,即256B(字节)。 对于 想快速实现I 2 C 功能应用,我们借助STM32的HAL库函数 可以 做到

一、工具版本

stm32cubemx 版本STM32CubeMX 6.12.1

AT24C02华轩阳电子生产

项目需要用I2C读写AT24C02。分别就读和写的两个典型函数来分析。

二、I2C写函数

1、IIC主机写函数

阻塞中断DMA三种分别

HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout); // 阻塞

HAL_I2C_Master_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size)// 中断

HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size)//DMA

三者功能基本一致选择阻塞发送

HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress,uint8_t *pData,uint16_t Size,uint32_t Timeout);

功能:IIC主机写数据

参数:

*hi2c 选择选用的II句柄 例:&hi2c1

DevAddress 写入的设备地址 设置写入数据的设备地址 例 0xA0

*pData 需要写入的数据8

Size 要发送的字节数16

Timeout 最大传输时间,超过传输时间将自动退出传输函数

我们查看收据手册地址一个8前面4固定10105-7选配支持主机挂载多个从机这里我们只用了一个从机A2A1A0拉低均为0

8/命令位:高电平进入模式低电平进入模式

读模式从机地址1010 0001 0xA1

模式从机地址1010 0000 0xA0

这个函数适用从机固定存储地址单个存储地址

我们AT24C02,编写一个主机写函数

HAL_I2C_Master_Transmit(&hi2c1, 0xA0,WriteBuffer, 1, 0xff);

2、写多个数据函数

HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)

功能:IIC主机对从机写入多个数据

参数:

*hi2c 选择选用的II句柄 例:&hi2c1

DevAddress 写入的从机设备地址 设置写入从机设备的地址 例 0xA0

MemAddress 从机寄存器或从机存储空间的起始地址

MemAddSize 从机寄存器从机存储单个字节长度 常见816

*pData 需要写入的数据8

Size 要发送的字节数16

Timeout 最大传输时间,超过传输时间将自动退出传输函数

这个函数适用从机内部寄存器或者从机存储空间有多个地址写入多个数据

我们AT24C02,编写一个写多个数据函数

HAL_I2C_Mem_Write(&hi2c1, 0xA0,0,I2C_MEMADD_SIZE_8BIT,WriteBuffer, 16,0xFF);

函数AT24C02写入16数据

这里选择字节16并不是8可能大家疑问之前别人写的文章8个。再来查看数据手册

可以看到这款AT24C0216每页有16字节。所以每次数据最多可以写入16字节

、I2C函数

1、IIC主机函数

阻塞中断DMA三种分别

HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout); // 阻塞

HAL_I2C_Master_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size)// 中断

HAL_I2C_Master_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size)//DMA

三者功能基本一致选择阻塞函数

HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress,uint8_t *pData,uint16_t Size,uint32_t Timeout);

功能:IIC主机读数据

参数:

*hi2c 选择选用的I2C句柄 例:&hi2c1

DevAddress 读出的设备地址 设置读数据的设备地址 例 0xA1。

*pData 需要读出的数据8

Size 要读出的字节数16

Timeout 最大传输时间,超过传输时间将自动退出传输函数

这个函数适用从机固定存储地址单个存储地址

我们AT24C02,编写一个主机函数

HAL_I2C_Master_Receive(&hi2c1, 0xA1,ReadBuffer, 1, 0xff);

2、读多个数据函数

HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)

功能:IIC主机对从机读出多个数据

参数:

*hi2c 选择选用的I2C句柄 例:&hi2c1

DevAddress 读出的从机设备地址 设置读出从机设备的地址 例 0xA1。

MemAddress 从机寄存器或从机存储空间的起始地址

MemAddSize 从机寄存器从机存储单个字节长度 常见816

*pData 需要读出的数据8

Size 要发送的字节数16

Timeout 最大传输时间,超过传输时间将自动退出传输函数

这个函数适用从机内部寄存器或者从机存储空间有多个地址连续读出多个数据

我们AT24C02,编写一个读出多个数据函数

HAL_I2C_Mem_Read(&hi2c1,0xA1,0,I2C_MEMADD_SIZE_8BIT,ReadBuffer, 10,0xFF);

函数AT24C02读出10数据

注意AT24C02数据不存在数字节的限制可以任意设置起始地址和数据长度,支持跨页读出

三、代码部分

我们stm32cubemx生成一个初始化代码

1、时钟,外部无源晶振

2、烧写模式选择SW模式

  • 3、I2C配置

选择I2C1模式选择标准模式100KHz均为默认

  • 4、串口设置

  • 选择USART1默认配置

  • 5、时钟

  • 6、勾选

  • 7、设置初始化代码地址名称生成初始化代码

8、打开初始化代码添加文件

/* USER CODE BEGIN Includes */

#include "stdio.h"

#include "string.h"

/* USER CODE END Includes */

9添加宏定义

/* USER CODE BEGIN PM */



#define ADDR_24LCxx_Write 0xA0 //AT24C02对应的写地址

#define ADDR_24LCxx_Read 0xA1 //AT24C02对应的读地址

#define BufferSize 256



/* USER CODE END PM */

10、添加变量

/* USER CODE BEGIN PV */

uint8_t WriteBuffer[BufferSize],ReadBuffer[BufferSize]; //写入数据和读出数据缓冲区

uint16_t i;

/* USER CODE END PV */

添加串口打印函数
/* USER CODE BEGIN 0 */

/**

* 函数功能: 重定向c库函数printf到DEBUG_USARTx

* 输入参数: 无

* 返 回 值: 无

* 说 明:无

*/

int fputc(int ch, FILE *f)

{

HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);

return ch;

}

/**

* 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx

* 输入参数: 无

* 返 回 值: 无

* 说 明:无

*/

int fgetc(FILE *f)

{

uint8_t ch = 0;

HAL_UART_Receive(&huart1, &ch, 1, 0xffff);

return ch;

}

/* USER CODE END 0 */
  • 11、写入

/* USER CODE BEGIN 2 */

for(i=0;i<256;i++)

{

WriteBuffer[i]=i;

}

printf("\r\n<<<<<<<<<<<<<<I2C Test<<<<<<<<<<<<<\r\n");

for (int j=0; j<16; j++)//分为16页,每页16个字节

{

if(HAL_I2C_Mem_Write(&hi2c1, ADDR_24LCxx_Write, 16*j, I2C_MEMADD_SIZE_8BIT,((uint8_t *)WriteBuffer+16*j),16, 1000) == HAL_OK)

{

HAL_Delay(20);//写入需要时间

printf("\r\n EEPROM 24C02 %d page Write Test OK \r\n",j+1);



}

else

{

HAL_Delay(20);//写入需要时间

printf("\r\n EEPROM 24C02 Write Test False \r\n");

}

}

printf("\r\n\r\n");

HAL_I2C_Mem_Read(&hi2c1, ADDR_24LCxx_Read, 0, I2C_MEMADD_SIZE_8BIT,ReadBuffer,BufferSize, 0xff);

for(i=0; i<256; i++)

printf("0x%02X ",ReadBuffer[i]);

printf("\r\n\r\n");

/* USER CODE END 2 */

运行结果

我们看到写入和读出都正常运行。

12、断电重启

为了验证I2C断电数据是否存在我们另外建立了一个专门数据工程文件

HAL_I2C_Mem_Read(&hi2c1, ADDR_24LCxx_Read, 0, I2C_MEMADD_SIZE_8BIT,RxBuffer,Max_Size, 0xff);

printf("\r\n<<<<<<<<<<<<<<<<<<<<<I2C OUTPUT <<<<<<<<<<<<<<<<<\r\n ");

for(i=0; i<256; i++)

{

printf("0x%02X ",RxBuffer[i]); //16进制读出

printf("%d ",RxBuffer[i]);

}

运行结果

可以看到,断电后,还能完整的读出数据。

13、跨页读取数据

接着,我们添加从AT24C02的地址空间第10位开始读取10个数据

HAL_I2C_Mem_Read(&hi2c1, ADDR_24LCxx_Read, 10, I2C_MEMADD_SIZE_8BIT,RxBuffer,10, 0xff);
		for(i=0; i<256; i++)
		{
			printf("0x%02X ",RxBuffer[i]);
       printf("%d ",RxBuffer[i]);  
		}		
						printf("\r\n\r\n");	

运行结果

我们看到,把读取的数组前10位数据做了覆盖。后面的数据没变化。

注意

接着,我们再说下,对于AT24C02不适用于HAL_I2C_Master_Transmit 和HAL_I2C_Master_Receive。

接着添加一个主机函数

HAL_I2C_Master_Receive(&hi2c1,ADDR_24LCxx_Read,RxBuffer,50,HAL_MAX_DELAY);//读取50个数据

for(i=0;i<100;i++)

{

printf("0x%02X ",RxBuffer[i]);

}

运行输出结果

然后我们继续添加一个主机函数

HAL_I2C_Master_Receive(&hi2c1,ADDR_24LCxx_Read,RxBuffer,50,HAL_MAX_DELAY);//读取50个数据

for(i=0;i<100;i++)

{

printf("0x%02X ",RxBuffer[i]);

}
//继续添加一个HAL_I2C_Master_Receive函数
HAL_I2C_Master_Receive(&hi2c1,ADDR_24LCxx_Read,RxBuffer,50,HAL_MAX_DELAY);//读取50个数据

for(i=0;i<100;i++)

{

printf("0x%02X ",RxBuffer[i]);

}

运行后输出结果

我们发现此时并不是0开始读数据而是从第一次读的位置(0x31),开始继续往后面数据。并将缓冲区前面50数据覆盖

这种就带来不可控风险

很有可能导致读出的不是我们想要的数据,为了保证程序的可靠性。

对于AT24C02最好使用 HAL_I2C_Mem_Write HAL_I2C_Mem_Read函数

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

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

相关文章

Python 基础学习(一)

一.基础语法 注释 Python中单行注释以 # 开头&#xff0c;如下&#xff1a; #!/usr/bin/python3# 第一个注释 print ("Hello, Python!") # 第二个注释多行注释可以用多个 # 号&#xff0c;还有 ‘’’ 和 “”"&#xff1a; #!/usr/bin/python3# 第一个注释…

guava 整合springboot 自定义注解实现接口鉴权调用保护

文章目录 一、简要概述二、实现过程1. pom引入依赖2. 自定义注解3. 定义切面4. 定义权限检查逻辑 三、注解使用四、运行结果五、源码放送 一、简要概述 Guava Cache是一个全内存的本地缓存实现&#xff0c;它提供了线程安全的实现机制。我们借助expireAfterWrite过期时间设置和…

Redis实战篇(二:商户查询缓存)

目录 三、商户查询缓存 1.缓存介绍 2.添加商户缓存 &#xff08;1&#xff09;缓存模型和思路 &#xff08;2&#xff09;代码实现 3.店铺类型缓存 4.缓存更新策略 5.实现商铺缓存与数据库双写一致 6.缓存穿透 &#xff08;1&#xff09;介绍 &#xff08;2&#x…

etcd分布式存储系统快速入门指南

在分布式系统的复杂世界中&#xff0c;确保有效的数据管理至关重要。分布式可靠的键值存储在维护跨分布式环境的数据一致性和可伸缩性方面起着关键作用。 在这个全面的教程中&#xff0c;我们将深入研究etcd&#xff0c;这是一个开源的分布式键值存储。我们将探索其基本概念、特…

Spring Boot + Spring AI快速体验

Spring AI快速体验 1 什么是Spring AI主要功能 2 快速开始2.1 版本说明2.2 配置文件2.3 pom依赖2.3.1 spring maven仓库2.3.2 核心依赖 2.4 定义ChatClient2.5 启动类2.6 测试 3 参考链接 1 什么是Spring AI Spring AI是Spring的一个子项目&#xff0c;是Spring专门面向于AI的…

【网络篇】TCP知识

TCP首部格式&#xff1f; 为什么需要 TCP 协议&#xff1f; TCP 工作在哪一层&#xff1f; IP 层是不可靠的&#xff0c;它不保证网络包的交付、不保证网络包的按序交付也不保证网络包中的数据的完整性。如果需要保障网络数据包的可靠性&#xff0c;那么就需要由上层&#xff0…

【Liunx篇】基础开发工具 - yum

文章目录 &#x1f335;一.Liunx下安装软件的方案&#x1f43e;1.源代码安装&#x1f43e;2.rpm包安装&#x1f43e;3.包管理器进行安装 &#x1f335;二.软件包管理器-yum&#x1f335;三.yum的具体操作&#x1f43e;1.查看软件包&#x1f43e;2.安装软件包&#x1f43e;3.卸载…

Co-Slam论文及复现记录

Overview 输入RGB-D流&#xff1a; { I t } t 1 N { D t } t 1 N \{I_t\}^{N}_{t1}\{D_t\}^{N}_{t1} {It​}t1N​{Dt​}t1N​&#xff0c;它们带有已知相机内参 K ∈ R 3 3 K\in \mathbb{R}^{3\times 3} K∈R33。通过联合优化相机姿态 { ξ t } t 1 N \{\xi_t\}^{N}_{t1} {…

《探索形象克隆:科技与未来的奇妙融合》

目录 一、什么是形象克隆 二、形象克隆的技术原理 三、形象克隆的发展现状 四、形象克隆的未来趋势 五、形象克隆的应用场景 六、形象克隆简单代码案例 Python 实现数字人形象克隆 Scratch 实现角色克隆效果&#xff08;以猫为例&#xff09; JavaScript 实现 Scratc…

解决view-ui-plus 中表单验证不通过问题,select 组件开启multiple模式 总是提示错误,即使不验证也提示,有值也验证失败

&#x1f609; 你好呀&#xff0c;我是爱编程的Sherry&#xff0c;很高兴在这里遇见你&#xff01;我是一名拥有十多年开发经验的前端工程师。这一路走来&#xff0c;面对困难时也曾感到迷茫&#xff0c;凭借不懈的努力和坚持&#xff0c;重新找到了前进的方向。我的人生格言是…

ARM V8 GIC中断模块

文章目录 1. 缩略语2. 简介2.1. 中断类型2.1.1 SGI软件中断2.1.2 PPI私有外设中断2.1.3 SPI 共享外设中断2.1.4 LPI(locality-specific peripheral interrupts) 2.2. GIC 架构2.2.1 Distributor2.2.2 Redistributor2.2.3 CPU Interfaces 2.3. 属性层次&#xff08;affinity&…

perl Window安装教程

perl Window安装教程 下载地址 https://platform.activestate.com/tangxing806/ActivePerl-5.28/distributions 运行state-remote-installer.exe 按下图截图步骤 检查perl版本 参考文献&#xff1a; perl安装教程

算法日记(2024.12.09)

1.二叉树的最小深度 给定一个二叉树&#xff0c;找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明&#xff1a;叶子节点是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;2 …

《操作系统 - 清华大学》6 -5:局部页面置换算法:最不常用置换算法 (LFU, Least Frequently Used)

文章目录 1. 最不常用算法的工作原理2.最不常用算法特征3. 示例 1. 最不常用算法的工作原理 最不常用算法&#xff1a;注意并不是表示算法本身不常用&#xff0c;而是采取最不常使用页面的策略&#xff0c;Least Frequently Used&#xff0c; LFU。LRU 是最久未被访问的页&…

Hive分区值的插入

对于Hive分区表&#xff0c;在我们插入数据的时候需要指定对应的分区值&#xff0c;而这里就会涉及很多种情况。比如静态分区插入、动态分区插入、提供的分区值和分区字段类型不一致&#xff0c;或者提供的分区值是NULL的情况&#xff0c;下面我们依次来展现下不同情况下的表现…

OpenAI12天 –第3天的实时更新,包括 ChatGPT、Sora、o1 等

OpenAI提前开启了假期&#xff0c;推出了为期 12 天的活动&#xff0c;名为“OpenAI 12 天”。在接下来的一周左右的每一天&#xff0c;OpenAI 都将发布现有产品的新更新以及新软件&#xff0c;包括备受期待的 Sora AI 视频生成器。 OpenAI 首席执行官 Sam Altman 表示&#x…

C#导出数据库到Excel文件(.NET)

随着企业业务的增长和复杂性的增加&#xff0c;对数据进行有效的分析、共享和报告变得至关重要&#xff1b;而Excel&#xff0c;作为一款广泛接受的数据处理工具&#xff0c;提供了强大的计算能力、可视化选项以及与多种数据分析工具的兼容性&#xff0c;使得它成为从数据库导出…

基于Java后台实现百度米制坐标转WGS84地理坐标实战

目录 前言 一、需求简介 1、信息查询 二、Java后台转换 1、相关属性 2、相关转换方法 3、实例转换 三、Leaflet可视化 1、准备展示数据 2、Marker标记 3、可视化效果 四、总结 前言 在现代信息技术高速发展的今天&#xff0c;地理信息系统&#xff08;GIS&#xff0…

声音克隆GPT-SoVITS

作者&#xff1a;吴业亮 博客&#xff1a;wuyeliang.blog.csdn.net 一、原理介绍 GPT-SoVITS&#xff0c;作为一款结合了GPT&#xff08;生成预训练模型&#xff09;和SoVITS&#xff08;基于变分信息瓶颈技术的歌声转换&#xff09;的创新工具&#xff0c;正在声音克隆领域掀…

自动驾驶数据集的应用与思考

数据作为新型生产要素&#xff0c;是数字化、网络化、智能化的基础&#xff0c;是互联网时代的“石油”“煤炭”&#xff0c;掌握数据对于企业而言是能够持续生存和发展的不竭动力&#xff0c;对于需要大量数据训练自动驾驶系统的企业而言更是如此。 而随着激光雷达、毫米波雷…