STMCUBEMX_IIC_DMA_AT24C64读取和写入
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 0xA1typedef 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; // 返回写入的数据数目
}
相关文章:

STMCUBEMX_IIC_DMA_AT24C64读取和写入
STMCUBEMX_IIC_DMA_AT24C64读取和写入 说明: 1、此例程只是从硬件IIC升级到DMA读写,因为暂时存储的掉电不丢失数据不多,一页就可以够用,不用担心跨页读写的问题 2、使用DMA后,程序确实是变快了,但是也要注意…...
wsl2相关问题
磁盘空间 wsl 删除相关文件后,如删除docker 无用的容器和镜像,windows上磁盘仍然无法自动回收空间 (参考:[microsoft/WSL](https://github.com/microsoft/WSL/issues/4699#issuecomment-627133168)) # 如清除无用do…...
使用idea时,光标变成了不能按空格键,只能修改的vim格式,怎么切换回正常光标
情况1 你可能不小心启用了 IntelliJ IDEA 中的 Vim 插件。你可以尝试以下步骤来禁用它: 在 IntelliJ IDEA 中,选择 "File" -> "Settings" (如果你在 macOS 上,选择 "IntelliJ IDEA" -> &quo…...

vue+antd——实现table表格的打印——分页换行,每页都有表头——基础积累
这里写目录标题 场景效果图功能实现1:html代码功能实现2:css样式功能实现3:js代码补充内容page-break-inside 属性page-break-after属性page-break-before 属性 场景 最近在写后台管理系统时,遇到一个需求,就是要实现…...
linux C MD5计算
#include <stdio.h> #include <string.h> #include <openssl/md5.h>int main() {char str[] "Hello, world!"; // 需要计算MD5哈希值的字符串unsigned char digest[MD5_DIGEST_LENGTH]; // 存储MD5哈希值的数组MD5((unsigned char*)&str, str…...

vue3学习源码笔记(小白入门系列)------ 组件更新流程
目录 说明例子processComponentcomponentUpdateFnupdateComponentupdateComponentPreRender 总结 说明 由于响应式相关内容太多,决定先接着上文组件挂载后,继续分析组件后续更新流程,先不分析组件是如何分析的。 例子 将这个 用例 使用 vi…...

数学建模B多波束测线问题B
数学建模多波束测线问题 1.问题重述: 单波束测深是一种利用声波在水中传播的技术来测量水深的方法。它通过测量从船上发送声波到声波返回所用的时间来计算水深。然而,由于它是在单一点上连续测量的,因此数据在航迹上非常密集,但…...
Pytest 框架执行用例流程浅谈
背景: 根据以下简单的代码示例,我们将从源码的角度分析其中的关键加载执行步骤,对pytest整体流程架构有个初步学习。 代码示例: import pytest def test_add(): assert 1 1 2 def test_sub(): assert 2 - 1 1 通过 pytes…...

C#__资源访问冲突和死锁问题
/// 线程的资源访问冲突:多个线程同时申请一个资源,造成读写错乱。 /// 解决方案:上锁,lock{执行的程序段}:同一时刻,只允许一个线程访问该程序段。 /// 死锁问题: /// 程序中的锁过多…...

机器学习——Logistic Regression
0、前言: Logistic回归是解决分类问题的一种重要的机器学习算法模型 1、基本原理: Logistic Regression 首先是针对二分类任务提出的一种分类方法如果将概率看成一个数值属性,则二元分类问题的概率预测就可以转化为一个回归问题。这种思路最…...
创建husky规范前端项目
创建husky规范前端项目 .husky文件是一个配置文件,用于配置Git钩子。Git钩子是在Git操作时触发的脚本,可以用于自动化一些任务,比如代码格式化、代码检查、测试等。.husky文件可以指定在Git的不同操作(如commit、push等ÿ…...

深浅拷贝与赋值
数据类型 数据类型 在JavaScript中,数据类型有两大类。一类是基本数据类型,一类是引用数据类型。 基本数据类型有六种:number、string、boolean、null、undefined、symbol。 基本数据类型存放在栈中。存放在栈中的数据具有数据大小确定&a…...
bert ranking pairwise demo
下面是用bert 训练pairwise rank 的 demo import torch from torch.utils.data import DataLoader, Dataset from transformers import BertModel, BertTokenizer from sklearn.metrics import pairwise_distances_argmin_minclass PairwiseRankingDataset(Dataset):def __ini…...

GPT引领前沿与应用突破之GPT4科研实践技术与AI绘图
GPT对于每个科研人员已经成为不可或缺的辅助工具,不同的研究领域和项目具有不同的需求。例如在科研编程、绘图领域:1、编程建议和示例代码: 无论你使用的编程语言是Python、R、MATLAB还是其他语言,都可以为你提供相关的代码示例。2、数据可视…...

SpringBoot整合Swagger3
前言 swagger是啥,是干什么的,有什么用,我想在这里我就不用介绍了,下面直接代码演示。 添加依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0…...
detectron2 install path
>>> import detectron2 >>> detectron2_path detectron2.__file__ >>> print(detectron2.__file__)...

如何将DHTMLX Suite集成到Scheduler Lightbox中?让项目管理更可控!
在构建JavaScript调度器时,通常需要为最终用户提供一个他们喜欢的方式来计划事件,这是Web开发人员喜欢认可DHTMLX Scheduler的重要原因,它在这方面提供了完全的操作自由,它带有lightbox弹出窗口,允许通过各种控件动态更…...

什么是JVM常用调优策略?分别有哪些?
目录 一、JVM调优 二、堆内存大小调整 三、垃圾回收器调优 四、线程池调优 一、JVM调优 Java虚拟机(JVM)的调优主要是为了提高应用程序的性能,包括提高应用程序的响应速度和吞吐量。以下是一些常用的JVM调优策略: 堆内存大小…...

《向量数据库指南》——向量数据库Milvus Cloud 2.3的可运维性:从理论到实践
一、引言 在数据科学的大家庭中,向量数据库扮演着重要角色。它们通过独特的向量运算机制,为复杂的机器学习任务提供了高效的数据处理能力。然而,如何让这些数据库在生产环境中稳定运行,成为了运维团队的重要挑战。本文将深入探讨向量数据库的可运维性,并分享一些有趣的案…...

select多选回显问题 (取巧~)
要实现的效果: 实际上select选择框,我想要的是数组对象,但是后端返回来的是个字符串。 以下是解决方法: 以上是一种简单的解决方法~ 也可以自己处理数据或者让后端直接改成想要的格式。...

label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...

MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...