【51单片机】I2C总线详解 + AT24C02

学习使用的开发板:STC89C52RC/LE52RC
编程软件:Keil5
烧录软件:stc-isp

开发板实图:
在这里插入图片描述

文章目录

  • AT24C02介绍
    • 存储器
  • I2C总线介绍
    • I2C时序结构
    • 数据帧
    • AT24C02数据帧
  • 编程实例 —— 按键控制数据大小&存储器写入读出

AT24C02介绍

  • AT24C02 是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想永久保存的数据信息
  • 存储介质:E2PROM
  • 通讯接口:I2C总线
  • 容量:256字节

在这里插入图片描述

引脚及应用电路如下:

在这里插入图片描述

详细结合I2C通信协议讲解

存储器

存储器大致分为两类:
RAM(Random Access Memory,随机存取存储器),掉电丢失
ROM(Read Only Memory,只读存储器),掉电不丢失

在这里插入图片描述

RAM

  • SRAM(静态随机存储器):访问时间短,速度快,用于CPU高速缓存(Cache)。
  • DRAM(动态随机存储器):访问时间长,速度较慢,用于主存,也就是运行内存。

ROM

  • Mask ROM:在制作过程写入,写入后不可更改,类似磁带,只用于读取
  • PROM:可改写一次的只读存储器。PROM在出厂时,存储的内容全为1,用户可以根据需要将其中的某些单元写入数据0(部分的PROM相反,出场全为0), 以实现对其“编程”的目的
  • EPROM(可擦除可编程ROM):具有可擦除功能,擦除后即可进行再编程,但是缺点是擦除需要使用紫外线照射一定的时间,且时间较长
  • E2PROM/E2PROM/EEPROM(电可擦除):可直接用电信号擦除,也可用电信号写入,写入时间为ms级别
  • Flash(闪存):属于E2PROM的改进产品。最大特点是必须按块(Block)擦除(每个区块的大小不定,不同厂家的产品有不同的规格), 而EEPROM则可以一次只擦除一个字节(Byte)。
  • 硬盘、软盘、光盘:相应控制器 + Flash闪存芯片

I2C总线介绍

单片机常用的通信方式有:UART(串口)、SPI、I2C、DS232

UART常用于两个单片机进行通信,详情参看【51单片机】串口通信
UART有三个缺陷:不能远距离传输、传输速度慢、不能一对多通信。针对这三个缺陷,衍生出了其他的通信方式:

远距离传输:RS232/RS485

传输速度:SPI(加了个clock线提供时钟信号),常用于SD卡,屏幕这类对通信速度要求高的外设

一对多通信:I2C —— 常用于开发板中,单片机与其他外设进行通信


  • I2C总线(Inter IC BUS) 是由 Philips 公司开发的一种通用数据总线
  • 同步、半双工、带数据应答
  • 有两根通信线:SCL(Serial Clock)、SDA(Serial Data)

所有I2C设备的 SCL 连接在一起,SDA 连在一起
设备的 SCL 和 SDA 均要配置成开漏输出模式

在这里插入图片描述

开漏输出可参看B站up主工科男孙老师的《推挽 开漏 高阻 这都是谁想出来的词??》
开漏输出可用于适配不同电压的芯片;在总线通信时避免不同设备输出高低电平导致设备烧毁。通过搭配外接上拉电阻输出高低电平
当 SCLKN1OUT 关闭,SCLKIN 为高电平;当 SCLK1OUT 打开,SCLKIN 为低电平


SCL 和 SDA 各添加一个上拉电阻,阻止一般为4.7KΩ左右
上拉电阻可参看B站up主工科男孙老师的《单片机的上拉电阻 到底在拉什么?》
上拉电阻阻值过小,会漏电;阻值过大,驱动能力(将低电平拉高的速度)下降。

当总线挂载设备增多时,可适当降低上拉电阻阻值

在这里插入图片描述
开漏输出 和 上拉电阻 的共同作用实现了“线与”的功能,解决多机通信互相干扰的问题
当总线设备较多且通信速度要求高,可以适当降低上拉电阻的阻值

详情参看B站up主工科男孙老师的《单片机I2C通信入门(上):硬件部分有哪些注意点?》

I2C时序结构

因为总线上挂载多个设备,需要约定通信协议才能让通信正确无误,畅通无阻
例如一次读数据通信,需要知道什么时候发起,向谁读数据,对方是否存在,读数据,停止读数据。
I2C通信协议将上述操作都抽象成了一个个时序,最终拼接成数据帧

