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选择框,我想要的是数组对象,但是后端返回来的是个字符串。 以下是解决方法: 以上是一种简单的解决方法~ 也可以自己处理数据或者让后端直接改成想要的格式。...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...



