IIC协议

news2025/1/10 11:05:01

1.认识IIC

1、IIC协议概述:

  • IIC(Inter-Integrated Circuit,集成电路总线)是一种串行通信协议,也被称为I2C协议。它是由荷兰的PHILIPS公司(现在philips公司将其半导体部门拆分出来并更名为NXP半导体公司)在1982年开发的一种简单、高效的通信协议。
  • IIC协议主要用与连接电路之间进行短距离的数字通信,比如连接微控制器及其外围设备。
  • IIC协议使用两线式串行总线。
  • IIC有点像串口,但是串口是全双工,但是IIC属于半双工同步通信方式,数据传输线只有一根,传输和接收要去占用SDA线。

2、IIC协议特点:

  1. 简单性:IIC协议只使用了两根信号线,并且由于接口直接在组件之上,因此IIC总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本。能够支持40个组件。
  2. IIC协议的通信速率:在一些特定的应用或特定的环境下(比如用于学习),为了提供高通信的稳定确定性和可靠性,某些设备或系统选择将IIC协议的传输速率限制在较低的速率,例如10 Kbps。但它并不代表IIC协议的最大通信速率就是10 Kbps。根据协议版本不同IIC协议的通信速率会有不同,标准模式的IIC协议支持最大传输速率为100 Kbps,快速模式则为 400 Kbps,高速模式则为 3.4 Mbps。
  3. 多主控(multimastering):其中任何能够进行发送和接收的设备都可以成为主控设备,这些主控设备可以是MCU、OLED、手持传感器、陀螺仪等其他I2C接口器件(如下图),这些I2C接口器件都共用这两根串行总线。当然,在任何时间点上只能有一个主控。主控设备负有责任发起和控制通信,它可以向其他设备发送命令、读取数据,并负责协调总线上的通信活动。其他设备被称为从属设备(Slave Device),它们被主控设备控制并响应主控设备的命令。从属设备不能主动发起通信,而正在主控设备的指示下进行相应的操作。因此,虽然任何设备都可以作为IIC协议中的主控设备,但在实际应用中,根据设备的功能和设计,选择合适的设备作为主控设备,其他设备则作为从属设备,以满足通信需求和数据交换的要求
  4. 硬件地址查找:每个从设备在总线上都有唯一一个硬件地址,主设备通过这个地址来选择与之通信的从设备。

3、IIC协议构成:IIC协议是两线式串行总线,两根信号线分别是数据线SDA和时钟线SCL。所有用IIC通讯的设备都需要遵循相同的通讯时序。

  1. SDA(Serial Data Line,数据线):用于传输数据。
  2. SCL(Serial Clock Line)时钟线:用于传输时间信息,时钟信号是由主控器件产生的。

  • 在时间信息的控制下,主设备(如微控制器)可以与多个从设备(如传感器、存储器、显示器等)进行双向通信。
  • 所有接到IIC总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。对于并联在一条总线上的每个IC都有唯一的地址。

4、单片机使用IIC协议的注意点:

  1. 由于51单片机开发板上刚好有硬件串口,也就是有与串口对应的寄存器支持,所以,51单片机的串口通信协议(波特率、数据位、起始位、停止位)是通过配置寄存器来完成的。
  2. 但是51单片机上没有IIC这种硬件设备,所以无法通过配置寄存器来驱动串行通信协议,需要分析I2C接口器件时序后转化为代码,通过I/O口来模拟IIC协议(类似于LCD模块、DHT11模块这些非标协议)。
  3. 接下来,我们以51单片机作为主设备,以OLED屏幕作为从设备,连接方式是直连。当然如果有多个从设备,那么就需要用到面包板,实现如上图中并联的效果。
  4. C语言在调用函数时有一个压栈和弹栈的过程,所以即使你调用的函数什么也没有做,在晶振为11.0592MHz的情况下,也需要耗费5微秒的时间。而单片机中_nop()_就是一个空函数,一个nop的耗时为5微秒。

5、IIC总线的信号类型:IIC总线在传输数据的过程中一共有三种类型信号,分别为:开始信号、结束信号和应答信号。

  • 类似于串口,多机通讯无非要关注:起始位,停止位,数据位,波特率。
  • 那么在IIC协议中,开始信号就相当于设置起始位,结束信号就相当于设置停止位,程序中根据时序图通过延时等方法去控制时间点相当于设置波特率。

