【嵌入式硬件芯片开发笔记】EEPROM芯片M24C32配置流程

news2025/2/24 9:20:34

【嵌入式硬件芯片开发笔记】EEPROM芯片M24C32配置流程
32-Kbit serial I²C bus EEPROM - 105°C operation
适用于M24C32/M24C32-DRE

在这里插入图片描述
读取存储的从机地址为:0x50
读取标识页面的从机地址为:0x58
WC引脚接地,存储可以进行写操作
地址长度为16位
存储地址:0x0000-0x0FFF,即4096个Bytes,32K-Bits
标识页面地址:0x0000-0x001F,即32个Bytes
标识页面在进行写操作时,b10为0,即add &= ~(1<<10)

开始运行

  1. 检查从机设备是否回应
  2. 读取制造商代码,并对比是否为0x20、0xE0、0x0C

初始化

按要求进行读写操作

  1. 在Mem地址0x0000-0x0007范围内进行读写测试:清空该区域(写入0x00);依次写入8、9、A、B、C、D、F
  2. 编译时间操作:
    共分3块区域,用于存储当前编译时间、中间编译时间、上次编译时间,分别为0x0008-0x000E,0x0010-0x0006,0x0018-0x001E;且正常写入一次后,0x000F、0x0017、0x001F都为1。
    时间存储格式为:yy yy mm dd hh mm ss 1
    以十进制的方式,由低到高存储到每个寄存器中,比如2022/11/29 16:45:30,存储后为:
    20d 22d 11d 29d 16d 45d 30d 1d,共8个地址存储64位数据
    当前编译时间每一次运行都会被写入到0x0008-0x000E中。
    当前时间与中间时间相同时,输出“上次运行后未重新编译”;当前时间与中间时间不同时,将中间时间写入到上次时间中,再将当前时间写入到中间时间中;上次时间标志0x001F的值不为1时,将当前时间写入到上次时间中,否则读取上次时间。
    以下表格为三种时间地址范围在不同运行状态下的结果:(数字越大表示时间越靠后,为0表示首次运行)
    在这里插入图片描述

代码例程

static char now_date[16] = __DATE__;
static char now_time[16] = __TIME__;
static char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
/*!
 * @brief       	初始化M24C32
 *
 * @param 				None
 *
 * @return				0/1: 错误/正确标志
 */