总共有六个时序结构,如下:

起始条件 —— 数据帧的起始,表示开始通信

  • SCL 高电平期间,SDA 从高电平切换到低电平
    在这里插入图片描述

终止条件 —— 数据帧的结尾,表示通信结束

  • SCL 高电平期间,SDA 从低电平切换到高电平
    在这里插入图片描述

发送一个字节 —— 可发送数据,I2C地址,字地址…

  • SCL 低电平期间,主机将数据位依次放到SDA线上(高位在前),然后拉高 SCL,从机(对方设备)将在 SCL 高电平期间读取数据位。SCL 高电平期间 SDA 不允许有数据变化,依次循环上述过程8次,即可发送一个字节数据
    在这里插入图片描述

注意:先拉低 SCL,再将数据放到 SDA,然后拉高 SCL,此时从机会读取 SDA 数据

接收一个字节 —— 主机(MCU) 接收从机数据

  • SCL 低电平期间,从机将数据依次放到 SDA 线上(高位在前),然后拉高 SCL,主机将在 SCL 高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)
    在这里插入图片描述

注意:先拉高 SDA,释放总线给从机。从机在 SCL 低电平时将数据放到 SDA ,主机拉高 SCL 读取数据,再拉低 SCL 让从机放数据

发送应答 —— 接收从机数据后,告诉从机无误或有误

  • 在接收完一个字节之后,主机在下一个时钟发送一位数据、数据0表示应答,数据1表示非应答。发送流程同发送一位数据
    在这里插入图片描述

接收应答 —— 主机发送一字节数据后,接收从机的接收应答

  • 在主机发送完一个字节之后,主机在下一个时钟接收一位数据,判断从机是否应答,数据0 表示应答,数据1 表示非应答(主机在接收之前,需要释放SDA)
    在这里插入图片描述

数据帧

I2C数据帧描述具体的一次通信,由上述时序结构拼接而成。

发送一帧数据 —— 向谁发什么

在这里插入图片描述

协议格式中第一个字节(为slave address)由7位地址和一位R/W读写位组成的,这字节是个器件地址。

I2C 挂载多个设备,通过从机地址(slave address)标识对哪个设备进行读/写操作

常用I2C接口通用器件的器件地址是由种类型号,及寻址码组成的,共7位。
如格式如下:

在这里插入图片描述

  1. 器件类型:A6 - A3 共4位决定的。这是由半导公司生产时就已固定此类型的了,也就是说这4位已是固定的。本开发板为 1010

  2. 用户自定义地址码:A2 - A0 共3位。这是由用户自己设置的,通常的作法如EEPROM这些器件是由外部IC的3个引脚所组合电平决定的(用常用的名字如A0,A1,A2)。这也就是寻址码。AT24C02 的寻址码为 000
    在这里插入图片描述

  3. 最低一位就是R/W位,,“0”表示写,“1”表示读(通常读写信号中写上面有一横线,表示低电平)。所以I2C设备通常有两个地址,即读地址和写地址

综上,AT24C02 的写地址为0xA0,读地址为0xA1


在这里插入图片描述

回到数据帧,发送一帧数据流程如下

S(起始位) -> 发送从机地址 + W -> 从机返回接收应答 -> 发送一字节数据 -> 从机返回接收应答 … -> P(终止位)


接收一帧数据

在这里插入图片描述

S(起始位) -> 发送从机地址 + W -> 从机返回接收应答 -> 接收一字节数据 -> 主机发送应答 -> … -> P(终止位)


复合格式 —— 先发送再接收

在这里插入图片描述

AT24C02数据帧

AT24C02是一个存储器,本质就是写入数据和读取数据,其数据帧分为字节写随机读

字节写

在这里插入图片描述
存储器内部还有字地址,需要指明将数据写到存储器的哪个位置 —— word address

随机读

在这里插入图片描述

需要先告诉 AT24C02 要读哪个地址的数据,再进行读字节数据帧

编程实例 —— 按键控制数据大小&存储器写入读出

按键和数码管部分参看【51单片机】独立按键 和 【51单片机】数码管

首先对I2C的时序结构进行封装,读者可以对照上述时序图,代码如下:

#include <REGX52.h>
#include "Delay.h"sbit I2C_SDA = P2^0;//数据线
sbit I2C_SCL = P2^1;//Clock线/*** @brief		I2C开始标志* @parm		无* @retval		无*/
void I2C_Start()
{//起始条件:SCL高电平期间,SDA从高电平切换到低电平//先置SDA = 1,确保从高电平切到低电平I2C_SDA = 1;//SCL置高电平I2C_SCL = 1;//SDA由高电平切换为低电平I2C_SDA = 0;//SCL恢复低电平I2C_SCL = 0;
}
/*** @brief		I2C停止标志* @parm		无* @retval		无*/
void I2C_Stop()
{//终止条件:SCL高电平期间,SDA从低电平切换到高电平//先置SDA = 0,确保从低电平切到高电平I2C_SDA = 0;//SCL置高电平I2C_SCL = 1;//SDA由低电平切换为高电平I2C_SDA = 1;
}
/*** @brief		I2C发送字节数据* @parm		Byte:要发送的数据,范围: 0 ~ 255* @retval		无*/
void I2C_SendByte(unsigned char Byte)
{//发送数据:从高位开始//SCL低电平期间,SDA写数据,SCL拉高后,从机读取数据unsigned char i = 0;for(i = 0; i < 8; ++i){I2C_SDA = Byte & (0x80 >> i);I2C_SCL = 1;//此处要注意若机器频率过快,可能导致从机还没读到数据,SCL就被拉低了I2C_SCL = 0;//需要查看手册。}
}
/*** @brief		I2C读取一字节数据* @parm		无* @retval		读取到的数据*/
unsigned char I2C_ReceiveByte()
{//接收数据,从高位开始//SCL高电平时,从SDA读数据unsigned char Byte = 0, i;//将SDA置高电平,释放SDA给从机I2C_SDA = 1;for(i = 0; i < 8; ++i){I2C_SCL = 1;if(I2C_SDA)	Byte |= (0x80 >> i);I2C_SCL = 0;}return Byte;
}
/*** @brief		发送应答* @parm		AckBit为0表示应答,为1表示非应答* @retval		无*/
void I2C_SendAck(unsigned char AckBit)
{//在读完一个字节后,主机在下一个时钟发送一位数据//数据0表示应答,数据1表示非应答I2C_SDA = AckBit;I2C_SCL = 1;I2C_SCL = 0;
}
/*** @brief		接收应答* @parm		无* @retval		Ack为0表示应答,为1表示非应答*/
unsigned char I2C_ReceiveAck()
{//在发完一个字节后,主机在下一个时钟接收一位数据,判断从机是否应答//数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)unsigned char Ack;//释放SDAI2C_SDA = 1;//SCL置高电平I2C_SCL = 1;//读响应Ack = I2C_SDA;//SCL置低电平I2C_SCL = 0;return Ack;
}

然后封装 AT24C02 的两个数据帧,对 I2C 的时序结构进行拼接

#include <REGX52.h>
#include "I2C.h"
//AT24C02的从机地址写,从机地址读需 |= 0x01
#define AT24C02_ADDRESS 0xA0/*** @brief		向AT24C02暂存器写入数据* @parm		WordAddress:写到暂存器的什么地址* @parm		Data:要写入的数据	* @retval		无*/
void AT24C02_WriteByte(unsigned char WordAddress, unsigned char Data)
{I2C_Start();I2C_SendByte(AT24C02_ADDRESS);I2C_ReceiveAck();I2C_SendByte(WordAddress);I2C_ReceiveAck();I2C_SendByte(Data);I2C_ReceiveAck();I2C_Stop();
}
/*** @brief		从AT24C02读取数据* @parm		WordAddress:读什么地址的数据* @retval		读出的数据*/
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{unsigned char Data;I2C_Start();I2C_SendByte(AT24C02_ADDRESS);I2C_ReceiveAck();I2C_SendByte(WordAddress);I2C_ReceiveAck();I2C_Start();I2C_SendByte(AT24C02_ADDRESS | 0x01);//此处是读I2C_ReceiveAck();Data = I2C_ReceiveByte();I2C_SendAck(1);I2C_Stop();return Data;
}

主程序 —— 监控按键按下,并执行相应操作

  • 按键一:变量++
  • 按键二:变量–
  • 按键三:将变量写入 AT24C02
  • 按键四:将数据读出 At24C02
