51单片机EEPROM-IIC原理及实验

发布时间:2023-01-12  

I2C介绍

  • I2C(Inter-Integrated Circuit)总线是由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备。是微电子通信控制领域广泛采用的一种总线标准。它是同步通信的一种特殊形式,具有接口线少,控制方式简单,器件封装形式小,通信速率较高等优点。I2C 总线只有两根双向信号线。一根是数据线 SDA,另一根是时钟线 SCL。由于其管脚少,硬件实现简单,可扩展性强等特点,因此被广泛的使用在各大集成芯片内。

I2C 内部结构

  • 常用连接方式及结构:

  • 相关术语及解释
    主机:启动数据传送并产生时钟信号的设备;
    从机:被主机寻址的器件;
    多主机:同时有多于一个主机尝试控制总线但不破坏传输;
    主模式:用 I2CNDAT 支持自动字节计数的模式; 位 I2CRM,I2CSTT,I2CSTP
    控制数据的接收和发送;
    从模式:发送和接收操作都是由 I2C 模块自动控制的;
    仲裁:是一个在有多个主机同时尝试控制总线但只允许其中一个控制总线并
    使传输不被破坏的过程;
    同步:两个或多个器件同步时钟信号的过程;
    发送器:发送数据到总线的器件;
    接收器:从总线接收数据的器件;

  • 结构特点
    (1)它是一个支持多设备的总线(如结构图)。“总线”指多个设备共用的信号线。在一个 I2C 通讯总线中,可连接多个 I2C 通讯设备,支持多个通讯主机及多个通讯从机。
    (2)一个 I2C 总线只使用两条总线线路(如结构图),一条双向串行数据线(SDA),一条串行时钟线(SCL)。数据线即用来表示数据,时钟线用于数据收发同步。
    (3)每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访问。
    (4)总线通过上拉电阻接到电源(如结构图)。当 I2C 设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。
    (5)多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。
    (6)具有三种传输模式:标准模式传输速率为 100kbit/s,快速模式为400kbit/s,高速模式下可达 3.4Mbit/s,但目前大多 I2C 设备尚不支持高速模式。

I2C 协议层(I2C实现原理)
I2C 的协议定义了通信的起始和停止信号、数据有效性、响应、仲裁、时钟
同步和地址广播等环节。

  • 数据有效性


I2C 总线进行数据传送时,时钟信号(SCL)为高电平期间,数据线上(SDA)的数据必须保
持稳定,只有在时钟线上(SCL)的信号为低电平期间,数据线上的高电平或低电平状态
才允许变化。

  • 起始信号和终止信号


SCL 线为高电平期间,SDA 线由高电平向低电平的变化表示起始信号;SCL线为高电平期间,SDA 线由低电平向高电平的变化表示终止信号。起始和终止信号都是由主机发出的,在起始信号产生后,总线就处于被占用
的状态;在终止信号产生后,总线就处于空闲状态。

  • 应答响应


1.每当发送器件传输完一个字节的数据后,后面必须紧跟一个校验位,这个校验位是接收端通过控制 SDA(数据线)来实现的,以提醒发送端数据我这边已经接收完成,数据传送可以继续进行。这个校验位其实就是数据或地址传输过程中的响应。
2.响应包括应答和非应答
应答(ACK):接收到数据或地址后希望对方继续发送数据,需要向对方发送应答信号(特定的低平脉冲)
非应答(NACK ):希望对方结束数据传输,发送非应答信号(特定的高平脉冲)。
3.字节的结构:每一个字节必须保证是 8 位长度(如结构图·)。数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有 9 位)。

  • 数据传输原则
    (1)由于某种原因从机不对主机寻址信号应答时(如从机正在进行实时性的处理工作而无法接收总线上的数据),它必须将数据线置于高电平,而由主机产生一个终止信号以结束总线的数据传送。
    (2)如果从机对主机进行了应答,但在数据传送一段时间后无法继续接收更多的数据时,从机可以通过对无法接收的第一个数据字节的“非应答” 通知主机,主机则应发出终止信号以结束数据的继续传送。
    (3)当主机接收数据时,它收到最后一个数据字节后,必须向从机发出一个结束
    传送的信号。这个信号是由对从机的“非应答”来实现的。然后,从机释放 SDA
    线,以允许主机产生终止信号。