uint8_t Init_M24C32(void)
{
	uint8_t dat=0;
	uint32_t dat_32=0;
	uint8_t i=0;
	
	char strings[]="";
	int int_data[3]={0,0,0};
	uint8_t now_time_buf[8];
	uint8_t last_time_buf[8];
	uint8_t mid_time_buf[8];
	
	if(I2C_Judge(&hi2c2,M24C32_Mem_Slave_Add)!=true || I2C_Judge(&hi2c2,M24C32_Id_Slave_Add)!=true)
	{
		return 0;
	}
		
	dat_32=I2C_Read_y(&hi2c1,M24C32_Id_Slave_Add,0x0000,2,3,true);
	if(dat_32!=0x0020E00C)
	{
		return 0;
	}
	
	printf("[INFO] 开始Mem写入测试\n");
	dat=0;
	for(i=0;i<8;i++)
	{
		dat=0;
		I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+i,2,&dat,1,true);		
		if(I2C_Read_y(&hi2c1,M24C32_Mem_Slave_Add,0x0000+i,2,1,true)==0)
		{
			printf("[INFO] Mem 0x000%d 清空正确:	%02X\n",i,dat);
		}
		else
		{
			printf("[INFO] Mem 0x000%d 清空错误:	%02X\n",i,dat);
			printf("[INFO] Mem 清空中断\n");
			return 0;
		}
		dat=i+8;
		I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+i,2,&dat,1,true);
		if(I2C_Read_y(&hi2c1,M24C32_Mem_Slave_Add,0x0000+i,2,1,true)==i+8)
		{
			printf("[INFO] Mem 0x000%d 写入正确:	%02X\n",i,dat);
		}
		else
		{
			printf("[INFO] Mem 0x000%d 写入错误:	%02X\n",i,dat);
			printf("[INFO] Mem 写入中断\n");
			return 0;
		}
	}
	
	sscanf(now_date, "%s %d %d", strings, &int_data[0], &int_data[1]);
	int_data[2]=(strstr(month_names, strings)-month_names)/3+1;
	dat=(uint8_t)(int_data[1]/100);
	I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x08,2,&dat,1,true);		
	dat=(uint8_t)(int_data[1]%100);
	I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x09,2,&dat,1,true);	
	dat=(uint8_t)int_data[2];
	I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x0A,2,&dat,1,true);	
	dat=(uint8_t)int_data[0];
	I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x0B,2,&dat,1,true);

	sscanf(now_time, "%d:%d:%d",&int_data[0], &int_data[1],&int_data[2]);
	dat=(uint8_t)int_data[0];
	I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x0C,2,&dat,1,true);		
	dat=(uint8_t)int_data[1];
	I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x0D,2,&dat,1,true);	
	dat=(uint8_t)int_data[2];
	I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x0E,2,&dat,1,true);	
	dat=1;
	I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x0F,2,&dat,1,true);
	
	for(i=0;i<8;i++)
	{
		now_time_buf[i]=I2C_Read_y(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x08+i,2,1,true);		
		mid_time_buf[i]=I2C_Read_y(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x10+i,2,1,true);
	}
	
	printf("[INFO] 写入当前编译时间:%02d%02d/%02d/%02d %02d:%02d:%02d\n",
		now_time_buf[0],
		now_time_buf[1],
		now_time_buf[2],
		now_time_buf[3],
		now_time_buf[4],
		now_time_buf[5],
		now_time_buf[6]);
	
	if( now_time_buf[0]!=mid_time_buf[0] || 
			now_time_buf[1]!=mid_time_buf[1] || 
			now_time_buf[2]!=mid_time_buf[2] || 
			now_time_buf[3]!=mid_time_buf[3] || 
			now_time_buf[4]!=mid_time_buf[4] || 
			now_time_buf[5]!=mid_time_buf[5] || 
			now_time_buf[6]!=mid_time_buf[6] )
	{
		for(i=0;i<8;i++)
		{
			dat=mid_time_buf[i];
			I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x18+i,2,&dat,1,true);	
			dat=now_time_buf[i];
			I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x10+i,2,&dat,1,true);
		}
	}
	else
	{
		printf("[INFO] 上次运行后未重新编译\n");
	}
	
	if(I2C_Read_y(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x1F,2,1,true)==1)
	{
		for(i=0;i<8;i++)
		{
			last_time_buf[i]=I2C_Read_y(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x18+i,2,1,true);
		}
		printf("[INFO] 上次编译时间:%02d%02d/%02d/%02d %02d:%02d:%02d\n",
			last_time_buf[0],
			last_time_buf[1],
			last_time_buf[2],
			last_time_buf[3],
			last_time_buf[4],
			last_time_buf[5],
			last_time_buf[6]);
	}
	else
	{
		printf("[INFO] 当前编译时间:%s %s\n",now_date,now_time);
		sscanf(now_date, "%s %d %d", strings, &int_data[0], &int_data[1]);
		int_data[2]=(strstr(month_names, strings)-month_names)/3+1;
		dat=(uint8_t)(int_data[1]/100);
		I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x18,2,&dat,1,true);		
		dat=(uint8_t)(int_data[1]%100);
		I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x19,2,&dat,1,true);	
		dat=(uint8_t)int_data[2];
		I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x1A,2,&dat,1,true);	
		dat=(uint8_t)int_data[0];
		I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x1B,2,&dat,1,true);

		sscanf(now_time, "%d:%d:%d",&int_data[0], &int_data[1],&int_data[2]);
		dat=(uint8_t)int_data[0];
		I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x1C,2,&dat,1,true);		
		dat=(uint8_t)int_data[1];
		I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x1D,2,&dat,1,true);	
		dat=(uint8_t)int_data[2];
		I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x1E,2,&dat,1,true);	
		dat=1;
		I2C_Write_x(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x1F,2,&dat,1,true);
		
		printf("[INFO] 写入当前编译时间至上次编译时间:%02d%02d/%02d/%02d %02d:%02d:%02d\n",
			I2C_Read_y(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x18,2,1,true),
			I2C_Read_y(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x19,2,1,true),
			I2C_Read_y(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x1A,2,1,true),
			I2C_Read_y(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x1B,2,1,true),
			I2C_Read_y(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x1C,2,1,true),
			I2C_Read_y(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x1D,2,1,true),
			I2C_Read_y(&hi2c1,M24C32_Mem_Slave_Add,0x0000+0x1E,2,1,true));
	}
		
	return 1;
}

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

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

