- 什么是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存取数据的更多相关文章
-
stm32软件模拟IIC读取PX4FLOW光流传感器数据
这段时间在做全国光电设计大赛,用到了px4的px4flow光流传感器,用软件模拟iic读取数据不定期会导致px4flow死机,查了资料和光流的源码,发现这个光流用了stm32的硬件iic,所以对软件模 ...
-
用I/O口模拟IIC总线协议遇到的一些问题
最近做的一个项目,是基于IIC总线通信的传感器系统.由于另外一个传感器使用的是类IIC协议,而不是标准IIC,所以MCU不能与其通信,最后没有办法,只有通过I/O口模拟的方式实现IIC的总线通信.具体 ...
-
模拟IIC总线多设备挂载(12864OLED屏幕+GY30光照传感器)
最终效果展示 OLED屏幕和GY30光照传感器(BH1750FVI)都连接在一个IIC(I2C)总线上,所以只需要接4根线即可.获取到的光照强度可以在OLED上实时显示并通过串口打印.IIC是IO模拟 ...
-
模拟IIC总线汇编程序软件包
一.概述 为了非常方便地对 I2C 从器件进行快速的.正确的读写操作,我们为此而设计出虚拟 I2C 总线操作平台软件包.本软件包是主方式下的虚拟 I2C 总线软件包,只要用户给子程序提供几个主要的参数 ...
-
IIC总线
一. 概述 1. IIC总线是PHILIPS公司推出的一种串口总线,是具备多主机系统所需的包括总线裁决和高低速器件同步功能的高性能串口总线. 2. IIC总线只有两根双向信号线.一根是数据线SDA,一 ...
-
对 IIC 总线的理解、调用函数以及常见面试问题
一.IIC 总线概述: IIC 即Inter-Integrated Circuit(集成电路总线) I2C总线是PHLIPS公司推出的一种串行总线, I2C总线只有两根双向信号线.一根是数据线SDA, ...
-
Exynos4412 IIC总线驱动开发(一)—— IIC 基础概念及驱动架构分析
关于Exynos4412 IIC 裸机开发请看 :Exynos4412 裸机开发 —— IIC总线 ,下面回顾下 IIC 基础概念 一.IIC 基础概念 IIC(Inter-Integrated Ci ...
-
RT-thread 设备驱动组件之IIC总线设备
本文主要介绍RT-thread中IIC总线设备驱动,涉及到的主要文件有:驱动框架文件(i2c_core.c,i2c_dev.c,i2c-bit-ops.c,i2c_dev.h,i2c.h):底层硬件驱 ...
-
十天学会单片机Day5 IIC总线AT2402芯片(EEPROM)应用
1.采用串行总线技术可以使系统的硬件设计大大简化.系统的体积减小.可靠性提高.同时,系统的更改和扩充极为容易. 常用的串行扩展总线有: IIC (Inter IC BUS)总线.单总线(1-WIRE ...
随机推荐
-
使用递归方法遍历TreeView的节点如配置则勾选
自己在网上找了一段时间都没有找到取自数据库的值与TreeView中的节点值进行对比如匹配则勾选中CheckBox的资料,后面自己写了一个递归方法实现,现在记录起来以备需要时使用.在没写这递归方法前如果 ...
-
Linux基础1之磁盘与分区
Linux上面设备皆文件,目前需要知道的,比如U盘和SARA硬盘的在Linux上面的文件名,/dev/sd[a-p].与IDE接口不同的是,SATA/USB接口的磁盘没有一定的顺序,这里就根据Linu ...
-
昨天做了一个使用javamail发送文件的demo
记录一下过程. 两种版本第一个demo是纯java文件.一个就可以,是我在网上搜索到的,第二个demo是我在ssh框中中写的jsp页面demo 1.java版本: package com.zq.www ...
-
ruby中如何调用与局部变量同名的私有方法
如果ruby中一个局部变量名和私有方法名同名的话,默认该名称被解释为变量而不是方法: x=10; def x;puts "what?" end 当你输入x实际不能执行x方法.解释器 ...
-
零基础学Python--------第5章 字符串及正则表达式
第5章 字符串及正则表达式 5.1 字符串常用操作 在Python开发过程中,为了实现某项功能,经常需要对某些字符串进行特殊处理,如拼接字符串.截取字符串.格式化字符串等.下面将对Python中常用的 ...
-
基于开发者中心DevOps流水线快速上云
导读:“DevOps”这个词现在很流行,它具体指的是什么呢?本文介绍了DevOps和开发者中心DevOps流水线,图文并茂,解答您的疑惑. 那么DevOps是什么?开发者中心<DevOps流水线 ...
-
Codeforces Hello 2018 E题Logical Expression dp+最短路 好题
j题目链接: http://codeforces.com/contest/913/problem/E 题意: 给你x,y,z三个变量,与& 或| 非! 括号() 四种运算符,规定括 ...
-
scrapy 爬取斗罗大陆漫画
# -*- coding: utf-8 -*- import scrapy import json import os import urllib import time from scrapy.ht ...
-
IO流_PrintWriter(字符打印流)与PrintStream(字节打印流)
PrintStream: 1.提供了打印方法可以对多种数据类型值进行打印,并保持数据的表示形式 2.它不抛IOException 3.构造函数接受三种类型的值: 字符串路径 File对象 ...
-
解决hibernate向mysql插入中文乱码问题(转)
转载自:http://blog.csdn.net/peditable/article/details/7047573 1.首先需要修改MySQL数据库的配置文件my.ini,此文件放在mysql根目录 ...