MSP430平台下实现AT24C02的读写操作

来源:互联网 发布:网络通信有哪些方式 编辑:程序博客网 时间:2024/06/05 17:26

EEPROM可以随机访问和修改其中的任何一个字节,可以往每个bit中写入0或者1,掉电后数据不丢失,可以保存100年,可以擦写100w次。具有较高的可靠性,但是电路复杂/成本也高。因此目前的EEPROM都是几十千字节到几百千字节的,绝少有超过512K的,常用来保存用户数据,运行过程中可以改变。

下面在MSP430平台下以AT24C02为例说明该类可擦除ROM的使用。AT24C02的存储容量为2K bits,内容分成32页,每页8 bytes,共256 bytes

AT24C02对外以I2C总线形式传输数据,外观如下图所示:

 430平台下实现AT24C02的读写操作

A0A1A2三个引脚作寻址用;SDASCLI2C总线的数据与时钟引脚;WP作写保护用,即WP在保持高电平时,MCUAT24C02 的读写操作无效;VCCGND分别接电源和接地。

MCU在挂载多片AT24C02时,其器件地址由8位构成,除A0A1A2三位外,其他位都被锁定为如下所示:

说明: C:\Users\38\AppData\Local\Temp\1509088227(1).png

最低位为R/W,进行读操作时,该位 = 1,写操作时,该位 = 0。地址写入正确时,AT24C02将会应答以”0”

AT24C02的读写遵循I2C总线的相关规范,所以有传输的开始条件和停止条件。每一次正常的读写均以开始条件开始,停止条件结束,这两者的时序如下图所示:

说明: C:\Users\38\AppData\Local\Temp\1509087542(1).png

其软件模拟的实现为:

void start(void){      SCL_H;      SDA_H;      _NOP();      SDA_L;      _NOP();      SCL_L;      _NOP();}void stop(void){      SDA_L;      _NOP();      SCL_H;      _NOP();      SDA_H;      _NOP();   }



SCL_HSDA_HSDA_LSCL_L均为宏定义,分别表示MCUAT24C02相应引脚输出高电平和低电平。

AT24C02的写操作分两种模式,分别为字节写入和页写入两种。

1、字节写入

该写操作需要以MCU写入开始条件开始,继以器件地址,收到AT24C02的应答后继续写入要进行写操作的字地址(即要将数据写入该AT24C02的什么位置),收到应答后才正式写入一个字节的数据,收到应答后写入停止条件,一个完整的字节写入才算完成。

说明: C:\Users\38\AppData\Local\Temp\1509089110(1).png

其软件模拟的实现为:

uchar Write_1Byte(uchar wdata,uchar dataaddress){     start();     write1byte(deviceaddress);     if(check())        write1byte(dataaddress);     else        return 0;     if(check())        write1byte(wdata);     else        return 0;     if(check())         stop();     else            return 0;  delay_10ms();       //等待EEPROM完成内部写入     return 1;}


delay_10ms()是因为AT24C02的每两次写操作之间存在一个写入时间周期tWR,其最大值为5 mscheck()检查AT24C02的应答操作,收到AT24C02回复的0,则应答正确,其软件模拟实现为:

uchar check(void){      uchar slaveack;      SDA_H;      _NOP(); _NOP();      SCL_H;      _NOP(); _NOP();   SDA_in;   _NOP(); _NOP();      slaveack = SDA_val;   //读入SDA数值      SCL_L;      _NOP();    SDA_out;    if(slaveack)    return FALSE;    else          return TRUE;}


SDA_inSDA_out分别表示MCU(MSP430)连接AT24C02I/O引脚方向改为输入或输出,此处SDA_in的作用是为MCU接收AT24C02的应答信号做准备,接收完成后改回SDA_outSDA_val = P2IN&BIT5P2.5连接AT24C02SDA引脚,接收应答信号。

write1byte()I2C总线写一个字节的数据,其软件模拟实现为:

void write1byte(uchar wdata){    uchar i;    for(i = 8;i > 0;i--)    {           if(wdata & 0x80)     write1();           else                         write0();           wdata <<= 1;    }                      SDA_H;    _NOP();  }


write1()I2C总线写一位“1”的数据,其软件模拟实现为:

void write1(void){      SDA_H;      _NOP();      SCL_H;      _NOP();      SCL_L;                              _NOP();}


write0()I2C总线写一位“0”的数据,其软件模拟实现为:

void write0(void){      SDA_L;      _NOP();      SCL_H;      _NOP();                    SCL_L;                              _NOP();}


2、页写入

AT24C02可以实现8位的页写入操作。页写入的形式大体和字节写入类似,只是在MCU写入第一个字节的数据后将会继续写入第二个数据,而不会像字节写入一样写入停止条件。如果写入AT24C02的数据超过8位,超过的数据将会覆盖已被写入的部分。

说明: C:\Users\38\AppData\Local\Temp\1509090891(1).png

其软件模拟的实现为:

uchar Write_NByte(uchar * outbuf,uchar n,uint dataaddress){     uchar  flag,dataaddressl,dataaddressh;        dataaddressl = dataaddress;        dataaddressh = dataaddress>>8;        start();     write1byte(deviceaddress);                  //写入器件地址     if(check() == 1)        write1byte(dataaddressh);                //写入数据字地址     else        return 0;   if(check())        write1byte(dataaddressl);   else        return 0;     if(check())        flag=writeNbyte(outbuf,n);     else       return 0;       delay_10ms();       //等待EEPROM完成内部写入            if(flag)          return 1;     else              return 0;}


writeNbyte()I2C总线写N个字节(对于AT24C02N = 8)的数据,其软件模拟实现为:

uchar writeNbyte(uchar * outbuffer,uchar n){     uchar i;     for(i = 0;i < n;i++)     {            write1byte(* outbuffer);            if(check())                 {                   outbuffer++;                          }            else            {                   stop();                   return FALSE;            }     }     stop();     return TRUE;                    }


AT24C02的读操作分三种模式,分别为当前地址读取、随机读取和顺序读取。

1、当前地址读取

上一次读写操作完成后,数据地址计数器加1,并停留在当前位置。这一位置只要不掉电就会一直有效。当R/W = 1时,就可以将当前地址位置的数据读出。

说明: C:\Users\38\AppData\Local\Temp\1509092086(1).png

其软件模拟的实现为:

uchar Read_1Byte_currentaddress(void){     uchar temp;     start();     write1byte((deviceaddress|0x01));     if(check())            temp = read1byte();     else        return 0;     mnack();     stop();     return temp;}uchar Read_NByte_currentaddress(uchar * readbuf,uchar n){      start();     write1byte((deviceaddress|0x01));     if(check())        readNbyte(readbuf,n);     else        return 0;        return  1;}


read1byte()I2C总线读取一个字节,其软件模拟的实现为:

uchar read1byte(void){     uchar  rdata = 0x00,i;   uchar flag;     for(i = 0;i < 8;i++)     {            SDA_H;            _NOP();            SCL_H;        SDA_in;            _NOP();            flag = SDA_val;            rdata <<= 1;            if(flag)   rdata |= 0x01;        SDA_out;            SCL_L;            _NOP();     }     return rdata;}


readNbyte()I2C总线读取一个字节,其软件模拟的实现为:

void readNbyte(uchar * inbuffer,uchar n){     uchar i;        for(i = 0;i < n;i++)     {            inbuffer[i] = read1byte();            if(i < (n-1))    mack();            else            mnack();     }           stop();}


mack()完成I2CMCU应答操作,其软件模拟的实现为:

void mack(void){     SDA_L;     _NOP(); _NOP();     SCL_H;     _NOP();     SCL_L;     _NOP();_NOP();     SDA_H;         _NOP(); }


mnack()完成I2CMCU无应答操作,其软件模拟的实现为:

void mnack(void){     SDA_H;     _NOP(); _NOP();     SCL_H;     _NOP();     SCL_L;     _NOP(); _NOP();     SDA_L;       _NOP();      }


2、随机读取

AT24C02的指定地址读取1个字节的数据。随机读取的操作先发送一个写操作来骗过AT24C02器件,使其内部的数据地址值修改,但是发送完毕数据地址后并不发送数据,而是发送一个开始信号,此时AT24C02中的数据地址值已经被修改了,然后通过“当前地址读取”去读取此地址上的数据。如下图所示:

说明: C:\Users\38\AppData\Local\Temp\1509093395(1).png

其软件模拟的实现为:

uchar Read_1Byte_Randomaddress(unsigned int dataaddress){     uchar temp,dataaddressh,dataaddressl;        dataaddressl = dataaddress;        dataaddressh = dataaddress>>8;        start();     write1byte(deviceaddress);     if(check())            write1byte(dataaddressh);     else        return 0;        if(check())              write1byte(dataaddressl);     else        return 0;     if(check())     {            start();            write1byte((deviceaddress|0x01));     }     else           return 0;     if(check())            temp = read1byte();     else        return 0;     mnack();     stop();     return temp;}uchar Read_NByte_Randomaddress(uchar * readbuf,uchar n,uchar dataaddress){     start();     write1byte(deviceaddress);     if(check())            write1byte(dataaddress);     else        return 0;     if(check())     {            start();            write1byte(deviceaddress|0x01);     }     else        return 0;     if(check())        readNbyte(readbuf,n);     else        return 0;     return 1;      }


read1byte()I2C总线读取一个字节,其软件模拟的实现为:

uchar read1byte(void){     uchar  rdata = 0x00,i;   uchar flag;     for(i = 0;i < 8;i++)     {            SDA_H;            _NOP();            SCL_H;      SDA_in;            _NOP();            flag = SDA_val;            rdata <<= 1;            if(flag)   rdata |= 0x01;      SDA_out;            SCL_L;            _NOP();     }     return rdata;}


readNbyte()I2C总线读取N个字节,其软件模拟的实现为:

void readNbyte(uchar * inbuffer,uchar n){     uchar i;     for(i = 0;i < n;i++)     {            inbuffer[i] = read1byte();            if(i < (n-1))         mack();            else            mnack();     }     stop();}


2、顺序读取

 

顺序读取的中的第一个字节既可以以“当前位置读取”实现,也可以以“随机读取”实现,只要读取完毕后MCUAT24C02回复应答信号而不发送停止条件,读取操作一直持续下去。当然,每一次读取都会使数据地址计数器加1。当读到计数器的边界时,数据地址值就会翻转到最开始的位置继续读取下去,直到AT24C02收到MCU发送的停止条件。

430平台下实现AT24C02的读写操作