相关文章

117. 填充每个节点的下一个右侧节点指针 II

文章目录1. 背2. 题目3. 答案1. 背 这道题本来可以很简答&#xff0c;一个队列&#xff0c;存储指针和它的行数就OK了&#xff0c;但是这道题的难点在于不用额外空间复杂度。 横向看一下&#xff0c;这一行是不是就是一个链表呢&#xff1f; 多加一个变量&#xff0c;用来存储第…

C++入门教程||C++ 判断||C++ 日期 时间

判断结构要求程序员指定一个或多个要评估或测试的条件&#xff0c;以及条件为真时要执行的语句&#xff08;必需的&#xff09;和条件为假时要执行的语句&#xff08;可选的&#xff09;。 下面是大多数编程语言中典型的判断结构的一般形式&#xff1a; 判断语句 C 编程语言提…

three.js实战 -自定义剪切器

1. 前言 这是我在github上看到大佬的一个作品&#xff0c;当时感觉很有意思&#xff0c;决定分享出来&#xff0c;不知道取这个名字是否正确&#xff0c;废话不多说看下面效果。 2.demo效果 3.需要掌握的知识 矩阵的基本运算&#xff0c;能够认是到一些基本变换用到的矩阵(…

晶圆级倒装装备及控制系统

晶圆级倒装装备主要由晶圆盘进料模块、晶圆盘工作台模块、覆晶模块、焊头模块、基板工作台模块、点胶模块、视觉模块和基板进出料模块组成&#xff0c;如图 2-2 所示。 晶圆级倒装装备控制系统结构晶圆级倒装装备的运控系统主要由工控机、运动控制卡、驱动器、反馈装置和直线电…

QA:observable and Subject

概念区别和常见的错误理解辩证&#xff1a; 通俗理解一下 1. Observable 是一条 "水管蓝图" ,每次打开水龙头&#xff0c;水流会按照设计好的路线流向终点。起点和终点一一对应。每次打开水流&#xff0c;都是新的流&#xff0c;水流之间互不影响。一次一管。 2. …

VMWare虚拟机设置CentOS7共享文件夹

1. 目录 系统版本&#xff1a;CentOS 7.9 文章目录1. 目录2. VMWare&#xff1a;虚拟机设置&#xff0c;设置共享文件夹3. 虚拟机设置&#xff1a;手动挂载共享文件夹4. 检查是否挂载成功5. (可选)创建共享文件夹的软链接(快捷方式)6. (可选)定时任务开机自动挂载2. VMWare&am…

博客文章分类导引(持续更新)

摘要&#xff1a;本文提供一篇博客目录&#xff0c;有物联网、安卓编程、硬件设计等若干主题&#xff0c;这些主题一般都是成系统的&#xff0c;可以实现从零开始做出自己的物联网系统。 文章结构如下&#xff1a; 1.物联网专栏 使用arduino编写mqtt客户端连接emqx服务器 VSC…

vue.js:组件化的实现和使用过程

什么是组件化&#xff1f; 当我们遇到复杂问题的时候&#xff1a; 任何一个人处理信息的逻辑能力都是有限的所以&#xff0c;当我们面对一个复杂的问题的时候&#xff0c;我们不可能一次性搞定处理掉一大堆内容但是我们都会有问题拆解的能力将一个复杂的问题拆解成很多小的问…

Springcloud笔记之Ribbon

Ribbon&#xff1a;负载均衡&#xff08;基于客户端&#xff09;1. 负载均衡以及Ribbon1.1 Ribbon 的概念1.2 Ribbon 的作用2. 集成Ribbon3. 使用Ribbon实现负载均衡3.1 步骤3.2 自定义规则1. 负载均衡以及Ribbon 1.1 Ribbon 的概念 Spring Cloud Ribbon 是基于Netflix Ribbo…

