STMCUBEMX_IIC_DMA_AT24C64读取和写入

news2024/9/20 16:24:34

STMCUBEMX_IIC_DMA_AT24C64读取和写入

说明:
1、此例程只是从硬件IIC升级到DMA读写,因为暂时存储的掉电不丢失数据不多,一页就可以够用,不用担心跨页读写的问题
2、使用DMA后,程序确实是变快了,但是也要注意一个问题,前一个时刻使用HAL_I2C_Mem_Read_DMA()函数把书从EEPROM读取出来了,下一时刻不能着急立马使用读取出来的值,因为此时DMA正在从IIC外设往内存中搬运数据,要等待DMA搬运完成,而使用HAL_I2C_Mem_Read()读取的话就没有这个问题,因为他是阻塞性函数,只有读取完成了程序才会往下继续执行
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1、stmcubemx配置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、逻辑分析仪捕捉发送和接收的过程更直观

写数据时候
在这里插入图片描述
读数据时候
在这里插入图片描述

3、应用代码

main.c

int main(void)
{
//	SCB->VTOR = FLASH_BASE | 0x14000;	
	HAL_Init();
	SystemClock_Config();
	
	MX_GPIO_Init();
	MX_DMA_Init();
	MX_I2C1_Init();
	
	while (1)
	{

	}
}

eeprom.h

#ifndef __EEPROM_H
#define __EEPROM_H
#include "main.h"
#include "log.h"
#include "i2c.h"
#include <string.h>

#define AT24C64_ADDR 		0xA0
#define AT24C64_ADDR_WRITE 	0xA0
#define AT24C64_ADDR_READ 	0xA1

typedef struct eeprom24c64_message
{
	unsigned char eeprom_flow_number;
	unsigned char eeprom_pressure_number;
	unsigned char eeprom_pressure_mode;
	unsigned char eeprom_buzzer_sound;
	unsigned short eeprom_air_number;
}eeprom24c64_message_t;

extern eeprom24c64_message_t eeprom24c64_data;

void eeprom_24c64_init(void);
void eeprom_24c64_task(void);

void eeprom_24c64_write(unsigned short addr,unsigned char *data,unsigned short len);
void eeprom_24c64_read(unsigned short addr,unsigned char *data,unsigned short len);
void eeprom_24c64_write_dma(unsigned short addr,unsigned char *data,unsigned short len);
void eeprom_24c64_read_dma(unsigned short addr,unsigned char *data,unsigned short len);

#endif


eeprom.c

#include "eeprom.h"

eeprom24c64_message_t eeprom24c64_data = {0,0,0,0,0};
eeprom24c64_message_t eeprom24c64_data_old = {0,0,0,0,0};

void eeprom_24c64_init(void)
{
	eeprom_24c64_read_dma(0x00,(unsigned char *)&eeprom24c64_data,sizeof(eeprom24c64_data));
	HAL_Delay(2);//保证DMA已经把数据从外设搬运到内存中
	Debug_printf("init eeprom_flow_number:%d\r\n",eeprom24c64_data.eeprom_flow_number);
	Debug_printf("init eeprom_pressure_number:%d\r\n",eeprom24c64_data.eeprom_pressure_number);
	Debug_printf("init eeprom_pressure_mode:%d\r\n",eeprom24c64_data.eeprom_pressure_mode);
	Debug_printf("init eeprom_buzzer_sound:%d\r\n",eeprom24c64_data.eeprom_buzzer_sound);
	Debug_printf("init eeprom_air_number:%d\r\n",eeprom24c64_data.eeprom_air_number);
	
	/********************避免新生产的机器中EEPROM中读出的都是0xff*********************/
	if(eeprom24c64_data.eeprom_flow_number == 0xff) eeprom24c64_data.eeprom_flow_number = 0;
	if(eeprom24c64_data.eeprom_pressure_number == 0xff) eeprom24c64_data.eeprom_pressure_number = 0;
	if(eeprom24c64_data.eeprom_pressure_mode == 0xff) eeprom24c64_data.eeprom_pressure_mode = 0;
	if(eeprom24c64_data.eeprom_buzzer_sound == 0xff) eeprom24c64_data.eeprom_buzzer_sound = 0;
	if(eeprom24c64_data.eeprom_air_number == 0xffff) eeprom24c64_data.eeprom_air_number = 0;

	memcpy(&eeprom24c64_data_old,&eeprom24c64_data,sizeof(eeprom24c64_data));
}

