单片机先向24C02写入256个字节的数据,再从24C02中一次读取2个字节的数据、并在数码管上动态显示,直至读完24C02中256个字节的数据。
I2C总线有两根双向的信号线,一根是数据线SDA,另一根是时钟线SCL。I2C总线通过上拉电阻接正电源,因此,当总线空闲时为高电平。
起始信号、停止信号由主机发出。在数据传送时,当时钟线为高电平时,数据线上的电平状态必须保持稳定;当时钟线为低电平时,数据线上的电平状态才允许变化。发送器将8位数据从高位到低位传送完成后,需要接收来自接收器的应答或非应答的信号。
51单片机需要编写模拟I2C总线通信的程序,才能与其他I2C总线器件通信。
<1>起始信号的程序
/*I2C起始信号*/
void i2c_start()//当SCL为高电平,SDA从高电平变为低电平
{
SDA=1;
delay6us();//将SDA置为高电平
SCL=1;
delay6us();//将SCL置为高电平
SDA=0;
delay6us();//SDA从高电平变为低电平
SCL=0;
delay6us();//将SCL置为低电平,准备发送数据
}
<2>停止信号的程序
/*I2C停止信号*/
void i2c_stop()//当SCL为高电平,SDA从低电平变为高电平
{
SDA=0;
delay6us();//将SDA置为低电平
SCL=1;
delay6us();//将SCL置为高电平
SDA=1;
delay6us();//SDA从低电平变为高电平
}
<3>发送8位数据的程序
/*I2C发送数据*/
bit i2c_sendbyte(uchar dat)//主机发送数据8位
{
uchar i;//整型变量i,用于循环
for(i=0;i<8;i++)//发8次
{
SDA=dat>>7;//每次发送高位
dat=dat<<1;//次高位补位
delay6us();//SDA形成电平
SCL=1;
delay6us();//SCL为高电平时,SDA值可以被接收器读取
SCL=0;//将SCL置为低电平
delay6us();//将SCL置为低电平,准备发送下一位数据
}
SDA=1;
delay6us();//释放SDA,准备接收应答信号
SCL=1;
delay6us();//当SCL置为高电平,读取SDA状态
while(SDA)//非应答时进入while循环
{
SCL=0;
delay6us();//将SCL置为低电平
return 0;//接收器非应答返回0
}
SCL=0;
delay6us();//将SCL置为低电平
return 1;//接收器应答返回1
}
<4>读取8位数据的程序
/*I2C读取数据*/
uchar i2c_readbyte()//主机读取数据8位
{
uchar dat=0;
uchar i;//整型变量i,用于循环
SDA=1;
delay6us();//释放SDA,准备读取数据
for(i=0;i<8;i++)
{
SCL=1;
delay6us();//当SCL为1时,接收器可以读取SDA
dat=dat<<1;//左移1位
dat=dat|SDA;//先高后低
delay6us();//延时
SCL=0;
delay6us();//将SCL置为低电平,准备读取数据
}
return dat;//返回读取的数值
}
<5>应答信号的程序
/*I2C应答信号*/
void i2c_ask()//当SCL为高电平时,SDA为低电平
{
SDA=0;
delay6us();//将SDA置为低电平
SCL=1;
delay6us();//将SCL置为高电平
SCL=0;
delay6us();//将SCL置为低电平
}
<6>非应答信号的程序
/*I2C非应答信号*/
void i2c_noask()//当SCL为高电平时,SDA为高电平
{
SDA=1;
delay6us();//将SDA置为高电平
SCL=1;
delay6us();//将SCL置为高电平
SCL=0;
delay6us();//将SCL置为低电平
}
存储器24C02存储容量256*8bit,24C02的器件地址为7位,高4位固定为1010、低三位由A0、A1、A2引脚的电平值决定。读写信号(1:读;0:写)加7位器件地址构成一个字节的数据,
通过这个字节的数据,选择目标器件并确定读或写 。
24C024可以根据需要一次写入2~16个字节的数据,通过循环可以实现写入256个字节的数据。
单片机向24C02一次写入多个字节的子程序如下:
/*主机向24C02器件发送数据(多字节写操作)
起始信号-器件地址(7位地址+写信号)
应答信号-写24C02器件的存储首地址(8位)
应答信号-写数据(8位)-应答信号
写数据(8位)-........-应答-停止信号*/
bit c02_mutiwrite(uchar addr,uchar *p,uchar num)//参数addr表示写24C02器件的存储首地址,指针p指向待写数据,num表示数据个数
{
bit flag=0;//用于判断I2C发送数据是否成功
uchar i;
i2c_start();//起始信号
flag=i2c_sendbyte(0xA0);//24C02器件地址1010000 0(写)
if(flag==0) return 0;
flag=i2c_sendbyte(addr);//写24C02器件的存储首地址
if(flag==0) return 0;
for(i=0;i
单片机每次从24C02读出2个字节,形成一个16位2进制数。
例如第一个字节数据是0000 0001即 (十进制数1),第二个字节数据的是0000 0010即(十进制数2)
新的16位2进制数0000 0001 0000 0010即(十进制数是258)。
子程序如下:
/*主机从24C02器件读取数据(每次读2个字节操作)
起始信号-器件地址(7位地址+写信号)//伪写操作
应答信号-目标读取的存储首地址(8位)
应答信号-起始信号-器件地址(7位地址+读信号)
读数据(8位)-应答-读数据(8位)-非应答-停止信号*/
bit c02_mutireadbyte(uchar addr,uint *p)//参数addr表示读24C02器件的存储首地址,指针p指向保存数据的地址
{
bit flag=0;//用于判断I2C发送数据是否成功
i2c_start();//起始信号
flag=i2c_sendbyte(0xA0);//24C02器件地址1010 000 0(写)
if(flag==0) return 0;
flag=i2c_sendbyte(addr);//目标读取的存储首地址(8位)
if(flag==0) return 0;
i2c_start();//起始信号
flag=i2c_sendbyte(0xA1);//24C02器件地址1010 000 1(读)
if(flag==0) return 0;
*p=i2c_readbyte();//主机读取第一个字节(8位)
i2c_ask();//主机发送应答
*p=(*p)<<8;//第一个字节(8位)左移8位作高8位
*p=(*p)+i2c_readbyte();//主机读取数据8位作低8位
i2c_noask();//非应答
i2c_stop();//停止信号
return 1;//读数据成功
}
注:具体工程见链接https://item.taobao.com/item.htm?id=835593680495https://item.taobao.com/item.htm?id=835593680495
按下写入按键,单片机向24C02写入256个字节的数据,同时指示灯会亮。当写入完成后,指示灯灭。
掉电重启后,按下读取按键,单片机从24C02一次读取两个字节,第一个字节作为高八位,第二个字节作为第八位,形成的新的16位2进制数,以十进制数的形式在数码管上动态显示,直到读完最后的2个字节、并在数码管上显示。
实物亲测有效!!!
视频如下:
51单片机———I2C总线存储器24C02的应用