IIC通信驱动EEPROM,AT24C02硬件存储器编程(2)

        接着上一篇博客文章讲解了IIC协议的原理及编程思路,本篇博客文章将以IIC为基础,从芯片手册入手,梳理讲解如何对AT24C02进行驱动编程,实现数据的读写操作。
IIC通信驱动硬件编程 (1)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_49337111/article/details/136216296?spm=1001.2014.3001.5502

1、存储器基础

        在对AT24C02进行编程驱动时,有必要先了解一下存储器的基本知识,这有助于对AT24C02的进一步了解,并且在一些公司的笔试或者面试时会进行基本的存储器知识考察。

        存储器是计嵌入式系统中用于存储数据和程序的关键组件。根据存储器的特点和用途,可以将其分为以下几类:

        ①、RAM(Random Access Memory,随机访问存储器):RAM是最常用的存储器之一,它允许设备快速读取和写入数据。RAM的特点是速度快,但数据在断电后会丢失。RAM通常用于存储正在运行的程序和临时数据。

        ②、ROM(Read-Only Memory,只读存储器):ROM是一种只能读取数据而不能写入数据的存储器。它的数据是以螺旋状的方式从中心向外散开状的顺序排列的。ROM的数据是以螺旋状的方式从中心向外散开状的顺序排列的,因此它非常适合存储固定的程序代码或系统数据。常见的ROM类型包括Mask ROM和PROM(Programmable Read-Only Memory,可编程只读存储器)。

        ③、EEPROM(Electrically Erasable Programmable Read-Only Memory,电可擦除可编程只读存储器):EEPROM是一种可以通过电子方式擦除和重新编程的ROM。它的特点是数据可以反复擦写,且断电后数据不会丢失。EEPROM通常用于存储需要频繁更新的数据,如BIOS(基本输入输出系统)程序。

        本次编程驱动的AT24C02就属于EEPROM这一类存储设备。

        ④、Flash Memory(闪存):Flash Memory是一种非易失性存储器,它的特点是可以快速地擦写和重新编程。Flash Memory的数据是以块为单位进行擦除和编程的,因此它非常适合用于存储大量的数据。Flash Memory广泛应用于U盘、SD卡、固态硬盘等存储设备中。

        ⑤、高速缓存(Cache):Cache是一种高速存取指令和数据的存储器,通常位于CPU和主存储器之间。Cache的存取速度非常快,但存储容量相对较小。其主要作用是减少CPU访问主存储器的次数,从而提高系统的运行效率。

2、AT24C02说明

        由下图所示的官方手册可知,AT24C02的的存储容量为2K位,而一个字节有8位,那么AT24C02的存储空间也就是有2048 / 8 = 256个字节的串行CMOS E2PROM(电可擦除可编程只读存储器)。它采用了CATALYST公司的先进CMOS技术,从而实质性地减少了器件的功耗。这个设备具有一个8字节的页写缓冲器,并通过IIC总线接口进行操作。此外,AT24C02还提供了一个专门的写保护功能,以确保数据的完整性和安全性。

        AT24C02的引脚包括SERIAL DATA(SDA),这是一个双向引脚,用于串行数据传输。此外,还有一个WRITE PROTECT(WP)引脚,用于提供硬件数据保护。

        在操作方面,AT24C02有两种寻址方式:片寻址存储单元寻址。AT24C02存储器可以分成32页,每页有8个字节,所以总共可以存储256个字节的数据。

        A0、A1、A2 器件地址输入端。

Device Address 从机设备地址

        结合上图所示的AT24C02在原理图中接线可知,A0、A1、A2引脚已进行接地操作,则AT24C02的设备从机地址为 1010 000x,(x表示读写位(R/W)的值,当x为0时,表示写数据,当x为0时,表示读数据)

        由IIC协议可知,从机的设备地址为7位,通信时需要将设备地址左移1位,然后最低位用于标识读写模式。为了便于记忆,也可说成IIC通信的从机设备地址为一个字节,即8位,而最低位用于标识读写(W/R)模式。

        读模式时,AT24C02的设备地址为 1010 0001 = 0xA1

        写模式时,AT24C02的设备地址为 1010 0000 = 0xA0

        WORD ADDRESS的值由用户决定,最大值由芯片的存储空间决定 AT24C02——2K (256 x 8)——0~256

3、AT24C02时序图

        在编写AT24C02的设备驱动程序时,需要严格遵循官方参考手册进行编写,如下所示为AT24C02系列设备的逻辑时序图。

        ①、Byte Write 字写

