如下疑问 :
关于程序中这个读字节的子函数 uchar read_byte() ,读取EEPROM内数据时,用了 “ k=(k<<1)|sda; ”,然后循环8次,这里是如何得到一个字节数据的,没弄明白。
我理解是k左移之后(不管k初值是什么),低位补0,而sda要么是0000 0000,要么是0000 0001,是固定的,所以进行按位或之后的k要么是0000 0000,要么是0000 0001,这个也是固定的,不管循环多少次,每次得到的k都是0000 0000,或者是0000 0001,怎么就读取到内部的0x55这个数据了呢? 而且实际运行用P1点亮LED也是正确的。
感谢指点!
以下是单片机代码(注释是自己写的,有错误的地方还请不吝指正):
#include <reg52.h>
#include <intrins.h>
sbit scl=P2^1;
sbit sda=P2^0;
typedef unsigned char uchar;
typedef unsigned int uint;
void delayms(uchar z)
{
int x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void delayus()
{
_nop_();_nop_();_nop_();_nop_();_nop_();
}
void start() //开始信号
{
sda=1;
scl=1;
delayus(); //根据时序图,scl和sda都为1的时候要保持4.7us以上。
sda=0; //在scl为高电平的状态下,sda产生下降沿
delayus(); //根据时序图,数据拉低后保持4us以上。
scl=0; //根据时序图,将scl拉低,后面开始字节传输。
delayus();
}
void stop() //停止信号
{
sda=0;
scl=1;
delayus(); //根据时序图,scl和sda分别为1、0的时候要保持4us以上。
sda=1; //在scl为高电平的状态下,sda产生上升沿
delayus(); //根据时序图,数据拉高后保持4.7us以上。
sda=0; //根据时序图,将sda拉低。
delayus();
}
void respons() //应答信号
{
uchar i;
sda=1; //不管之前sda是什么状态,先释放sda
delayus();
scl=1; //将scl拉高,用于sda响应。
delayus();
while((sda==1)&&(i<250)) i++;
scl=0;
delayus();
}
void write_byte(uchar date) //写字节,可以用来写 器件地址 或 内存地址 或 数据。
{
uchar i,temp;
temp=date;
scl=0;
for(i=0;i<8;i++) //总共8位(器件地址是7位+1位读写位,内存地址是8位),所以需要循环8次。
{
temp=temp<<1; //将器件地址进行左移,左移之后会溢出,因为IIC是从MSB开始写,所以要左移。
sda=CY; //每当有数据溢出1,CY都会置1,溢出0,会置0,赋给sda,就得到了本次移出来的地址数据
delayus();
scl=1;
delayus(); //延时,给从机时间读取sda信号。
scl=0; //传输完一位后就将SCL拉低,下一次循环时sda才允许发生变化。
}
scl=0;
delayus();
sda=1;
delayus();
}
uchar read_byte() //字节读取
{
uchar j,k;
scl=0;
delayus();
sda=1;
delayus();
for(j=0;j<8;j++)
{
scl=1;
delayus();
k=(k<<1)|sda; //k的初值不管是什么,左移之后LSB都是0
scl=0;
delayus();
}
return k;
}
void init()
{
sda=1;
scl=1;
delayus();
}
void main() // 主程序思路为先往24C02中写0x55,然后再读出来并且赋值给P1
{
init();
start();
write_byte(0xa0); //寻址,并且下一步为写。
respons(); //从机响应,疑问:respons函数中,没有响应时超时后也会继续,那主机往哪里写?
write_byte(22); //写存储地址,指定后面要往存储器的第22个地址去写数据。24c02总共256个字节地址,所以0~255都可以。
respons();
write_byte(0x55); //往存储器的第22个地址中写入数据0x55
respons();
stop();
delayms(100); //进入24C02的写周期,需>10ms
/*下面一段参考24c02的随机读时序来写,将上面刚刚写进第22个地址的数据读出来赋值给P1*/
start();
write_byte(0xa0); //寻址,并且下一步为写
respons(); //从机响应
write_byte(22); //指定要访问的地址为22
respons();
start(); //由写变为读,所以要重新开始一下
write_byte(0xa1); //寻址,并且下一步为读
respons();
P1=read_byte();
stop();
while(1); //主程序写、读完之后,将读到的数据给P1,然后让程序停在这里。
}
|