数据线(SDA)与时钟线(SCL)关系:
只有在时钟限号为低电平期间,数据线上的高电平或低电平状态才允许变化。
接下来附上51单片机模拟iic总线通讯的模拟时序图(后面的总线与信号会依照此图):
AT24C02的读写操作时序图:
具体控制程序如下(分成三个文件):
mian.c:
#include"reg52.h"
#include"i2c.h"
typedef unsigned int u16;
typedef unsigned char u8;
sbit k1=P3^1;//保存(写入)数据
sbit k2=P3^0;//读取数据
sbit k3=P3^2;//num累加
sbit k4=P3^3;//num清零
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
u8 num=0,disp[4];
u8 code smg[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
void delay(u16 i)
{
while(i--);
}
void Keypros()
{
if(k1==0)
{
delay(1000);//10ms
if(k1==0)//延迟确认,老方法了
{
At24C02Write(1,num);//如果确定按下了k1,就写入数据与地址
}
while(!k1);
}
if(k2==0)
{
delay(1000);//10xms
if(k2==0)
{
num=At24C02Read(1);
}
while(!k2);
}
if(k3==0)
{
delay(1000);//10xms
if(k3==0)
{
num++;
if(num>255) num=0;
}
while(!k3);
}
if(k4==0)
{
delay(1000);//10xms
if(k4==0)
{
num=0;
}
while(!k4);
}
}
void datapros()
{
disp[0]=smg[num/1000];
disp[1]=smg[num%1000/100];
disp[2]=smg[num%1000%100/10];
disp[3]=smg[num%1000%100%10];
}
void display()
{
u8 i;
for(i=0;i<4;i++)
{
switch(i)
{
case 0:LSA=0;LSB=0;LSC=0; break;
case 1:LSA=1;LSB=0;LSC=0; break;
case 2:LSA=0;LSB=1;LSC=0; break;
case 3:LSA=1;LSB=1;LSC=0; break;
}
P0=disp[3-i];
delay(100);
P0=0x00;
}
}
void main()
{
while(1)
{
Keypros();
datapros();
display();
}
}
IIC.c
#include "i2c.h"
void Delay10us()
{
unsigned char a,b;
for(b=1;b>0;b--)
for(a=2;a>0;a--);
}
void I2cStart()/起始信号
{
SDA=1;
Delay10us();
SCL=1;
Delay10us();
SDA=0;
Delay10us();
SCL=0;
Delay10us();
}
void I2cStop()//终止信号
{
SDA=0;
Delay10us();
SCL=1;
Delay10us();
SDA=1;
Delay10us();
}
har I2cSendByte(unsigned char dat)//向IIC总线进行写操作
{
unsigned char a=0,b;
for(a=0;a<8;a++)//写8位的数据,从高到低
{
SDA=dat>>7;//dat取最高位给SDA
dat<<=1;//dat把给过的最高位去掉
Delay10us();
SCL=1;
Delay10us();
SCL=0;
Delay10us();//高低电压变化,发送数据
}
SDA=1;//发送完成,释放时钟线
Delay10us();
SCL=1;//释放数据线
while(SDA)//判断是应答还是非应答,若产生应答,SDA=0,会跳出while循环
{
b++;
if(b>200)
{
SCL=0;
Delay10us();
return 0;//应答失败即未发送数据
}
}
SCL=0;
Delay10us();
return 1;//发送成功
}
unsigned char I2cReadByte()//IIC总线进行读操作
{
unsigned char a=0,dat=0;
SDA=1;
for(a=0;a<8;a++)
{
SCL=1;//SCL置1 ,限制SDA变化(可以把SCL=1理解为关上)
Delay10us();
dat<<=1;//位移一次理解为填一位(0->00)
dat|=SDA; //00->01
//根据循环如此往复8次即可将8位数据全都按顺序赋给dat
Delay10us();
SCL=0;//高低电平变化,读取数据
Delay10us();
}
return dat;
}
void At24C02Write(unsigned char addr,unsigned char dat)//AT24C02写入数据(参照上面时序图)
{
I2cStart();
I2cSendByte(0xa0);//AT24C02固定的器件地址为1010 0000(+0为写入/+1为读取)
I2cSendByte(addr);
I2cSendByte(dat);
I2cStop();
}
unsigned char At24C02Read(unsigned char addr)//AT24C02读取数据(参照上面时序图)
{
unsigned char num;
I2cStart();
I2cSendByte(0xa0);
I2cSendByte(addr);
I2cStart();
I2cSendByte(0xa1);
num= I2cReadByte();
I2cStop();
return num;
}
IIC.h
#ifndef _I2C_H
#define _I2C_H
#include<reg52.h>
sbit SCL=P2^1;
sbit SDA=P2^0;
void At24C02Write(unsigned char addr,unsigned char adt);
unsigned char At24C02Read(unsigned char addr);
#endif
新手上路,欢迎指教。
还请问一下,为什么我复制代码块的时候我原本程序里面的注释都会变成问号。这个稿件的编辑界面还会变得无法选中,有大佬知道解决的方法吗?求教。