51单片机IIC-EEPROM

IIC介绍

1、IIC简介

I2C(Inter-Integrated Circuit)总线是由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备。它是同步通信的一种特殊形式,具有接口线少,控制方式简单, 器件封装形式小,通信速率较高等优点。I2C 总线只有两根双向信号线。一根是数据线 SDA,另一根是时钟线 SCL

2、IIC物理层

I2C 通信设备常用的连接方式如下图所示:


它的物理层有如下特点:

  • 它是一个支持多设备的总线。“总线”指多个设备共用的信号线。在 一个 I2C 通讯总线中,可连接多个 I2C 通讯设备,支持多个通讯主机及多个通讯从机。

  • 一个 I2C 总线只使用两条总线线路,一条双向串行数据线(SDA),一条串行时钟线(SCL)。数据线即用来表示数据,时钟线用于数据收发同步。

  • 每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访问。

  • 多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。

下面我们来了解下 I2C 总线常用的一些术语:

主机:启动数据传送并产生时钟信号的设备;

从机:被主机寻址的器件;

多主机:同时有多于一个主机尝试控制总线但不破坏传输;

主模式:用 I2CNDAT 支持自动字节计数的模式; 位 I2CRM,I2CSTT,I2CSTP 控制数据的接收和发送;

从模式:发送和接收操作都是由 I2C 模块自动控制的;

仲裁:是一个在有多个主机同时尝试控制总线但只允许其中一个控制总线并使传输不被破坏的过程;

同步:两个或多个器件同步时钟信号的过程;

发送器:发送数据到总线的器件;

接收器:从总线接收数据的器件。

3、IIC协议层

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

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


每次数据传输都以字节为单位,每次传输的字节数不受限制。

(2)起始和停止信号

SCL 线为高电平期间,SDA 线由高电平向低电平的变化表示起始信号;SCL 线为高电平期间,SDA 线由低电平向高电平的变化表示终止信号。如下图:


起始和终止信号都是由主机发出的,在起始信号产生后,总线就处于被占用的状态;在终止信号产生后,总线就处于空闲状态。

(3)应答响应

每当发送器件传输完一个字节的数据后,后面必须紧跟一个校验位,这个校验位是接收端通过控制 SDA(数据线)来实现的,以提醒发送端数据我这边已经接收完成,数据传送可以继续进行。这个校验位其实就是数据或地址传输过程中的响应。响应包括“应答(ACK)”和“非应答(NACK)”两种信号。作为数据接收端时,当设备(无论主从机)接收到 I2C 传输的一个字节数据或地址后,若希望对方继续发送数据,则需要向对方发送“应答(ACK)”信号即特定的低电平脉冲, 发送方会继续发送下一个数据;若接收端希望结束数据传输,则向对方发送“非应答(NACK)”信号即特定的高电平脉冲,发送方接收到该信号后会产生一个停止信号,结束信号传输。应答响应时序图如下:


每一个字节必须保证是 8 位长度。数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有 9 位)

由于某种原因从机不对主机寻址信号应答时(如从机正在进行实时性的处理工作而无法接收总线上的数据),它必须将数据线置于高电平,而由主机产生一个终止信号以结束总线的数据传送。

如果从机对主机进行了应答,但在数据传送一段时间后无法继续接收更多的数据时,从机可以通过对无法接收的第一个数据字节的“非应答”通知主机,主机则应发出终止信号以结束数据的继续传送。

当主机接收数据时,它收到最后一个数据字节后,必须向从机发出一个结束传送的信号。这个信号是由对从机的“非应答”来实现的。然后,从机释放 SDA 线,以允许主机产生终止信号。

这些信号中,起始信号是必需的,结束信号和应答信号都可以不要。

(4)总线的寻址方式

I2C 总线寻址按照从机地址位数可分为两种,一种是 7 位,另一种是 10 位。采用 7 位的寻址字节(寻址字节是起始信号后的第一个字节)的位定义如下:


D7~D1 位组成从机的地址。D0 位是数据传送方向位,为“ 0”时表示主机向从机写数据,为“1”时表示主机由从机读数据。

10 位寻址和 7 位寻址兼容,而且可以结合使用。10 位寻址不会影响已有 的 7 位寻址,有 7 位和 10 位地址的器件可以连接到相同的 I2C 总线。我们就以 7 位寻址为例进行介绍。

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

(5)数据传输

