0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

I2C的使用说明

454398 来源:网络整理 作者:网络整理 2019-11-13 09:20 次阅读

步骤1:什么是I2C-1

I2C的使用说明

I2C(内部集成电路总线),最初是由Phillips(现为NXP Semiconductor)开发的,并且通常由Atmel和其他有条件的公司称为TWI(两线接口) 两线式同步串行总线是我们不想涉及的商标问题。让我们看一下每个单词的含义:

两根线-这很简单,I2C使用两根线(当然,除了地线!),它们被称为 SDA (串行数据)和 SCL (串行时钟)。它们以漏极开路配置进行接线,这意味着所有连接设备的输出不能直接输出逻辑电平1(高电平),而只能拉低(接地),输出低电平。 0)。为了使线路变高,所有设备都释放其对线路的拉力,并在线路和正轨之间的上拉电阻器将电压上拉。好的上拉电阻应为 1-10K欧姆,该电阻应足够低,以至于所有设备都可以将信号视为高电平,但又足够高,可以很容易地将其短路(拉低),而不会导致损坏或大量用电。 SDA上有一个上拉电阻,SCL上有一个上拉电阻。

同步-这意味着数据传输通过存在于所有连接的时钟信号进行同步设备。这是由主机生成的。相比之下,异步串行系统没有时钟信号。相反,它使用预定的时基或波特率。异步串行的一个示例是RS-232(许多计算机上的通用串行端口)。

串行-串行传输的数据表示一次通过一根电线传输一位数据。相比之下,并行数据传输有多条导线,每条导线都包含一个位,所有这些导线都被一次采样以并行传输多个位。

总线-总线是一种允许许多设备执行以下操作的系统:通过单条电线相互通信。尽管可以将其称为总线,但是USB硬件级别上并不是真正的总线,因为连接多个设备需要集线器。诸如I2C之类的总线允许简单地通过将它们的SDA和SCL连接连接到现有线路来添加新设备。总线(I2C,USB,PCI等)均使用寻址系统,其中每个设备都具有唯一地址。在这种情况下,地址只是一个二进制数,到该设备的所有消息都必须使用该地址发送。

步骤2:什么是I2C-2

在I2C总线上,有主机和从机。主机启动连接,而从机必须等待主机寻址才能发送或接收任何内容。 I2C具有多主机功能,这意味着可能存在多个主机,并且如果两个主机同时尝试传输,则它们必须执行仲裁以纠正问题。本教程不会介绍多主机配置,但应注意它们确实存在。

主机可以请求从主机发送或接收数据。在发送期间,主机将数据写入总线,而从机则从总线读取数据并将其存储在其内存中。在接收期间,主机读取总线上从机发送的数据。在这两种情况下,主设备都会在SCK上提供时钟信号。

在I2C总线上传输的每个字节(即8位)的末尾,接收设备必须提供一个确认(ACK)。唯一不会发生这种情况的时间是主机从从机接收数据时,主机会以不确认(NACK或NAK)结束传输,指示从机应停止发送数据。 ACK由低(下拉或0)状态表示,而NACK由高(下拉或1)状态表示。由于总线的默认状态为高,因此ACK确认存在另一个设备并已成功处理了传输。

除了ACK和NACK之外,I2C还具有两个另外的成帧条件,称为起始条件和停止条件。主机发送开始条件以指示传输开始。在开始转换期间,SDA线首先从高电平转换为低电平,然后在一段明显的时间后,SCL执行相同的操作。主机在传输结束时发出的停止条件是相反的。首先,SCL线从低变高,然后,SDA执行相同的操作。请注意,当总线不活动时,SDA和SCL线都为高电平。

I2C传输中的第一个字节是地址字节。这是由主机发送的,用于确定与哪个从机通信以及是否执行发送或接收(分别称为写和读)。从机地址是7位长,并且有几个保留地址。这样的保留地址之一是0x00,通常被认为是全局写入(写入所有从站)。通常,您可以通过将地址选择引脚连接到高电平或低电平来配置从设备的地址,尽管在微控制器上可以像在ATTiny2313上那样通过编程方式设置地址。地址字节的最低有效位是“读/写”位,它指示执行读还是写操作。如果为1,则该操作为读取,如果为0,则为写入。

