【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;
	//释放SDA
	I2C_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通信


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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Kafka 可观测性最佳实践

Kafka 概述 Kafka 是由 LinkedIn 开发一个分布式的基于发布订阅模式的消息队列&#xff0c;是一个实时数据处理系统&#xff0c;可以横向扩展。与 RabbitMQ、RockerMQ 等中间件一样拥有几大特点&#xff1a; 异步处理服务解耦流量削峰 监控 Kafka 是非常重要的&#xff0c;因…

智能制造基础- TPM(全面生产维护)

TPM 前言一、TPM二、TPM实施步骤三、 消除主要问题3.1 实施指南3.2 如何进行“主要问题”的消除&#xff1f; 四、自主维护4.1 实施指南4.2 主要工作内容4.3 如何进行“自主维护“ 五、计划维护5.1 实施指南5.2 如何实施计划维护 六、TPM 适当的 设备 设计5.1 实施指南5.2 如何…

数据库SQLite的使用

SQLite是一个C语言库&#xff0c;实现了一个小型、快速、独立、高可靠性、功能齐全的SQL数据库引擎。SQLite文件格式稳定、跨平台且向后兼容。SQLite源代码属于公共领域(public-domain)&#xff0c;任何人都可以免费将其用于任何目的。源码地址&#xff1a;https://github.com/…

openpyxl处理Excel模板,带格式拷贝行和数据填入

本文中用openpyxl操作Excell 模板,进行行拷贝和数据填充. 主要涉及单元格格式的拷贝,合并单元格的拷贝,行高和列宽的处理. 将模板表格分为三部分,头部,中间循环填充部分,尾部.模板参数中设置头部高度,循环部分高度,剩余为尾部. 拷贝时先拷贝填充头部 ,然后根据数据循环拷贝填…

【FPGA开发】AXI-Lite总线协议解读、Verilog逻辑开发与仿真、Alex Forencich代码解读

目录 AXI是什么AXI是如何工作的AXI-Lite定义AXI-Lite的关键特性AXI-Lite信号列表AXI-Lite信号时序时钟和复位握手机制写请求通道&#xff08;AW&#xff09;写数据通道&#xff08;W&#xff09;写响应通道&#xff08;B&#xff09;读请求通道&#xff08;AR&#xff09;读数据…

zabbix 7.0 安装(服务器、前端、代理等)

https://www.zabbix.com/download 使用上面的地址&#xff0c;按教程执行命令安装

uniapp—android原生插件开发(2原生插件开发)

本篇文章从实战角度出发&#xff0c;将UniApp集成新大陆PDA设备RFID的全过程分为四部曲&#xff0c;涵盖环境搭建、插件开发、AAR打包、项目引入和功能调试。通过这份教程&#xff0c;轻松应对安卓原生插件开发与打包需求&#xff01; ***环境问题移步至&#xff1a;uniapp—an…

【DCCMCI】多模态情感分析的层次去噪、表征解纠缠和双通道跨模态-上下文交互

abstract 多模态情感分析旨在从文本、声音和视觉数据等各种模态中提取情感线索&#xff0c;并对其进行操作&#xff0c;以确定数据中固有的情感极性。尽管在多模态情感分析方面取得了重大成就&#xff0c;但在处理模态表征中的噪声特征、消除模态表征之间情感信息的实质性差距…

【网络安全】线程安全分析及List遍历

未经许可,不得转载。 文章目录 线程线程安全问题遍历List的方式方式一方式二方式三方式四(Java 8)方式五(Java 8 Lambda)遍历List的同时操作ListVector是线程安全的?使用线程安全的CopyOnWriteArrayList使用线程安全的List.forEach线程 线程是程序执行的最小单位。一个程…

基于MFC实现的赛车游戏

一、问题描述 游戏背景为一环形车道图&#xff0c;选择菜单选项“开始游戏”则可开始游戏。游戏的任务是使用键盘上的方向键操纵赛道上的蓝色赛车追赶红色赛车&#xff0c;红色赛车沿车道顺时针行驶&#xff0c;出发点和终点均位于车道左上方。任一赛车先达到终点则比赛结束。…

SpringBoot赋能的共享汽车业务管理系统

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

「QT」几何数据类 之 QLineF 浮点型直线类

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「QT」QT5程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasolid…

Elasticsearch专栏-4.es基本用法-查询api

es基本用法-查询api 说明查询所有某一字段匹配查询多字段查询bool查询范围查询精确查询正则匹配模糊查询结果处理 说明 es对数据的检索&#xff0c;总结下来就是两部分&#xff0c;即查询和处理。查询指的是查找符合条件的数据&#xff0c;包括查询所有、匹配查询、布尔查询、…

讨论一个mysql事务问题

最近在阅读一篇关于隔离级别的文章&#xff0c;文章中提到了一种场景&#xff0c;我们下面来分析一下。 文章目录 1、实验环境2、两个实验的语句执行顺序3、关于start transaction和start transaction with consistent snapshot4、实验结果解释4.1、实验14.2、实验24.3、调整实…

【AIGC】腾讯云语音识别(ASR)服务在Spring Boot项目中的集成与实践

腾讯云语音识别&#xff08;ASR&#xff09;服务在Spring Boot项目中的集成与实践 引言 在现代软件开发中&#xff0c;语音识别技术的应用越来越广泛&#xff0c;从智能助手到自动客服系统&#xff0c;语音识别技术都在发挥着重要作用。腾讯云提供了强大的语音识别服务&#…

基于Spring Boot的工程认证计算机课程管理系统

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理基于工程教育认证的计算机课程管理平台的相…

2024年度国际荐酒师(香港)协会花式马刀开香槟表演赛在穗举行

2024年度国际荐酒师&#xff08;香港&#xff09;协会花式马刀开香槟表演赛在穗举行 近日&#xff0c;一场别开生面的花式马刀开香槟表演赛在广州四季酒店盛大举行&#xff0c;此次活动由国际荐酒师&#xff08;香港&#xff09;协会精心指导&#xff0c;广东海上丝绸之路文化促…

mysql全量与增量备份

binlog日志&#xff1a; 从上一次全量备份到下一次全量备份直接产生的数据。 一、全备和增量备份介绍 1、全量备份&#xff1a; 备份所有数据库或只备份一个数据库&#xff0c;全量备份之后&#xff0c;全量备份之前的binlog日志就没用了&#xff0c;一般生产环境会保留3-7天…

Web前端开发--HTML语言

文章目录 前言1.介绍2.组成3.基本框架4.常见标签4.1双标签4.1.1.标题标签4.2.2段落标签4.1.3文本格式化标签4.1.4超链接标签4.1.5视频标签4.1.6 音频标签 4.2单标签4.2.1换行标签和水平线标签4.2.2 图像标签 5.表单控件结语 前言 生活中处处都有网站&#xff0c;无论你是学习爬…

存算一体化与边缘计算:重新定义智能计算的未来

随着数据量爆炸式增长和智能化应用的普及&#xff0c;计算与存储的高效整合逐渐成为科技行业关注的重点。数据存储和处理需求的快速增长推动了对计算架构的重新设计&#xff0c;“存算一体化”技术应运而生。同时&#xff0c;随着物联网、5G网络、人工智能&#xff08;AI&#…