#include<reg52.h>
#include<intrins.h> //内部有_nop_();
//IIC模拟时序实现
//注意:SCL为高电平时变化SDA数据是起始或者终止信号;所以若不是起始或者终止信号,需要在SCL为低电平时变化SDA数据
sbit SDA = P2^0;
sbit SCL = P2^1;
sbit LED = P2^3;
void delay3us()
{
_nop_();
_nop_();
_nop_();
}
void delayms(unsigned char t)
{
unsigned char i,j;
for(i = t; i > 0; i --)
{
for(j = 250; j > 0; j --);
}
}
void start()
{
SDA = 1;//scl=1写在SDA=1后面
delay3us();
delay3us();
SCL = 1;////scl=1写在SDA=1后面,若是不这么做的话,万一SDA=1之前SDA是0就变成命令信号了
delay3us();//SCL = 1需延时至少4.7us
delay3us();
SDA = 0;
delay3us();//SDA = 0;SCL = 1需延时至少4us
delay3us();
SCL = 0;//释放SCL
delay3us();
}
void stop()
{
SDA = 0;
delay3us();
delay3us();
SCL = 1;
delay3us();//SCL = 1;SDA = 0需要至少延时4.7us
delay3us();
SDA = 1;
delay3us();//SCL = 1;SDA = 1需要至少延时4.7us
delay3us();
//SDA = 0; //这一句如果写了就是在SCL=1时变化了SDA
}
void ack()
{
SCL = 0;
SDA = 1;
delay3us();
SDA = 0; //SDA先清零,让SCL = 1,等最少4us,看SDA数据线是否被接收设备拉低了,拉低表示接收设备应答了
delay3us();//如果不写上面的SDA = 0;万一是SDA = 1,下面SCL = 1,之后等待SDA被接收设备拉低,会出现,SCL=1时SDA拉低了,变成了起始信号了
SCL = 1; //SCL=1,等接收设备拉低SDA表示应答
delay3us();
delay3us();
SCL = 0;//释放总线
delay3us();
delay3us();
SDA = 1;//可写可不写该句,这里必须要写,不然报错,原因不太清楚
}
void noack()
{
SCL = 0;
SDA = 0;
delay3us();
SDA = 1;
delay3us();
SCL = 1;
delay3us();
delay3us();
SCL = 0;//释放总线
delay3us();
delay3us();
// SDA = 0;//可写可不写
}
//字节写入
void write_byte(unsigned char byte)
{
unsigned char tmp_i,tmp_byte;
tmp_byte = byte;
//启动信号发出后,便发出控制字,看start函数里SDA,SCL最后状态下笔
for(tmp_i = 0; tmp_i < 8; tmp_i ++)
{
SCL = 0;//START函数里末尾也是SCL=0,应该可以不用写,但是循环所以建议写
//scl=0 时可以变化SDA数据
tmp_byte <<= 1;//高位先移,移出数据会进入PSW寄存器CY内
// delay3us();
SDA = CY;
delay3us();
SCL = 1;//数据停止变化,并保持一段时间
delay3us();
delay3us();
}
SCL = 0;//释放总线
delay3us();
}
//字节读取
unsigned char read_byte()
{
unsigned char i,byte;
for(i = 0; i < 8; i ++)
{
SCL = 0; //应答之后读取数据,看ack内部最后SDA,SCL状态
byte <<= 1;//高位先移出,高位就先移入。ack函数内部,SCL是低电平的,这里循环所以再写一下
// delay3us();
byte |= SDA; //scl = 0从SDA获取数据,这里处理可能需要延时,防止时间太短
delay3us();
SCL = 1; //数据停止变化,并保持一段时间
delay3us();
delay3us();
// byte |= SDA; //SCL为高并延时了至少4.7us,SDA稳定了,再处理数据亦可
}
SCL = 0;//释放总线
delay3us();
return byte;
}
//unsigned char read_byte()
//{
// unsigned char i,byte;
// for(i = 0; i < 8; i ++)
// {
// SCL = 1; //数据停止变化,并保持一段时间
// delay3us();
// delay3us();
// byte <<= 1;//高位先移出,高位就先移入。ack函数内部,SCL是低电平的,这里循环所以再写一下
// byte |= SDA; //SCL为高并延时了至少4.7us,SDA稳定了,再处理数据亦可
//
// SCL = 0; //应答之后读取数据,看ack内部最后SDA,SCL状态
// delay3us();
//// byte |= SDA; //scl = 0从SDA获取数据,这里处理可能需要延时,防止时间太短
//// delay3us();
//
//
// }
// SCL = 0;//释放总线
//
// delay3us();
// return byte;
//}
//单字节写入数据到指定地址
void write_data(unsigned char add,unsigned char val)
{
start();
write_byte(0xae);
ack();
write_byte(add);
ack();
write_byte(val);
ack();
stop();
}
//单字节读取
unsigned char read_data(unsigned char add)
{
unsigned char val=0;
start();
write_byte(0xae);
ack();
write_byte(add);
ack();
start();
write_byte(0xaf);
ack();
val = read_byte();
noack();
stop();
return val;
}
void main()
{
unsigned char value = 0;
LED = 0;//先打开LED
write_data(0x00,0xfd);
delayms(5);
// while(1);
value = read_data(0x00);
// delayms(5);
while(1)
{
if(value == 0xfd)
{
LED = 0;
}
else
{
LED = 1;
}
}
}