步骤3:什么是I2C-3

基本上涵盖了I2C协议本身,因为主机可以启动读取或写入,然后继续传输,直到主机发送停止条件为止。当主机从从机读取数据时,它将在停止条件之前在最后一个字节上发出NACK而不是ACK,以指示已完成接收。从这里开始,通过正确的实施,您可以与所需的所有设备进行通信。但是,我还需要指出一件事,因为它经常使用。

在某些I2C设备上(或者我应该说最多,这很常见),访问协议设置为注册银行。要从这些寄存器读取或写入,必须首先编写一个内部地址,该地址是您希望读取或写入的寄存器的地址。写入内部地址后,您可以读取或写入多个字节,并且内部地址将随每个字节递增。这是几乎所有I2C存储设备以及大多数传感器和I/O扩展器的首选协议。虽然可能有一个不遵循寄存器组协议的协议,但绝大多数设备都遵循该协议,并且围绕它构建了许多I2C工具。因此,值得指出。这也是我将在ATTiny2313上实现的协议。

如前所述,在读取或写入任何寄存器之前,您必须发送设备内部地址,这是通过执行以下操作来完成的:一个字节,其中包含内部地址。对于写操作,传输可以继续进行数据值,数据值中的第一个将存储在所需的地址中,并且任何其他字节每次都将递增一个。对于读取,主机将发送停止条件,然后开始新的传输以进行读取。这是因为您不能在同一传输中同时进行写操作和读操作。在某些情况下,可以发送重复开始而不是先停止再开始。 重复开始是SCL为高时SDA上的从高到低过渡。

步骤4:ATTiny USI I2C代码实现-概述

在本教程的这一点上,您至少应该基本熟悉I2C协议。现在,我将详细介绍ATTiny USI硬件的实际I2C协议实现。

为此,本步骤主要图片中显示的板是定制的单极步进电机控制器,我将其设计为自己的一部分。今年春季的高级项目。该板能够以PWM,可变速度和三种不同的步进模式(单步,功率步进和半步)驱动单个单极步进电机。它也可以突发运行,因为控制器将仅以给定的步数运行电动机。对于连续操作,步进计数器必须在其达到零之前通过驱动板的任何东西重新加载。这对本教程来说都不重要。

这里的重要部分是这些板提供动力的机器人具有三个轮子(全向轮子,以三角形模式排列)。我想构建三个相同的板,但仅使用机器人主计算机(笔记本电脑)中的单个RS-232串行接口来控制全部三个。我想到的想法是使用串行端口连接计算机接口和I2C总线来连接所有三个板。在此设置中,连接到PC的板除了充当从节点之外,还承担着主角色。然后,PC将I2C格式的消息发送到总线上,以使这三块板得以运行。

对于此任务,我的板将必须支持两种 I2C模式,并且必须能够同时使用 slave 和 master ,具体取决于串行端口的操作。一般而言,我对USI硬件了解甚少,而对I2C协议了解甚少,因此我着手掌握I2C协议,使其成为我的从属设备并命令它进行数据传输。而且我做到了,并且在该项目中效果很好。

直到我至少拥有Raspberry Pi为止,因为当我终于开始玩Pi时,我尝试将I2C电机板连接到其I2C端口以尝试使用Pi驱动的机器人。不幸的是,无论我发送了什么命令,Pi都无法进行通信。由于我从未在自己的主代码与自己的从代码进行对话之外验证过协议,因此我认为自己并不是在正确地实现协议,因此坐下来使其全部正常工作。我做到了,新代码更加精简,井井有条,而且易于理解(任何想学习的人都赞不绝口!)。由于进入I2C世界的旅程很艰难,因此我决定在此处发布消息,以供所有人查看,并尽我所能详细说明I2C的功能。

