I2C总线与AT24C02

目录

I2C总线

I2C总线介绍

I2C电路规范

I2C时序结构

起始与终止

代码理解

发送字节

代码理解

接收字节

代码理解

数据应答

代码理解

I2C的数据据帧

发送数据帧

接收数据帧

发送接收数据帧

AT24C02芯片

AT24C02介绍

引脚及应用电路

内部结构图

AT24C02数据帧

字节写

代码理解

随机读

代码理解

注意:

仿真案例

电路图

keil文件

I2C总线

I2C总线介绍

  • I2C(inter IC BUS)是由Philips公司开发的一种通用数据总线
  • 两根通信线:SCL(Serial Clock)SDK(Serial Data)
  • 同步(有同步时钟线)、半双工(一根串行数据线),带数据应答
  • 通用的I2C总线可以使各种设备的通信标准统一,对于厂家来说,使用成熟的方案可以缩短芯片的设计周期、提高稳定性,对于应用者来说使用通用的通信协议可以避免学习各种各样的自定义协议,降低了学习和应用的难度

I2C电路规范

  • 所有的I2C设备的SCL连在一起,SDA连在一起
  • 设备的SCL和SDA均要配置成开漏输出模式
  • SCL和SDA各添加一个上拉电阻,阻值一般为4.7K欧左右
  • 开漏输出和上拉电阻共同作用实现了“线与的功能”,同时此设计主要是为了解决多机通信互相干扰的问题

理解:

  • CPU让引脚想发0的时候,就把他拉到低电平,CPU让引脚想发1的时候,就让NOMS关闭,那么引脚就会被外部的电源自动拉到高电平。
  • 若所有设备都开漏(都不接地)那么就由两个电阻承担上拉的能力。

I2C时序结构

起始与终止

  • 起始条件:SCL高电平期间,SDA从高电平切换到低电平。
  • 终止条件:SCL高电平期间,SDA从低电平切换到高电平。

代码理解
//I2C的start阶段
void I2C_Start(){
	SDA=1;
	SCL=1;
	SDA=0;
	SCL=0;
}
//I2C的stop阶段
void I2C_Stop(){
	SDA=0;
	SCL=1;
	SDA=1;
}

发送字节

理解:SCL低电平期间,主机将数据位依次放到SDA线上(高位在前)然后拉高SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节。

注意:时序中SDA为数据,所以才可以看到电平的两种状态(电平可高可低)

代码理解
//I2C的发送一个字节s数据(先发高位)
void I2C_SendByte(unsigned char byte){
	unsigned char i=0;
    SCL=0;
	for(i=0;i<8;i++){
		SDA=byte&(0x80>>i);
		SCL=1;
		SCL=0;
	}
}

接收字节

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

注意:紫色的线代表是从机控制的。

代码理解
//I2C的接收数据(先接收高位)
unsigned char I2C_ReceiveByte(){
	unsigned char byte=0,i=0;
	SCL=0;
	SDA=1; //主机释放SDA总线
	for(i=0;i<8;i++){
		SCL=1;
		if(SDA==1){
			byte=byte|(0x80>>i);
		}
	SCL=0;
	}
	return byte;
}

数据应答

  • 发送应答:主机在接收完一个字节后,其将在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答
  • 接收应答:主机在发送完一个字节之后,其在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前需要释放SDA)

代码理解
//I2C发送应答
void I2C_SendAck(unsigned char ackBit){
	SDA=ackBit;
	SCL=1; //写入数据时拉高SCL
	SCL=0;
}
//I2C接收应答
unsigned char I2C_ReceiveAck(){
	unsigned char ackBit=0;
	SDA=1; //主机释放SDA总线
	SCL=1; //scl高电平期间就可以读取数据位了
	ackBit=SDA;
	SCL=0;
	return ackBit;
}

I2C的数据据帧

发送数据帧

前言:发送数据帧描述了要向谁发送什么。

理解:首先发送start起始,然后发送从机地址和读写位(确定是写)之后是从机的接收应答,再者就是主机发送的数据直到终止位。

注意:从机地址为前7位中,前4位是固定的,其他三位可配置,配置方式取决于AT24C02的对应三个引脚的接法;R/W中写数据该位为0,读数据为1。

接收数据帧

前言:接收数据帧描述了向谁收什么。

理解:首先发送start起始,然后发送从机地址和读写位(确定是读)之后是从机的接收应答,从机知道是读后就向主机发送数据了(主机释放SDA),然后就是主机接收数据后发送应答,直到终止位