总线的寻址方式

  • I2C 总线寻址按照从机地址位数可分为两种,一种是 7 位,另一种是 10位。
    10 位寻址和 7 位寻址兼容,而且可以结合使用。这里讲解一下7位的。

  • 地址结构图


如图所示,该地址共有8位。高位(D7到D1位)为从机的地址,低位(D0)为数据传送方向位,为“ 0”时表示主机向从机写数据,为“1”时表示主机由从机读数据。

  • 寻址原则
    当主机发送了一个地址后,总线上的每个器件都将头 7 位与它自己的地址比较,如果一样,器件会判定它被主机寻址,其他地址不同的器件将被忽略后面的数据信号。至于是从机接收器还是从机发送器,都由 R/W 位决定的。从机的地址由固定部分和可编程部分组成。在一个系统中可能希望接入多个相同的从机,从机地址中可编程部分决定了可接入总线该类器件的最大数目。如一个从机的 7 位寻址位有 4 位是固定位,3 位是可编程位,这时仅能寻址 8 个同样的器件,即可以有 8 个同样的器件接入到该 I2C 总线系统中。

数据传输
/* 注:图中有阴影部分表示数据由主机向从机传送,无阴影部分则表示数据由从机向主机传送。横杠A 表示应答,A 非表示非应答(高电平)。S 表示起始信号,P 表示终止信号 * /

  • 在总线的一次数据传送过程中,可以有以下几种组合方式:
    1.主机向从机发送数据,数据传送方向在整个传送过程中不变


过程描述:主机发送起始信号->寻址->找到响应地址后选择写(0)或者读(1),图中为写过程(主机向从机发送数据)->从机做出应答(希望主机继续传输)或非应答(希望主机中止数据传输),图中为应答->数据继续传输->从机应答->数据再继续传输->从机非应答,请求中止->主机发送中止信号
2.主机在第一个字节后,立即从从机读数据


过程描述:主机发送起始信号->寻址->方向为1,即主机由从机读数据->从机发送数据->主机应答,希望希望从机继续发送数据->从机发送数据再继续传输->主机非应答,从机中止发送数据->主机发送中止信号
3.在传送过程中,当需要改变传送方向时,起始信号和从机地址都被重复产生一次,但两次读/写方向位正好相反。


过程描述:略,注意一点就可以了,就是在转换方向前,起始信号和从机地址都要重复产生一次。

软件模拟I2C

  • 引入原因:
    硬件 IIC 设计的比较复杂,而且稳定性不怎么好,程序移植比较麻烦,而用软件模拟 IIC,最大的好处就是移植方便,同一个代码兼容所有单片机,任何一个单片机只要有 IO 口(不需要特定 IO),都可以很快的移植过去。

  • AT24C02 芯片介绍
    AT24C01/02/04/08/16...是一个 1K/2K/4K/8K/16K 位串行 CMOS,内部含有128/256/512/1024/2048 个 8 位字节,AT24C01 有一个 8 字节页写缓冲器,AT24C02/04/08/16 有一个 16 字节页写缓冲器。该器件通过 I2C 总线接口进行操作,它有一个专门的写保护功能。此开发板使用的是 AT24C02(EEPROM)
    芯片,此芯片具有 I2C 通信接口,芯片内保存的数据在掉电情况下都不丢失,所以通常用于存放一些比较重要的数据等。

  • 芯片资料
    管脚及外观图


各管脚功能说明

  • AT24C02 芯片地址格式


AT24C02 器件地址为 7 位,高 4 位固定为 1010,低 3 位由 A0/A1/A2 信号线的电平决定。 因为传输地址或数据是以字节为单位传送的,当传送地址时,器件地址占 7 位,还有最后一位(最低位 R/W)用来选择读写方向。
A0/A1/A2 默认连接到 GND,所以器件地址为1010000,即 0x50(未计算最低位)。如果要对芯片进行写操作时,R/W 即为 0,写器件地址即为 0XA0;如果要对芯片进行读操作时,R/W 即为 1,此时读器件地址为 0XA1。开发板上我们也将 WP 引脚直接接在 GND 上,此时芯片允许数据正常读写。

典型信号模拟
为了保证数据传送的可靠性,标准的I2C总线的数 据传送有严格的时序要求。I2C总线的起始信号、终 止信号、发送“0”及发送“1”的模拟时序。
如图所示:


如图,起始信号S SDA为低电平,SCL为高电平至少>4微秒,应答需要SDA为低电平,SCL为高电平>4微秒,其他看图可知。


实验内容

  • 0实验功能
    开发板上集成了 1 个 EEPROM 模块,可实现IIC 通信。实现的功能是:系统运行时,数码管后 4 位显示 0,按 K1 将数据写入到 EEPROM 内保存,按 K2 读取 EEPROM 内保存的数据,按 K3 显示数据加 1,按 K4 显示数据清零,最大能写入的数据是 255。

  • 硬件设计
    (1)独立按键(K1-K4)
    (2)动态数码管
    (3)EEPROM 模块电路(AT24C02)

  • 原理图


在介绍 II C 总线的时候我们说过,为了让 IIC 总线默认为高电平,通常会在IIC 总线上接上拉电阻,在图中并没有看到 SCL 和 SDA 管脚有上拉电阻,这是因为我们单片机 IO 都外接了 10K 上拉电阻,当单片机 IO 口连接到芯片的 SCL 和SDA 脚时即相当于它们外接上拉电阻,所以此处可以省去。由于该模块电路是集成的,所以 24C02 芯片的 SCL 和 SDA 管脚可以通过使用单片机的 P2^0~P2^1 管脚连接即可。

程序实现
主要分为三部分
第一部分为头文件,主要为函数和端口的定义
代码:

#ifndef __I2C_H_

#define __I2C_H_

#include


sbit SCL=P2^1;

sbit SDA=P2^0;


void I2cStart();

void I2cStop();

unsigned char I2cSendByte(unsigned char dat);

unsigned char I2cReadByte();

void At24c02Write(unsigned char addr,unsigned char dat);

unsigned char At24c02Read(unsigned char addr);

#endif


第二部分为I2c软件模拟实现
这一步部分一定要对照时序图严格按照时序图的要求进行编写,为了保证都能够正常运行,延时函数为10us.
起始信号和终止信号都需要延时函数进行延时。

代码:

#include"i2c.h"


/*

* 函数名         : Delay10us()

* 函数功能    : 延时10us

*/