在接下来的几步中,我将讨论USI硬件及其作为主机和从机的工作方式。我还附加了我的USI代码文件。我希望人们拥有良好的USI实现,也希望他们阅读它的工作原理,确切地了解发生的情况对于处理复杂的低级系统至关重要,因此,我对文件进行了完整的评论。

步骤5:ATTiny USI I2C代码实现-USI硬件

因此,在看代码之前,让我们看一下数据表即可。具体来说,我正在查看ATTiny2313数据表,因为这是我使用的芯片,但是在许多不同的ATTiny型号中都可以找到相同的USI硬件。请注意,芯片之间的输出引脚可能有所不同,但否则硬件的工作方式相同,寄存器也相同。

USI硬件具有三个引脚:

DO-数据输出,仅用于三线(SPI)通信模式

DI/SDA-数据输入/串行数据,在I2C配置中用作SDA

USCK/SCL-时钟,在I2C配置中用作SCK

,USI硬件具有三个寄存器:

USIDR-USI数据移位寄存器-将数据移入和移出USI硬件

USISR-USI状态寄存器-具有状态标志和 4位计数器(详情请参见下文)

USICR-USI控制寄存器-具有中断允许,时钟模式和软件时钟选通功能

4位计数器 《该4位计数器占用USISR的低4位,用于在从模式下操作时为溢出中断计时,并帮助在主模式下生成SCK时钟脉冲。作为4位计数器,它在溢出之前从0递增到15。溢出时,它可以触发中断(USI_OVERFLOW_vect,由USICR中的某个位启用)。当USI从状态表在传输状态之间切换时,它用于跟踪传输(有关详细信息,请参见从代码部分)。

当用作主设备时,4位计数器与计数器一起使用。 USICR中的时钟选通位产生SCK时钟。您将计数器设置为希望产生的时钟脉冲数溢出(通常为8或1,其中8为数据传输,1为ACK/NACK传输)。然后循环,直到计数器溢出,连续设置时钟选通位并执行延迟等待。有关更多信息,请参见主代码部分。

两线制时钟控制单元(启动条件检测器)

TWI时钟控制单元是USI中的模块,用于监视SCK。开始和停止条件的行。它的主要目的是启动条件检测器,启用该功能后,只要检测到有效的启动条件,就会生成USI_START_vect中断。此中断处理程序是从机模式USI I2C传输处理的起点,并且必须将4位计数器设置为在发生地址传输后溢出。从那以后,溢出中断将管理该I2C消息的其余部分,并为下一条消息重置启动条件检测器。

阅读数据表

我将不对每个消息进行详细介绍这些寄存器中每个位的位数,但是如果您要编写一些USI代码,则必须阅读数据表的这些部分。我建议阅读整个通用串行接口-USI部分(ATTiny2313完整数据表的第142-150页)。除了我在这里指出的内容之外,这还将为您提供所有您需要的信息。

步骤6:ATTiny USI I2C代码实现-USI I2C主控

