普中51单片机AT24C02芯片EPROM数据存储技术详解(十二)

文章目录

  • 引言
  • 什么是EEPROM?
  • EEPROM的特性
  • 芯片概述
  • 芯片及引脚说明
  • 电路图
  • 起始停止信号
  • 应答与非应答
  • 代码演示
  • 引言

    AT24C02是一款由Atmel(现为Microchip Technology公司的一部分)生产的2Kb(256字节)I²C接口EEPROM存储器芯片。它常用于需要非易失性存储的小型嵌入式系统中,比如存储配置信息或校准数据。可用于保存单片机运行时想要永久保存的数据信息。存储介质是E2PROM。

    什么是EEPROM?

    EEPROM(Electrically Erasable Programmable Read-Only Memory,电可擦除可编程只读存储器)是一种非易失性存储器,可以通过电信号擦除和重新编程。

    EEPROM的特性

    数据在断电后依然保存,这使得EEPROM非常适合存储需要长期保存的配置信息、校准数据和其他重要信息。EEPROM可以通过电信号进行擦除和写入,无需物理移除芯片。EEPROM支持字节级别的读写操作,这意味着可以对单个字节进行修改,而无需擦除整个块。EEPROM的读写速度相对较慢,特别是与RAM相比,但足以满足大多数非实时数据存储需求。

    芯片概述

    AT24C02是EEPROM的一种具体实现,它采用了IIC接口进行数据传输。具体而言,AT24C02是EEPROM大家族中的一个成员,具备了EEPROM的基本特性,同时结合了I²C总线接口,方便与微控制器进行通信。它具有以下特点:

  • 存储容量:最大容量2Kb(256字节)
  • 接口类型:IIC通信协议(Inter-Integrated Circuit)
  • 工作电压:1.8V至5.5V
  • 工作温度范围:-40°C至+85°C
  • 封装类型:常见封装包括8引脚的PDIP、SOIC、TSSOP等
  • 注意:有关IIC通信协议,可查看此博客内容讲解:IIC总线原理特性解析及通信要点

    芯片及引脚说明

    AT24C02通常采用8引脚的封装形式,如PDIP、SOIC、TSSOP等。每个引脚都有其特定的功能,具体引脚配置如下:

    各引脚功能详解

  • 地址引脚0(A0, 引脚1):用于设置I²C设备地址的一部分。通过连接到Vcc或GND,可以设置不同的设备地址。A0引脚的电平值决定了地址的最低位(A0位)。
  • 地址引脚1(A1, 引脚2):用于设置I²C设备地址的一部分。通过连接到Vcc或GND,可以设置不同的设备地址。A1引脚的电平值决定了地址的次低位(A1位)。
  • 地址引脚2(A2, 引脚3):用于设置I²C设备地址的一部分。通过连接到Vcc或GND,可以设置不同的设备地址。A2引脚的电平值决定了地址的次高位(A2位)。
  • GND(引脚4):电源地连接,提供芯片的基准电压,是整个电路的参考点。
  • SDA(引脚5):串行数据线,用于IIC总线上的双向数据传输。通过这条线,主设备和从设备之间可以进行数据交换。
  • SCL(引脚6):串行时钟线,提供IIC总线上的时钟信号,用于同步数据传输。主设备生成时钟信号,控制通信的节奏。
  • WP(引脚7):写保护引脚,控制EEPROM的写保护状态。当WP引脚接高电平时,EEPROM进入写保护模式,禁止写操作;当WP引脚接低电平时,允许写操作。
  • 0 Vcc(引脚8):电源引脚,连接到电源正极,提供工作电压给芯片,工作电压范围为1.8V至5.5V。

  • 高四位是固定的,为1010,低四位是可编程的,最后一位用于设置数据传输方向。在前面提到的IIC总线原理特性解析及通信要点有详细讲解。

    电路图

    下图是普中A7开发板EEPROM模块电路图,采用STC89C51RC/RD+系列,SCL连接P2_1引脚,SDA连接P2_0引脚。(从图中可以看出,这两条线上带有上拉电阻),操作方式可以采用IIC时序,IIC总线原理特性解析及通信要点有详细讲解。这里不过多说明。

    起始停止信号

    根据IIC总线通信时序,进行编写代码,下图则是对应时序图:

    //起始信号
    void iic_start()
    {
    	IIC_SCL = 1;
    	IIC_SDA = 1;
    	DelayXms(1);
    	IIC_SDA = 0;
    	DelayXms(1);
    	IIC_SCL = 0;//开始占用总线
    }
    
    //停止信号
    void iic_stop()
    {
    	IIC_SCL = 1;
    	IIC_SDA = 0;
    	DelayXms(1);
    	IIC_SDA = 1;
    }
    

    应答与非应答

    时钟线SCL为低电平期间,SDA数据允许发生更改。SDA低电平表示应答信号,高电平表示非应答信号。下方为对应时序图:

    //应答信号
    void iic_ack()
    {
    	IIC_SCL = 0;
    	IIC_SDA = 0;
    	DelayXms(1);
    	IIC_SCL = 1;
    	DelayXms(1);
    	IIC_SCL = 0;
    }
    
    //非应答信号
    void iic_nack()
    {
    	IIC_SCL = 0;
    	IIC_SDA = 1;
    	DelayXms(1);
    	IIC_SCL = 1;
    	DelayXms(1);
    	IIC_SCL = 0;
    }
    

    代码演示

    系统运行时,数码管右3位显示0,按K1键将数据写入到EEPROM内保存,按K2键读取EEPROM内保存的数据,按K3键显示数据加1,按K4键显示数据清零。

    #include <REGX52.H>
    #include <INTRINS.H>
    #define EEPROM_ADDRESS 0
    
    sbit KEY1 = P3^0;
    sbit KEY2 = P3^1;
    sbit KEY3 = P3^2;
    sbit KEY4 = P3^3;
    
    sbit IIC_SCL = P0^0;
    sbit IIC_SDA = P0^1;
    
    
    sbit LED1 = P2^0;
    sbit LED2 = P2^1;
    
    //共阴极数码管显示 0~F 的段码数据
    unsigned char gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
    0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
    
    void DelayXms(unsigned int xms)	//@12.000MHz
    {
    	unsigned char data i, j;
    	
    	while(xms)
    	{
    		i = 2;
    		j = 239;
    		do
    		{
    			while (--j);
    		} while (--i);
    		xms--;
    	}
    }
    
    unsigned char Scan_keys()
    {
    	if(KEY1 == 0 || KEY2 == 0 || KEY3 == 0 || KEY4 == 0)
    	{
    		DelayXms(100);//消抖处理
    		if(KEY1 == 0)
    			return 1;
    		else if(KEY2 == 0)
    			return 2;
    		else if(KEY3 == 0)
    			return 3;
    		else if(KEY4 == 0)
    			return 4;
    	}
    	return 0;
    }
    
    void Init_Port_Smg(unsigned char Location,unsigned char dat[])
    {
    	unsigned char i = 0;
    	unsigned char local = Location - 1;
    	for(i = Location;i < 8;i++)
    	{
    		switch(i+1)
    		{
    			case 1:
    				P2_2 = 0;P2_3 = 0;P2_4 = 0;
    				break;
    			case 2:
    				P2_2 = 1;P2_3 = 0;P2_4 = 0;
    				break;
    			case 3:
    				P2_2 = 0;P2_3 = 1;P2_4 = 0;
    				break;
    			case 4:
    				P2_2 = 1;P2_3 = 1;P2_4 = 0;
    				break;
    			case 5:
    				P2_2 = 0;P2_3 = 0;P2_4 = 1;
    				break;
    			case 6:
    				P2_2 = 1;P2_3 = 0;P2_4 = 1;
    				break;
    			case 7:
    				P2_2 = 0;P2_3 = 1;P2_4 = 1;
    				break;
    			case 8:
    				P2_2 = 1;P2_3 = 1;P2_4 = 1;
    				break;
    		}
    		P1 = gsmg_code[dat[i-Location]];
    		DelayXms(1);
    		P1 = 0x00;//消影	
    	}	
    
    }
    
    //起始信号
    void iic_start()
    {
    	IIC_SCL = 1;
    	IIC_SDA = 1;
    	_nop_();
    	IIC_SDA = 0;
    	_nop_();
    	IIC_SCL = 0;//开始占用总线
    }
    
    //停止信号
    void iic_stop()
    {
    	IIC_SCL = 1;
    	IIC_SDA = 0;
    	_nop_();
    	IIC_SDA = 1;
    }
    
    //应答信号
    void iic_ack()
    {
    	IIC_SCL = 0;
    	IIC_SDA = 0;
    	_nop_();
    	IIC_SCL = 1;
    	_nop_();
    	IIC_SCL = 0;
    }
    
    //非应答信号
    void iic_nack()
    {
    	IIC_SCL = 0;
    	IIC_SDA = 1;
    	_nop_();
    	IIC_SCL = 1;
    	_nop_();
    	IIC_SCL = 0;
    }
    
    unsigned char iic_wait_ack()
    {
    	unsigned char time = 0;
    	IIC_SCL = 1;
    	_nop_();
    	while(IIC_SDA)
    	{
    		time++;
    		if(time>100)
    		{
    			iic_stop();
    			return 1;
    		}
    	}
    	IIC_SCL = 0;
    	return 0;
    }
    
    void iic_write_byte(unsigned char dat)
    {
    	unsigned char i = 0;
    	IIC_SCL = 0;//数据可以发生变化
    	for(i = 0;i< 8;i++)
    	{
    		if((dat&0X80)>0)//先发送高位
    		{
    			IIC_SDA = 1;
    		}
    		else
    		{
    			IIC_SDA = 0;
    		}
    		dat<<=1;
    		IIC_SCL = 1;//数据发送
    		_nop_();
    		IIC_SCL = 0;
    		_nop_();
    	}
    }
    
    unsigned char iic_read_byte(unsigned char ack)
    {
    	unsigned char i = 0;
    	unsigned char res = 0;
    	for(i = 0;i < 8;i++)
    	{
    		IIC_SCL = 0;
    		_nop_();
    		IIC_SCL = 1;//数据发送
    		_nop_();
    		res<<=1;
    		if(IIC_SDA)
    		{
    			res++;	
    		}
    	}
    	if(!ack)//nack
    		iic_nack();
    	else
    		iic_ack();
    	return res;
    }
    
    
    void at24c02_write_byte(unsigned char dat,unsigned char addr)
    {
    	iic_start();//发送起始信号 A0写 A1读
    	iic_write_byte(0xa0);
    	iic_wait_ack();//等待从机的ack
    	iic_write_byte(addr);//发送要写的设备地址
    	iic_wait_ack();//等待从机的ack
    	iic_write_byte(dat);//发送数据
    	iic_wait_ack();//等待从机的ack
    	iic_stop();//停止
    	_nop_();
    }
    
    unsigned char at24c02_read_byte(unsigned char addr)
    {
    	unsigned char temp = 0;
    	iic_start();//发送起始信号 A0写 A1读
    	iic_write_byte(0xa0);
    	iic_wait_ack();//等待从机的ack
    	iic_write_byte(addr);//发送要写的设备地址
    	iic_wait_ack();//等待从机的ack
    	iic_start();//发送起始信号 A0写 A1读
    	iic_write_byte(0xa1);//发送数据
    	iic_wait_ack();//等待从机的ack
    	temp = iic_read_byte(0);
    	iic_stop();//停止
    	return temp;
    }
    
    void main()
    {
    	unsigned char keynum = 0;
    	unsigned char i = 0;
    	unsigned char sava_value = 0;
    	unsigned char save_buf[3];
    	while(1)
    	{
    
    		keynum = Scan_keys();
    		if(keynum == 1)
    		{
    			at24c02_write_byte(sava_value,EEPROM_ADDRESS);	
    		}
    		else if(keynum == 2)
    		{
    			sava_value = at24c02_read_byte(EEPROM_ADDRESS);
    		}
    		else if(keynum == 3)
    		{
    			sava_value++;
    			if(sava_value >= 255)//最大值
    			{
    				sava_value = 255;
    			}
    		}
    		else if(keynum == 4)
    		{
    			sava_value = 0;
    		}
    		save_buf[0] = sava_value/100;//百位
    		save_buf[1] = sava_value%100/10;//十位
    		save_buf[2] = sava_value%100%10;//个位
    
    		Init_Port_Smg(5,save_buf);
    	}
    }
    

    作者:墨辰JC

    物联沃分享整理
    物联沃-IOTWORD物联网 » 普中51单片机AT24C02芯片EPROM数据存储技术详解(十二)

    发表回复