IIC总线的设置及理解
一、首先需要了解IIC的时序,写出来利用IIC总线进行数据传输时所必要的子函数,如下:
① IIC初始化函数
② 微秒级延时函数
③ 启动函数
④ 停止函数
⑤ 主机向从机写数据的函数
⑥ 主机从从机读数据的函数
⑦ 等待从机应答的函数
⑧ 主机发送应答的函数
⑨ 主机发送非应答的函数
二、根据所选择的芯片的Datasheet,查找这款芯片在数据传输时的IIC时序图是什么,比如51单片机开发板中的AT24C02。
三、根据Datasheet的规定,再继续写芯片的读写函数。
注意:下面的代码是单片机向AT24C02写数据,以及从AT24C02读数据的代码,写数据使用的是Datasheet中的ByteWrite方式,读数据使用的是Datasheet中的RandomRead方式,其对应的IIC时序图可以从Datasheet中找到。
/*************** IIC总线的设置 ***************/
# include <reg52.h>
# include <math.h>
# include <intrins.h>
#define AT24C02_ADDRESS0 0xA0 //从机地址0xA0为对从机进行写操作
#define AT24C02_ADDRESS1 0xA1 //从机地址0xA1为对从机进行读操作
sbit SDA=P3^0;
sbit SCL=P3^1;
sbit Key1=P1^0;
sbit Key2=P1^1;
void delay(); //3us延时
void init();
void Start();
void Stop();
void Ack();
void NoAck();
void WaiteAck();
void WriteByte(unsigned char Byte);
unsigned char ReadByte();
void AT24C02_WriteByte(unsigned char WordAddress_Write,Data);
unsigned char AT24C02_ReadByte(unsigned char WordAddress_Read);
void DelayMs(int Delaytime);
void main()
{
while(1)
{
if (Key1==0)
{
AT24C02_WriteByte(0,0xaa);
DelayMs(5);
AT24C02_WriteByte(1,0xcd);
DelayMs(5);
}
if (Key2==0)
{
P0 = AT24C02_ReadByte(0);
DelayMs(2000);
P0 = AT24C02_ReadByte(1);
DelayMs(2000);
P0 = 0xff;
}
}
}
void delay() //延迟程序,延迟约3us
{
;;
}
void init() //IIC初始化使SCL与SDA均为高电平
{
SCL=1;
SDA=1;
}
//SCL为低时SDA可以进行电平切换,SCL为高时读取SDA数据
void Start() //单片机发送启动信号
{
SDA=1; //首先操作SDA,再操作SCL,防止SCL在高电平时,SDA出现高低电平的变化
SCL=1; //在SCL高电平期间,SDA由高到低
delay();
SDA=0;
delay();
SCL=0; //钳住总线,让IIC总线失效:SCL为高电平时的数据是有效的
}
void Stop() //单片机发送停止信号
{
SDA=0;
SCL=1; //在SCL高电平期间,SDA由低到高
delay();
SDA=1;
delay();
SCL=0; //钳住总线,让IIC总线失效
}
void Ack() //单片机发送应答
{
SDA=0;
SCL=1;
delay();
SCL=0; //钳住总线,让IIC总线失效
}
void NoAck() //单片机发送非应答
{
SDA=1;
SCL=1;
delay();
SCL=0; //钳住总线,让IIC总线失效
}
void WaiteAck() //等待从机应答
{
unsigned int i,RepreAck; //定义从机应答标志位,当应答时RepreAck=0;不应答时RepreAck=1
SDA=1; //将SDA置成高电平等待从机应答
delay();
SCL=1;
if(SDA==1)
{
i++;
if(i>200)
{
SCL = 0;
RepreAck=1;
Stop();
}
}
else
SCL=0;
RepreAck=0;
}
void WriteByte(unsigned char Byte) //单片机向从机写数据
{
unsigned char i;
for(i=0;i<8;i++)
{
SDA=Byte&(0x80>>i); //给SDA写一位
SCL=1; //SCL拉高,使数据保持稳定
delay();
SCL=0; //再把SCL拉低,使SDA进行高低电平的变化
delay();
}
}
unsigned char ReadByte() //单片机从从机读数据
{
unsigned char i,Byte=0x00;
SDA=1;
for(i=0;i<8;i++)
{
SCL=1; //拉高SCL使SDA的值保持稳定
delay();
if(SDA)
{
Byte|=(0x80>>i); //把SDA的值传给Byte
}
SCL=0;
delay();
}
return Byte;
}
void AT24C02_WriteByte(unsigned char WordAddress_Write,Data)
{
init(); //IIC总线初始化
Start(); //主机发送启动信号
WriteByte(AT24C02_ADDRESS0); //主机发送从机地址,最后一位是写
WaiteAck(); //等待从机应答
WriteByte(WordAddress_Write); //主机发送存储地址
WaiteAck(); //等待从机应答
WriteByte(Data); //主机写地址
WaiteAck(); //等待从机应答
Stop(); //主机发送停止信号
}
unsigned char AT24C02_ReadByte(unsigned char WordAddress_Read)
{
unsigned char Data;
init(); //IIC总线初始化
Start(); //主机发送启动信号
WriteByte(AT24C02_ADDRESS0); //主机发送从机地址,这时仍旧是写操作
WaiteAck(); //等待从机应答
WriteByte(WordAddress_Read); //主机发送读取地址!!!注意是读取地址
WaiteAck(); //等待从机应答
Start(); //主机再次发送启动信号
WriteByte(AT24C02_ADDRESS1); //主机发送从机地址!!!注意这时是读操作
WaiteAck(); //等待从机应答
Data=ReadByte(); //调用单片机从从机读数据的程序,把数据存入Data
NoAck; //主机向从机发送非应答信号,这是AT24C02的Datasheet规定的
Stop(); //主机发送停止信号
return Data;
}
void DelayMs(int Delaytime) //借鉴别人的程序,大概是延时1ms
{
int x,y;
for(x=Delaytime;x>0;x--)
for(y=110;y>0;y--);
}