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

个人博客:http://brainware360.cn/



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

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

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

 MSP430平台下实现AT24C02的读写操作_第1张图片

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总线的相关规范,所以有传输的开始条件和停止条件。每一次正常的读写均以开始条件开始,停止条件结束,这两者的时序如下图所示:

MSP430平台下实现AT24C02的读写操作_第2张图片

其软件模拟的实现为:

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的什么位置),收到应答后才正式写入一个字节的数据,收到应答后写入停止条件,一个完整的字节写入才算完成。

MSP430平台下实现AT24C02的读写操作_第3张图片

其软件模拟的实现为:

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位,超过的数据将会覆盖已被写入的部分。

MSP430平台下实现AT24C02的读写操作_第4张图片

其软件模拟的实现为:

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时,就可以将当前地址位置的数据读出。

MSP430平台下实现AT24C02的读写操作_第5张图片

其软件模拟的实现为:

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中的数据地址值已经被修改了,然后通过“当前地址读取”去读取此地址上的数据。如下图所示:

MSP430平台下实现AT24C02的读写操作_第6张图片

其软件模拟的实现为:

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发送的停止条件。

MSP430平台下实现AT24C02的读写操作_第7张图片




你可能感兴趣的:(MSP430,AT24C02,EEPROM)