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

news2024/11/16 6:21:23

        接着上一篇博客文章讲解了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;
}

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

⑤、连续读写实现效果图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1463139.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

flannel网络拓扑

测试环境创建 在k8s中部署flannel网络插件 https://blog.csdn.net/weixin_64124795/article/details/128894411 参考文章部署k8s集群和flannel网络插件 我的k8s集群物理环境 我的集群中只有两个节点master和node1节点 [rootmaster sjs]# kubectl get node NAME STATU…

智慧安防/视频监控汇聚平台EasyCVR如何通过接口调用获取设备录像回看的流地址?

视频云存储/视频融合/安防监控EasyCVR视频汇聚系统可兼容各品牌的IPC、NVR、移动单兵、智能手持终端、移动执法仪、无人机、布控球等设备的接入&#xff0c;支持的接入协议包括&#xff1a;国标GB28181、RTSP/Onvif、RTMP&#xff0c;以及厂家的私有协议与SDK&#xff0c;如&am…

【DDD】学习笔记-领域事件

作为一种领域分析建模方法&#xff0c;事件风暴将事件视为一种建模的手段&#xff0c;将不同的团队角色统一到一个共同的业务场景下&#xff0c;同时又利用了事件的因果关系驱动我们把握业务的整体流程。在这个过程中&#xff0c;领域事件在事件风暴中起到了核心的驱动作用&…

JSON.stringify() 第三个参数的使用

语法 JSON.stringify(value[, replacer[, space]]) 参数说明&#xff1a; value: 必需&#xff0c; 要转换的 JavaScript 值&#xff08;通常为对象或数组&#xff09;。 replacer: 可选。用于转换结果的函数或数组。 如果 replacer 为函数&#xff0c;则 JSON.stringify …

C++从入门到精通 第十四章(STL容器)【上】

写在前面&#xff1a; 本系列专栏主要介绍C的相关知识&#xff0c;思路以下面的参考链接教程为主&#xff0c;大部分笔记也出自该教程&#xff0c;笔者的原创部分主要在示例代码的注释部分。除了参考下面的链接教程以外&#xff0c;笔者还参考了其它的一些C教材&#xff08;比…

分享58个NodeJs爬虫源码总有一个是你想要的

分享58个NodeJs爬虫源码总有一个是你想要的 学习知识费力气&#xff0c;收集整理更不易。 知识付费甚欢喜&#xff0c;为咱码农谋福利。 链接&#xff1a;https://pan.baidu.com/s/1_Im6ituI4izxP05oyA2z3Q?pwd8888 提取码&#xff1a;8888 项目名称 anyproxy 、nodejs …

【算法 - 动态规划】最长回文子序列

上篇文章中&#xff0c;我们学习一个新的模型&#xff1a; 样本对应模型&#xff0c;该模型的套路就是&#xff1a;以结尾位置为出发点&#xff0c;思考两个样本的结尾都会产生哪些可能性 。 而前篇文章中的 纸牌博弈问题 属于 [L , R]上范围尝试模型。该模型给定一个范围&…

爬虫基本库的使用(requests库的详细解析)

注&#xff1a;本文一共4万多字&#xff0c;希望读者能耐心读完&#xff01;&#xff01;&#xff01; 前面,我们了解了urllib库的基本用法&#xff08;爬虫基本库的使用(urllib库的详细解析)-CSDN博客&#xff09;。其中&#xff0c;确实又不方便的地方。例如处理网页验证…

P2670 [NOIP2015 普及组] 扫雷游戏 ---- 洛谷

题目描述 扫雷游戏是一款十分经典的单机小游戏。在 n 行 m 列的雷区中有一些格子含有地雷&#xff08;称之为地雷格&#xff09;&#xff0c;其他格子不含地雷&#xff08;称之为非地雷格&#xff09;。玩家翻开一个非地雷格时&#xff0c;该格将会出现一个数字——提示周围格子…

【前端素材】推荐优质后台管理系统Xoric平台模板(附源码)

