【单片机】14-I2C通信之EEPROM

news2024/11/29 7:55:47

1.EEPROM概念

1.EEPROM

1.1 一些概念

(1)一些概念:ROM【只读存储器---硬盘】,RAM【随机访问存储器--内存】,PROM【可编程的ROM】,EPROM【可擦除ROM】,EEPROM【电可擦除ROM】

1.2 为什么需要EEPROM

单片机内部的ROM只能在程序下载时进行擦除和改写,但是程序运行本身是不能改写的。

单片机内部的RAM中的数据程序运行时可以改,但是掉电就丢失了。

有时候我们需要有一些数据存在系统中,要求掉电不丢失,而且程序还要能改。所以内部ROM和RAM都不行。【这时候系统需要一块EEPROM】

1.3 EEPROM和flash的区别与联系

单片机解密中Flash和EEPROM的区别-电子工程世界

1.4 EEPROM存在系统中的2种形式

1:内置在单片机内部

2:外部扩展

2.EEPROM如何编程

1.I2C接口底层时序

底层:CPU和I2C的接口

2.器件定义的寄存器读写时序

上层:器件时序

2.原理图和数据手册

1.接线确定

查看SCL和SDA无其他接线影响

SCL对应P2.1 SDA对应P2.0

2.数据手册理论

立创商城_一站式电子元器件采购自营商城_现货元器件交易网-嘉立创电子商城

24c02中文官方资料手册pdf - 百度文库

1.芯片的基本信息

类似于一个主持人叫A说话,其他人就不可以说话,但是其他人可以听到主持人和A说话,但是不可以回应。 --广播式

主设备:51单片机---发送器

从设备:24Cxxx---接收器

2.I2C从地址确定

每一个I2C都有从地址

3.I2C底层时序

起始信号:

发送字节:一般第一个是从设备的地址【因为我们在通话之前,要先发送要进行通话的地址,设备都与自己的地址是否相同,如果相同则响应;如果不同,则丢弃】

读取字节:

停止信号:

3.I2C总结

(1)主CPU和其附属芯片之间最常用的接口,尤其是各种传感器,因此在物联网时代非常重要

(2)三根线:SCL,SDA,GND,串行,电平式

(3)总线式结构:可以一对多,总线上可以挂上百个器件【一个主设备,多个从设备】,用【从地址】来区分--主设备不需要地址

(4)主从式,由主设备来发起通信及总线仲裁,从设备被动响应

(5)通信速率一般(kbps级别),不合适语音,视频等信息类型

4.I2C总线协议定义

起始信号

终止信号

应答信号

从设备回复主设备,判断从设备是否得到数据。

可以设置是否要进行”应答信号“【可有可无】

3.I2C低层时序图和程序

1.起始信号和结束信号

SCL和SDA交互进行判断

(1)起始信号:SCL保持高时,SDA有一个从高到低(下降沿)
(2)结束信号:SCL保持高时,SDA有一个从低到高(上升沿)

起始信号

/*******************************************************************************
* 函 数 名       : iic_start
* 函数功能		 : 产生IIC起始信号
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void iic_start(void)
{
	IIC_SDA=1;//如果把该条语句放在SCL后面,第二次读写会出现问题
	delay_10us(1);
	IIC_SCL=1;
	delay_10us(1);
	IIC_SDA=0;	//当SCL为高电平时,SDA由高变为低,表示起始信号
	delay_10us(1);
	IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
	delay_10us(1);
}

终止信号

/*******************************************************************************
* 函 数 名         : iic_stop
* 函数功能		   : 产生IIC停止信号   
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void iic_stop(void)
{	
	IIC_SDA=0;//如果把该条语句放在SCL后面,第二次读写会出现问题
	delay_10us(1);
	IIC_SCL=1;
	delay_10us(1);
	IIC_SDA=1;	//当SCL为高电平时,SDA由低变为高,表示结束信号
	delay_10us(1);			
}

2.I2C发送一个字节

传输”0“或应答位(A)

传输”1“或应答位(/A)

/*******************************************************************************
* 函 数 名         : iic_write_byte
* 函数功能		   : IIC发送一个字节 
* 输    入         : dat:发送一个字节
* 输    出         : 无
*******************************************************************************/
void iic_write_byte(u8 dat)
{                        
    u8 i=0; 
	   	
    //为了保证时序正确,这里要加上    
    //当SDA将数据放好才可以将SCL置为高电平
    IIC_SCL=0; 
    for(i=0;i<8;i++)	//循环8次将一个字节传出,先传高再传低位
    {              
        if((dat&0x80)>0) 
			IIC_SDA=1;
		else
			IIC_SDA=0;
        dat<<=1; //将次高位移动到最高位	  
		delay_10us(1);  
		IIC_SCL=1; //产生一个上升沿
		delay_10us(1); 
		IIC_SCL=0; //产生一个下降沿	
		delay_10us(1);
    }	 
}

 

