- 什么是IIC总线

IIC总线是同步通信的一种特殊形式,具有接线口少、控制简单、器件封装形式小、通信速率高等特点。在主从通信中,可以有多个IIC总线器件同时连接到IIC总线上,所有与IIC兼容的器件都具有标准的接口,通过地址来识别通信对象,使他们可以经由IIC总线互相直接通信。
IIC总线由SDA数据线和SCL时钟线俩条线构成通信线路,既可发送数据也可以接收数据。在CPU和IC之间、IC与IC间都可以双向传播,每个器件都有唯一的地址,这样就可以使信息进行准确的传输。CPU发出的信号分为地址码和数据码俩部分,地址码用来选址,数据码是通信的内容。
总而言之,IIC总线就是器件之间的通信线路,主器件可以通过IIC总线向从器件发送数据,也可以从从器件接收数据。51单片机不具备IIC总线接口,但我们可以通过软件模拟IIC总线的工作时序,只需要正确调用各个函数就能够方便的拓展IIC总线接口器件。

-什么是EEPROM

EEPROM就是一种存储介质,就像ROM、PROM、FLASH储存器等,下面我粗略地介绍一下EEPROM的由来
ROM:只读存储器,其中的内容在工厂中就烧录好了,内容只能读,不能改,所以用户只能读取其中数据,一旦数据出错,ROM就相当于废掉了。
PROM:可编程的ROM,相比于原来的ROM,用户可以将自己所需要的数据写入,但也只有一次机会,数据一旦写入之后就无法修改。
EPROM:可擦除可编程ROM,相比较PROM,此芯片可以重复擦除和写入,虽然它解决了PROM只能写入一次的弊端,但EPROM数据的擦除是通过紫外线的照射来完成的,所以使用此芯片时对紫外线的防护是很重要的。
EEPROM电可擦除可编程ROM,鉴于EPROM擦除数据的不容易,EEPROM应运而生,它是以电子信号来修改其内容的,而且是以byte为最小修改单位的,不需要将数据全部清除来写入,可以实现定向修改数据。而且因为其数据保存具有掉电不丢失的特性备受追捧。
在下的程序就是通过51单片机模拟IIC总线对AT24C02(EEPROM的型号)进行数据的存取和修改。
AT24C02的储存容量为256B一般通过片内子地址寻址对内部256B中任意一个进行读\写操作,其寻址范围为00~FF。

-IIC总线的通信格式

就像串口通讯和红外遥控一样,IIC总线也有一套通信方式。
硬件结构
先来认识一下IIC总线的硬件结构,SDA是数据线,SCL是时钟线,总线上个器件均采用漏极开路结构与总线相连,因此SDA和SCL都需要上拉电阻,总线在空闲状态保持高电平,一旦某一器件输出低电平,都将使总线的信号变低,所以说各器件的SDA和SCL都是线“与”关系。

数据位有效性
IIC中数据的传输是通过SDA和SCL进行高低电平变化来完成的,在传送数据时,只有当时钟线SCL为高电平的时候数据线SDA上的电平才有效(即SDA高电平代表1;SDA低电平代表0),所以在SCL为高电平的时候SDA上的数据一定要保持稳定才行,不然数据的传输会很不稳定的。那就是说SCL为低电平的时候SDA怎么变化都没有关系,但SCL为高电平时SDA一定要稳定,可以理解为传输信号的改变是在SCL为低电平的时候进行的(SCL高电平时SDA的改变即为传输信号的改变)。

启始信号、停止信号
IIC每次进行数据传输时先由主机发出启始信号,代表数据传输的开始,信号格式为:在SCL高电平时期SDA产生下降沿(注意这与数据的传输不同,SCL高电平时器SDA要变化),这样从器件就会检测到该信号并做好准备。
相对应,停止信号时在SCL高电平时期SDA产生上升沿信号。俩种信号的时序图如下
寻址信号
主机在发出启始信号后,再发出寻址信号,这里介绍一下七位寻址方式。
寻址信号由一个字节(8byte)构成,高七位为地址位,用来确定要进行通信的从器件,最低位是方向位,用来说明是传输数据还是接收数据。每一个从器件都会对比主机发送的地址码和自己的地址,如果安排上了,再判断从器件是接收主机数据还是向主机发送数据。
从器件的地址由固定地址和可编程地址俩部分组成,固定地址用于区别类别,可编程地址用来区别同类从器件。比如AT24C02有四位固定地址和三位可编程地址,三位可编程地址可以有八种表达方式,所以最多可以有八个AT24C02器件接再IIC中。
方向位为0时,主机向从机传输数据;方向位为1时,从机向主机传输数据。
应答信号
IIC总线协议规定:每传输1字节数据(含地址及命令)后,都要有一个应答信号,以确定数据传送是否被对方收到。应答信号由接收方产生,应答信号的格式为:在SCL为高电平时SDA为低电平(被动的,我们到时候只要检测一下SDA是否被拉低即可),表示数据传输正确,产生应答。但当主机为接收方时,对最后一字节不应答。