#include <REGX52.h>
#include "AT24C02.h"
#include "SoleKey.h"
#include "LCD1602.h"
#include "Delay.h"void main()
{unsigned char Key = 0;unsigned int Count = 0;LCD_Init();//LCD1602初始化LCD_ShowNum(1, 1, Count, 5);while(1){Key = SoleKey();//获取哪个按键按下if(Key){if(Key == 1)//1按键按下,Count++{Count++;LCD_ShowNum(1, 1, Count, 5);}else if(Key == 2)//2按键按下,Count--{Count--;LCD_ShowNum(1, 1, Count, 5);}else if(Key == 3)//3按键按下,存储数据{AT24C02_WriteByte(0x00, Count / 256);Delayms(5);//因为写速度较慢,不能连续写,会导致数据错误AT24C02_WriteByte(0x01, Count % 256);LCD_ShowNum(1, 1, Count, 5);	//显示写入成功LCD_ShowString(2, 1, "Write OK!");Delayms(1000);LCD_ShowString(2, 1, "         ");}else if(Key == 4)//4按键按下,读出数据{Count = AT24C02_ReadByte(0x00) * 256 + AT24C02_ReadByte(0x01);LCD_ShowNum(1, 1, Count, 5);//显示读出成功LCD_ShowString(2, 1, "Read OK! ");Delayms(1000);LCD_ShowString(2, 1, "         ");}}}
}

效果如下:

【51单片机AT24C02 & I2C通信】

完整项目链接:

AT24C02 存储数据 & I2C通信


以上就是本篇博客的所有内容,感谢你的阅读
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

全球海工供应链,中国建造!第十一届全球FPSOFLNGFSRU大会在上海隆重召开

10月30日-31日&#xff0c;全球海洋工程与高端装备领域的年度国际交流盛会——第十一届全球FPSO&FLNG&FSRU大会暨海上能源全产业链博览会在上海隆重召开&#xff0c;同期举办第七届亚洲海洋风能大会。本次大会暨博览会由上海船舶工业行业协会、上海市工业合作协会、决策…

Linux网络编程——网络字节序和IP地址详解

一、网络字节序 1、大端模式和小端模式 字节序是指多字节数据的存储顺序&#xff0c;在设计计算机系统的时候&#xff0c;有两种处理内存中数据的方法&#xff1a;大端格式、小端格式。 小端格式(Little-Endian)&#xff1a;将低位字节数据存储在低地址&#xff1b; 大端格式(…

解析低代码开发在企业数字化转型中的多重优势

在数字化转型的浪潮中&#xff0c;企业面临着前所未有的机遇和挑战。为了在竞争激烈的市场中脱颖而出&#xff0c;企业需要迅速且高效地构建和更新应用程序&#xff0c;以适应不断变化的业务需求。数字化转型已不再是企业的选择&#xff0c;而是关乎生存和发展的必由之路。在这…

JMeter项目实战

目录 一、流程&#xff1a; 1.接口测试流程&#xff1a; 2.测试数据准备&#xff1a; 3.接口功能测试&#xff1a; 4.自动化测试流程&#xff1a; 5.情景压力测试分析&#xff1a; 6.生成图形化测试报告&#xff1a; 一、流程&#xff1a; 1.接口测试流程&#xff1a; …

SHARE 100M A10风力发电机动态巡检

背景 随着碳中和、碳达峰“3060”目标的提出&#xff0c;“十四五”时期乃至本世纪中叶应对气候变化工作、绿色低碳发展和生态文明建设提出了更高要求。在时代建设的背景下&#xff0c;清洁能源行业蓬勃发展&#xff0c;传统静态巡检模式与高度依赖人力的风机巡检运维手段已经无…

数据分析:宏基因组DESeq2差异分析筛选差异物种

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍原理:计算步骤:结果:加载R包准备画图主题数据链接导入数据Differential abundance (No BP vs 2BP TA)构建`countData`矩阵过滤低丰度物种构建DESeq数据对象DESeq2差异分析画图Di…

Linux进程信号(信号的产生)

目录 什么是信号&#xff1f; 信号的产生 信号产生方式1&#xff1a;键盘 前台进程 后台进程 查看信号 signal系统调用 案例 理解进程记录信号 软件层面 硬件层面 信号产生方式2:指令 信号产生方式3:系统调用 kill系统调用 案例 其他产生信号的函数调用 1.rais…

【ESP】一小时速通入门笔记

【ESP】一小时速通入门笔记 前言: 之前上学时就用过一次esp32, 当时初次使用搭建编译环境费了老大功夫.在我第一篇esp32笔记中也有说明.以至于我好像忘记记录完整的入门笔记了.最近因为工作需要又开始接触esp32才发现,现在已经方便得多了.顺利的话一小时速通. 前排提醒: 本笔记…

22.04Ubuntu---ROS2使用rclcpp编写节点C++