(1)I2C发送和接收字节时,都是从高位开始的

3.应答位处理

在接收完8位bit后,在第9个时间周期

应答处理:SDA变低【AT2402拉低】。

如果我们去检测,如果此时SDA为低电平,则表示已经被拉低,则表示已经响应到;如果SDA为高电平,则表示未能响应到。

 产生ACK应答  

/*******************************************************************************
* 函 数 名         : iic_ack
* 函数功能		   : 产生ACK应答  
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void iic_ack(void)
{
	IIC_SCL=0;
	IIC_SDA=0;	//SDA为低电平
	delay_10us(1);
   	IIC_SCL=1;   //将SCL拉高
	delay_10us(1);
	IIC_SCL=0;  //在将SCL拉低
}

 产生NACK非应答 

/*******************************************************************************
* 函 数 名         : iic_nack
* 函数功能		   : 产生NACK非应答  
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void iic_nack(void)
{
	IIC_SCL=0;
	IIC_SDA=1;	//SDA为高电平
	delay_10us(1);
   	IIC_SCL=1;
	delay_10us(1);
	IIC_SCL=0;	
}

等待应答信号到来 

/*******************************************************************************
* 函 数 名         : iic_wait_ack
* 函数功能		   : 等待应答信号到来   
* 输    入         : 无
* 输    出         : 1,接收应答失败
        			 0,接收应答成功
*******************************************************************************/
u8 iic_wait_ack(void)
{
	u8 time_temp=0;
	
	IIC_SCL=1;
	delay_10us(1);
	while(IIC_SDA)	//等待SDA为低电平
	{
		time_temp++;
		if(time_temp>100)//超时则强制结束IIC通信
		{	
			iic_stop();
			return 1;	
		}			
	}
	IIC_SCL=0;
	return 0;	
}

4.I2C接收一个字节

释放总线

在51单片机中,SDA=1就是释放总线【相当于主持人把话筒给嘉宾】;在其他更高级的单片机(比如STM32)这里的处理还会不一样。【因为拉高,则可以拉低(接地);但是拉低了,但是无法拉高】

为什么SDA=1就是释放总线??是因为当51单片机把引脚拉高时,从设备可以选择再把引脚拉高或者拉低;但是当51单片机把这个引脚拉低(接地)后,从设备也没有办法把这个引脚拉高了。

unsigned char IIC_ReadByte()
{
    unsigned char a=0,dat=0;
    //释放总线
    IIC_SDA=1;  //起始和发送一个字节之后IIC_SCL都是0
    IIC_delay();
    //按道理来说这里应该有一个SCL=0的
    for(a=0;a<8;a++){
        IIC_SCL=1;//通知从设备我要开始读了,可以放bit数据到SDA了
        IIC_delay();
        dat<<=1; //读取的时候高位再前
        dat|=IIC_SDA;
        IIC_delay();
        IIC_SCL=0;// 拉低为下一个bit周期做准备
        ICC_delay();
    }
    return dat;
}

4.EEPROM读写测试

1.  器件寻址

(1)从器件的地址是由器件自身定义的,不同的从器件的地址的定义方式是不同的,要查具体的芯片数据手册来确定

(2)同一个I2C网络中只有一个主设备,但是从设备可以有多个。这多个从设备的地址不能相同。【硬件工程师必须保证这一点。因为从地址是不能通过软件设定的】

(3)A0,A1,A2----2的三次方=8【表示最多只能接8个EEPROM】

从CPU的角度来分析24C02的地址定义【如果不是从CPU角度看则得出结果不一样】

        从设备地址是:读地址:0xa1

                                 写地址:0xa0

2.24C02写高层时序

写操作时序

 

start-send_byte(从地址)--send_byte(字节地址)---send_byte(写入数据)

 字节写