(在敲代码时我们一般将应答信号的检验放在数据发送函数中)

模块化设计注解

这里只是挑重要模块进行注解,后面有完整代码。
延时10um函数

void dy()
{
uint a;
for(a=3;a>0;a--)
;
}

IIC启始函数

void IICstart()//产生下降沿,启动信号
{
SDA=1;
dy();
SCL=1;
dy();
SDA=0;
dy();
SCL=0; }

IIC停止函数

void IICstop()//产生上升沿,停止信号
{
SDA=0;
dy();
SCL=1;
dy();
SDA=1;
dy();
SCL=0;
}

IIC发送一个字节函数

uchar IICsendbyte(uchar dat)//将dat一个字节的内容发送出去,先发送最高位,并检测应答
{
uint i;
SCL=0
for(i=0;i<8;i++)//8位逐次发送
{
dat<<=1;
SDA=CY;//进行左移操作后最高位自动移入PSW寄存器中的CY位(可以用来zb)
dy();
SCL=1;
dy();
SCL=0;
dy();
}
SDA=1;//拉高SDA电平,准备检测应答信号
dy();
SCL=1;
while(SDA)
{
j++;
if(j>200)//当超过2000umSDA还没被拉低,算应答失败或非应答
{
SDA=0;
dy();
return 0;//发送失败返回0
}
}
SCL=0;
dy();
return 1;//发送成功返回1
}

IIC接收一个字节函数

uchar IICreadbyte()//读取一个字节数据,并返回
{
uint i;
uchar dat;
for(i=0;i<8;i++)
{
SCL=1;
dy();
dat<<=1;//一定要先移位
dat |=SDA;//与运算
dy();
SCL=0;
dy();
}
return dat;
}

向AT24C02写字节

void AT24C02write(uchar addr,uchar dat)//往addr地址写入dat数据
{
IICstart();//开始
IICsendbyte(0Xa0);//发送寻址 0Xa0代表寻址AT24C02并且方向位为0,主机向从机传输数据
IICsendbyte(addr);//发送储存地址
IICsendbyte(dat);//发送储存数据
ICCstop();//结束
}

从AT24C02读字节

uchar AT24C02read(uchar addr)//读取AT24C02中addr位置数据并返回
{
uchar dat;
IICstart();
IICsendbyte(0Xa0);//伪写
IICsendbyte(addr);
IICstart();//开始读取
IICsendbyte(0Xa1);//发送寻址 0Xa0代表寻址AT24C02并且方向位为1,从机向主机传输数据
dat=IICreadbyte(addr);//读取数据
IICstop();
return dat;//返回数据
}

整体代码

在下通过按键k1、k2、k3、k4实现数据在AT14C02中的保存、读取、自增、清零等操作,并通过数码管显示数值(38译码器),亲自测试可以运行。

 #include"reg52.h"