一、需求分析 当我们从多个层次来详细分析后台管理系统时&#xff0c;可以将其功能和定义进一步细分&#xff0c;以便更好地理解其在不同方面的作用和实际运作。 1. 功能层次 a. 用户管理功能&#xff1a; 用户注册和登录&#xff1a;管理用户账户的注册和登录过程。权限管…

C#上位机与三菱PLC的通信08---开发自己的通讯库(A-1E版)

1、A-1E报文回顾 具体细节请看&#xff1a; C#上位机与三菱PLC的通信03--MC协议之A-1E报文解析 C#上位机与三菱PLC的通信04--MC协议之A-1E报文测试 2、为何要开发自己的通讯库 前面使用了第3方的通讯库实现了与三菱PLC的通讯&#xff0c;实现了数据的读写&#xff0c;对于通…

熬夜整理的考研考公学习资料,祝愿大家成功上岸

现如今大学生毕业大都在考研、考公这两条道路上选一个。今天给这些朋友同学分享一下考研、考公的学习资料。希望能够帮助到部分努力的同学&#xff01; 以下就是考研、考公的学习资料 学习资料获取地址 点击获取学习资料 就拿考研来说这里不仅包含了深入浅出的复习笔记&#x…

steam搬砖项目还能不能做,新手小白月入过万真的假的

steam搬砖项目还能不能做&#xff1f;今天&#xff0c;我们将通过实际数据来告诉你&#xff0c;当前市场上存在着大量没有实操过Steam搬砖项目的人&#xff0c;他们也开始参与其中&#xff0c;导致市场格局混乱。这些人可能是第一次接触该项目&#xff0c;但却毫不犹豫地发表自…

Facebook Horizon:探索虚拟现实中的社交空间

随着科技的不断进步&#xff0c;虚拟现实&#xff08;VR&#xff09;技术正成为社交互动和娱乐体验的新前沿。在这个数字时代&#xff0c;Facebook作为全球最大的社交媒体平台之一&#xff0c;正在引领虚拟社交的新时代&#xff0c;其推出的虚拟社交平台Facebook Horizon成为了…

如何使用Docker部署MongoDB并结合内网穿透实现远程访问本地数据库

文章目录 前言1. 安装Docker2. 使用Docker拉取MongoDB镜像3. 创建并启动MongoDB容器4. 本地连接测试5. 公网远程访问本地MongoDB容器5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定TCP地址远程访问 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的 …

Fiddler工具 — 19.Fiddler抓包HTTPS请求(二)

5、查看证书是否安装成功 方式一&#xff1a; 点击Tools菜单 —> Options... —> HTTPS —> Actions 选择第三项&#xff1a;Open Windows Certificate Manager打开Windows证书管理器。 打开Windows证书管理器&#xff0c;选择操作—>查看证书&#xff0c;在搜索…

【webrtc】m77 PacedSender

mediasoup是m77的代码,m77的代码并没有paced controller ,而且与paced sender 的逻辑混在了一起。结合大神们的代码分析,对照m77 进行 理解。m77 有ProbeController。给pacersender 更新飞行数据:PacedSender::InsertPacket(size_t bytes) 对应的是 PacingController::OnPa…

微信小程序错误----config is not defined

微信小程序出错 请求头发生错误 修改 options.header {// 为请求头对象添加 token 验证的 Authorization 字段Access-Token: token,platform: MP-WEIXIN,// 保留原有的 header...options.header,}

运维SRE-11 备份服务及备份项目

1.第一个服务-rsync备份服务-守护进程模式 1.1概述 守护进程&#xff1a;持续运行的进程&#xff0c;也可以叫作服务服务一般分为&#xff1a;服务端与客户端服务端&#xff1a;linux服务器上运行的各种服务软件客户端&#xff1a;linux中的客户端可能是一个命令&#xff0c;…

Android 11以上获取不到第三方app是否安装

开年第一篇&#xff0c;处理了一下年前的小问题。 问题&#xff1a;本地app跳转到第三方app地图进行导航&#xff0c;获取不到第三方地图是否安装。 解决&#xff1a; 1.添加包名 This can be done by adding a <queries> element in the Android manifest.在app下的…