51单片机快速入门之 IIC I2C通信
51单片机快速入门之 IIC 总线通信
协议:
- 空闲时 SCL/SDA 为高电平
- SCL高时 SDA下降沿 为开始信号
- 开始信号之后:
SCL高电平时 SDA不能变化 ,
SCL低电平时 SDA才可变
SDA 传数据时 从高到低按位传输 SCL一个脉冲高电平对应一位数据
4.SCL高电平时 SDA上升沿 为停止信号
数据格式:
1.单字节格式:
开始信号>数据(高到低)>应答(ACK)信号接收方SDA低电平>停止信号
2.多字节格式:
开始信号>发送设备地址和读写方向>应答(ACK)信号>数据传输>应答(ACK)信号接收方SDA低电平>停止信号
I2C 元器件 24c02(E^2PROM)
读/写操作:
1.单字节写流程:
开始信号>7位地址(1010固 0A 0B 0C)+读1/写0>24C02回复ACK信号>发送一个字节>ACK信号>停止信号
2.页写流程(多字节):
开始信号>7位地址(1010固 0A 0B 0C)+读1/写0>24C02回复ACK信号>发第一个字节数据地址>ACK>第一个字节数据>ACK>第二个字节数据...>一直到停止信号 或者16字节
最多可一次写入2-16字节!
超出会自动从初始位置覆盖数据 17时覆盖第一个字节数据,之后还有数据往后递增覆盖
3.立即地址读操作:
N范围(0~255)00H~FFH
开始信号>7位地址(1010固 0A 0B 0C)+读1/写0>ack回复>读取一个字节数据(上次操作地址N+1的数据)>停止信号
N=255时 下一个跳转读取 0
4.选择读操作:
任选地址读
开始信号>7位地址(1010固 0A 0B 0C)+读1/写0>低0伪写操作>ack>N字节地址>从ack>开始信号>7位地址(1010固 0A 0B 0C)+读1/写0>读信号 1>从ack>获取N地址下的数据>停止信号
5.连续读操作:
立即地址读操作 连续
开始信号>7位地址+读1>读取FFH(255)为第一个数据,>主ACK>00H>主ack...直到出现主ack不回复 停下来>停止信号才结束本次读取
选择读操作 连续
开始信号>7位地址(1010固 0A 0B 0C)+读1/写0>低0伪写操作>ack>N字节地址>从ack>开始信号>7位地址(1010固 0A 0B 0C)+读1/写0>读信号 1>从ack>获取N地址下的数据>ack>N+1数据>ack .....直到停止信号
电路图:
捣鼓了好几天,终于调试通了原来这元器件和书上的不同 所以说还是要多看看元器件数据手册才好,不然出了问题都找不到在哪! 就是这里 地址位我弄错了,书上很模糊所以我理解为
A0 A1 A2 顺序错了 实际上是A2 A1 A0
代码(简单发送):
#include <STC89C5xRC.H>//加载头文件,晶振12MHzsbit SCL=P2^0; //时钟线
sbit SDA=P2^1; //数据线void delay(unsigned int t); // 延时函数声明
void startI2C();//开始信号
void stopI2C();//停止信号void SendByte(unsigned char dat);//发送字节数据void main()
{SendByte(0xA2);//发送从机地址SendByte(0x00);//发送需要存入那个字节的地址 00H~FFHSendByte(0x44); //发送需要存储的数据 P17=0;模拟环境提示操作成功用 ,实际使用可删除while(1); // 防止程序重复运行
}void startI2C() //开始信号
{SDA=1; //首先拉高SDAdelay(10);//给他点时间SCL=1; //拉高SCLdelay(10); //1usSDA=0; //拉低SDA 触发开始信号delay(10); //1usSCL=0; //手动拉低确保时序准确 初始化以接受数据delay(10); //1us
}void stopI2C() //停止信号
{if(SCL==1&&SDA==0) //只有当SCL=1 而且SDA=0时才触发 SDA=0保证已经接受到ACK回复信号{delay(10); //等一会SDA=1; //拉高SDA ,上升沿触发停止信号} else if(SCL==0) //当SCL=0时,这句没啥用其实 ,防止 SCL=0 触发不了停止信号
{delay(10);SCL=1; //把scl 拉高if(SDA==0) //判断是否接收到ACK回复
{delay(10);SDA=1;}}}void SendByte(unsigned char dat)//发送字节数据
{unsigned char bita;startI2C();//发送开始信号for(bita=0; bita<8; bita++) {if((dat<<bita)&0x80) //每次根据bita 的值左移 bita位 再和 0x80(1000 0000) 与操作(只保最高位)
{SDA=1; //如果是1,拉高sda传送一个1 过去} else {SDA=0;// 反之给0}delay(10); //让它们稳定一下SCL=1;//上升读取 因开始信号已经拉低SCLdelay(10); //稳定时间 SCL=0; //下降写入数据 也可以说这是复位delay(10); //稳定时间} SDA=1; //8位传完就拉高等待ACK触发SCL=0; //下降写入数据 保证循环正确输出8位SCL=1; //拉高以配合ACK delay(10);//等待if(SDA!=1) //sda=0 证明 ack已回复 触发停止信号
{stopI2C();P30=0; //模拟环境提示操作成功用 ,实际使用可删除} else {P10=0;//模拟环境提示操作成功用 ,实际使用可删除}}void delay(unsigned int t) // 简单延迟函数
{while(t--);
}
运行效果:
程序设置了一个监视,操作成功会拉低P30
代码(简单读取):
#include <STC89C5xRC.H>sbit SCL=P2^0; //时钟线
sbit SDA=P2^1; //数据线
sbit DQ=P2^4;//读取按键
void delay(unsigned int t); // 延时函数声明
void startI2C();//开始信号
void stopI2C();//停止信号
bit x; //用于存储ACK信息
unsigned char u;void SendByte(unsigned char dat);//发送字节数据void main()
{SendByte(0xA2);//发送从机地址 最后一位置0 写入x=0;SendByte(0x01);//发送字节地址x=0;SendByte(0x66); //发送需要存储的数据if(x==1) {stopI2C(); //停止信号}P1=0;x=0;while(DQ==1);//阻断程序运行,当按钮按下往下执行//按键判断读取并赋值给P1寄存器if(DQ==0) {SendByte(0xA3);//发送从机地址 最后一位置1 实际读取if(x==1) { //表示读取请求被响应unsigned char red,bint;P33=0;red=0;// 在读取数据的循环之前添加SDA释放if(SDA!=1&&SCL!=1) {SDA = 1; // 释放SDA线delay(0);}// 读取数据的循环for(bint=0; bint<8; bint++) {delay(20);//延时等待SCL=0;//读取数据delay(20);//延时等待SCL=1;//delay(20);// 检查SDA状态,并更新red的值if(SDA==1) { //如果读取到高电平red |=1<<(7 - bint); // 设置对应位为1} else {red |=0<<(7-bint);}delay(10);//延时等待}SCL=0;//读取数据delay(10);//延时等待SDA = 1; // nackdelay(10);P1=red;//把获取到的值直接用到P1中stopI2C(); //停止信号}}while(1); // 防止程序重复运行
}void startI2C()
{SDA=1;delay(10);SCL=1;delay(10); //1usSDA=0;delay(10); //1usSCL=0; //手动拉低确保时序准确delay(10); //1us
}void stopI2C()
{if(SCL==1&&SDA==0) {delay(10);SDA=1;} else if(SCL==0) {delay(10);SCL=1;if(SDA==0) {delay(10);SDA=1;}}}void SendByte(unsigned char dat)//发送字节数据
{unsigned char bita;startI2C();//发送开始信号for(bita=0; bita<8; bita++) {if((dat<<bita)&0x80) {SDA=1;} else {SDA=0;}delay(10);SCL=1;//上升读取 因开始信号已经拉低SCLdelay(10);SCL=0; //下降写入数据delay(10);}SDA=1;SCL=0; //下降写入数据 保证循环正确输出8位SCL=1;delay(10);if(SDA==0) {x=1; //有回复为1P30=0;} else {x=0; //无回复为0// P10=0;}}void delay(unsigned int t) // 简单延迟函数
{while(t--);
}
读取运行效果 :
由图可以看出,元器件根本没有回复数据(试过选择地址读取,也没效果) 所以就这样吧!
最后更新于2024/10/24 0:01
相关文章:

51单片机快速入门之 IIC I2C通信
51单片机快速入门之 IIC 总线通信 协议: 空闲时 SCL/SDA 为高电平SCL高时 SDA下降沿 为开始信号开始信号之后: SCL高电平时 SDA不能变化 , SCL低电平时 SDA才可变 SDA 传数据时 从高到低按位传输 SCL一个脉冲高电平对应一位数据 4.SCL高电平时 SDA上升沿 为停止信号 数…...

腾讯推出ima.copilot智能工作台产品 由混元大模型提供技术支持
腾讯公司近期推出了一款名为ima.copilot(简称ima)的智能工作台产品,它由腾讯混元大模型提供技术支持。这款产品旨在通过其会思考的知识库,为用户开启搜读写的新体验。ima.copilot的核心功能包括知识获取、打造专属知识库以及智能写…...
1024是什么日子
【1024程序员日数字编织梦想的赞歌】 在这个由二进制构建的宇宙里,每一行代码都是通往未来的桥梁,每一位程序员都是这浩瀚数字海洋中的航海家。今天,10月24日,不仅是一个简单的日期,它是属于我们的节日——程序员日&a…...
驱动开发系列20 - Linux Graphics Xorg-server 介绍
一: 概述 X.Org Server 是由 X.Org 基金会管理的 X Window System (X11) 显示服务器的自由开源实现。客户端 X Window System 协议的实现以 X11 库的形式存在,这些库作为与 X 服务器通信的有用 API。有两个主要的 X11 库。第一个库是 Xlib,它是最初的 C 语言 X11 API;…...

晶台推出SOP5封装的高速光耦KLM45X,提供1MBit/s超快速率
KLM452 和 KLM453 器件均由一个红外发射二极管与一个高速光电检测晶体管组成,两者之间光学耦合。光电二极管偏置和输出晶体管集电极的独立连接可以通过减少输入晶体管的基极-集电极电容来使速度比传统的光电晶体管耦合器提高几个数量级。它们采用行业内标准的 5 引脚…...

软物质流变探究:从宏观微观差异,到水凝胶界面特性
大家好!今天我们要探讨的是一篇关于纳米级界面水凝胶粘弹性的研究论文——《Nanoscopic Interfacial Hydrogel Viscoelasticity Revealed from Comparison of Macroscopic and Microscopic Rheology》发表于《Nano Letters》,该研究通过比较宏观和微观流…...

Axure中继器单选、多选和重置
亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢! 课程主题:Axure中继器单选、多选和重置 主要内容:根据查询条件,通过单选、多选和重置,从中继器中得到数据 应用场景&…...
微软公司用没有使用证据的商标申请驰名商标,该怎么维权?
收集证据:首先需要收集微软公司商标使用的证据,包括但不限于销售记录、广告宣传材料、市场调查报告等,以证明商标的实际使用情况和知名度。如果微软公司的商标确实没有在市场上使用,或者使用证据不足以证明其商标的知名度…...

学习分布式系统我来助你!【基本知识、基础理论、设计模式、应用场景、工程应用、缓存等全包含!】
基本知识 什么是分布式 分布式系统是一种通过网络连接多个独立计算机节点,共同协作完成任务的系统架构,具有高度的可扩展性、容错性和并发处理能力,广泛应用于大数据处理、云计算、分布式数据库等领域。 通俗来讲:分布式系统就…...

ubuntu查看系统版本命令
查看系统版本指令 在 Ubuntu 操作系统中,您可以使用多个命令来查看系统版本。以下是一些常用的命令: lsb_release -a 这个命令会显示详细的 Ubuntu 版本信息,包括发行版名称、版本号、代号等。lsb_release -acat /etc/os-release 这个命令会显…...

使用yield压平嵌套字典有多简单?
我们经常遇到各种字典套字典的数据,例如: nest_dict {a: 1,b: {c: 2,d: 3,e: {f: 4}},g: {h: 5},i: 6,j: {k: {l: {m: 8}}} } 有没有什么简单的办法,把它压扁,变成: {a: 1,b_c: 2,b_d: 3,b_e_f: 4,g_h: 5,i: 6,j_k_l_…...
express中使用morgan打印请求数据日志文件,按日期分割
使用morgan可以打印日志,但是要分割日志文件就需要使用file-stream-rotator,下面介绍使用方法: 1.安装2个依赖 npm i morgan file-stream-rotator 2.在入口文件app.js中引入相关插件 var express require("express"); var fs require("fs"); var pat…...

干货 | 2024 AI+智慧城市安全解决方案白皮书(免费下载)
导读:新型智慧城市是推动城市治理体系和治理能力现代化、提升城市居民幸 福感和满意度的新理念和新路径,也是网络强国建设和数字经济发展的重要载体。随着 AI 技术的不断发展和在智慧城市智领域广泛的应用,人们享受技 术红利的同时࿰…...
超越 React Query:探索更高效的数据请求策略
我们常常遇到组件间通信的难题。你是否也曾为如何优雅地在组件间传递信息而头疼?今天,我想和大家分享一个让我眼前一亮的解决方案——使用 alova。 跨组件触发请求的挑战 如果你正在构建一个电商应用,用户在更新了购物车后,需要…...

Scala trait
一.trait 基本使用 idea实例 二.实现单个特质 三.实现多个特质 idea实例 四.特质成员的处理方式...
AI大法之C语言哈希表算法比较两个文件去重
最近朋友在工作上遇到了一个问题,经常需要比对两个文件,筛选出文件中不同的订单号。比如有两个文件:计费.txt 和 受理.txt,文件中每一行都是一个订单号,需要找出计费.txt文件中有而受理.txt文件中没有的单号和计费.txt…...
Scala 提取器(Extractor)
Scala 提取器(Extractor) Scala 提取器(Extractor)是一个非常有用的特性,它允许你为任何类型定义自定义的解构赋值语法。在Scala中,提取器是一种用于从对象中提取值的工具,它可以帮助你以一种更直观和声明式的方式处理数据。本文将详细介绍Scala提取器的工作原理、使用场景…...

【主机漏洞扫描常见修复方案】:Tomcat安全(机房对外Web服务扫描)
文章目录 引言I SSL/TLS Not ImplementedTomcat 服务器 SSL 证书安装部署(JKS 格式)Tomcat 服务器 SSL 证书安装部署(PFX 格式)HTTP 自动跳转 HTTPS 的安全配置(可选)修复SSL证书版本低II 主机漏洞扫描常见修复方案Apache JServ protocol serviceSlow HTTP DEnial of Ser…...

MySQL数据库之——事务(Transaction)详解
一、MySQL 事务定义 MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在银行管理系统中,用户张三向李四账户转账的操作,账户转账是一个完整的业务,最小的单元,不可再分,这样,…...

LabVIEW提高开发效率技巧----事件日志记录
在LabVIEW开发中,集成事件日志记录系统是提升程序调试效率和确保系统运行稳定的关键步骤。通过记录关键操作和异常事件,开发人员可以快速定位问题、优化程序性能,并确保系统的稳定性和可靠性。 1. 事件日志的作用 事件日志是指在程序运行过…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

Unity中的transform.up
2025年6月8日,周日下午 在Unity中,transform.up是Transform组件的一个属性,表示游戏对象在世界空间中的“上”方向(Y轴正方向),且会随对象旋转动态变化。以下是关键点解析: 基本定义 transfor…...