USI I2C Master(usi_i2c_master.c/h)库使用USI硬件提供I2C master模式功能。用户应该熟悉两个重要功能。第一个是初始化功能,用于设置SDA/SCL引脚和USI硬件,第二个是传输功能,该功能对I2C消息执行读取或写入操作,返回1(如果成功,则返回true(真),如果发生错误(接收到NACK),则返回0(假)。收发器功能使用第三个功能传输功能来发送和接收数据。传递函数不应在usi_i2c_master库的外部使用。

传递函数带有两个参数。第一个是指向数据缓冲区的指针,数据将在其中发送或接收。假定该缓冲区的第一个字节是ADDRESS + R/W字节(高7位地址,LSB是R/W)。根据协议,该字节始终被发送,而从未被接收。其余的缓冲区将根据R/W位发送出去或由接收到的数据填充(读为1,写为0)。第二个参数是缓冲区的总大小(包括地址字节)。

这是一个简短的示例。假设我们要将值 0x70 输出到地址为 0x40 的设备的内部地址 0x12 。首先,我们必须创建一个缓冲区来存储我们的传输:

char i2c_transmit_buffer [3];

char i2c_transmit_buffer_len = 3;

i2c_transmit_buffer [0] =(0x40 《《1)| 0//不需要与0进行“或”运算,但为清楚起见,这会将R/W位置1进行写操作。

i2c_transmit_buffer [1] = 0x12;//内部地址

i2c_transmit_buffer [2] = 0x70;//要写入的值

//传输I2C消息

USI_I2C_Master_Start_Transmission(i2c_transmit_buffer,i2c_transmit_buffer_size);

有,消息传输完成!那很简单!如果您想了解有关USI_I2C_Master代码的内部工作的更多信息,只需浏览 usi_i2c_master.c 文件,在其中我对状态,传递函数和其他有趣的部分进行了注释。我使用了单行#define宏,以便更清楚地说明每行的用途。

下一步,我将介绍从属模式代码,该代码要复杂得多,但也易于使用从最终用户的角度来看。我采用了另一种方法来实现从属代码,这是我在其他任何教程中都没有看到的,这很有趣且有用!

步骤7:ATTiny USI I2C代码实现-USI I2C从站

与主代码不同,USI I2C从站代码(usi_i2c_slave.c/h)使用USI中断几乎完全实现。如前所述,USI模块有两个中断,一个中断是在检测到START条件时产生的,另一个是基于4位计数器的溢出而产生的。计数器对于从属代码正常工作至关重要,在我阅读的教程和代码中并没有很好地说明。在流程图中,我注意到了逻辑中每个状态的数字。这些数字(8、1和0)是计数器计数值,指示在转换到下一个状态之前计数器应计数的滴答数。由于使用SCL时钟为计数器提供时钟,因此这些值表明在下一个状态之前必须发生多少个SCL时钟脉冲。通常,等待8个时钟脉冲的事物正在等待数据字节的发送/接收,而等待1个时钟脉冲的事物正在等待ACK/NACK的发送/接收。有些事情等待0个时钟,这意味着它们会立即继续到下一个状态,或者是前一个状态的扩展部分(对于Write或Read?)。

因此,作为最终用户,您可能是对如何将库与自己的代码接口更感兴趣!这简单,这就是原因。我已经取消了其他USI I2C实现(主要是基于AVR312应用笔记的实现)中使用的接收/发送缓冲区,而是实现了本教程开始时所述的注册银行协议 。银行存储为指针数组,而不是数据值,因此您必须在代码中附加局部变量到I2C寄存器组中的存储器地址设置指针以指向变量。这意味着您的主线代码不必轮询I2C缓冲区或处理数据到达,只要它们到达,这些值就会立即更新。它还允许通过I2C接口在任何时间轮询程序变量,而不会影响主代码(除了由于中断引起的延迟之外)。这是一个非常整洁的系统。让我们再举一个简短的例子。例如,我们有一个非常基本的软件PWM发生器来驱动LED。我们希望能够在不使主循环复杂的情况下更改PWM值( 16位值,仅用于学习指针)。借助异步I2C从设备的魔力,我们可以做到这一点!

#include“ usi_i2c_slave.h”

//定义对I2C从设备寄存器组指针数组的引用extern char * USI_Slave_register_buffer [];

int main()

{

//创建16位PWM值无符号int pwm_val = 0;

//将pwm值低字节分配给I2C内部地址0x00

//将pwm值高字节分配给I2C内部地址0x01

USI_Slave_register_buffer [0] =(unsigned char *)&pwm_val;

USI_Slave_register_buffer [1] =(unsigned char *)(&pwm_val)+1;

//使用从设备地址为0x40的I2C从设备初始化

USI_I2C_Init(0x40);

//将引脚A0设置为LED的输出(我们假设所使用的任何芯片都具有引脚A0)

DDRA | = 0x01;

while(1)

{

PORTA | = 0x01;//为(unsigned int i = 0; i {

PORTA&=〜(0x01);//关闭LED灯

}

}

}