void Delay10us() //大约延时10us

{

unsigned char a,b;

for(b=1;b>0;b--)

for(a=2;a>0;a--);


}


/*

* 函数名         : I2cStart()

* 函数功能 : 起始信号:在SCL时钟信号在高电平期间SDA信号产生一个下降沿

* 备注           : 起始之后SDA和SCL都为0

*/

void I2cStart()

{

SDA=1;

Delay10us();

SCL=1;

Delay10us();//SCL,SDA为高电平,建立时间是SDA保持时间>4.7us

SDA=0;

Delay10us();//SCL为高电平,SDA为低电平,保持时间是>4us

SCL=0;

Delay10us();//起始之后SCL和SDA都为0,表示总线繁忙

}


/*

* 函数名         : I2cStop()

* 函数功能 : 终止信号:在SCL时钟信号高电平期间SDA信号产生一个上升沿

* 输入           : 无

* 输出          : 无

* 备注           : 结束之后保持SDA和SCL都为1;表示总线空闲

*/

void I2cStop()

{

SDA=0;

Delay10us();

SCL=1;

Delay10us();//SCL为高电平,SDA由低电平变为高电平建立时间大于4.7us

SDA=1;

Delay10us();  //都为高电平,表示总线空闲

}


/*

* 函数名         : I2cSendByte(unsigned char dat)

* 函数功能 : 通过I2C发送一个字节。在SCL时钟信号高电平期间,保持发送信号SDA保持稳定

* 输入           : num

* 输出          : 0或1。发送成功返回1,发送失败返回0

* 备注           : 发送完一个字节SCL=0,SDA=1

*/

unsigned char I2cSendByte(unsigned char dat)  //实现数据传输