6、分析时序图的正确逻辑:回顾DHT11模块的时序分析,我们做的还不好,正确的分析逻辑应该如下。

  1. 对总线上的信号进行分类:因为不同信号的表达方式是不一样的,比如启动信号是置高低电平,响应信号是被拉成高低电平。分类完成后的每部分信号都是总体通讯时序图中的一部分。
  2. 在每种信号时序上标注字母:每种信号时序图上可能有多个数据线,所以标注的点最好划分的细致一点
  3. 三步骤读时序图:读时序图关注开始、转折、结尾。读的时候进行记录,可以使用“置高/低电平”、“电平被拉高/低”、“从低/高电平转折为高/低电平”、“维持高/低电平”、“延时”、“卡x点,直到数据线变成高/低电平”等字眼帮助判断。
  4. 编写代码:将时序逻辑复制到代码编辑器中,照着时序分析写代码(一个时序分析完之后就进行一次函数封装)。
  • 注意:当时序图中总线多的时候(比如LCD1602的读写时序图中有4根总线),那么就需要先查看引脚说明。

2.IIC协议通讯时序分析1:起始、终止、应答

1、起始信号:

  1. o点:
    1. SCL置高电平
    2. SDA置低电平
  2. a点:
    1. SCL维持高电平
    2. SDA从低电平转折为高电平,时间未知
  3. a—>b:
    1. SCL维持高电平
    2. SDA延时4.7微秒
  4. b—>c:
    1. SCL维持高电平
    2. SDA从高电平转折为低电平,时间未知
  5. c—>d:
    1. SCL延时4微秒
    2. SDA维持低电平
  6. d点:
    1. SCL从高电平转折为低电平,时间未知
    2. SDA维持低电平
  7. void IIC_Start()
    {
        // a点:
        scl = 1;    // SCL置高电平
        sda = 1;    // SDA从低电平转折为高电平,时间未知
        // a—>b:
                    // SCL维持高电平
        _nop_();    // SDA延时4.7微秒
        // b—>c:
                    // SCL维持高电平
        sda = 0;    // SDA从高电平转折为低电平,时间未知
        // c—>d:
        _nop();    // SCL延时4微秒
                    // SDA维持低电平
        // d点:
        scl = 0;    // SCL从高电平转折为低电平,时间未知
                    // SDA维持低电平
    }

2、终止信号:

  1. o点:
    1. SCL置低电平
    2. SDA置低电平
  2. a点:
    1. SCL从低电平转折为高电平,时间未知
    2. SDA维持低电平
  3. a—>b:
    1. SCL维持高电平
    2. SDA延时4微秒
  4. b—>c:
    1. SCL维持高电平
    2. SDA从低电平转折为高电平,时间未知
  5. c—>d:
    1. SCL维持低高电平
    2. SDA延时4.7微秒
  6. d点:
    1. SCL维持高电平
    2. SDA从高电平转折为低电平,时间未知
  7. void IIC_Stop()
    {
        // a点:
        scl = 1;    // SCL从低电平转折为高电平,时间未知
        sda = 0;    // SDA置低电平
        // a—>b:
                    // SCL维持高电平
        _nop_();    // SDA延时4微秒
        // b—>c:
                    // SCL维持高电平
        sda = 1;    // SDA从低电平折为高电平,时间未知
        // c—>d:
                    // SCL维持低高电平
        _nop_();    // SDA延时4.7微秒
        // d点:
                    // SCL维持高电平
        sda = 0;    // SDA从高电平转折为低电平,时间未知
    }

