IIC通信

来源:互联网 发布:免费网络课程 编辑:程序博客网 时间:2024/06/10 19:49

下面介绍ATMEL公司的串行E2PROM产品——AT24C系列

AT24C01128字节(128×8位);

AT24C02256字节(256×8位);

AT24C04512字节(512×8位)AT24C081K字节(1K×8位);

AT24C162K字节(2K×8位);

 

本次实验用的是AT24C02,所以存储器的地址有256字节(在IIC总线寻址中读取存储器首地址时首地址的范围为0~256,因为AT24C02的容量为256字节


SDA和SCL都是双向线路,通过电流源或者上拉电阻连接到一个正向电压.(见下图)当总线空闲时,两条线都是高电平.连接到总线的设备的输出级必须是OD(漏极开路)或者OC(集电极开路)门才能执行线与功能.


开始条件和终止条件一直由主机产生.在开始条件后总线就处于忙状态.在终止条件后隔上一个固定时间总线就处于空闲状态.如果没有终止条件产生,而是一个重复的开始条件(start),那总线依旧是忙状态.
如果连接到总线的设备包含了必须的接口硬件那么开始条件和终止条件的检测时很容易的.但是没有这样接口的微控制器在每个时钟周期内至少要采样两次SDA线来识别有没有电平变化.

#include<reg52.h>
#define uchar unsigned char
sbit sda=P2^0;
sbit scl=P2^1;
uchar a;
void delay()   //延时2us
{ ;; }
void start()  //开始信号

 sda=1;
 delay();
 scl=1;
 delay();
 sda=0;
 delay();
}

void stop()   //停止
{
 sda=0;
 delay();
 scl=1;
 delay();
 sda=1;
 delay();
}

void respons()  //应答
{
 uchar i;
 scl=1;
 delay();
 while((sda==1)&&(i<250))i++;
 scl=0;
 delay();
}

void init()   //初始化
{
 sda=1;
 delay();
 scl=1;
 delay();
}

void write_byte(uchar date)    //写数据函数
{
 uchar i,temp;
 temp=date;


 for(i=0;i<8;i++)
 {
  temp=temp<<1;
  scl=0;
     delay();
  sda=CY;
  delay();
  scl=1;
  delay();
 // scl=0;
     //   delay();
 }
 scl=0;
 delay();
 sda=1;    //数据总线释放,养成良好习惯
 delay();
}

uchar read_byte()    //读数据函数
{
 uchar i,k;
 scl=0;
 delay();
 sda=1;   //数据总线释放,使总线处于空闲状态
 delay();
 for(i=0;i<8;i++)
 {
  scl=1;
  delay(); 
  k=(k<<1)|sda;   //一次读一位,从SDA的最低位读起
  scl=0;
  delay(); 
 }
 return k;
}

void delay1(uchar x)
{
 uchar a,b;
 for(a=x;a>0;a--)
  for(b=100;b>0;b--);
}

void write_add(uchar address,uchar date)
{
 start();
 write_byte(0xa0);
 respons();
 write_byte(address);
 respons();
 write_byte(date);
 respons();
 stop();
}

uchar read_add(uchar address)
{
 uchar date;
 start();
 write_byte(0xa0);
 respons();
 write_byte(address);
 respons();
 start();
 write_byte(0xa1);
 respons();
 date=read_byte();
 stop();
 return date;
}

void main()
{
 init();
 write_add(23,0xaa);
 delay1(100);   //此延时非常重要,单片机在写和读数据之间需要加一延时,否则单片机不能

              //正常响应读操作
 P1=read_add(23);
 while(1);
}

其中:

unsigned char readbyte()
{
unsigned char i,temp;
for(i=0;i<8;i++)
{
scl=1;
temp<<=1;
if(sda==1)temp=temp|0x01;
scl=0;_nop_();
}
return temp;
}


sda的数据要在scl低电平期间跳变,在scl高电平期间采样sda的数据。

下面分析代码:

在一次通信中,数据位有8个,那么读一个byte的数据,要采8次sda上的数据,故代码中用了8次循环,每次循环采样一次数据。

在每次循环中,scl设为高电平,将读入数据;temp用来存储读入的数据,对其左移1位,就可以存放本次读入的数据;如果sda此时为高那么将temp与0x01做或运算将最后一位置1,否则不用管,本来就是零;然后用将scl设置为0,并用_nop_();做一次空操作等待sda上的数据变化。

 

sda上的数据变化是在scl为低的时候发生,上面的代码中语句_nop_();就是为了等待sda的变化而用。


原创粉丝点击