{

unsigned char a=0,b=0;//最大255,一个机器周期为1us,最大延时255us。

for(a=0;a<8;a++)  //要发送8位,从最高位开始,所以循环8次

{

SDA=dat>>7; //起始信号之后SCL=0,所以可以直接改变SDA信号

dat=dat<<1;  //左移移位下一次循环执行时,次高位就变为最高位

Delay10us();

SCL=1;       //根据数据有效性原则,SCL为高电平时,SDA保持稳定,先保持稳定一段时间

Delay10us(); //建立时间>4.7us

SCL=0;       //稳定一段时间后,SCL为低电平,则SDA可以发生变化,高低电平的变化使得数据发送

Delay10us();//时间大于4us,继续延时,为下一字节传输准备

}

SDA=1;        //数据传输完成后,SDASDL都置为高电平,表示 总线空闲

Delay10us();

SCL=1;

while(SDA)    //等待应答,也就是等待从设备把SDA拉低

{

b++;

if(b>200)//如果超过2000us没有应答发送失败,或者为非应答,表示接收结束

{

SCL=0;

Delay10us();

return 0;//返回0代表非应答或者数据传输失败

}

}  

SCL=0;     //如果应答,则SDA为0(低电平),直接跳过循环

Delay10us();

  return 1;  //返回1代表数据传输成功或应答

}


/*

* 函数名         : I2cReadByte()

* 函数功能    : 使用I2c读取一个字节

* 输入           : 无

* 输出          : dat

* 备注           : 接收完一个字节SCL=0,SDA=1.

*/

unsigned char I2cReadByte()

{

unsigned char a=0,dat=0;

SDA=1; //拉高表示SDA总线空闲可以等待数据

Delay10us();

for(a=0;a<8;a++)//接收8个字节

{

SCL=1;   //SCL置为高电平,表示数据保持稳定以保持数据的读取

Delay10us();

dat<<=1;   // 数据左移1位

dat|=SDA;  //位运算种的或运算,即两个数据只要有一个数据为高电平,则或运算后为高电平

Delay10us();

SCL=0; //SCL置0,数据发生翻转

Delay10us();

}

return dat;

}


/*

* 函数名         : void At24c02Write(unsigned char addr,unsigned char dat)

* 函数功能    : 往24c02的一个地址写入一个数据

*/

void At24c02Write(unsigned char addr,unsigned char dat) //对At24c02进行写,所以需要定义写的地址和数据

{

I2cStart();

I2cSendByte(0xa0);//发送写器件地址 ,地址末位为0表示,器件地址固定,即1010,转为十六进制为a

I2cSendByte(addr);//发送要写入内存地址(首地址),调用发送数据的函数

I2cSendByte(dat); //发送数据

I2cStop();  

}


/*

* 函数名         : unsigned char At24c02Read(unsigned char addr)

* 函数功能    : 读取24c02的一个地址的一个数据

*/

unsigned char At24c02Read(unsigned char addr)

{

unsigned char num;

I2cStart();   //起始信号

I2cSendByte(0xa0); //发送写器件地址 (寻址)

I2cSendByte(addr); //发送要读取的地址

I2cStart();

I2cSendByte(0xa1); //发送读器件地址

num=I2cReadByte(); //读取数据

I2cStop();

return num;

}

第三部分为利用I2C软件实现独立按键控制数码管


/*

实验现象:下载程序后数码管后4位显示0,按K1保存显示的数据,按K2读取上次保存的数据,

  按K3显示数据加一,按K4显示数据清零。最大能写入的数据是255

*/


#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器

#include "i2c.h"


typedef unsigned int u16;   //对数据类型进行声明定义

typedef unsigned char u8;


sbit LSA=P2^2;   //138译码器端口

sbit LSB=P2^3;

sbit LSC=P2^4;


sbit k1=P3^1;

sbit k2=P3^0;

sbit k3=P3^2;

sbit k4=P3^3; //定义按键端口


char num=0;

u8 disp[4];

u8 code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};   //0~9的数据段


/*

* 函 数 名         : delay

* 函数功能    : 延时函数,i=1时,大约延时10us

*/

void delay(u16 i)

{

while(i--);

}



/*

* 函数名         :Keypros()

* 函数功能 :按键处理函数

* 输入           : 无

* 输出          : 无

*/

void Keypros() //独立按键实现功能:k1按下写入存即保存数据,k2按下读取保存的数据,K3按下数据加1,k4按下数据清0