发送接收数据帧

前言:发送接收数据帧描述了向谁收指定的什么。

理解:首先主机发送起始位,然后发送从机地址和读写位(确定是写)之后是从机的接收应答,接收应答后主机发送指定数据并接收应答,发送完毕后,主机发送起始位开始读,直到最后的终止位

AT24C02芯片

AT24C02介绍

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

引脚及应用电路

内部结构图

理解:右边的最大模块就是我们的E2PROM,就是上面介绍的存储网格,左边跟个地址译码器(对应的线是地址线)下面就是数据的输入输出端(serial mux串行数据选择端数据通过Y译码器将数据一位一位输出出去)而E2PROM上面模块就是数据擦除模块;DATA WORD ADDR/COUNTER(数据字地址计数器)用来设置具体地址的,里面有存储地址的寄存器,我们每写入或读出一个数据,该寄存器会自动加1;左上三个分别为开始结束逻辑,器件地址比较器,串行控制逻辑。

AT24C02数据帧

字节写

前言:在word address处写入数据data。

代码理解
#define AT24C02_ADDRESS 0xA0
//字节写
void AT24C02_WriteByte(unsigned char wordAddress,unsigned char dat){
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);
	I2C_ReceiveAck();
	I2C_SendByte(wordAddress);
	I2C_ReceiveAck();
	I2C_SendByte(dat);
	I2C_ReceiveAck();
	I2C_Stop();
}

随机读

前言:读出在word address处的数据data

代码理解
#define AT24C02_ADDRESS 0xA0
//随机读
unsigned char AT24C02_ReadByte(unsigned char wordAddress){
	unsigned char dat;
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);
	I2C_ReceiveAck();
	I2C_SendByte(wordAddress);
	I2C_ReceiveAck();
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS|0x01);
	I2C_ReceiveAck();
	dat=I2C_ReceiveByte();
	I2C_SendAck(1);
	I2C_Stop();
	return dat;
}

注意:

  • AT24C02的slave address中前4位固定为1010,可配置地址在开发板上为000,所以slave address+w的地址为0xA0;slave address+r地址为0xA1。
  • word address为要发送或读取的芯片内部地址。

仿真案例

需求:将236存储在AT24C02中地址1处,并读出来。

电路图

注意:当在某个地址写入数据后,掉电以后再次开启单片机还可以读出该地址的数据(掉电以后数据不会丢失)

keil文件

#include "reg51.h"
sbit RS=P3^0;
sbit RW=P3^1;
sbit E=P3^2;
void delay(unsigned int n){
	unsigned int i=0,j=0;
	for(i=0;i<n;i++){
		for(j=0;j<120;j++);
	}
}
//写指令
void writecom(unsigned char com){
	//写指令
	RS=0;
	RW=0;
	E=0;
	P2=com;
	delay(5);
	E=1;
	E=0;
}
//写数据
void writedat(unsigned char dat){
	//写指令
	RS=1;
	RW=0;
	E=0;
	P2=dat;
	delay(5);
	E=1;
	E=0;
}
//初始化液晶屏
void initlcd(){
	writecom(0x38);
	writecom(0x0c);
	writecom(0x06);
	writecom(0x01);
}
int LCD_Pow(int X,int Y){
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++){
		Result*=X;
	}
	return Result;
}
//展示数字
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length){
	unsigned char i;
	if(Line==1){
		writecom(0x80|(Column-1));
	}else{
		writecom(0x80|(Column-1)+0x40);
	}
	for(i=Length;i>0;i--){
		writedat('0'+Number/LCD_Pow(10,i-1)%10);
	}
}
//I2C部分
sbit SCL=P3^3;
sbit SDA=P3^4;
//I2C的start阶段
void I2C_Start(){
	SDA=1;
	SCL=1;
	SDA=0;
	SCL=0;
}
//I2C的stop阶段
void I2C_Stop(){
	SDA=0;
	SCL=1;
	SDA=1;
}
//I2C的发送一个字节s数据(先发高位)
void I2C_SendByte(unsigned char byte){
	unsigned char i=0;
	SCL=0;
	for(i=0;i<8;i++){
		SDA=byte&(0x80>>i);
		SCL=1;
		SCL=0;
	}
}
//I2C的接收数据(先接收高位)
unsigned char I2C_ReceiveByte(){
	unsigned char byte=0,i=0;
	SCL=0;
	SDA=1; //主机释放SDA总线
	for(i=0;i<8;i++){
		SCL=1;
		if(SDA==1){
			byte=byte|(0x80>>i);
		}
	SCL=0;
	}
	return byte;
}
//I2C发送应答
void I2C_SendAck(unsigned char ackBit){
	SDA=ackBit;
	SCL=1;
	SCL=0;
}
//I2C接收应答
unsigned char I2C_ReceiveAck(){
	unsigned char ackBit=0;
	SDA=1; //主机释放SDA总线
	SCL=1; //scl高电平期间就可以读取数据位了
	ackBit=SDA;
	SCL=0;
	return ackBit;
}
//AT24C02部分
#define AT24C02_ADDRESS 0xA0
//字节写
void AT24C02_WriteByte(unsigned char wordAddress,unsigned char dat){
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);
	I2C_ReceiveAck();
	I2C_SendByte(wordAddress);
	I2C_ReceiveAck();
	I2C_SendByte(dat);
	I2C_ReceiveAck();
	I2C_Stop();
}
//随机读
unsigned char AT24C02_ReadByte(unsigned char wordAddress){
	unsigned char dat;
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);
	I2C_ReceiveAck();
	I2C_SendByte(wordAddress);
	I2C_ReceiveAck();
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS|0x01);
	I2C_ReceiveAck();
	dat=I2C_ReceiveByte();
	I2C_SendAck(1);
	I2C_Stop();
	return dat;
}
unsigned char redat=0;
void main(){
	initlcd();
	AT24C02_WriteByte(1,236);
	delay(5);	//每次写完后需要延时5ms
	redat=AT24C02_ReadByte(1);
	LCD_ShowNum(2,1,redat,3);
	while(1);
}

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

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