void eeprom_24c64_task(void)
{
	if(memcmp(&eeprom24c64_data,&eeprom24c64_data_old,sizeof(eeprom24c64_data)) != 0)
	{
		eeprom_24c64_write_dma(0x00,(unsigned char *)&eeprom24c64_data,sizeof(eeprom24c64_data));
		HAL_Delay(50);
		eeprom_24c64_read_dma(0x00,(unsigned char *)&eeprom24c64_data,sizeof(eeprom24c64_data));
//		eeprom_24c64_read(0x00,(unsigned char *)&eeprom24c64_data,sizeof(eeprom24c64_data));
//		Debug_printf("/*************************************************************/\r\n");
//		Debug_printf("eeprom_flow_number:%d\r\n",eeprom24c64_data.eeprom_flow_number);
//		Debug_printf("eeprom_pressure_number:%d\r\n",eeprom24c64_data.eeprom_pressure_number);
//		Debug_printf("eeprom_pressure_mode:%d\r\n",eeprom24c64_data.eeprom_pressure_mode);
//		Debug_printf("eeprom_buzzer_sound:%d\r\n",eeprom24c64_data.eeprom_buzzer_sound);
//		Debug_printf("eeprom_air_number:%d\r\n",eeprom24c64_data.eeprom_air_number);
//		Debug_printf("/*************************************************************/\r\n");
		memcpy(&eeprom24c64_data_old,&eeprom24c64_data,sizeof(eeprom24c64_data));
	}
}

void eeprom_24c64_write(unsigned short addr,unsigned char *data,unsigned short len)
{
	if(HAL_I2C_Mem_Write(&hi2c1, AT24C64_ADDR_WRITE,addr,I2C_MEMADD_SIZE_16BIT,data,len,100) != HAL_OK)
	{
		Debug_error("eeprom_24c64_write fail!!!");
	}
}

void eeprom_24c64_read(unsigned short addr,unsigned char *data,unsigned short len)
{
	if(HAL_I2C_Mem_Read(&hi2c1, AT24C64_ADDR_READ,addr,I2C_MEMADD_SIZE_16BIT,data,len,100) != HAL_OK)
	{
		Debug_error("eeprom_24c64_read fail!!!");
	}
}

void eeprom_24c64_write_dma(unsigned short addr,unsigned char *data,unsigned short len)
{
	if(HAL_I2C_Mem_Write_DMA(&hi2c1, AT24C64_ADDR_WRITE,addr,I2C_MEMADD_SIZE_16BIT,data,len) != HAL_OK)
	{
		Debug_error("eeprom_24c64_write_dma fail!!!");
	}
}

void eeprom_24c64_read_dma(unsigned short addr,unsigned char *data,unsigned short len)
{
	if(HAL_I2C_Mem_Read_DMA(&hi2c1, AT24C64_ADDR_READ,addr,I2C_MEMADD_SIZE_16BIT,data,len) != HAL_OK)
	{
		Debug_error("eeprom_24c64_read_dma fail!!!");
	}
}

预告一下跨页写入的算法:

 
#define EEP_MAX_PAGE_SIZE  32			// 最大页写字节数
#define EEP_MAX_ROM_SIZE   8192		// EEROM容量
#define EEP_ADDR_SIZE      2			// EEROM地址字节数
 
#define EEP_WRITE_DELAY_TIME   (OS_TICKS_PER_SEC/10)
 
#define SYS_HEAD_LEN				    7			// 参数版本号,如果EEPROM中的参数版本号和程序中不同则更新参数
// EEPROM各地址分配
#define SYS_HEAD_ADDR				0			// 是否第一次运行标志地址
#define SYS_INFO_ADDR				7			// 系统信息保存地址
//#define PHONE_VOLUME_ADDR			199			// 电话音量保存地址
#define CENTER_NUM_ADDR				200			// 中心号码保存地址
#define PHONE_BOOK_NUM				392			// 呼入呼出电话条数,前四位保存呼入条数,后四位保存呼出条数
#define RING_IN_ADDR				    393			// 呼入限制电话保存地址
#define RING_OUT_ADDR				852			// 呼出限制电话保存地址
#define VIRTUAL_PHONE_ADDR			1281		    // 虚拟号码保存地址
#define AREA_ALARM_ADDR				1292		    // 区域报警信息地址
 
