这几天在医院陪同亲人,学习上稍有些许缓慢了,而且感觉内容也比以前的难了,但是我并没有畏惧艰难,依然要走完这艰难的一步,下面是我的一些笔记。多年以后自己看到亦是美好的回忆。说了一些废话,下面入正题。
我个人认为,学这一部分内容,关键是理解时序图以及其中的逻辑关系,要严格按照步骤进行,每一步骤都要码好代码。
EEPROM字节写数据流程:
1.首先是IIC的起始信号,接着跟上首字节,也就是IIC的器件地址,并且在读写方向上选择“写”操作。(电器开发部的为0XA2)
2.发送数据的存储地址。24C02一共256个字节的存储地址,地址为:0x00~0xFF。想把数据存储在哪个位置,就写出那个地址就行了。
3.发送要存储的数据的字节,若写入成功,则EEPROM的每个字节都会回应一个应答位“0”,反之则不。
EEPROM字节读数据流程:
1.首先是IIC的起始信号,接着跟上首字节,也就是IIC的器件地址,并且在读写方向上选择“写”操作。(电器开发部的为0XA2),这里有一点要注意,刚开始我也不太理解,读数据方向也要选“写”,实际上,这个写只是把所要读的数据的存储地址先写进去,告诉EEPEOM要读取那个地址的数据。就相当于打电话拔打了主机的号码。
2.发送要读取数据的//地址//。
3.重新发送IIC起始信号和器件地址,并且在方向位上选“读”操作。
4.读取从器件发回的数据,读完一个字节后,若还想继续往下读,则发送应答位ACK(0),反之则发送NAK(1)。
下面是一段例程:
#include <reg52.h>
extern void InitLcd1602();
extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
extern void I2CStart();
extern void I2CStop();
extern unsigned char I2CReadNAK();
extern bit I2CWrite(unsigned char dat);
unsigned char E2ReadByte(unsigned char addr);
void E2WriteByte(unsigned char addr, unsigned char dat);
void main()
{
unsigned char dat;
unsigned char str[10];
InitLcd1602(); //初始化液晶
dat = E2ReadByte(0x02); //读取指定地址上的一个字节
str[0] = (dat/100) + '0'; //转换为十进制字符串格式
str[1] = (dat/10%10) + '0';
str[2] = (dat%10) + '0';
str[3] = '\0';
LcdShowStr(0, 0, str); //显示在液晶上
dat++; //将其数值+1
E2WriteByte(0x02, dat); //再写回到对应的地址上
while (1);
}
unsigned char E2ReadByte(unsigned char addr)
{
unsigned char dat;
I2CStart();
I2CWrite(0x50<<1);
I2CWrite(addr);
I2CStart();
I2CWrite((0x50<<1) |0x01);
dat = I2CReadNAK();
I2CStop();
return dat;
}
void E2WriteByte(unsigned char addr, unsigned char dat)
{
I2CStart();
I2CWrite(0x50<<1);
I2CWrite(addr);
I2CWrite(dat);
I2CStop();
}
#include <reg52.h>
#include <intrins.h>
#define I2CDelay() {_nop_();_nop_();_nop_();_nop_();}
sbit I2C_SCL = P3^7;
sbit I2C_SDA = P3^6;
/* 产生总线起始信号 */
void I2CStart()
{
I2C_SDA = 1; //首先确保SDA、SCL都是高电平
I2C_SCL = 1;
I2CDelay();
I2C_SDA = 0; //先拉低SDA
I2CDelay();
I2C_SCL = 0; //再拉低SCL
}
/* 产生总线停止信号 */
void I2CStop()
{
I2C_SCL = 0; //首先确保SDA、SCL都是低电平
I2C_SDA = 0;
I2CDelay();
I2C_SCL = 1; //先拉高SCL
I2CDelay();
I2C_SDA = 1; //再拉高SDA
I2CDelay();
}
/* I2C总线写操作,dat-待写入字节,返回值-从机应答位的值 */
bit I2CWrite(unsigned char dat)
{
bit ack; //用于暂存应答位的值
unsigned char mask; //用于探测字节内某一位值的掩码变量
for (mask=0x80; mask!=0; mask>>=1) //从高位到低位依次进行
{
if ((mask&dat) == 0) //该位的值输出到SDA上
I2C_SDA = 0;
else
I2C_SDA = 1;
I2CDelay();
I2C_SCL = 1; //拉高SCL
I2CDelay();
I2C_SCL = 0; //再拉低SCL,完成一个位周期
}
I2C_SDA = 1; //8位数据发送完后,主机释放SDA,以检测从机应答
I2CDelay();
I2C_SCL = 1; //拉高SCL
ack = I2C_SDA; //读取此时的SDA值,即为从机的应答值
I2CDelay();
I2C_SCL = 0; //再拉低SCL完成应答位,并保持住总线
return (~ack); //应答值取反以符合通常的逻辑:
//0=不存在或忙或写入失败,1=存在且空闲或写入成功
}
unsigned char I2CReadNAK()
{
unsigned char mask;
unsigned char dat;
I2C_SDA = 1;
for(mask=0x80; mask!=0; mask>>=1)
{
I2CDelay();
I2C_SCL = 1;
if(I2C_SDA == 0)
dat &= ~mask;
else
dat |= mask;
I2CDelay();
I2C_SCL = 0;
}
I2C_SDA = 1;
I2CDelay();
I2C_SCL = 1;
I2CDelay();
I2C_SCL = 0;
return dat;
}
unsigned char I2CReadACK()
{
unsigned char mask;
unsigned char dat;
I2C_SDA = 1;
for(mask=0x80; mask!=0; mask>>=1)
{
I2CDelay();
I2C_SCL = 1;
if(I2C_SDA == 0)
dat &= ~mask;
else
dat |= mask;
I2CDelay();
I2C_SCL = 0;
}
I2C_SDA = 0;
I2CDelay();
I2C_SCL = 1;
I2CDelay();
I2C_SCL = 0;
return dat;
}
以上程序例子很好的说明了应用过程。
|