/*******************************************************************************
* 函 数 名         : at24c02_write_one_byte
* 函数功能		   : 在AT24CXX指定地址写入一个数据
* 输    入         : addr:写入数据的目的地址 
					 dat:要写入的数据
* 输    出         : 无
*******************************************************************************/
void at24c02_write_one_byte(u8 addr,u8 dat)
{				   	  	    																 
    iic_start();  
	iic_write_byte(0XA0);	//发送写命令,发送写器件地址	    	  
	iic_wait_ack();	//表示要接收应答 
    iic_write_byte(addr);	//发送写地址   
	iic_wait_ack(); //表示要接收应答 	 										  		   
	iic_write_byte(dat);	//发送字节    							   
	iic_wait_ack();  		    	   
    iic_stop();				//产生一个停止条件
	delay_ms(10);	 
}

页写

/*******************************************************************************
* 函 数 名         : at24c02_write_one_byte
* 函数功能		   : 在AT24CXX指定地址写入一个数据
* 输    入         : addr:写入数据的目的地址 
					 dat:要写入的数据
* 输    出         : 无
*******************************************************************************/
void at24c02_write_one_byte(u8 addr,u8 dat[],u8 i)
{				   	
    u8 j;  	    																 
    iic_start();  
	iic_write_byte(0XA0);	//发送写命令,发送写器件地址	    	  
	iic_wait_ack();	//表示要接收应答 
    iic_write_byte(addr);	//发送写地址   
	iic_wait_ack(); //表示要接收应答 	 										  		   
	for(j=0;j<i;i++){
        iic_write_byte(dat[i]);	//发送字节    							   
	    iic_wait_ack();
    }  		    	   
    iic_stop();				//产生一个停止条件
	delay_ms(10);	 
}

3. 24C02读高层时序

/*******************************************************************************
* 函 数 名         : at24c02_read_one_byte
* 函数功能		   : 在AT24CXX指定地址读出一个数据
* 输    入         : addr:开始读数的地址 
* 输    出         : 读到的数据
*******************************************************************************/
u8 at24c02_read_one_byte(u8 addr)
{				  
	u8 temp=0;		  	    																 
    iic_start();  
	iic_write_byte(0XA0);	//发送写命令	   
	iic_wait_ack(); 
    iic_write_byte(addr); 	//发送写地址  
	iic_wait_ack();	    
	iic_start();  	 	   
	iic_write_byte(0XA1); 	//进入接收模式         			   
	iic_wait_ack();	 
    temp=iic_read_byte(0);	//读取字节		   
    iic_stop();				//产生一个停止条件    
	return temp;			//返回读取的数据
}

4.加入串口输出代码

/*******************************************************************************
* 实验名			  : EEPROM实验
* 使用的IO	    : 
* 实验效果      : 按K1保存显示的数据,按K2读取上次保存的数据,按K3显示数据加一,
*按K4显示数据清零。
*	注意					:由于P3.2口跟红外线共用,所以做按键实验时为了不让红外线影响实验效果,最好把红外线先
*取下来。
*
*********************************************************************************/
#include <reg51.h>
#include "at24c02.h"
#include "uart.h"



void delay20ms(void)   //误差 -0.000000000005us
{
    unsigned char a,b,c;
    for(c=1;c>0;c--)
        for(b=222;b>0;b--)
            for(a=40;a>0;a--);
}

/*******************************************************************************
* 函 数 名         : main
* 函数功能		   : 主函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/

void main()
{
	unsigned char i;
	unsigned char addr;	
	unsigned char src_data[] = "()ab#cde!fg1234567";	
	unsigned char buf[8] = "ABCDEFGH";

	uart_init();
/*
	for (i=0; i<128; i++)
	{
		uart_send_byte(i);
	}
	while (1);
*/
	// 先随便找一堆数据,譬如"abcdefg1234567-_-*&%@/\"
	// 把这些写入EEPROM的特定地址中
	// 然后读EEROM的这些地址,读出后通过串口打印出来看是不是我们写入的

	uart_send_byte('%');

	addr = 0;
	for (i=0; i<8; i++)
	{
		At24c02Write(addr, src_data[i]);
		delay20ms();
		addr++;
	}

	//先打印出buf
    //如果这里没有给buf初始化,则打印会出现问题
	for (i=0; i<8; i++)
	{
		uart_send_byte(buf[i]);
	}
	

	//分割
	for (i=0; i<20; i++)
	{
		uart_send_byte('-');
	}
	
	// 读出测试
	addr = 0;
	for (i=0; i<8; i++)
	{
		buf[i] = At24c02Read(addr);
		delay20ms();
		addr++;
	}

	//将数据打印出来
	for (i=0; i<8; i++)
	{
		uart_send_byte(buf[i]);
	}
 
	while (1);

	// 进一步测试
	// 先写入一些特定内容,然后关机断电;然后改代码为读出并打印显示看内容

}		