/********************************************************************************************************* 
** 函数名称: EepromRead
** 功能描述: 读EEPROM处理函数,在使用前,必须定义最大页写字节数,并且定义EEPROM的容量
** 输 入: 
**			buf:读取数据存放地址
**			len:要读取的数据长度
**			ptr:EEPROM存储位置 
** 输 出: 实际读取的数据数目 
********************************************************************************************************/ 
uint16 EepromRead(uint8 *buf , uint16 len , uint16 ptr)
{
	uint8  EeromAddr[2];
	EeromAddr[0] = ptr >> 8;
	EeromAddr[1] = ptr & 0xff;
	return(I2cRead(AT24CXX , buf , EeromAddr , EEP_ADDR_SIZE , len));
}
 
 
/********************************************************************************************************* 
** 函数名称: EepromWrite
** 功能描述: 写EEPROM处理函数,在使用前,必须定义最大页写字节数,并且定义EEPROM的容量
** 输 入: 
**			buf:所要发的数据
**			len:要发的数据长度
**			ptr:EEPROM存储位置 
** 输 出: 实际所发的数据数目 
********************************************************************************************************/ 
uint16 EepromWrite(uint8 *buf , uint16 len , uint16 ptr)
{
	uint8 bufTemp[EEP_MAX_PAGE_SIZE + EEP_ADDR_SIZE] , i , j = 0;
	uint8 flowSize , flowLen;
	uint16 sizeTemp , lenTemp = 0;
	
	if((ptr + len) > (EEP_MAX_ROM_SIZE - 1))	// EEPROM溢出保护
		return 0;
        
	flowSize = ptr % EEP_MAX_PAGE_SIZE;
	if(flowSize)								// 如果不是在页的起点
	{
		flowLen = EEP_MAX_PAGE_SIZE - flowSize; // 当前页可写长度
		if(flowLen < len)						// 所要写的数据将跨页
		{
			bufTemp[0] = ptr >> 8;				// 地址高位
			bufTemp[1] = ptr;					// 地址低位
			for(i = 0;i < flowLen;i++)
				bufTemp[i + EEP_ADDR_SIZE] = buf[i];
			ptr += flowLen;                     // 下次将写入的地址
			len -= flowLen;                     // 剩余未写数据的长度
			sizeTemp = I2cWrite(AT24CXX , bufTemp , flowLen + EEP_ADDR_SIZE);//本次写入的长度
			OSTimeDly(EEP_WRITE_DELAY_TIME);    // 写入延时
			lenTemp = lenTemp + sizeTemp - EEP_ADDR_SIZE;
		}
		else//所要写的数据未能跨页
		{
			bufTemp[0] = ptr >> 8;				// 地址高位
			bufTemp[1] = ptr;					// 地址低位
			for(i = 0;i < len;i++)
				bufTemp[i + EEP_ADDR_SIZE] = buf[i];
			sizeTemp = I2cWrite(AT24CXX , bufTemp , len + EEP_ADDR_SIZE);
			OSTimeDly(EEP_WRITE_DELAY_TIME);
			return (sizeTemp - EEP_ADDR_SIZE);  // 完毕返回
		}
	}
	while(len / EEP_MAX_PAGE_SIZE)              //剩余未写数据长度仍大于整页长度
	{
		bufTemp[0] = ptr >> 8;					// 地址高位
		bufTemp[1] = ptr;						// 地址低位
		j = lenTemp;							
		for(i = 0;i < EEP_MAX_PAGE_SIZE;i++)
			bufTemp[i + EEP_ADDR_SIZE] = buf[j + i];
		ptr += EEP_MAX_PAGE_SIZE;
		j += EEP_MAX_PAGE_SIZE;                 // 
		len -= EEP_MAX_PAGE_SIZE;
		sizeTemp = I2cWrite(AT24CXX , bufTemp , EEP_MAX_PAGE_SIZE + EEP_ADDR_SIZE);
		OSTimeDly(EEP_WRITE_DELAY_TIME);
		lenTemp = lenTemp + sizeTemp - EEP_ADDR_SIZE;
	}
	if(len)                                 // 剩余未写数据长度不足整页长度 
	{
		bufTemp[0] = ptr >> 8;				// 地址高位
		bufTemp[1] = ptr;					// 地址低位
		j = lenTemp;							
		for(i = 0;i < len;i++)
			bufTemp[i + EEP_ADDR_SIZE] = buf[j + i];
		sizeTemp = I2cWrite(AT24CXX , bufTemp , len + EEP_ADDR_SIZE);
		OSTimeDly(EEP_WRITE_DELAY_TIME);
		lenTemp = lenTemp + sizeTemp - EEP_ADDR_SIZE;
	}
	return lenTemp;                         // 返回写入的数据数目
}
 
 

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

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