{

if(k1==0)

{

delay(1000);  //消抖处理

if(k1==0)

{

At24c02Write(1,num);   //在地址1内写入数据num

}

while(!k1);

}

if(k2==0)

{

delay(1000);  //消抖处理

if(k2==0)

{

num=At24c02Read(1);   //读取EEPROM地址1内的数据保存在num中

}

while(!k2);

}

if(k3==0)

{

delay(100);  //消抖处理

if(k3==0)

{

num++;    //数据加1

if(num>255)num=0;  //数据不能大于255

}

while(!k3);

}

if(k4==0)

{

delay(1000);  //消抖处理

if(k4==0)

{

num=0; //数据清零

}

while(!k4);

}

}


/*

* 函数名         :datapros()

* 函数功能 :数据处理函数

* 输入           : 无

* 输出          : 无

*/

void datapros()   //将num数据处理为段选数据

{

disp[0]=smgduan[num/1000];//千位

disp[1]=smgduan[num%1000/100];//百位

disp[2]=smgduan[num%1000%100/10];//个位

disp[3]=smgduan[num%1000%100%10];

}



/*

* 函数名         :DigDisplay()

* 函数功能 :数码管显示函数

* 输入           : 无

* 输出          : 无

*/

void DigDisplay()  //动态显示数码管原理

{

u8 i;

for(i=0;i<4;i++)

{

switch(i) //位选,选择点亮的数码管,

{

case(0):

LSA=1;LSB=1;LSC=0; break;//显示第0位

case(1):

LSA=0;LSB=1;LSC=0; break;//显示第1位

case(2):

LSA=1;LSB=0;LSC=0; break;//显示第2位

case(3):

LSA=0;LSB=0;LSC=0; break;//显示第3位

}

P0=disp[i];//发送数据

delay(100); //间隔一段时间扫描

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

相关文章

    如何用STM32单片机蜂鸣器来演奏音乐;本文用STM32单片机蜂鸣器来演奏音乐,用的开发软件是STM32CubeIDE。 蜂鸣器 有源蜂鸣器 内部有震荡源,只要通电就会有响声,但是......
    STM32蜂鸣器音乐播放实例教程;本文用STM32单片机蜂鸣器来演奏音乐,用的开发软件是STM32CubeIDE。 蜂鸣器 有源蜂鸣器 内部有震荡源,只要通电就会有响声,但是声音频率固定。 无源蜂鸣器......
    51单片机学习:蜂鸣器实验;实验名称:蜂鸣器实验接线说明:实验现象:下载程序后蜂鸣器发出声音,一段......
    基于51单片机实现无源蜂鸣器控制;前言 前篇教程我们已经介绍了如何控制51 单片机的IO 口输出高低电平,本章我们通过另外一个实验来讲述51单片机IO口的输出。通过单片机的一个IO口控制板载无源蜂鸣器......
    基于51单片机的简易时钟设计;功能: 1、使用单片机内部定时器实现时分秒计时 2、能够设置闹钟时间 3、闹钟时间到,蜂鸣器响 4、使用LCD1602显示时间 部分程序: #include......
    报警电路导通,蜂鸣器报警。 5、默认监测到甲醛浓度高于0.100mg/m3蜂鸣器报警。 主要硬件设备:STM32F103单片机 资料下载链接: https://docs.qq.com......
    的发声原理是电流通过电磁线圈,使电磁线圈产生磁场来驱动振动膜发音,因此需要一定的电流才能驱动它。单片机的I/O引脚的输出电流比较小输出的TTL电平基本上驱动不了蜂鸣器,因此需要增加一个电流放大的电路,如图4-4......
    51单片机与蜂鸣器实现摩斯电码转换;具体功能实现 当我们按下矩阵按键中不同的按键时,在LCD1602显示相应的内容,同时一个按键按下多次可以切换不同的字母或数字,并且LED灯会闪烁。最后......
    通过单片机来控制蜂鸣器;开发板原理图上面蜂鸣器的电路图是这样的,根据视频知道它是一个无源蜂鸣器。 可以看到蜂鸣器的一端和电阻相连,另一端和引脚BZ相连,注意这个BZ并不是元气名称,有图可知,元气......
    下:       AT89C52控制蜂鸣器电路图   蜂鸣器电路由一个220欧的电阻,三极管8550,及蜂鸣器组成,如图10所示。通过控制三极管的导通和截止来实现蜂鸣器的响与不响。   流程图   单片机控制有源蜂鸣器......

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>