问题分析

(1)通过调试发现程序跑飞了,经检测发现uart中没有关中断

(2)读出内容不对,怀疑是EEPROM经不起快速的连续读写,所以在读和写之间加入20ms的delay,测试后发现读写正确了

(3)定义了局部变量没有初始化,程序中直接去通过串口输出,结果导致程序

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

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

相关文章

Ps:移动工具

移动工具 Move Tool是 Ps 最常用的工具之一。使用移动工具&#xff0c;不仅可以移动、复制对象&#xff0c;还可以对多个图层进行对齐、分布等操作。 快捷键&#xff1a;V 使用快捷键改变图层不透明度或者选择图层混合模式时&#xff0c;也建议先切换到移动工具状态。 ◆ ◆ …

CS SD NAND在STM32精英V2开发板的测试-是时候将TF卡换为SD NAND了

前言 嵌入式项目中,比较常见的存储扩展方案是使用TF/SD卡或者EMMC或者RAW NAND,各种方案都有其优缺点,而SD NAND相对于上述方案具备很多优势,是目前嵌入式项目中存储扩展方案的一个非常不错的选择,正好一个项目在选择NAND存储方案, 恰巧论坛中联系到雷龙公司申请到了两片SD NAN…

LCD 的RGB接口(SYNC Mode/ SYNC-DE Mode/ DE Mode)

1、 SYNC Mode Timing Diagram 2、 SYNC-DE Mode Timing Diagram 3、 DE Mode Timing Diagram RGB接口&#xff08;SYNC Mode/ SYNC-DE Mode/ DE Mode&#xff09;-CSDN博客

【复盘】记录一次锁库的生产故障

java.sql.SQLException: The MySQL server is running with the LOCK_WRITE_GROWTH option so it cannot execute this statement在国庆期间晚上突然收到系统报警&#xff0c;然后查看日志发现是数据库磁盘满了之后触发了&#xff0c;禁止写操作&#xff0c;删除数据都不可以。…

Node18.x基础使用总结(二)

Node18.x基础使用总结 1、Node.js模块化1.1、模块暴露数据1.2、引入模块 2、包管理工具2.1、npm2.2、npm的安装2.3、npm基本使用2.4、搜索包2.5、下载安装包2.6、生产环境与开发环境2.7、生产依赖与开发依赖2.8、全局安装2.9、修改windows执行策略2.10、安装包依赖2.11、安装指…

架构师习题--嵌入式习题

架构师习题--嵌入式习题 可靠度&#xff1a;是单个系统的可靠性 避错和容错 N版本程序设计是静态 恢复块是动态 恢复块是主机坏了调用备用机&#xff0c;每次只有单机运行 N版本是N机器同时运行 恢复块是主机坏了调用备用机&#xff0c;后向恢复到之前的状态 N版主直接向前走

【深度学习】RNN循环神经网络和LSTM深度学习模型

1. 循环神经网络 RNN&#xff08; Recurrent Neural Network&#xff09; 循环神经网络的一个核心是可以把前面的序列数据用到后面的结果预测里面。怎么样实现这一点呢。RNN 结构如下图所示。 前部序列的信息经处理后&#xff0c;作为输入信息传递到后部序列。 数学模型&…

C++ 强制类型转换(int double)、查看数据类型、自动决定类型、三元表达式、取反、

强制类型转换&#xff08; int 与 double&#xff09; #include <iostream> using namespace std;int main() {// 数据类型转换char c1;short s1;int n 1;long l 1;float f 1;double d 1;int p 0;int cc (int)c;// 注意&#xff1a;字符 转 整形时 是有问题的// “…

CTFSHOW SSTI

目录 web361 【无过滤】 subprocess.Popen os._wrap_close url_for lipsum cycler web362 【过滤数字】 第一个通过 计算长度来实现 第二个使用脚本输出另一个数字来绕过 使用没有数字的payload web363 【过滤引号】 使用getitem 自定义变量 web364 【过…

深度学习 二:COVID 19 Cases Prediction (Regression)