相关文章

Python的pandas库来实现将Excel文件转换为JSON格式的操作

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

024 - STM32学习笔记 - LTDC与DMA2D显示屏

024- STM32学习笔记 - LTDC控制液晶屏 在学习如何控制液晶屏之前&#xff0c;先了解一下显示屏的分类&#xff0c;按照目前市场上存在的各种屏幕材质&#xff0c;主要分为CRT阴极射线管显示屏、LCD液晶显示屏、LED显示屏、OLED显示屏&#xff0c;在F429的开发板上&#xff0c;…

未势能源首份ESG报告:“社会型企业”为何能实现长期主义?

企业的未来模样&#xff0c;其实可以用一把价值标尺来衡量。 外界常常用财报里的各项指标&#xff0c;包括收入、盈利、偿债能力等等&#xff0c;评判一家企业的过去和现在。 但是在商业世界里&#xff0c;比拼的是谁能活的更久、笑到最后。那么&#xff0c;有没有一套衡量可…

基于SpringBoot + Vue的项目整合WebSocket的入门教程

1、WebSocket简介 WebSocket是一种网络通信协议&#xff0c;可以在单个TCP连接上进行全双工通信。它于2011年被IETF定为标准RFC 6455&#xff0c;并由RFC7936进行补充规范。在WebSocket API中&#xff0c;浏览器和服务器只需要完成一次握手&#xff0c;两者之间就可以创建持久性…

快手根据ID取商品详情 API 返回值说明

item_get-根据ID取商品详情 ks.item_get 公共参数 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;API接口secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,item_s…

来看看Python都有哪些特点(优点和缺点)

Python 是一种开源的解释型脚本编程语言&#xff0c;它之所以非常流行&#xff0c;主要有三点原因&#xff1a; Python 简单易用&#xff0c;学习成本低&#xff0c;看起来非常优雅干净&#xff1b;Python 标准库和第三库众多&#xff0c;功能强大&#xff0c;既可以开发小工具…

Allegro引流方式有哪些?Allegro平台注意事项

正确的引流&#xff0c;你的平台才会让更多人发现&#xff0c;才能提高转化率&#xff0c;那么Allegro引流方式有哪些&#xff0c;Allegro平台注意事项是什么呢&#xff1f; Allegro引流方式有哪些 商品优化&#xff1a;在Allegro上&#xff0c;关键是确保您的商品能够在搜索…

智慧公厕实现公共厕所全方位“上云用数赋智”根本之道

智慧公厕是一种全新的公共厕所管理形式&#xff0c;主要的特点是集合了物联网、互联网、云计算、大数据、区块链等技术&#xff0c;通过云服务、大数据融合应用以及智能化的管理手段&#xff0c;对公共厕所进行全面升级与改造&#xff0c;提升其服务质量和管理效率。在智慧公厕…

用Canape录制数据的操作方法

介绍 本文档可帮助读者实现用canape上车录制所需数据的方法。 一、打开ASAP2 Studio 软件,先对elf中的变量进行A2L转换 1、首先在电脑上插入canape盒子,打开你的ASAP2 Studio 软件,对elf中的变量进行A2L转换。 2、点击新建 New Database。 下面就是新建后的界面。 3、按…

工单管理系统如何操作?在线工单系统有什么作用?

在公司高速发展的过程中&#xff0c;管理者越来越认识到工单管理系统的重要性。工单系统能够利用后台系统整合多渠道客户数据&#xff0c;实现全面、系统化的客户数据管理&#xff0c;进而帮助企业优化工作流程管理&#xff0c;显著降低成本。在线工单系统能够自动分配工单&…

