登录  | 立即注册

游客您好!登录后享受更多精彩

扫一扫,访问微社区

QQ登录

只需一步,快速开始

开启左侧

[寒假笔记] IIC总线与EEPROM的字节写入/读

[复制链接]
发表于 2019-2-14 20:35:44 | 显示全部楼层 |阅读模式
学习笔记
学习科目: IIC总线与EEPROM的字节写入和(单片机的编程)
学习安排: 充分理解逻辑原理以及读懂时序图。重在实践
开始时间: 2019-02-13
结束时间: 2019-02-14
这几天在医院陪同亲人,学习上稍有些许缓慢了,而且感觉内容也比以前的难了,但是我并没有畏惧艰难,依然要走完这艰难的一步,下面是我的一些笔记。多年以后自己看到亦是美好的回忆。说了一些废话,下面入正题。
我个人认为,学这一部分内容,关键是理解时序图以及其中的逻辑关系,要严格按照步骤进行,每一步骤都要码好代码。

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;
}

以上程序例子很好的说明了应用过程。
好懒~~不想说~~~
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表