#define uint unsigned int
#define uchar unsigned char
uchar num,duan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
sbit SDA=P2^0;
sbit SCL=P2^1; sbit a=P2^2;
sbit b=P2^3;
sbit c=P2^4; sbit k1=P1^3;
sbit k2=P1^2;
sbit k3=P1^1;
sbit k4=P1^0; void delay10us() //时间>4.7um就ok
{
unsigned char a;
for(a=3;a>0;a--);
} void dy(uint x) //按键时用的延时函数
{
while(x--);
} void xs() //数码管显示
{
uint i;
for(i=0;i<4;i++)
{
switch(i)
{
case 0:a=0;b=0;c=0;P0=duan[num/1000];break; //千位
case 1:a=1;b=0;c=0;P0=duan[num/100];break; //百位
case 2:a=0;b=1;c=0;P0=duan[num/10%10];break; //十位
case 3:a=1;b=1;c=0;P0=duan[num%10];break; //个位
}
dy(100);
P0=0X00;
}
} void IICstart() //起始信号
{
SDA=1;
delay10us();
SCL=1;
delay10us();
SDA=0;
delay10us();
} void IICstop() //停止信号
{
SDA=0;
delay10us();
SCL=1;
delay10us();
SDA=1;
delay10us();
} uchar IICsendbyte(uchar dat) //发送一个字节的数据
{
uint i,j=0;
SCL=0;
for(i=0;i<8;i++) //从最高位开始发送
{
dat<<=1;
SDA=CY; //左移时最高位会移入PSW寄存器的CY位中
delay10us();
SCL=1;
delay10us();
SCL=0;
delay10us();
}
SDA=1;
delay10us();
SCL=1;
while(SDA) //等待应答 即等待设备把SDA拉低
{
j++;
if(j>200) //如果超过2000um没有应答就算发送失败或非应答 表示接收结束
{
SCL=0;
delay10us();
return 0;
}
}
SCL=0; //不管应答或非应答,SCL都置0
delay10us();
return 1;
} uchar IICreadbyte() //读一个字节,从最高位开始
{
uint i,dat=0;
SDA=1; //因为下面开始时SCL=1,所以SDA要稳定
delay10us();
for(i=0;i<8;i++)
{
SCL=1;
delay10us();
dat<<=1;
dat |=SDA;
delay10us();
SCL=0;
delay10us();
}
return dat; //返回读到的数据dat(一个字节)
} void AT24c02write(uchar addr,uchar dat) //往AT24c02的addr地址写入dat数据
{
IICstart();
IICsendbyte(0Xa0); //发送要与之通信的器件地址,此处为AT24c02的地址
IICsendbyte(addr); //发送要写入的内存地址,AT24c02内部可储存256字节,故地址可以为0~255
IICsendbyte(dat); //发送数据
IICstop();
} uchar AT24c02read(uchar addr) //读取AT24c02中addr地址的值,并返回给函数
{
uchar dat;
IICstart();
IICsendbyte(0Xa0); //伪写
IICsendbyte(addr);
IICstart(); //真正开始读数据
IICsendbyte(0Xa1);
dat=IICreadbyte();
IICstop();
return dat;
} void key()
{
if(k1==0)
{
dy(1000);
if(k1==0)
{
AT24c02write(1,num);
}
while(!k1); //检测放手
}
if(k2==0)
{
dy(1000) ;
if(k2==0)
{
num=AT24c02read(1);
}
while(!k2); //检测放手
}
if(k3==0)
{
dy(1000);
if(k3==0)
{
num++;
if(num==256)
num=0;
}
while(!k3); //检测放手
}
if(k4==0)
{
dy(1000);
if(k4==0)
{
num=0;
}
while(!k4); //检测放手
}
} void main()
{
while(1)
{
key();
xs();
}
}