3、应答信号ACK:应答信号的时序图如下图所示,由于SDA是被读量,所以只在SCL数据线上划分点。

  • 目的:IIC的设计是当SDA和SCL总线上连接有上拉电阻(电平被拉高)时,实际上是不走数据的,也就是释放数据线。在从设备收到完整的一个字节(8位)之后,就主动去拉低SDA总线上的电平,代表接收器成功地接收了该字节。
  • 响应形式:
    • 应答信号为低电平时,规定为有效应答位(ACK,Acknowledgement Character,简称应答位),表示接收器已经成功地接收了该字节;
    • 应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
  1. o点:
    1. SCL置低电平
    2. SDA:在主控设备发送完成一个字节数据后,就立马发送一个高电平,代表释放SDA数据线
  2. o—>a:
    1. SCL延时
  3. a点:
    1. SCL从低电平转折为高电平,代表释放SCL数据线
  4. a—>b:
    1. SCL延时4微秒,因为读取SDA的时候一定要保证SCL处于高电平的状态
    2. SDA被读
    3. SCL延时4微秒,因为读取SDA的时候一定要保证SCL处于高电平的状态
  5. b点:
    1. SCL从高电平转折为低电平
  6. b—>c:
    1. SCL延时
  • 实际上我们不是很关心ACK函数,只有在后面显示出问题了,比如说显示乱码了才会去调用这个函数进行判断。
    void IIC_ACK()
    {
        char flag;
        // o点:
                    // SCL置低电平
        sda = 1;    // SDA:在主控设备发送完成一个字节数据后,就立马发送一个高电平,代表释放SDA数据线
        // o—>a:
        _nop_();    // SCL延时
        // a点:
        scl = 1;    // SCL从低电平转折为高电平,代表释放SCL数据线
        // a—>b:
        _nop_();    // SCL延时4微秒,因为读取SDA的时候一定要保证SCL处于高电平的状态
        flag = sda; // SDA被读
        _nop_();    // SCL延时4微秒,因为读取SDA的时候一定要保证SCL处于高电平的状态
        // b点:
        scl = 0;    // SCL从高电平转折为低电平
        // b—>c:
        _nop_();    // SCL延时
        return flag;
    }

3.IIC协议通讯时序分析2:数据发送

1、回顾串口和LCD的数据发送:

  • 在学习串口的时候,我们不去关心数据的发送需要根据数据发送时序图写什么代码,只需要往SBUF里面传输数据就可以了,这是因为单片机上有对应的寄存器硬件;
  • 在学习LCD1602的时候,我们也不去关心数据的发送需要根据写操作时序图写什么代码,只需要往单片机的P0这个I/O口组(和LCD的DB0~DB7相连)里面传输数据就可以了,这也是因为有硬件。
  • 二者相同点:数据传输伴随着一个脉冲信号。
    • 串口发送数据时,脉冲信号由串行移位寄存器SHIFT提供:
      • SHIFT为低电平时进行一位数据的发送;
      • SHIFT由低变高(上升沿)代表发送结束;
      • SHIFT为高电平时允许数据翻转;
      • SHIFT由高变低(下降沿)代表开始发送下一位数据。
    • LCD发送数据时,脉冲信号由使能引脚E提供:
      • 在E由低变高(上升沿)之前就开始发送一字节数据;
      • 一字节数据发送完毕之后E由高变低(下降沿)。

 

 

2、IIC数据发送的时序:

  1. 与起始/终止信号的区别:IIC在进行数据发送的时候,需要注意:
    1. 在SCL为高电平时,允许SDA上进行一位数据的传输,期间不允许数据的翻转;
    2. 在SCL为低电平时,允许数据的翻转。
    3. 如果在SCL为高电平时出现了SDA上数据的翻转,那么IIC接收器会误以为这是起始信号或终止信号。所以每次SDA上进行数据翻转前都要保证SCL处于低电平。
  2. 时序逻辑
    1. o点:
      1. SCL置低电平:允许数据翻转
      2. SDA发送1bit数据
    2. o—>a:
      1. SCL延时5微秒
      2. SDA正在发送数据
    3. a点:
      1. SCL从低电平转折为高电平
    4. a—>b:
      1. SCL延时5微秒
      2. SDA正在发送数据
    5. b点:
      1. SCL从高电平转折为低电平:为下一次数据翻转做准备
    6. b—>c:
      1. SCL延时5微秒

 