相关文章

Android 高德地图

1.获取Key 进入高德开放平台控制台&#xff0c;创建一个新应用。在创建的应用上点击"添加key"按钮&#xff0c;在弹出的对话框中&#xff0c;依次输入key名称&#xff0c;选择服务平台为“Android平台”&#xff0c;输入发布版安全码 SHA1、以及 Package。 获取 S…

贵州省NPP净初级生产力数据/NDVI数据

数据福利是专门为关注小编博客及公众号的朋友定制的&#xff0c;未关注用户不享受免费共享服务&#xff0c;已经被列入黑名单的用户和单位不享受免费共享服务。参与本号发起的数据众筹&#xff0c;向本号捐赠过硬盘以及多次转发、评论的朋友优先享有免费共享服务。 净初级生产…

Vue3从入门到实战:路由的query和params参数

在Vue 3中&#xff0c;我们可以通过路由的查询参数来传递数据。这意味着我们可以在不同的页面之间传递一些信息&#xff0c;以便页面可以根据这些信息来显示不同的内容或执行不同的操作。 查询参数的使用方式类似于在URL中添加附加信息&#xff0c;以便页面之间可以根据这些信息…

基于springboot+vue实现的酒店客房管理系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;spring…

Redis高可用主从复制与哨兵模式

前言 在生产环境中&#xff0c;除了采用持久化方式实现 Redis 的高可用性&#xff0c;还可以采用主从复制、哨兵模式和 Cluster 集群的方法确保数据的持久性和可靠性。 目录 一、主从复制 1. 概述 2. 作用 3. 主从复制流程 4. 部署 4.1 安装 redis 4.2 编辑 master 节…

Xxxxxx

数据库 1&#xff0c;B树与B树区别 1&#xff0c;B树每个节点存ID与其他数据字段&#xff0c;B非叶子结点&#xff0c;只存ID&#xff0c;叶子结点存完整数据 好处&#xff1a;每个层级B树&#xff0c;可以存储更多的额数据&#xff0c;层级更少&#xff0c;更扁平&#xff…

代码块的理解

如果成员变量想要初始化的值不是一个硬编码的常量值&#xff0c;而是需要通过复杂的计算或读取文件、或读取运行环境信息等方式才能获取的一些值&#xff0c;该怎么办呢&#xff1f;此时&#xff0c;可以考虑代码块&#xff08;或初始化块&#xff09;。 代码块(或初始化块)的作…

【Linux】IO多路转接

文章目录 一、selectselect函数select基本工作流程select的优缺点select的适用场景 二、pollpoll函数poll的优缺点 三、epollepoll相关系统调用epoll工作原理epoll的优点epoll工作方式对比LT和ET 一、select select是系统提供的一个多路转接接口。 select系统调用可以让我们的…