Deep Learning 1. 回归算法思路2. 代码2.1 基础操作2.2 定义相关函数2.3.1 定义图像绘制函数2.3.2 数据集加载及预处理2.3.3 构造数据加载器2.3.4 构建前馈神经网络&#xff08;Feedforward Neural Network&#xff09;模型2.3.5 神经网络的训练过程2.3.6 模型评估2.3.7 模型测…

【转存】 fluent mybatis 与Mybatis 简答介绍

感谢&#xff1a;IT码徒 提供 原文请关注 前言 使用fluent mybatis也可以不用写具体的 xml 文件&#xff0c;通过 java api 可以构造出比较复杂的业务 sql 语句&#xff0c;做到代码逻辑和 sql 逻辑的合一。不再需要在 Dao 中组装查询或更新操作&#xff0c;或在 xml 与 mappe…

云安全之HTTP协议介绍

HTTP的基本概念 什么是网络协议 网络协议是计算机之间为了实现网络通信而达成的一种“约定”或者”规则“&#xff0c;有了这种”约定不同厂商生产的设备&#xff0c;以及不同操作系统组成的计算机之间&#xff0c;就可以实现通信。 网络协议由三个要素构成&#xff1a;1、语…

<C++> 哈希表模拟实现STL_unordered_set/map

哈希表模板参数的控制 首先需要明确的是&#xff0c;unordered_set是K模型的容器&#xff0c;而unordered_map是KV模型的容器。 要想只用一份哈希表代码同时封装出K模型和KV模型的容器&#xff0c;我们必定要对哈希表的模板参数进行控制。 为了与原哈希表的模板参数进行区分…

IntelliJ IDEA配置Cplex12.6.3详细步骤

Cplex12.6.3版IntelliJ IDEA配置详细步骤 一、Cplex12.6.3版下载地址二、Cplex安装步骤三、IDEA配置CPLEX3.1 添加CPLEX安装目录的cplex.jar包到项目文件中3.2 将CPLEX的x64_win64文件夹添加到IDEA的VM options中 四、检查IDEA中Cplex是否安装成功卸载Cplex 一、Cplex12.6.3版下…

案例题真题-数据库系统

案例题真题-数据库系统 真题 扩展方式和水平扩展是一个东西 关系数据库向上扩展强&#xff0c;水平扩展弱&#xff08;向外扩展&#xff09; NoSQL模式向上扩展弱&#xff0c;水平扩展强&#xff08;向外扩展&#xff09; 向上扩展就是增加数据库 向外扩展就是将数据库划分开&a…

SmartX 边缘计算解决方案:简单稳定,支持各类应用负载

在《一文了解近端边缘 IT 基础架构技术需求》文章中&#xff0c;我们为大家分析了边缘应用对 IT 基础架构的技术要求&#xff0c;以及为什么超融合架构是支持边缘场景的最佳选择。值得一提的是&#xff0c;IDC 近日发布的《中国软件定义存储&#xff08;SDS&#xff09;及超融合…

Halcon中灰度直方图的使用与学习

目录 第一步:当前打开窗口的显示灰度图或者mono图片第二步:激活后,我们可以去调整调整右边直方图灰阶值的中蓝色和红色竖线,获取左边图上的灰阶值的范围内的特征显示。第三步:插入代码:总结:它的直观目的,就是查看灰度的分布情况!灰度直方图,是我们经常使用,抓取不同…

objective-c 基础学习

目录 第一节&#xff1a;OC 介绍 ​​第二节&#xff1a;Fundation 框架 ​第三节&#xff1a;NSLog 相对于print 的增强 ​第四节&#xff1a;NSString ​第五节&#xff1a;oc新增数据类型 第六节&#xff1a; 类和对象 ​类的方法的声明与实现 ​第七节&#xff1a;类…

思维模型 冷热水效应

本系列文章 主要是 分享 思维模型&#xff0c;涉及各个领域&#xff0c;重在提升认知。冷热水效应可以改变你90%的人际关系。对于技术人员的沟通大有助益。 1 冷热水效应的应用 1.1 生活中的冷热水效应 恋爱和恋爱关系&#xff1a;在恋爱关系中&#xff0c;一对情侣可能会经历…

【人工智能导论】机器学习环境配置

一、Anaconda 1、安装Anaconda Anaconda的安装&#xff1a;https://www.anaconda.com/ Anaconda-国内镜像站 在terminal上看到(base)说明安装已完成 2、conda换源 添加中科大源 conda config --add channels https://mirrors.ustc.edu.cn/anaconda/pkgs/main/ conda confi…