3、IIC协议发送一个字节数据:

  1. 编程逻辑:我们用字符型变量cdata来保存8bit的待发数据。
    1. cdata从哪里来?答:函数传递。
    2. 怎么往SDA线上发1个字节?答:将cdata的每一bit依次传输给sda,共传输8次。
  2. 前提:基于SDA总线数据传输时高位先出的原则。不同的数据传输方法对应不同的读取方式。
  3. 方法:不同于串口的数据位是低位在先,IIC的数据位是高位在先。根据高位先出的原则,每次从SDA发送出去的都是字符型变量cdata的最高位。
    1. 让cdata位与上二进制数1000 0000,即十六进制的0x80(按位运算):这是取位技巧,将取到的最高位结果发送给SDA。
    2. 传输完1bit后让cdata进行左移1位(移位运算):剔除cdata的最高位。

     

  4. void IIC_Send_Byte(char cdata)
    {
        int i;
        for(i=0; i<8; i++){
            // o点:
            scl = 0;            // SCL置低电平:允许数据翻转
            sda = cdata & 0x80; // SDA发送1bit数据
            // o—>a:
            _nop_();            // SCL延时5微秒
                                // SDA正在发送数据
            // a点:
            scl = 1;            // SCL从低电平转折为高电平
            // a—>b:
            _nop_();            // SCL延时5微秒
                                // SDA正在发送数据
            // b点:
            scl = 0;            // SCL从高电平转折为低电平:为下一次数据翻转做准备
            // b—>c:
            _nop_();            // SCL延时5微秒
            cdata = cdata << 1;
        }
    }

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

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

相关文章

KVM虚拟化技术学习-KVM管理

二&#xff0c;KVM管理 1.升级配置 1.创建一个空磁盘卷 [rootlocalhost ~]# qemu-img create -f qcow2 /kvm/images/disk2.qcow2 5G Formatting disk2.qcow2, fmtqcow2 size5368709120 encryptionoff cluster_size65536 lazy_refcountsoff 2.修改配置文件 <disk typefi…

SpringCloudAlibaba整合分布式事务Seata

文章目录 1 整合分布式事务Seata1.1 环境搭建1.1.1 Nacos搭建1.1.2 Seata搭建 1.2 项目搭建1.2.1 项目示意1.2.2 pom.xml1.2.2.1 alibaba-demo模块1.2.2.2 call模块1.2.2.3 order模块1.2.2.4 common模块 1.2.3 配置文件1.2.3.1 order模块1.2.3.2 call模块 1.2.4 OpenFeign调用1…

想要成为一个性能测试工程师需要掌握哪些知识?

如果想要成为一个性能测试工程师需要掌握哪些知识&#xff1f; 可以看看下方教程&#xff01; 2023年最新版Jmeter性能测试项目实战讲解&#xff0c;从入门到精通价值8888的实战教程_哔哩哔哩_bilibili2023年最新版Jmeter性能测试项目实战讲解&#xff0c;从入门到精通价值888…

idea不识别yml文件了

添加上这两个就好了

recurdyn实用操作

目录 1.剖视图查看 2.自动重复操作 3.多个面生成FaceSurface 4.查看质心&#xff0c;质量坐标工具Mass 5.履带仿真建立其他特征路面 6.joint单位 7.创建样条插值函数AKISPL 8.导出结果曲线数据 9.后处理各名称含义 1.剖视图查看 取消剖视图需要重新进入&#xff0c;取…

Redis的ZipList和QuickList和SkipList和RedisObject(未完成)

ZipList:压缩列表&#xff0c;为了节省内存而设计的一种数据结构 ZipList是一种特殊的双端链表&#xff0c;是由一系列的特殊编码的连续内存块组成&#xff0c;不需要通过指针来进行寻址来找到各个节点&#xff0c;可以在任意一端进行压入或者是弹出操作&#xff0c;并且该操作…

C# | 凸包算法之Andrew‘s,获取围绕一组点的凸多边形的轮廓点

C#实现凸包算法之Andrew’s 文章目录 C#实现凸包算法之Andrews前言示例代码实现思路测试结果结束语 前言 这篇关于凸包算法的文章&#xff0c;本文使用C#和Andrew’s算法来实现凸包算法。 首先消除两个最基本的问题&#xff1a; 什么是凸包呢&#xff1f; 凸包是一个包围一组…

上海城市开发者社区小聚有感

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是Rockey&#xff0c;不知名企业的不知名Java开发工程师 &#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44d;三连支持&#x1f44d;一下博主哦 &#x1f4dd;联系方式&#xff1a;he18339193956&…

JAVAWEB(上)

一、HTML和CSS 1.盒子 2.表单 3.机器人回答&#xff1a; 3.1 label标签 <label>标签用于关联表单元素和文本标签&#xff0c;通过为表单元素定义文本标签&#xff0c;可以使表单更易于使用和访问。它的基本语法如下&#xff1a;<label for"input_id">…