(echarts)vue中循环生成多个相同的echarts图表,但数据动态、第一次渲染失败问题

(echarts)vue中循环生成多个相同的echarts图表&#xff0c;但数据动态 效果&#xff1a; 代码&#xff1a; <!-- 动态图表 --> <el-row :gutter"20"><el-col v-for"(item,index) in echartsList" :key"index" :span"10&quo…

wordpress课程项目主题电脑版+手机版自适应

这款主题适合做资源、课程、素材等&#xff0c;演示站&#xff1a;点击查看

openwrt开发包含路由器基本功能的web问题记录

1.这里的扫描怎么实现的先找一些luci代码&#xff0c;在openwrt21版本后&#xff0c;luci用js替换了lua写后台&#xff0c;先找一些代码路径 在openrwt15这部分代码是在这个目录下 feeds/luci/modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_join.htm 里面包含…

javaWeb旅游网站设计

一、概述 1.1 项目研究背景 社会经济的发展和提高潜移默化的影响了人们对精神消费的日益看中与提高&#xff0c;所以越来越多的人们开始选择更健康有趣的生活活动&#xff0c;随之而来的旅游便成了人们消费的必选。随着旅客需求的日趋丰富和个性化&#xff0c;这势必将推动我…

理解main方法的语法

由于JVM需要调用类的main()方法&#xff0c;所以该方法的访问权限必须是public&#xff0c;又因为JVM在执行main()方法时不必创建对象&#xff0c;所以该方法必须是static的&#xff0c;该方法接收一个String类型的数组参数&#xff0c;该数组中保存执行Java命令时传递给所运行…

【零基础C语言】编译和链接

1.翻译环境和运行环境 翻译环境&#xff1a;将源代码转化为可执行的机器指令 运行环境&#xff1a;用于执行机器指令 1.1 翻译环境 翻译环境由编译和链接两大过程构建&#xff0c;编译又可以分为三大过程&#xff1a; 【1】预处理(预编译) 【2】编译 【3】汇编 不同的.c文件经…

计算机网络_工具

从你的电脑到指定ip网站&#xff0c;用时3ms ttl TTL Time To Live 数据包存活时间 指一个数据包在经过一个路由器时&#xff0c;可传递的最长距离&#xff08;跃点数&#xff09;。每当数据包经过一个路由器时&#xff0c;其存活次数就会被减一 256 - 249 7&…

什么!Intel/AMD/Apple Silicon也能本地部署的Llama工具来了

主流的LLM都需要通过CUDA才能高效的运行在本地&#xff0c;但是随着Github上出现了Llama.cpp这个神器&#xff0c;一切都改变了。它通过AVX指令和MPI来实现CPU上并行计算&#xff0c;从而在本地计算机高效地运行各种主流的类Llama模型。同时它也支持metal&#xff0c;使得Apple…

Mybatis的SQL高级查询与各符号用法

test语句里面的logparam是Mapper层传入的参数&#xff0c;读取logparam的属性不用再用#{}符号表示。 如果需要计算的式子很长&#xff0c;那么可用${}表示里面的式子是计算式&#xff0c;需要进行计算操作。同样不用通过#{logparam.Page}来读取logparam的Page属性的值&#xff…

第19次修改了可删除可持久保存的前端html备忘录:换了一个特别的倒计时时钟

第19次修改了可删除可持久保存的前端html备忘录:换了一个特别的倒计时时钟 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><met…

合同约定的绩效奖金说不给就不给了, 这合法吗?

目录 一、北京海淀法院参考案例 二、关于绩效奖金的性质&#xff1f; 三、绩效奖金应否发放取决于哪些因素&#xff1f; 四、员工如何举证与质证 五、提前离职的员工 是否享受当年度绩效奖金&#xff1f; 一、北京海淀法院参考案例 https://mp.weixin.qq.com/s/sq0mFCC8M…

微信开发者工具编译后,页面空白,Wxml内容为空

最近遇到了一个奇怪的问题&#xff0c;使用的uniapp运行的微信小程序&#xff0c;改动代码保存后页面就变成空&#xff0c;接口调用一切正常&#xff0c;Wxml内容为空。如下图 重新编译后&#xff0c;偶尔会报这个错误 根据错误提示&#xff0c;尝试了以下方法也没有用。 更…