AT24C02单字节写程序编写思路

①、发送IIC启动信号

②、发送AT24C02的地址

③、接收AT24C02的有效应答信号

④、发送芯片内部的字地址

⑤、接收AT24C02的有效应答信号

⑥、发送写入的1个字节数据

⑦、接收AT24C02的有效应答信号

⑧、发送IIC停止信号

        ②、Page Write 页写

AT24C02多字节页写程序编写思路

①、发送IIC启动信号

②、发送AT24C02的地址

③、接收AT24C02的有效应答信号

④、发送芯片内部的字地址

⑤、接收AT24C02的有效应答信号

⑥、发送写入的1个字节数据

⑦、接收AT24C02的有效应答信号

......

这一部分持续循环⑥、⑦步骤的操作,直到写数据结束

......

⑧、发送IIC停止信号

        ③、Current Address Read 当前地址读取

AT24C02当前地址读取程序编写思路

①、发送IIC启动信号

②、发送AT24C02的地址

③、接收AT24C02的有效应答信号

④、接收AT24C02的数据

⑤、发送无效应答信号

⑥、发送IIC停止信号

        ④、Random Read 随机读取

AT24C02单字节读取程序编写思路

①、发送IIC启动信号

②、发送AT24C02的地址

③、接收AT24C02的有效应答信号

④、发送芯片内部的字地址

⑤、接收AT24C02的有效应答信号

⑥、发送IIC启动信号

⑦、发送AT24C02的地址

⑧、接收AT24C02的有效应答信号

⑨、接收的AT24C02存储的数据

⑩、发送无应答信号

11、发送IIC停止信号

        ⑤、Sequential Read 顺序读取

AT24C02顺序连续读取程序编写思路

①、发送IIC启动信号

②、发送AT24C02的地址

③、接收AT24C02的有效应答信号

④、发送芯片内部的字地址

⑤、接收AT24C02的有效应答信号

⑥、发送IIC启动信号

⑦、发送AT24C02的地址

⑧、接收AT24C02的有效应答信号

⑨、接收的AT24C02存储的数据

⑩、发送有效应答信号

11、接收的AT24C02存储的数据

12、发送有效应答信号

......

这一部分持续循环⑥、⑦步骤的操作,直到读取数据结束

......

13、发送无效应答信号

14、发送IIC停止信号

4、AT24C02驱动源码

        在这一部分中的AT24C02代码也同样适用于AT24C01A/02/04/08A/16A等型号的存储器。

        ①、IIC通信讲解及源码

                在上一篇博客中已经对IIC通信协议及通信代码做了较为详细的说明,故而在这里就不过多描述了,如果有不理解的地方可以参考这篇博客文章:

IIC通信驱动硬件编程 (1)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_49337111/article/details/136216296?spm=1001.2014.3001.5502

        ②、AT24C02.h

#ifndef __AT24C02_H
#define __AT24C02_H

#include "stm32g4xx_hal.h"
#include "stdio.h"
#include "iic.h"

#define AT24C02_WRITE_ADDR     0xA0
#define AT24C02_READ_ADDR      0xA1

void AT24C02_Init(void);

int AT24C02_Write_Byte(unsigned char word_addr, unsigned char data);
int AT24C02_Read_Byte(int word_addr, unsigned char *data);
int AT24C02_Write_Page(unsigned char word_addr, unsigned char *data, int data_len);

int AT24C02_Read_Sequential(unsigned char word_addr, unsigned char buf[], int buf_size);

int AT24C02_Read_Current_addr(unsigned char *cur_addr);

#endif

        ③、AT24C02.c

#include "AT24C02.h"

/**
  * @brief AT24C02初始化
  * @param None
  * @retval None
  */
void AT24C02_Init(void)
{
    IIC_Init();
}

/**
  * @brief AT24C02写1个字节
  * @param word_addr: 字地址
  * @param data:需要写入的数据
  * @retval 成功返回0,失败返回-1
  */
int AT24C02_Write_Byte(unsigned char word_addr, unsigned char data)
{
    int ret = 0;
    IIC_Start();
    IIC_Write_Byte(AT24C02_WRITE_ADDR);
    ret = IIC_Wait_Ack();
    if(ret == -1)
    {
        IIC_Stop();
        return -1;
    }
    IIC_Write_Byte(word_addr);
    ret = IIC_Wait_Ack();
    if(ret == -1)
    {
        IIC_Stop();
        return -1;
    }
    IIC_Write_Byte(data);
    ret = IIC_Wait_Ack();
    if(ret == -1)
    {
        IIC_Stop();
        return -1;
    }
    IIC_Stop();
    return 0;
}