C51—模拟IIC总线实现EEPROM存取数据的更多相关文章

  1. stm32软件模拟IIC读取PX4FLOW光流传感器数据

    这段时间在做全国光电设计大赛,用到了px4的px4flow光流传感器,用软件模拟iic读取数据不定期会导致px4flow死机,查了资料和光流的源码,发现这个光流用了stm32的硬件iic,所以对软件模 ...

  2. 用I/O口模拟IIC总线协议遇到的一些问题

    最近做的一个项目,是基于IIC总线通信的传感器系统.由于另外一个传感器使用的是类IIC协议,而不是标准IIC,所以MCU不能与其通信,最后没有办法,只有通过I/O口模拟的方式实现IIC的总线通信.具体 ...

  3. 模拟IIC总线多设备挂载(12864OLED屏幕+GY30光照传感器)

    最终效果展示 OLED屏幕和GY30光照传感器(BH1750FVI)都连接在一个IIC(I2C)总线上,所以只需要接4根线即可.获取到的光照强度可以在OLED上实时显示并通过串口打印.IIC是IO模拟 ...

  4. 模拟IIC总线汇编程序软件包

    一.概述 为了非常方便地对 I2C 从器件进行快速的.正确的读写操作,我们为此而设计出虚拟 I2C 总线操作平台软件包.本软件包是主方式下的虚拟 I2C 总线软件包,只要用户给子程序提供几个主要的参数 ...

  5. IIC总线

    一. 概述 1. IIC总线是PHILIPS公司推出的一种串口总线,是具备多主机系统所需的包括总线裁决和高低速器件同步功能的高性能串口总线. 2. IIC总线只有两根双向信号线.一根是数据线SDA,一 ...

  6. 对 IIC 总线的理解、调用函数以及常见面试问题

    一.IIC 总线概述: IIC 即Inter-Integrated Circuit(集成电路总线) I2C总线是PHLIPS公司推出的一种串行总线, I2C总线只有两根双向信号线.一根是数据线SDA, ...

  7. Exynos4412 IIC总线驱动开发(一)—— IIC 基础概念及驱动架构分析

    关于Exynos4412 IIC 裸机开发请看 :Exynos4412 裸机开发 —— IIC总线 ,下面回顾下 IIC 基础概念 一.IIC 基础概念 IIC(Inter-Integrated Ci ...

  8. RT-thread 设备驱动组件之IIC总线设备

    本文主要介绍RT-thread中IIC总线设备驱动,涉及到的主要文件有:驱动框架文件(i2c_core.c,i2c_dev.c,i2c-bit-ops.c,i2c_dev.h,i2c.h):底层硬件驱 ...

  9. 十天学会单片机Day5 IIC总线AT2402芯片(EEPROM)应用

    1.采用串行总线技术可以使系统的硬件设计大大简化.系统的体积减小.可靠性提高.同时,系统的更改和扩充极为容易. 常用的串行扩展总线有: IIC (Inter IC BUS)总线.单总线(1-WIRE ...

随机推荐

  1. Java 在Word中创建邮件合并模板并合并文本和图片

    Word里面的邮件合并功能是一种可以快速批量操作同类型数据的方式,常见的如数据填充.打印等.其中必不可少的步骤包括用于填充的模板文档.填充的数据源以及实现邮件合并的功能.下面,通过Java程序展示如何 ...

  2. MYSQL_Join注入技巧

    Join注入技巧 join无名列报错注入 约束条件 在知到表名的前提下才能操作 注入语句 and extractvalue(1,concat(0x7e,(select * from (select * ...

  3. 小白都能理解的TCP三次握手四次挥手

    前言 TCP在学习网络知识的时候是经常的被问到知识点,也是程序员必学的知识点,今天小杨用最直白的表述带大家来认识认识,喜欢的朋友记得点点关注哈. 何为TCP 上点官方的话:是一种面向连接(连接导向)的 ...

  4. VisualEffectGraph基础操作 --创建VEG项目步骤讲解

    一:建立VEG项目步骤 首先打开Unity Hub,  使用unity2020.1 新建项目(本技术博客,默认使用unity2020.1 版本演示),选择HDRP 高清渲染管线,确定项目目录与名称. ...

  5. 『与善仁』Appium基础 — 3、ADB命令介绍

    目录 1.ADB命令简介 2.ADB命令运行原理 3.通过ADB命令连接安卓模拟器 (1)安装安卓模拟器 (2)ADB命令连接安卓模拟器 (3)常用Android模拟器端口号 1.ADB命令简介 AD ...

  6. Windows内核驱动--实现修改线程优先级demo

    在User下修改优先级比较麻烦,该驱动可以直接用线程ID,和优先级级数两个参数直接修改线程的优先级: Client代码: #include <Windows.h> #include < ...

  7. ES6 数值类型常用方法

    ES6 数值类型常用方法 <script type="text/javascript"> // Number常用方法 /* Number.isFinite() 用来检查 ...

  8. Spark—RDD编程常用转换算子代码实例

    Spark-RDD编程常用转换算子代码实例 Spark rdd 常用 Transformation 实例: 1.def map[U: ClassTag](f: T => U): RDD[U]  ...

  9. selenium3 + python - js&jquery操作处理

    # 推荐学习:https://www.w3school.com.cn/js/index.asp## 下面以简书登录&注册定位元素为例"""js定位 id name ...

  10. Oracle19c 如何用rman duplicate 克隆一个数据库。(Active方式)

    Oracle19c 如何用rman duplicate 克隆一个数据库. 首先克隆有两种方法,一种是Backup-Based,一种是Active方式.官网文档链接https://docs.oracle ...