I2C 总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据信号。在起始信号后必须传送一个从机的地址(7 位),第 8 位是数据的传送方向位(R/W),用“ 0”表示主机发送(写)数据(W),“ 1”表示主机接收数据(R)。每次数据传送总是由主机产生的终止信号结束。但是,若主机希望继续占用总线进行新的数据传送,则可以不产生终止信号,马上再次发出起始信号对另一从机进行寻址。

在总线的一次数据传送过程中,可以有以下几种组合方式:

a、主机向从机发送数据,数据传送方向在整个传送过程中不变

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

b、主机在第一个字节后,立即从从机读数据


c、在传送过程中,当需要改变传送方向时,起始信号和从机地址都被重复产生一次,但两次读/写方向位正好相反


到这里我们就介绍完 I2C 总线,由于 51 单片机没有硬件 I2C 接口,即使有硬件接口我们通常还是采用软件模拟 I2C。主要原因是硬件 I2C 设计的比较复杂,而且稳定性不怎么好,程序移植比较麻烦,而用软件模拟 I2C,最大的好处就是移植方便,同一个代码兼容所有单片机,任何一个单片机只要有 IO 口(不需要特定 IO),都可以很快的移植过去。

AT24C02介绍

1、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 通信接口,芯片内保存的数据在掉电情况下都不丢失, 所以通常用于存放一些比较重要的数据等。

2、AT24C02工作原理

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 总线时序如下图所示:

硬件原理

从图中可以看出,芯片的 SCL 和 SDA 管脚是连接在单片机的 P2.1 和 P2.0 上, 在介绍 I2C 总线的时候我们说过,为了让 I2C 总线默认为高电平,通常会在 I2C 总线上接上拉电阻,在图中并没有看到 SCL 和 SDA 管脚有上拉电阻,这是因为开发板单片机 IO 都外接了 10K 上拉电阻,当单片机 IO 口连接到芯片的 SCL 和 SDA 脚时即相当于它们外接上拉电阻,所以此处可以省去。

软件编写

程序框架如下:

  • 编写按键检测功能
  • 编写数码管显示功能
  • 编写 I2C 驱动,包括起始、停止、应答信号等
  • 编写 AT24C02 读写功能
  • 编写主函数

实验:系统运行时,数码管右 3 位显示 0,按 K1 键将数据 写入到 EEPROM 内保存,按 K2 键读取 EEPROM 内保存的数据,按 K3 键显示数据加 1,按 K4 键显示数据清零,最大能写入的数据是 255

Key.c(按键检测函数)