/**
  * @brief AT24C02读取1个字节
  * @param word_addr:字地址
  * @param data:数据
  * @retval 成功返回0,失败返回-1
  */
int AT24C02_Read_Byte(int word_addr, unsigned char *data)
{
    int ret = 0;
    IIC_Start();
    IIC_Write_Byte(AT24C02_WRITE_ADDR);
    ret = IIC_Wait_Ack();
    if(ret == -1)
    {
        IIC_Stop();
        printf("%s\t%d\r\n", __FUNCTION__, __LINE__);
        return -1;
    }
    IIC_Write_Byte(word_addr);
    ret = IIC_Wait_Ack();
    if(ret == -1)
    {
        IIC_Stop();
        printf("%s\t%d\r\n", __FUNCTION__, __LINE__);
        return -1;
    }
    
    IIC_Start();
    IIC_Write_Byte(AT24C02_READ_ADDR);
    ret = IIC_Wait_Ack();
    if(ret == -1)
    {
        IIC_Stop();
        printf("%s\t%d\r\n", __FUNCTION__, __LINE__);
        return -1;
    }
    *data = I2CReceiveByte();
    IIC_Write_Ack(1);
    IIC_Stop();
    
    return 0;
}

/**
  * @brief AT24C02页写
  * @param word_addr:字地址
  * @param data:需要被写入的数据数组
  * @param data_len:数据长度
  * @retval 成功返回0,失败返回-1
  */
int AT24C02_Write_Page(unsigned char word_addr, unsigned char *data, int data_len)
{
    int ret = 0;
    IIC_Start();
    IIC_Write_Byte(AT24C02_WRITE_ADDR);
    ret = IIC_Wait_Ack();
    if(ret == -1)
    {
        IIC_Stop();
        return -1;
    }
    IIC_Write_Byte(word_addr);
    ret = IIC_Wait_Ack();
    if(ret == -1)
    {
        IIC_Stop();
        return -1;
    }
    
    //连续写数据
    for(int i=0; i<data_len; i++)
    {
        IIC_Write_Byte(data[i]);
        ret = IIC_Wait_Ack();
        if(ret == -1)
        {
            IIC_Stop();
            return -1;
        }
    }
    IIC_Stop();
    
    return 0;
}

/**
  * @brief AT24C02连续读取
  * @param word_addr:字地址
  * @param buf:存储数组
  * @param buf_size:数组大小
  * @retval 成功返回0,失败返回-1
  */
int AT24C02_Read_Sequential(unsigned char word_addr, unsigned char buf[], int buf_size)
{
    int ret = 0;
    IIC_Start();
    IIC_Write_Byte(AT24C02_WRITE_ADDR);
    ret = IIC_Wait_Ack();
    if(ret == -1)
    {
        IIC_Stop();
        printf("%s\t%d\r\n", __FUNCTION__, __LINE__);
        return -1;
    }
    IIC_Write_Byte(word_addr);
    ret = IIC_Wait_Ack();
    if(ret == -1)
    {
        IIC_Stop();
        printf("%s\t%d\r\n", __FUNCTION__, __LINE__);
        return -1;
    }
    
    IIC_Start();
    IIC_Write_Byte(AT24C02_READ_ADDR);
    ret = IIC_Wait_Ack();
    if(ret == -1)
    {
        IIC_Stop();
        return -1;
    }
    
    for(int i=0; i<buf_size; i++)
    {
        buf[i] = IIC_Read_Byte();
        IIC_Write_Ack(0);//Ack
    }
    IIC_Write_Ack(1);     //No Ack
    
    return 0;
}

/**
  * @brief AT24C02连续读取
  * @param word_addr:字地址
  * @param buf:存储数组
  * @param buf_size:数组大小
  * @retval 成功返回0,失败返回-1
  */
int AT24C02_Read_Current_addr(unsigned char *cur_addr)
{
    int ret = 0;
    IIC_Start();
    IIC_Write_Byte(AT24C02_READ_ADDR);
    ret = IIC_Wait_Ack();
    if(ret == -1)
    {
        IIC_Stop();
        return -1;
    }
    
    *cur_addr = IIC_Read_Byte();
    IIC_Write_Ack(1);
    IIC_Stop();
    
    return 0;
}

④、单字节读写实现效果图

⑤、连续读写实现效果图

  • 28
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值