LeetCode高频算法刷题记录9

文章目录 1. 二叉树的最大深度【简单】1.1 题目描述1.2 解题思路1.3 代码实现 2. 对称二叉树【简单】2.1 题目描述2.2 解题思路2.3 代码实现 3. 二叉树的直径【简单】3.1 题目描述3.2 解题思路3.3 代码实现 4. 验证二叉搜索树【中等】4.1 题目描述4.2 解题思路4.3 代码实现 5. …

基于51单片机的项目作品汇总

篇记录下自己做的项目作品&#xff0c;作品有实物也有仿真&#xff0c;以实物居多&#xff0c;主要是以单片机为主&#xff0c;单片机有HC32,STM32,STC,51等&#xff0c;本人从事单片机行业5年&#xff0c;拥有丰富的经验。也涉及QT&#xff0c;LVGL&#xff0c;嵌入式&#xf…

Java学习笔记20——常用API

常用API 常用APIMath类Math的常用方法 System类System类常用方法 Object类Object类常用方法 Arrays类Arrays常用方法 基本类型包装类Integer类的概述和使用int和String的相互转换自动装箱和拆箱 日期类Date类Date类的常用方法 SimpleDateFormat类SimpleDateFormat的构造方法Sim…

C++ priority_queue

C priority_queue &#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;C &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 本博客主要内容讲解了优先队列的对应接口的使用 文章目录…

APT(Advanced Persistent Threat高级持续性威胁)——网络安全

APT&#xff08;高级持续性威胁&#xff09; 特点攻击过程防御策略与APT相关的加密技术&#xff08;学习侧重&#xff09; 网络安全APT&#xff08;Advanced Persistent Threat高级持续性威胁&#xff09;是一种复杂的网络攻击&#xff0c;旨在长期潜伏在目标网络中&#xff0c…

【线程池】Java线程池的核心参数

目录 一、简介 二、构造方法 三、线程池的核心参数 3.1 corePoolSize 线程池核心线程大小 3.2 maximumPoolSize 线程池最大线程数量 3.3 keepAliveTime 空闲线程存活时间 3.4 unit 空间线程存活时间单位 3.5 workQueue 工作队列 ①ArrayBlockingQueue ②LinkedBlocki…

嵌入式Linux中pinctrl 子系统和 gpio 子系统分析

目录 1、gpio 子系统 API 2、pinctrl 子系统 API 本文讲解 pinctrl 子系统和 gpio 子系统的 API&#xff0c;以及使用示例。 传统的配置 pin 的方式就是直接操作相应的寄存器&#xff0c;但是这种配置方式比较繁琐、而且容易出问题(比如 pin 功能冲突)。pinctrl 子系统就是为…

Linux :: 【基础指令篇 :: 文件及目录操作:(2)】::Linux操作系统的文件“框架”、绝对路径与相对路径及路径定位文件对象的解释

前言&#xff1a;本篇是 Linux 基本操作篇章的内容&#xff01; 笔者使用的环境是基于腾讯云服务器&#xff1a;CentOS 7.6 64bit。 学习集&#xff1a; C 入门到入土&#xff01;&#xff01;&#xff01;学习合集Linux 从命令到网络再到内核&#xff01;学习合集 本篇内容&am…

Linux常见IO模型

这篇博客开始我们Linux的最后一个章节--常见IO模型&#xff0c;在之前的博客当中我们讲述过Linux中基础的IO操作&#xff0c;欢迎大家去阅读。 我们通常指的IO操作便是数据的输入和输出&#xff0c;对应的具体操作过程我们可以将其分为两个步骤&#xff1a;等待IO就绪和数据拷…

Eclipse教程 Ⅵ

今天分享Eclipse Java 构建路径、Eclipse 运行配置(Run Configuration)和Eclipse 运行程序 Eclipse Java 构建路径 设置 Java 构建路径 Java构建路径用于在编译Java项目时找到依赖的类&#xff0c;包括以下几项&#xff1a; 源码包项目相关的 jar 包及类文件项目引用的的类…

postgresql 内核源码分析 语法解析 gram.y

专栏内容&#xff1a;postgresql内核源码分析个人主页&#xff1a;我的主页座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物&#xff0e; 目录 前言 概述 流程简介 调用流程 语法解析详细分解 raw_parser的主流程 词法…