问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

蓝桥杯51单片机-AT24C02模块(EEPROM)的应用

创作时间:
作者:
@小白创作中心

蓝桥杯51单片机-AT24C02模块(EEPROM)的应用

引用
CSDN
1.
https://blog.csdn.net/m0_64167498/article/details/136607682

本文主要介绍了AT24C02 EEPROM模块在蓝桥杯51单片机中的应用。文章详细描述了AT24C02的引脚定义、存储组织、以及通过I2C总线进行读写操作的具体流程,并提供了相应的代码示例。此外,文章还分享了在实现特定功能(如数码管显示、按键控制等)过程中遇到的问题及解决方案。

基本功能:定义一个变量,范围在0-99, 在数码管上显示出来,S7是加1,S6是减1,将变量存储在EEPROM里,在平台断电后能回到上一次改变的值。


以上为我们需要用到的模块

我们先来了解一下EEPROM

AT24C02是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想要永久保存的数据信息

存储介质:E2PROM

通讯接口:I2C总线

容量:256字节

引脚定义:

A0-A2是在I2C总线协议中识别AT24C02的器件地址,高4位是生产厂家规定器件地址为1010(不可更改),而A0-A2器件地址有三位,也就是说在I2C总线系统中,最多识别到8个AT24C02

串行时钟信号引脚
(SCL):在 SCL 输入时钟信号的上升沿将数据送入 EEPROM 器件,并在时钟的下降沿将数据读出。

串行数据输入/输出引脚
(SDA):SDA 引脚可实现双向串行数据传输。该引脚为开漏输出,可与其它多个开漏输出器件或开集电极器件线或连接。

写保护引脚
(WP):具有用于硬件数据写保护功能的引脚。当该引脚接 GND 时,允许正常的读/写操作。当该引脚接 VCC 时,芯片启动写保护功能。WP写保护如果使能,那么我们在写入数据的时候就会进行某些特定操作。

存储组织:

AT24C02, 2K SERIAL EEPROM:

内部组织32页,每个8字节2K需要8位数据字地址用于随机字寻址也就是说有32页,每一页8Byte,每1Byte是8位,总共就是3288=2048Byte=2Kbit的存储空间

1K/2K指的是1K/2K的存储器的寄存器地址

编写代码:

【1】24C02功能概述

24C02是一个2K Bit的串行EEPROM存储器,内部含有256个字节。在24C02里面有一个8字节的页写缓冲器。该设备的工作电压为1.8V到6.0V,芯片的第7引脚WP为写保护引脚,将该引脚接地允许正常的读写。

【2】设备地址

24C02的设备地址包括固定部分和可编程部分。可编程部分需要根据硬件引脚A0、A1和A2来设置。设备地址的最后一位用于设置数据传输的方向,即读/写位。格式如下图:

在IIC总线协议中,设备地址是起始信号后第一个发送的字节。如果硬件地址引脚A0、A1、A2均接地,那么,24C02的设备的读操作地址为:0xA1;而写操作地址则为:0xA0。

【3】读写操作中的应答信号

在写操作中,24C02每接收一个8位字节后会产生一个应答信号。在读操作中,24C02在发送一个8位数据后会释放SDA线并监视应答信号。一旦收到应答信号,将继续发送数据。如果主机没有发送应答信号,从机则停止发送数据且等待一个停止信号。

【4】字节写操作

24C02接收完设备地址后,产生应答信号;然后接收8位内存字节地址,产生应答信号,接着接收一个8位数据,产生应答信号;最后主机发送停止信号,字节写操作结束。

【5】页写操作

24C02有一个8字节的页写缓冲器,也就是说可以一次连续写入8个字节到缓冲器,然后由缓冲器一次性写到EEPROM。页写操作初始化与字节写操作相同,只是主机不会在写完第一个数据后就发送停止信号,而是在24C02应答后,接着发送7个数据。

需要注意的是,24C02接收到每个数据后,其字节地址的低3位会自动加1,高位地址不变,维持在当前页内。当内部产生的字节地址到达该页边界时,随后的数据将写入该页的页首,先前的写入的数据将会被覆盖。

【6】当前地址读操作

24C02内部的地址寄存器会保存着上次读/写操作最后一个地址加1的值。只要芯片有电,该地址就一直保存着。如果上次读/写操作的地址为N,那么当前地址读操作就从N+1开始。当读到最后一个字节(即255处),地址会回转到0。

【7】字节读操作

主机首先发送起始信号,接着发送设备地址和它想要读取的数据内存字节地址,执行一个伪写操作。在24C02应答主机之后,主机重新发送起始信号和从设备地址,进行读操作。24C02响应并发送应答信号,然后输出所要求的一个8位字节数据。主机接收完这个8位数据后,产生一个“非应答”信号,最后发送停止条件,字节读操作结束。

【8】连续读操作

在24C02发送完一个8位字节数据之后,主机产生一个应答信号来响应,告知24C02要求读取更多的数据,直到读完最后一个数据,主机向24C02发送一个“非应答”信号,然后发送一个停止信号,结束此操作。

【9】基本读写操作流程

24C02的字节写操作,参考代码:


void Write_24C02(unsigned char addr, unsigned char dat)  
{  
    IIC_Start();		//IIC总线起始信号					
    IIC_SendByte(0xa0); 	//24C02的写设备地址
    IIC_WaitAck();		//等待从机应答	
    IIC_SendByte(addr); 	//内存字节字节
    IIC_WaitAck(); 		//等待从机应答	
    IIC_SendByte(dat); 	//写入目标数据
    IIC_WaitAck();		//等待从机应答	
    IIC_Stop();		//IIC总线停止信号		
}  