就可以了!主循环完全不引用I2C,但是将PWM值发送到I2C内部地址0x00/0x01中的16位位置后,我们可以完全控制LED的PWM!为了增加稳定性(确保仅使用您正在使用的指针值并防止出现杂散指针),我建议您将#define USI_SLAVE_REGISTER_COUNT更改为所需的寄存器指针的数量,不要更多,不少。尝试对范围从0x00到USI_SLAVE_REGISTER_COUNT-1之外的寄存器索引进行访问(读取或写入)时,不写入任何内容,并且返回零。

步骤8:ATTiny USI I2C代码实现-编写代码!

要获取(git)代码,请转到我的GitHub页面!该代码是我的高级项目步进电机控制器的一部分,因此您可以使用I2C驱动程序检查我对电机控制器的实现。我也有一个不错的中断驱动的USART串行驱动程序,您也可以在其中使用。

https://github.com/CalcProgrammer1/Stepper-Motor-Controller/tree/master/UnipolarStepperDriver

请注意,名称由于我实施的错误修复和更新,I2C驱动程序中使用的功能和功能可能会略有不同。如果有什么严重的问题,我将编辑该教程,但是现在它应该非常准确。

现在,您已经掌握了I2C的知识,那么您就可以准备开始讨论任何东西!借助I2C的总线设计,您可以将许多设备(理论上最多为128,但受地址限制的限制)连接到网络

责任编辑:wv

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • I2C
    I2C
    +关注

    关注

    28

    文章

    1346

    浏览量

    120826
收藏 人收藏

    评论

    相关推荐

    最简单的总线通讯!I2C通讯总线的原理原来这么好懂

    通讯I2C
    安泰仪器维修
    发布于 :2024年01月02日 11:16:31

    全面掌握面试必考题I2C协议 - 第13节

    I2C协议
    充八万
    发布于 :2023年09月01日 19:08:34

    全面掌握面试必考题I2C协议 - 第12节

    I2C协议
    充八万
    发布于 :2023年09月01日 19:07:43

    全面掌握面试必考题I2C协议 - 第11节

    I2C协议
    充八万
    发布于 :2023年09月01日 19:06:53

    全面掌握面试必考题I2C协议 - 第10节

    I2C协议
    充八万
    发布于 :2023年09月01日 19:06:03

    全面掌握面试必考题I2C协议 - 第7节

    I2C协议
    充八万
    发布于 :2023年09月01日 19:03:32

    全面掌握面试必考题I2C协议 - 第6节

    I2C协议
    充八万
    发布于 :2023年09月01日 19:02:42

    全面掌握面试必考题I2C协议 - 第5节

    I2C协议
    充八万
    发布于 :2023年09月01日 19:01:51

    全面掌握面试必考题I2C协议 - 第4节

    I2C协议
    充八万
    发布于 :2023年09月01日 19:01:01

    全面掌握面试必考题I2C协议 - 第1节

    I2C协议
    充八万
    发布于 :2023年09月01日 18:58:30

    80 第23.1讲 I2C实验-I2C协议和6U的I2C控制器详解 - 第7节 #硬声创作季

    程序代码I2C协议
    充八万
    发布于 :2023年08月17日 10:07:44

    80 第23.1讲 I2C实验-I2C协议和6U的I2C控制器详解 - 第5节 #硬声创作季

    程序代码I2C协议
    充八万
    发布于 :2023年08月17日 10:06:04

    80 第23.1讲 I2C实验-I2C协议和6U的I2C控制器详解 - 第4节 #硬声创作季

    程序代码I2C协议
    充八万
    发布于 :2023年08月17日 10:05:14

    80 第23.1讲 I2C实验-I2C协议和6U的I2C控制器详解 - 第3节 #硬声创作季

    程序代码I2C协议
    充八万
    发布于 :2023年08月17日 10:04:23

    80 第23.1讲 I2C实验-I2C协议和6U的I2C控制器详解 - 第2

    程序代码I2C协议
    充八万
    发布于 :2023年08月17日 10:03:33