IIC_51单片机模拟时序_单字节读写
#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; } } }