[附源码]计算机毕业设计JAVA智能超市导购系统

[附源码]计算机毕业设计JAVA智能超市导购系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybati…

WebRTC Native M96 回调音频裸数据IAudioFrameObserver--采集的音频(onRecordAudioFrame)

上篇已经说道,通过注册回调,给上层APP抛音频裸数据: 《WebRTC Native M96 SDK接口封装–注册语音观测器对象获取原始音频数据registerAudioFrameObserver》[https://dabaojian.blog.csdn.net/article/details/128218542] 此篇,就详细讲述一下,如果实现onRecordAudioFrame…

vue学习笔记(二)-vue生命周期

概念 a.又名生命周期回调函数、生命周期函数、生命周期钩子b.是什么&#xff1a;Vue在关键时刻帮我们调用的一些特殊名称的函数c.生命周期函数的名字不可更改&#xff0c;但函数的具体内容是程序员根据需求编写的d.生命周期函数中的 this 指向是vm或组件实例对象 示例代码&am…

来一场关于元宇宙可持续的灵魂辩论|BOOK DAO 内容共建 第6期 招募

小杜《元宇宙创意图谱》是 BOOK DAO 的共建书籍项目&#xff0c;12.03我们举行了虚拟时尚主题的第5次公开共建活动。本周六晚8点&#xff0c;我们将举办第6期 元宇宙可持续 专题的共建活动。BOOK DAO 以搭建产业界与用户之间的交流平台、挖掘业界最值得深入探讨研究的话题为目标…

【linux】ssh免密登录

概要 服务器免密登录实际上是基于公钥的认证&#xff0c;比如希望A服务器可以免密访问B服务器&#xff0c;则需要进行如下步骤 A服务器生成密钥对将A服务器生成的公钥分发到B服务器&#xff08;写入~/.ssh/authorized_keys&#xff09;A服务器即可免密登录B服务器 生成密钥对…

特殊类的设计(单类模式)

一.不能拷贝的类 首先要知道拷贝的场景&#xff1a;拷贝构造函数以及赋值运算符重载&#xff0c;想要让一个类禁止拷贝&#xff0c;只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。 方法1&#xff1a;将这两个函数只声明&#xff0c;不定义&#xff08;防止编译器默…

【愚公系列】2022年12月 Redis数据库-Cache和Redis缓存的无缝切换使用

文章目录前言一、Cache和Redis缓存的无缝切换使用1.安装包2.服务配置3.创建控制器4.启动程序前言 Redis是分布式缓存&#xff0c;是将数据随机分配到不同服务器的&#xff0c;catch属于单机缓存&#xff0c;只能本机访问。 Redis和Cache的区别吧 Redis和cache都是将数据存放…

Nginx rewrite 详解

Nginx rewrite 详解 本篇主要介绍 nginx 的 rewrite 重定向这个功能进行 详解介绍, 以及介绍它的使用场景 1. rewrite 基本介绍 rewrite是实现URL重写的关键指令&#xff0c;根据regex (正则表达式)部分内容,重定向到replacement&#xff0c;结尾是flag标记。 基本语法: re…

JAVA SCRIPT设计模式--结构型--设计模式之Decorator装饰模式(9)

JAVA SCRIPT设计模式是本人根据GOF的设计模式写的博客记录。使用JAVA SCRIPT语言来实现主体功能&#xff0c;所以不可能像C&#xff0c;JAVA等面向对象语言一样严谨&#xff0c;大部分程序都附上了JAVA SCRIPT代码&#xff0c;代码只是实现了设计模式的主体功能&#xff0c;不代…

JSP ssh房地产项目管理系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 JSP ssh房地产项目管理系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用 B/S模式开发。开发环境为TOMCAT7…

吉林省教育学院学报杂志社吉林省教育学院学报编辑部2022年第11期目录

特稿 高职院校思政课“一体两翼四融合”教学模式的构建探索——以吉林工业职业技术学院为例 杨宝忠;解静; 1-5 高校业财融合体系研究 朱延辉; 6-9 教育理论与管理《吉林教育学院学报》投稿&#xff1a;cn7kantougao163.com 新教育评价改革背景下幼儿园教师评价能力…