节点需要存在于功能包当中&#xff0c;功能包需要存在于工作空间当中。 所以我们要想创建节点&#xff0c;就要先创建一个工作空间&#xff0c;再创建功能包。 第一步&#xff1a;创建工作空间 mkdir -p chapt2_ws/src/ 第二步&#xff1a;创建example_cpp功能包&#xff0c…

QML项目实战:自定义CheckBox

目录 一.添加模块 import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.4 import QtGraphicalEffects 1.15 二.自定义CheckBox 1.CheckBox设置 2.勾选框设置 3.标签部分 4. 状态变化处理 5.文本设置 三.效果 1.当enabled为true 2.当enabled为true 3.当…

【Git】Liunx环境下Git的使用:“克隆,提交,推送“

目录 一、常用参数 二、我们为什么要使用Git&#xff1f; 三、创建远程仓库 第一步&#xff1a;创建对应代码托管平台账号。 第二步&#xff1a;在托管平台创建仓库 第三步&#xff1a;完善仓库内容&#xff08;选择性使用&#xff09; 开源和私有 四、克隆远程仓库到本…

《Python网络安全项目实战》项目4 编写网络扫描程序

《Python网络安全项目实战》项目4 编写网络扫描程序 项目4 编写网络扫描程序任务4.1 扫描内网有效IP地址任务描述任务分析任务实施任务拓展 任务4.2 编写端口扫描工具任务描述任务分析任务实施相关知识任务评价任务拓展项目评价 项目4 编写网络扫描程序 许多扫描工具是由Pytho…

软件设计开发规程,制度(word原件)

技术解决方案过程包括&#xff1a; 1、选择最佳解决方案&#xff1b; 2、制定架构设计&#xff1b; 3、制定概要设计&#xff1b; 4、制定详细设计和数据库设计&#xff1b; 5、利用准则进行接口设计&#xff1b; 6、实现设计&#xff1b; 7、进行单元测试&#xff1b; 8、进行…

Spring Boot框架的知识分类技术解析

2 开发技术 2.1 VUE框架 Vue.js&#xff08;读音 /vjuː/, 类似于 view&#xff09; 是一套构建用户界面的渐进式框架。 Vue 只关注视图层&#xff0c; 采用自底向上增量开发的设计。 Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。 2.2 Mysql数据库 …

Knowledge Graph-Enhanced Large Language Models via Path Selection

研究背景 研究问题&#xff1a;这篇文章要解决的问题是大型语言模型&#xff08;LLMs&#xff09;在生成输出时存在的事实不准确性&#xff0c;即所谓的幻觉问题。尽管LLMs在各种实际应用中表现出色&#xff0c;但当遇到超出训练语料库范围的新知识时&#xff0c;它们通常会生…

Spark中的宽窄依赖

一、什么是依赖关系 这里通过一张图来解释&#xff1a; result_rdd是由tuple_rdd使用reduceByKey算子得到的&#xff0c; 而tuple_rdd是由word_rdd使用map算子得到的&#xff0c;word_rdd又是由input_rdd使用flatMap算子得到的。它们之间的关系就称为依赖关系&#xff01; 二…

实现uniapp-微信小程序 搜索框+上拉加载+下拉刷新

pages.json 中的配置 { "path": "pages/message", "style": { "navigationBarTitleText": "消息", "enablePullDownRefresh": true, "onReachBottomDistance": 50 } }, <template><view class…

在vscode中如何利用git 查看某一个文件的提交记录

在 Visual Studio Code (VSCode) 中&#xff0c;你可以使用内置的 Git 集成来查看某个文件的提交历史。以下是具体步骤&#xff1a; 使用 VSCode 内置 Git 功能 打开项目&#xff1a; 打开你的项目文件夹&#xff0c;确保该项目已经是一个 Git 仓库&#xff08;即项目根目录下…

如何用python求导数

打开python运行环境。 导入微分的模块包&#xff1a;from sympy import *。 定义符号变量&#xff1a;x symbols(x) 定义一个函数&#xff1a;f x**9 diff diff(f,x)求导 最后输入diff&#xff0c;即可显示其变量值了。

Protobuf——基本使用

什么是Protobuf Protobuf是 Google的⼀种语⾔⽆关、平台⽆关、可扩展的序列化结构数据的⽅法&#xff0c;它可⽤于&#xff08;数据&#xff09;通信协议、数据存储等。 Protobuf类比于XML&#xff0c;是一种灵活&#xff0c;高效&#xff0c;自动化机制的结构数据序列化方法&…