I^2C总线通过上拉电阻接电源
电阻一般选择10k
每个器件有唯一地址
由总线仲裁
时钟信号为高电平期间,数据线上的数据必须稳定,只有在时钟为低电平期间,数据线上的电平才可以改变
起始信号
SCL为高电平期间,SDA由高电平变为低电平的变化为起始信号
终止信号
SCL为高电平期间,SDA由低电平变为高电平的变化为终止信号
起始终止信号有主机发出
接收器件接受完一个字节信号后,有可能需要处理一些内部事务,这时接收器件可以将SCL拉为低电平,使主机处于等待状态。直到接收器件完成内部事务可以进行下一字节的接收再将SCL拉为高电平。
字节传送必须为8位
先传送最高位MSB
每一个字节传送后必须跟随一位应答位
应答信号为从机发出的
一帧数据有9位
若主机等待一段时间没有等到从机应答主机默认接收到了
数据帧的格式
传送数据既有地址信号又有数据信号
寻址找到元器件再传送数据
起始信号后必须转送从机的地址(7位)
第8位为数据传送方向(R/T)
用0表示(下一字节)主机发送数据(T)
用1表示主机接受数据(R)
每次数据总是由主机产生终止信号结束
可以不发送终止信号再次发送起始信号进行寻址
IIC总线规定采用7位的寻址字节
即起始信号后的第一个字节
从机地址由固定部分和可编程部分组成
一般可编程的有三位
如何编程?
(有3个编程引脚,接的电平即为该芯片的地址)
EEPROM
eletrcic elmation program
(电可擦除存储芯片)
AT24C02:256字节
连续读写操作
每8个字节连续,在该连续区域内每连续读写一次地址自动加1,读写超出8个字节时地址计数器将翻转,再次从0开始。将覆盖原来数据。
连续区域
0~8 [0 1 2 3 4 5 6 7]
8~16 [8 9 10 11 12 13 14 15]
16~24 [16 17 18 19 20 21 22 23]
.
.
.
(起始地址为8的倍数,终止地址为起始地址加8)该区域内含左不含右。)
#include<reg52.h>
#include<intrins.h>
#define NOP() _nop_
#define uchar unsigned char
#define uint unsigned int
sbit SDA=P2^0;
sbit SCL=P2^1;
void Delay_IIC();
void IIC_Start();//起始信号
void IIC_End();//结束
void Respons();//应答信号
void Init();
void Send_Byte(uchar dat1);
uchar Read_Byte();
void Write_date(uchar *buffer,first_address,uchar lenth); //24wc16 lenth max 16
void Read_date(uchar *buffer,uchar first_address,uchar lenth); //24wc16 lenth max 16
uchar code LED_CODE[9]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x00};
void main()
{
uchar date[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
Write_date(LED_CODE,8,8); //24wc16 lenth max 16
Read_date(date,8,8);
while(1)
{
uchar i=0;
for(i=0;i<8;i++)
{
uchar a=200;
//P0=LED_CODE[i];
P0=date[i];
while(a--)
{
Delay_IIC();
Delay_IIC();
Delay_IIC();
Delay_IIC();
Delay_IIC();
Delay_IIC();
Delay_IIC();
Delay_IIC();
}
P0=0x00;
}
}
}
void Delay_IIC()
{
uchar a=0,b=0;
for(a=10;a>0;a--)
{
for(b=10;b>0;b--);
}
}
void IIC_Start()//起始信号
{
SDA=1;
Delay_IIC();
SCL=1;
Delay_IIC();
SDA=0;
Delay_IIC();
}
void IIC_End()//结束
{
SDA=0;
Delay_IIC();
SCL=1;
Delay_IIC();
SDA=1;
Delay_IIC();
}
void Respons()//应答信号
{
uchar i=0;
SCL=1;//while response sda=0
Delay_IIC();
SDA=1;
Delay_IIC();
while((SDA==1)&&(i<200))
i++;
SCL=0;
Delay_IIC();
}
void Init()
{
SDA=1;
Delay_IIC();
SCL=1;
Delay_IIC();
}
void Send_Byte(uchar dat1)
{
uchar i=0,j=0,dat;
dat=dat1;
SCL=0;
Delay_IIC();
for(i=0;i<8;i++)
{
SDA=dat>>7;
dat<<=1;
// dat<<=1;
// SDA=CY;
Delay_IIC();
SCL=1;
Delay_IIC();
SCL=0;
Delay_IIC();
}
SDA=1;
Delay_IIC();
}
uchar Read_Byte()
{
uchar i,k,dat;
SCL=0;
Delay_IIC();
SDA=1;
Delay_IIC();
for(i=0;i<8;i++)
{
SCL=1;
Delay_IIC();
k=SDA;
dat=(dat<<1)|k;
SCL=0;
Delay_IIC();
}
return dat;
}
void Write_date(uchar *buffer,first_address,uchar lenth) //24wc16 lenth max 16
{
uchar i=0;
Init();
IIC_Start();
Send_Byte(0xa0);//器件地址 最后一位为0表示写数据
Respons();
Send_Byte(first_address);//存储器 内存地址 example 36
Respons();
Send_Byte(*buffer);
Respons();
for(i=1;i<lenth;i++)
{
Send_Byte(*(buffer+i));// 写入数据0xfe
Respons();//应答后进行擦写操作,在此期间不答应任何主机请求
}
IIC_End();
}
void Read_date(uchar *buffer,uchar first_address,uchar lenth) //24wc16 lenth max 16
{
uchar i=0;
SDA=1;
Delay_IIC();
SCL=1;
Delay_IIC();
IIC_Start();
Send_Byte(0xa0);//器件地址 最后一位为0表示写 进行读之前的伪写操作。
Respons();
Send_Byte(first_address);//存储器 内存地址0x03
Respons();
IIC_Start();
Send_Byte(0xa1);
Respons();
*buffer=Read_Byte(); //读取第一个字节完毕
SCL=0;
Delay_IIC();
SDA=1;
Delay_IIC();
SDA=0;//主机向从机应答 表明要读多个字节
Delay_IIC();
SCL=1;
for(i=1;i<lenth;i++)
{
Delay_IIC();
*(buffer+i)=Read_Byte();
SCL=0;
Delay_IIC();
SDA=1;
Delay_IIC();
SDA=0;//主机向从机应答 表明要读多个字节
Delay_IIC();
SCL=1;
}
IIC_End();
}
|