#include <Key.h>//独立按键扫描函数
unchar Key_Scan()
{unchar Keynumber=0;if(Key1==0||Key2==0||Key3==0||Key4==0){Delay(1000);    //消抖if(Key1==0)Keynumber=1;if(Key2==0)Keynumber=2;if(Key3==0)Keynumber=3;if(Key4==0)Keynumber=4;}while(Key1==0||Key2==0||Key3==0||Key4==0);   //如果按键未松,则一直循环return Keynumber;
}

Smg.c(数码管显示函数)

#include <Smg.h>//共阴极数码管显示 0~F 的段码数据
unchar Smg_Code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//动态数码管显示
void Smg_Display(unchar Data[],unchar Location)
{unchar i=0;unchar temp=Location-1;for(i=temp;i<8;i++){switch(i)    //位选{case 0: LSC=1;LSB=1;LSA=1; break;case 1: LSC=1;LSB=1;LSA=0; break;case 2: LSC=1;LSB=0;LSA=1; break;case 3: LSC=1;LSB=0;LSA=0; break;case 4: LSC=0;LSB=1;LSA=1; break;case 5: LSC=0;LSB=1;LSA=0; break;case 6: LSC=0;LSB=0;LSA=1; break;case 7: LSC=0;LSB=0;LSA=0; break;}LED=Smg_Code[Data[i-temp]];   //传送段选数据Delay(100);          //延时一段时间,等待显示稳定LED=0x00;            //消影}
}

IIC.c(IIC驱动,包括起始、停止、应答信号函数)

#include <IIC.H>//产生 IIC 起始信号
void IIC_Start()
{IIC_SDA=1;    //如果把该语句放在 SCL 后面,第二次读写会出问题Delay(1);IIC_SCL=1;Delay(1);IIC_SDA=0;    //当 SCL 为高电平时,SDA 由高变为低Delay(1);IIC_SCL=0;    //钳住 IIC 总线,准备发送或接收数据Delay(1);
}//产生 IIC 停止信号
void IIC_Stop()
{IIC_SDA=0;    //如果把该语句放在 SCL 后面,第二次读写会出问题Delay(1);IIC_SCL=1;Delay(1);IIC_SDA=1;   //当 SCL 为高电平时,SDA 由低变为高Delay(1);
}//产生 ACK 应答
void IIC_Ack()
{IIC_SCL=0;IIC_SDA=0;    //SDA 为低电平Delay(1);IIC_SCL=1;Delay(1);IIC_SCL=0;
}//产生 NACK 非应答
void IIC_NoAck()
{IIC_SCL=0;IIC_SDA=1;    //SDA 为高电平Delay(1);IIC_SCL=1;Delay(1);IIC_SCL=0;
}//等待应答信号到来
unchar IIC_Wait_Ack()
{unint time=0;IIC_SCL=1;while(IIC_SDA)    //等待 SDA 为低电平{time++;if(time>100)    //超时则强制结束 IIC 通信{IIC_Stop();return 1;   //接收应答失败}}IIC_SCL=0;return 0;    //接收应答成功
}//IIC 发送一个字节
void IIC_Write_Byte(unchar Data)
{unchar i=0;IIC_SCL=0;for(i=0;i<8;i++)    //循环 8 次将一个字节传出,先传高位在传低位{if((Data&0x80)>0)IIC_SDA=1;else IIC_SDA=0;Data<<=1;IIC_SCL=1;Delay(1);IIC_SCL=0;Delay(1);}
}//IIC 读一个字节
unchar IIC_Read_Byte(unchar Ack)
{unchar i=0;unchar value=0;for(i=0;i<8;i++)    //循环 8 次将一个字节读出,先传高位在传低位{IIC_SCL=0;Delay(1);IIC_SCL=1;value<<=1;if(IIC_SDA==1) value|=0x01;Delay(1);}if(Ack==1)IIC_Ack();else IIC_NoAck();return value;
}

24C02.c(AT24C02函数)

#include <24C02.H>
#include <IIC.H>//在 AT24C02 指定地址写入一个数据
void AT24C02_Write_Byte(unchar Addr,unchar Data)
{IIC_Start();IIC_Write_Byte(0xA0);   //发送写命令IIC_Wait_Ack();IIC_Write_Byte(Addr);   //发送写地址IIC_Wait_Ack();IIC_Write_Byte(Data);   //发送字节IIC_Wait_Ack();IIC_Stop();              //产生一个停止条件Delay(10);
}//在 AT24C02 指定地址读出一个数据
unchar AT24C02_Read_Byte(unchar Addr)
{unchar value=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();value=IIC_Read_Byte(0);  //读取字节IIC_Stop();return value;       //返回读取的数据
}

Init.c(初始化函数)

#include <Init.h>//延时函数
void Delay(unint x)
{while(x--);
}

main.c(主函数)

#include <Init.H>
#include <24C02.H>
#include <Key.H>
#include <Smg.H>//定义数据存入EEPROM的起始地址
#define EEPROM_ADDRESS   0void main()
{unchar KeyNumber=0;    //键值unchar Save_Value=0;   //存储数值unchar Save_Buf[3];    //存储段码数组while(1){KeyNumber=Key_Scan();    //独立按键扫描if(KeyNumber==1)         //键值为 1 ,将数值保存AT24C02_Write_Byte(EEPROM_ADDRESS,Save_Value);else if(KeyNumber==2)    //键值为 2 ,读取数值Save_Value=AT24C02_Read_Byte(EEPROM_ADDRESS);else if(KeyNumber==3)    //键值为 3 ,数值加一{Save_Value++;if(Save_Value==255)  //最大数值不可超过 255Save_Value=255;}else if(KeyNumber==4)    //键值为 4 ,数值清零Save_Value=0;Save_Buf[0]=Save_Value/100;      //数值形成断码Save_Buf[1]=Save_Value%100/10;Save_Buf[2]=Save_Value%100%10;Smg_Display(Save_Buf,6);}
}

51单片机IIC_EEPROM相关推荐

  1. 51单片机实现对24C02进行页写、顺序读取并显示验证

    源:51单片机实现对24C02进行页写.顺序读取并显示验证 //******************************************************************** ...

  2. 51单片机编码自学_这是9个月的自学式编码看起来像什么

    51单片机编码自学 by Stephen Mayeux 斯蒂芬·马约(Stephen Mayeux) 这是9个月的自学式编码看起来像什么 (Here's What 9 Months of Self-T ...

  3. 跳过51单片机,直接学STM32有什么严重后果?

    STM32现在之所以这么普及,主要是教程资料非常丰富,一些卖开发板做教程的至少有50%的功劳. 再价格也算合理,导致很多企业用这个单片机去做产品,初学者也更渴望掌握这款芯片. 不过STM32这两年涨价 ...

  4. 单片机从事什么工作?只会51单片机能找到工作吗?

    我当初是自学转行进入单片机行业,没有211/985这种学历背景. 转行纯粹是为了脱离阶层,我们那个年代都兴蓝领,白领. 我们学的专业就是属于蓝领类的. 蓝领就是做苦力活的,白领就是衣光鲜艳,坐办公室拿 ...

  5. 放弃51单片机,直接学STM32开发会有什么严重的问题?

    本人从事单片机开发10年,我一直认为只有起点和你差不多的人,经历过的路,才具备参考的价值. 别人开局就是一套终极装,在各种资源背景加持下经历像开挂一样,你参考个锤子啊. 我当初是电气工程转行到嵌入式单 ...

  6. 51单片机可以做什么实用的产品?

    我用51的单片机做过不少于10款产品了. 我看到很多文章,说51已经过时了,新手没必要学习51单片机,可以直接学STM32. 我个人认为这种说法存在一定的误导,51还是有很大的市场. 很多人想从事嵌入 ...

  7. 51单片机好学嘛?学完51单片机学什么?

    大家好,我是无际单片机编程的徐导,很多想学单片机又担心自己学不会的兄弟们,都想问这个问题:51单片机好学嘛? 作为一个资深的老工程师,我还是要客观地回答一下这个问题. 关于的"0基础15天学 ...

  8. 单片机如何使用?51单片机C语言编程实例有哪些?

    大家好,我是无际单片机编程的徐明,今天和大家一起探讨一下"单片机如何使用?" 单片机如何使用,我们要知道单片机在哪里使用? 单片机是很多电子产品的核心器件,它具有一定的逻辑判断和事 ...

  9. 51单片机怎么编程,有什么好的课程?

    虽然现在stm32单片机很火,很多招聘的公司都要求必须要会stm32,但是我依然建议新手从51开始学起. 这也是当初我自学的路径,51相对简单,新手可以在短时间内学习见到效果,比如说做个流水灯,让数码 ...

最新文章

  1. 【设计模式】责任链模式
  2. 操作数据库(对战小游戏)
  3. 支付宝pc支付php,laravel框架下的pc支付宝支付接入
  4. (转载)今天的她坐在凳子上面的【飞秋】
  5. rm命令linux00,Linux限制rm命令
  6. VB.NET工作笔记002---asp调用vb6编写的activex dll
  7. Boostnote跨平台 Markdown 编辑器
  8. 【面向对象设计基础】UML统一建模语言初学
  9. C语言实现“轰炸”代码(QQ)
  10. python脚本编写
  11. 《机器学习实战》--资料下载和运行环境
  12. python 好用的库_12个超好用的Python库,都帮你们整理好了!
  13. 浅谈团队提高软件质量的方式
  14. Linux S3C2440 学习笔记02
  15. Express框架概述
  16. c语言水解猴子吃桃问题
  17. CDO玩“跨界”,数据驱动有戏了
  18. 怎么根据读到的ADC值,推算实际电压值(一)
  19. python自然语言处理-广度优先搜索
  20. 信创操作系统--统信UOS桌面版(玩游戏:安装Steam、Linux游戏、Windows游戏)

热门文章

  1. Input.mousePosition与hit.point的区别
  2. 两数相加——哈希表算法
  3. 机器学习之Artificial Neural Networks
  4. icon图标和文字对不齐(已解决)
  5. Python爬虫:爬取“Boss直聘”招聘数据
  6. Dmitrinbsp;Fomin风光摄影作品
  7. bgcolor是html的属性,HTML表格标记教程(7):背景颜色属性BGCOLOR
  8. 如何使用通达信收费接口?
  9. 突然发现, 保障性住房问题在我国, 由来已久
  10. java编程入门教材,差点挂在了美团三面