24C02的字节读操作,参考代码:


unsigned char Read_24C02(unsigned char addr)  
{  
    unsigned char tmp;  
    //进行一个伪写操作
    IIC_Start();		//IIC总线起始信号					
    IIC_SendByte(0xa0); 	//24C02写设备地址
    IIC_WaitAck();		//等待从机应答	
    IIC_SendByte(addr); 	//内存自己地址
    IIC_WaitAck(); 		//等待从机应答	
    //进行字节读操作
    IIC_Start();		//IIC总线起始信号					
    IIC_SendByte(0xa1); 	//24C02读设备地址
    IIC_WaitAck();		//等待从机应答	
    tmp = IIC_RecByte();	//读取目标数据
    IIC_Ack(0); 		//产生非应答信号		
    IIC_Stop();		//IIC总线停止信号			
    return tmp;
}  

实现基本功能我遇到的bug

1.数码管出现鬼影

解决方法

void ShowSMG_Bit(unsigned char dat, unsigned pos)
{
P0=0xff;//加入0xff消隐
InitHC138(6); //数码管的位置
P0 = 0x01 << pos;
InitHC138(7); //数码管的内容
P0 = dat;
}

2.一直按住按键数码管只能显示一位

解决方法

while(S7 == 0)Display_Dynamic();

3.无法关闭蜂鸣器和继电器

解决方法

void InitSystem()
{
InitHC138(5);
P0=0X00;
InitHC138(4);
P0=0XFF;
InitHC138(0);
}

4.没有分清EEPROM的读和写要用到的地方,上电才需要读,按下按键才需要写

5.加入iic.h头文件报错。。。重定义

解决方法:需要保持iic.c和main.c的头文件“re52.h”一样,不能一个“STC15F2K61S2.H”一个“reg51.h”

以下是实现基本功能的代码


#include "regx52.h"
#include "iic.h"
#define uchar unsigned char
sbit S7 = P3^0;
sbit S6 = P3^1;
sbit S5 = P3^2;
void Display_Dynamic(void);
void Read_Write(void);
void Write_24C02(unsigned char addr, unsigned char dat);
char num=10;
unsigned char code SMG_duanma[18]=
        {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
     0x80,0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e,
     0xbf,0x7f};
 
void InitHC138(unsigned char n)
{
    switch(n)
    {
        case 4:
            P2 = (P2 & 0x1f) | 0x80;
        break;
        case 5:
            P2 = (P2 & 0x1f) | 0xa0;
        break;
        case 6:
            P2 = (P2 & 0x1f) | 0xc0;
        break;
        case 7:
            P2 = (P2 & 0x1f) | 0xe0;
        break;
        case 0:
            P2 = (P2 & 0x1f) | 0x00;		//所有锁存器不选择
        break;
    }
}
 
void ShowSMG_Bit(unsigned char dat, unsigned pos)
{
    P0=0xff;
    InitHC138(6);			//数码管的位置
    P0 = 0x01 << pos;
    InitHC138(7);			//数码管的内容
    P0 = dat;
}
void DelaySMG(unsigned char t)
{
    while(t--);
}
void ScanKeys_Alone()
{
    if(S7 == 0)
    {
        DelaySMG(100);
        if(S7 == 0)
        {
            num+=10;
            if(num>=90)num=90;
            while(S7 == 0)Display_Dynamic();
        }
    }
    if(S6 == 0)
    {
        DelaySMG(100);
        if(S6 == 0)
        {
            num-=10;
            if(num<=0)num=0;
            while(S6 == 0)Display_Dynamic();
        }
    }
    if(S5 == 0)
    {
        DelaySMG(100);
        if(S5 == 0)
        {
            Write_24C02(0x01, num);
            while(S5 == 0)Display_Dynamic();
        }
    }
}
void Display_Dynamic()
{
        ShowSMG_Bit(SMG_duanma[num/10],0);
        DelaySMG(500);
        ShowSMG_Bit(SMG_duanma[num%10],1);
        DelaySMG(500);
        
}
void Write_24C02(unsigned char addr, unsigned char dat)
{
    IIC_Start();		//IIC总线起始信号					
    IIC_SendByte(0xa0); 	//24C02的写设备地址
    IIC_WaitAck();		//等待从机应答	
    IIC_SendByte(addr); 	//内存字节字节
    IIC_WaitAck(); 		//等待从机应答	
    IIC_SendByte(dat); 	//写入目标数据
    IIC_WaitAck();		//等待从机应答	
    IIC_Stop();		//IIC总线停止信号		
}
unsigned char Read_24C02(unsigned char addr)
{
    unsigned char tmp;
    //进行一个伪写操作
    IIC_Start();		//IIC总线起始信号					
    IIC_SendByte(0xa0); 	//24C02写设备地址
    IIC_WaitAck();		//等待从机应答	
    IIC_SendByte(addr); 	//内存自己地址
    IIC_WaitAck(); 		//等待从机应答	
    //进行字节读操作
    IIC_Start();		//IIC总线起始信号					
    IIC_SendByte(0xa1); 	//24C02读设备地址
    IIC_WaitAck();		//等待从机应答	
    tmp = IIC_RecByte();	//读取目标数据
    IIC_Ack(0); 		//产生非应答信号		
    IIC_Stop();		//IIC总线停止信号			
    return tmp;
}
void InitSystem()
{
    InitHC138(5);
    P0=0X00;
    InitHC138(4);
    P0=0XFF;
    InitHC138(0);
}
void main()
{
    num = Read_24C02(0x01);
    InitSystem();
    while(1)
    {
        Display_Dynamic();
        ScanKeys_Alone();
    }
}
  
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号