服务器巡检表-监控指标

1、巡检指标 系统资源K8S集群NginxJAVA应用RabbitMQRedisPostgreSQLElasticsearchELK日志系统 2、巡检项 检查项目 检查指标 检查标准 系统资源 CPU 使用率 正常&#xff1a;&#xff1c;70% 低风险&#xff1a;≥ 70% 中风险&#xff1a;≥ 85% 高风险&#xff1a;≥ 9…

Pod和容器设计模式

为什么需要Pod 一些应用的实现是需要多个进程配合完成的&#xff0c;由于容器实际上是一个“单进程”模型&#xff0c;如果在容器里启动多个进程会存在进程管理的难题。在Kubernetes里面&#xff0c;实际上会被定义为一个拥有四个容器的Pod。 Pod相当于进程组 Kubernetes 是…

第一课 实现用WASD控制一个物体前后左右移动

using System.Collections; using System.Collections.Generic; using UnityEngine;//实现让被挂在的物体往前移动 //按下W键往前移动&#xff0c;按下S键往后移动 public class RoleMove : MonoBehaviour { public float myspeed 0.1f;void Update(){if (Input.GetKey(KeyCo…

英飞凌TC3xx--深度手撕HSM安全启动(三)--TC3xx HSM系统架构

今天聊TC3xx HSM系统,包括所用内核、UCB相关信息、Host和HSM交互方式。 1、HSM系统架构 下图来源于英飞凌官网培训材料。 TC3xx的HSM内核是一颗32位的ARM Cortex M3,主频可达100MHz,支持对称算法AES128、非对称算法PKC(Public Key Crypto) ECC256、Hash SHA2,以及T…

(2023,DiffWA 水印 攻击 )DiffWA:用于水印攻击的扩散模型

DiffWA: Diffusion Models for Watermark Attack 公众号&#xff1a;EDPJ&#xff08;添加 VX&#xff1a;CV_EDPJ 进交流群获取资料&#xff09; 目录 0. 摘要 1. 简介 2. 背景 2.1 HiDDeN 2.2 去噪扩散模型 3. 提出的方法 3.1 准备工作 3.2 DiffWA 框架 3.3…

Xshell只能打开一个会话、左边栏消失不见、高级设置在哪儿、快捷键设置解决

Xshell只能打开一个会话、左边会话栏消失不见、高级设置在哪儿解决 1.问题&#xff1a; xshell会话&#xff08;窗口&#xff09;上方切换栏不见了的处理办法 解决方法&#xff1a;ctrl shift t 2.问题&#xff1a; 左边会话管理器不见了 解决方法&#xff1a; 3.问题…

国内访问香港服务器选择什么路线?

​  国内访问香港服务器可以选择多种路线。首先&#xff0c;我们了解下各个线路的速度延迟。 一、CN2直连&#xff1a;解决了不同互联网服务提供商之间访问的难题&#xff0c;不需要绕到国际网络再从中国的三个网络入口进入。 二、优化直连&#xff1a;全国平均延迟60ms&…

【C++】递归,搜索与回溯算法入门介绍和专题一讲解

个人主页&#xff1a;&#x1f35d;在肯德基吃麻辣烫 我的gitee&#xff1a;C仓库 个人专栏&#xff1a;C专栏 前言 从本文开始进入递归&#xff0c;搜索与回溯算法专题讲解。 文章目录 前言一、名词解释1、什么是递归&#xff1f;2、为什么会用到递归&#xff1f;3、如何理解…

ARKit功能初学

文章目录 一、ARKit简介二、ARKit API 中的几个主要的类1. ARSCNView2. ARSession3. ARFrame4.ARAnchor5. ARWorldTrackingSessionConfiguration6. ARSCNViewDelegate7. ARSessionDelegate 三、ARKit示例1. 导入框架2. 设置SceneKit View3. 配置ARSCNView Session4. Camera 授权…

MyBatis数据库操作

文章目录 前言一、MyBatis的各种查询功能1.查询一个实体类对象2.查询一个List集合3.查询单个数据4.查询一条数据为map集合5.查询多条数据为map集合方法一方法二 6.测试类 二、特殊SQL的执行1.模糊查询2.批量删除3.动态设置表名5.添加功能获取自增的主键6.测试类 三、自定义映射…