i2c 订阅
I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件.在总线上主和从、发和收的关系不是恒定的,而取决于此时数据传送方向。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件.然后主机接收从器件发送的数据,最后由主机终止接收过程。在这种情况下.主机负责产生定时时钟和终止数据传送。 [1] 展开全文
I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件.在总线上主和从、发和收的关系不是恒定的,而取决于此时数据传送方向。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件.然后主机接收从器件发送的数据,最后由主机终止接收过程。在这种情况下.主机负责产生定时时钟和终止数据传送。 [1]
信息
模    式
两线式串行总线
外文名
Inter-Integrated Circuit
中文名
I2C总线
I2C总线工作原理
SDA(串行数据线)和SCL(串行时钟线)都是双向I/O线,接口电路为开漏输出.需通过上拉电阻接电源VCC.当总线空闲时.两根线都是高电平,连接总线的外同器件都是CMOS器件,输出级也是开漏电路.在总线上消耗的电流很小,因此,总线上扩展的器件数量主要由电容负载来决定,因为每个器件的总线接口都有一定的等效电容.而线路中电容会影响总线传输速度.当电容过大时,有可能造成传输错误.所以,其负载能力为400pF,因此可以估算出总线允许长度和所接器件数量。主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件.在总线上主和从、发和收的关系不是恒定的,而取决于此时数据传送方向。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件.然后主机接收从器件发送的数据,最后由主机终止接收过程。在这种情况下.主机负责产生定时时钟和终止数据传送。 [2] 
收起全文
精华内容
下载资源
问答
  • I2C详解(一)

    万次阅读 多人点赞 2019-01-03 17:22:21
    I2C Bus(Inter-Integrated Circuit Bus) 最早是由Philips半导体(现被NXP收购)开发的两线时串行总线,常用于微控制器与外设之间的连接。要想了解详细I2C协议,目前最新的I2C标准协议是2014年第6版本,如下: I2C-...

    I2C Bus(Inter-Integrated Circuit Bus) 最早是由Philips半导体(现被NXP收购)开发的两线时串行总线,常用于微控制器与外设之间的连接。要想了解详细I2C协议,目前最新的I2C标准协议是2014年第6版本,如下:
    I2C-Bus Standards Specification


    硬件连接

    I2C仅需两根线就可以支持一主多从或者多主连接,I2C使用两个双向开漏线,配合上拉电阻进行连接,关于上拉电阻阻值大小有最大值和最小值的限制,具体计算请参考 I2C-上拉电阻计算

    • SDA:串行数据线
    • SCL:串行时钟线

    在这里插入图片描述

    在这里插入图片描述

    • 硬件拉低(Open-Drain Pulling Low)

    下图代表了总线电平拉低过程,当总线要传输低电平’0’时,Logic会控制FET使其导通VBUS总线连接到地,将总线拉低,注意在快速模式下最大的灌电流不超过3mA,这限制了上拉电阻的最小值。

    在这里插入图片描述

    • 硬件拉高(Open-Drain Releasing Bus)

    下图代表了总线电平高电平过程,当总线要传输高电平’1’时,Logic会控制FET使其关断VBUS总线上拉到电源,将总线拉高。

    在这里插入图片描述


    软件通讯协议

    I2C是串行传输总线,按照下面格式进行一位一位传输。协议如下:
    在这里插入图片描述


    总线速度

    双向传输总线:

    • 标准模式(Standard-mode):速率高达100kbit/s
    • 快速模式(Fast-mode):速率高达400kbit/s
    • 快速模式+(Fast-mode Plus):速率高达1Mbit/s。
    • 高速模式(High-speed mode):速率高达3.4Mbit/s

    单向传输总线:

    • 超快速模式(Ultra Fast-mode):速率高达5Mbit/s

    起始和停止条件及重复起始条件(START and STOP conditions and Repeated start condition):
    起始和终止条件都是由主机(master)发起产生。总线在起始条件之后处于忙碌状态,在停止条件之后又处于空闲状态。

    • 起始条件:SCL线是高电平时,SDA线从高电平向低电平切换。
    • 停止条件:SCL线是高电平时,SDA线从低电平向高电平切换。
    • 重复起始条件:和起始条件相似,重复起始条件发生在停止条件之前。主机想继续给从机发送消息时,一个字节传输完成后可以发送重复起始条件,而不是产生停止条件。
      在这里插入图片描述

    字节格式
    SDA数据线上的每个字节必须是8位,每次传输的字节数量没有限制。每个字节后必须跟一个响应位(ACK)。首先传输的数据是最高位(MSB),SDA上的数据必须在SCL高电平周期时保持稳定,数据的高低电平翻转变化发生在SCL低电平时期。
    在这里插入图片描述
    以传输Byte:1010 1010 (0xAAh)为例,SDA SCL传输时序如下所示:
    在这里插入图片描述


    响应ACK(Acknowledge)和非响应NACK(Not Acknowledge)
    每个字节传输必须带响应位,相关的响应时钟也由主机产生,在响应的时钟脉冲期间(第9个时钟周期),发送端释放SDA线,接收端把SDA拉低。以上图传输101010101为例,SCL第9位时钟高电平信号期间,SDA拉低其代表了有ACK响应位。
    当在SCL第9位时钟高电平信号期间,SDA仍然保持高电平,这种情况定义为NACK非响应位。这种情况下,主机可以直接产生STOP条件终止以后的传输或者继续重新START开始一个新的传输。以下情况会导致出现NACK位:

    • 接收机没有发送机响应的地址,接收端没有任何ACK发送给发射机
    • 由于接收机正在忙碌处理实时程序导致接无法接收或者发送
    • 传输过程中,接收机识别不了发送机的数据或命令
    • 接收机无法接收
    • 主机接收完成读取数据后,要发送NACK结束告知从机
      以下图例代表NACK时序:
      在这里插入图片描述

    7-bit 地址格式和读写位
    一个7-bit的地址是从最高位(MSB) 开始发送的,这个地址后面会紧跟1-bit(R/W)的操作符,1表示读操作,0表示写操作。 接下来的一个bit是NACK/ACK,当这个帧中前面8 bit发送完后,接收端的设备获得SDA控制权,此时接收设备应该在第9个时钟脉冲之前回复一个ACK(将SDA拉低)以表示接收正常,如果接收设备没有将SDA拉低,则说明接收设备可能没有收到数据(如寻址的设备不存在或设备忙)或无法解析收到的消息,如果是这样,则由master来决定如何处理(stop或repeated start condition)。

    在这里插入图片描述

    展开全文
  • 硬件I2C与模拟I2C

    千次阅读 多人点赞 2019-03-11 17:48:22
    硬件I2C对应芯片上的I2C外设,有相应I2C驱动电路,其所使用的I2C管脚也是专用的,因而效率要远高于软件模拟的I2C;一般也较为稳定,但是程序较为繁琐。硬件(固件)I2C是直接调用内部寄存器进行配置;而软件I2C是...

    硬件I2C对应芯片上的I2C外设,有相应I2C驱动电路,其所使用的I2C管脚也是专用的,因而效率要远高于软件模拟的I2C;一般也较为稳定,但是程序较为繁琐。硬件(固件)I2C是直接调用内部寄存器进行配置;而软件I2C是没有寄存器这个概念的。

    软件I2C一般是使用GPIO管脚,用软件控制SCL,SDA线输出高低电平,模拟i2c协议的时序。

     

    例如下面这段I2C的开始和结束信号,我们使用GPIOB模拟:

     

    I2C接线
    GPIO引脚模拟I2C引脚
    GPIOB11SDA
    GPIOB12SCL

                                     

                                           

                                                                                             I2C开始/结束时序图

    代码如下:

    Void I2C_START(void)
    
    {
    
        GPIOB11 = High;
    
        GPIOB12 = High;
    
        Delay();
    
        GPIOB11 = Low;
    
        Delay();
    
        GPIOB12 = Low;
    
    }
    
    
    
    
    Void I2C_STOP(void)
    
    {
    
        GPIOB11 = Low;
    
        GPIOB12 = High;
    
        Delay();
    
        GPIOB11 = High;
    
    }

    同样,我们可以按照波形完成读/写一个字节的函数,再进一步封装完成更为复杂的功能(发送指令等等)

    硬件i2c程序员只要调用i2c的控制函数即可,不用直接的去控制SCL,SDA高低电平的输出。

    但是有些单片机的硬件i2c不太稳定,调试问题较多。例如网上很多人吐槽的STM32…

     

    主要对比

    1.硬件IIC用法比较复杂,模拟IIC的流程更清楚一些。

    2.硬件IIC速度比模拟快,并且可以用DMA

    3.模拟IIC可以在任何管脚上,而硬件只能在固定管脚上。

     

    展开全文
  • USB转I2C I2C工具 I2C助手

    千次阅读 2019-03-29 10:35:08
    USB转I2C小工具,支持单字节、多字节读写,支持定时读数据。非常的好用! 界面如下: 设备地址:十六进制输入的设备地址,一般I2C 设备的地址都是7 位+1 位的读写位,这里设备地址就是7 位地址左移一位。也就 是...

    USB转I2C小工具,支持单字节、多字节读写,支持定时读数据。非常的好用!

    界面如下:

    设备地址:十六进制输入的设备地址,一般I2C 设备的地址都是7 位+1 位的读写位,这里设备地址就是7 位地址左移一位。也就  是最后一位肯定是0。有些数据手册中会直接写出左移之后的地址。这里需要大家多注意一下。
    寄存器    :十六进制的寄存器地址(注意:8bit寄存器时填写范围:00~ff。16bit寄存器时填写范围:0000~ffff
    读取长度:十进制方式输入(输入范围任意
    读数据    :点击一次就会读取一次规定数据长度的数据,十六进制显示
    写数据    :点击一次写数据,工具就会将写入数据框中的数据发送出去。数据框中只能输入十六进制数据
    定时读取:在输入框中输入时间,单位是ms。点击定时读取框后,开始定时读取。

    支持4种速率:20K、100K、400K、750K

    下载链接如下:

    链接:https://pan.baidu.com/s/1uqg4ZBuVH15egxHh2IOMjg

    展开全文
  • 【组件】i2c抽象/模拟i2c

    万次阅读 2017-12-23 09:27:26
    关于i2c的使用,并不陌生,C51、ARM、MSP430等,都基本集成硬件i2c,或者不集成i2c的,可以根据总线时序图使用普通IO口翻转模拟一根i2c总线。对于当下流行的stm32饱受诟病的硬件i2c,相信很多人都是使用模拟i2c。...

    1.写在前面

    i2c总线是由PHILIPS公司开发的一种简单、双向二线制同步串行总线。关于i2c的使用,并不陌生,C51、ARM、MSP430等,都基本集成硬件i2c,或者不集成i2c的,可以根据总线时序图使用普通IO口翻转模拟一根i2c总线。对于当下流行的stm32饱受诟病的硬件i2c,相信很多人都是使用模拟i2c。模拟i2c的源码比较多,大多都是大同小异,对于各类例程,提供的模拟i2c似乎都不是太规范(个人见解),特别是一根i2c总线挂多个外设、模拟多根i2c总线、以及更换一个i2c外设时,都需要大幅度修改源码、复制源码、重新调试时序等重复的工作。在阅读过Linux设备驱动框架和RT-Thread的驱动框架,发现在总线分层上处理就特别好,完美解决了上述提及的问题。参考RT-Thread和Linux下的模拟i2c,整理修改在裸机上使用。

    2.Linux、RT-Thread设备驱动模型

    1)模型分为总线驱动和设备驱动;

    2)  总线驱动与外设驱动分离,方便一根总线挂多个外设,方便移植;

    3)  底层(与硬件相关)与上层分离,方便添加总线及移植到不同处理器,移植到其他处理器,只需重新实现硬件相关的“寄存器”层即可;

    3.MCU下裸机形式i2c总线抽象

    此部分实现源码为:i2c_core.c  i2c_core.h

    1)i2c总线抽象对外接口(API)

    “i2c_bus_xfer”为i2c封装对外的API,函数原型如下,提供一个函数模型,具体需要实例化函数指针。

    int i2c_bus_xfer(struct i2c_dev_device *dev,struct i2c_dev_message msgs[],unsigned int num)
    {
    	int size;
    	
    	size = dev->xfer(dev,msgs,num);	
    	return size;
    }

    a)此函数即作为驱动外设的对外接口,所有操作通过此函数接口,与底层总线实现分离,如EEPROM、RTC、温度传感器等;

    b)一个对外函数已经实现90%的情况使用,对应一些特殊情况,后期再完善或增加API。

    a)struct i2c_dev_device *i2c_dev

    2)i2c总线抽象API参数

    a)i2c_dev:i2c设备指针,类型为“struct i2c_dev_device”,驱动一个i2c外设时,首先要对此指针设备初始化;

    b)msgs:i2c一帧数据,发送数据及存放返回数据的缓存;

    c)num:数据帧数量。

    3)struct i2c_dev_device

    该结构体为关键,调用API驱动外设时,首先对此初始化(类似于Linux/RT-Thread注册设备)。完整的设备包括两部分,数据操作函数和i2c相关信息(如硬件i2c或者模拟i2c)。因此“struct i2c_dev_device”的原型为:

    struct i2c_dev_device
    {
            int (*xfer)(struct i2c_dev_device *dev,struct i2c_dev_message msgs[],unsigned int num);
            void *i2c_phy;
    };

    a)第一个参数是函数指针,数据收发通过此函数指针调用实体函数实现;

    b)第二个参数是一个void指针,初始化时指向我们使用的物理i2c(硬件/模拟),使用时可强制转换为对应的类型。

    4)xfer

    该函数与i2c总线设备对外接口函数“i2c_bus_xfer”具有相同的参数,形参参数参考此项的第2点,初始化时实例化指向实体函数。

    5)struct i2c_dev_message

    “struct i2c_dev_message”为i2c总线访问外设的一帧数据信息,包括发送数据、外设从地址、访问标识等。原型如下:

    struct i2c_dev_message
    {
    	unsigned short 	addr;
    	unsigned short	flags;
    	unsigned short	size;
    	unsigned char	*buff;
    	unsigned char   retries;		
    };

    a)addr:i2c外设从机地址,常用为7位,10位较少用;

    b)flags:标识,发送、接收、应答、地址位选择等标识;几种标识如下:

    #define I2C_BUS_WR             0x0000
    #define I2C_BUS_RD             (1u << 0)
    #define I2C_BUS_ADDR_10BIT     (1u << 2)
    #define I2C_BUS_NO_START      (1u << 4)
    #define I2C_BUS_IGNORE_NACK    (1u << 5)
    #define I2C_BUS_NO_READ_ACK    (1u << 6)

    c)size:发送的数据大小,或者接收的缓存大小;

    d)buff:缓存区;

    e)retries:i2c启动失败时,重启的次数。

    4.模拟i2c抽象

    对于模拟i2c,在以往的实现方式中,基本是时序图和外设代码混合在一起,增加外设或者使用新的i2c外设时,需要对模拟2ic代码进行较大工作量的修改,或者以“复制”的方式实现一套新的i2c总线。但同理,可以把模拟i2c时序部分代码抽象出来,以“复用”代码的形式实现。此部分实现源码为:i2c_bitops.c  i2c_bitops.h

    1)模拟i2c抽象对外接口

    根据上述封装的对外API,使用时,首先需要实现入口参数“i2c_dev”实例化,用模拟i2c即是调用模拟i2c相关接口。

    int i2c_bitops_bus_xfer(struct ops_i2c_dev *i2c_bus,struct i2c_dev_message msgs[],unsigned long num)
    {
    	struct i2c_dev_message *msg;
    	unsigned long i;
    	unsigned short ignore_nack;
    	int ret;
    	
    	ignore_nack = msg->flags & I2C_BUS_IGNORE_NACK;
    	i2c_bitops_start(i2c_bus);							
    	for (i = 0; i < num; i++)
        	{
    		msg = &msgs[i];
           		if (!(msg->flags & I2C_BUS_NO_START))
           		{
                		if (i)
                		{
                    		i2c_bitops_restart(i2c_bus);	
                		}
    			ret = i2c_bitops_send_address(i2c_bus,msg);
    			if ((ret != 0) && !ignore_nack)
    				goto out;
    		}
    		if (msg->flags & I2C_BUS_RD)
           		{//read
    			ret = i2c_bitops_bus_read(i2c_bus,msg);
    			if(ret < msg->size)
    			{
    				ret = -1;
    				goto out;
    			}
    		}
    		else
    		{//write
    			ret = i2c_bitops_bus_write(i2c_bus,msg);
    			if(ret < msg->size)
    			{
    				ret = -1;
    				goto out;
    			}
    		}
    	}
    	ret = i;
    out:
    	i2c_bitops_stop(i2c_bus);
    		
    	return ret;
    }
    int ops_i2c_bus_xfer(struct i2c_dev_device *i2c_dev,struct i2c_dev_message msgs[],unsigned int num)
    {
    	return(i2c_bitops_bus_xfer((struct ops_i2c_dev*)(i2c_dev->i2c_phy),msgs,num));
    }

    a)模拟一根i2c总线时,对外的操作函数都通过上诉函数;i2c信息帧相关参数由上层调用传递进入,此处主要增加“struct ops_i2c_dev”的封装;

    b)该函数使用到的函,其中入口参数为“struct ops_i2c_dev”类型的都是模拟i2c相关;

    d)模拟i2c封装实现主要针对“struct ops_i2c_dev”原型的实例化。

    2)struct ops_i2c_dev

    “struct ops_i2c_dev”原型如下:

    struct ops_i2c_dev
    {
            void (*set_sda)(int8_t state);
            void (*set_scl)(int8_t state);
            int8_t (*get_sda)(void);
            int8_t (*get_scl)(void);
            void (*delayus)(uint32_t us);
    };

    a)set_sda:数据线输出;

    b)set_scl:时钟线输出;

    c)get_sda:数据线输入(捕获);

    d)get_scl:时钟线输入(捕获);

    e)delayus:延时函数;

    要实现一个模拟i2c,只需将上诉函数指针的实体实现即可,具体看后面描述。

    3)模拟i2c时序

    以产生i2c起始信号函数为例子,简要分析:

    static voidi2c_bitops_start(struct ops_i2c_dev *i2c_bus)
    {
        i2c_bus->set_sda(0);                                          
        i2c_bus->delayus(3);
        i2c_bus->set_scl(0);                                                       
    }        

    入口参数为struct ops_i2c_dev *i2c_bus,其实就是i2c_bitops_bus_xfer应用层函数传入的参数,最终是在此调用,底层需要实现的就是io模拟的输入/输出状态函数。

    其他函数,如

    static void i2c_bitops_restart(struct ops_i2c_dev *i2c_bus)
    static chari2c_bitops_wait_ack(struct ops_i2c_dev *i2c_bus)
    static int i2c_bitops_send_byte(struct ops_i2c_dev*i2c_bus,unsigned char data)

    等等,入口参数都是i2c_bus,时序实现与常规裸机程序设计是一致的,不同的是函数指针的分离调用,具体看附件源码。

    4)标识位

    在以往的模拟i2c或者硬件i2c中,操作外设时都有各类情况,如读和写方向的切换、连续操作(不需启动i2c总线,如写EEPROM,先写地址再写数据)等。对于这类情况,我们处理办法是选择相关的宏标识即可,具体实现由“中间层”实现,让i2c外设驱动起来更简单!以上述对外函数为例:

    a)通过标识位判断是读还是写状态

    if (msg->flags & I2C_BUS_RD)
    {//read
            ret = i2c_bitops_bus_read(i2c_bus,msg);
            if(ret < msg->size)
            {
                    ret = -1;
                    goto out;
            }
    }

    b)应答状态标识

    ignore_nack = msg->flags & I2C_BUS_IGNORE_NACK;

    5)读写函数

    读写函数最终是通过io口1bit的翻转模拟出时序,从而获得数据,这部分与常规模拟i2c一致,通过函数指针方式操作。主要实现接口函数:

    static unsigned long i2c_bitops_bus_write(struct ops_i2c_dev *i2c_bus,struct i2c_dev_message *msg);
    static unsigned long i2c_bitops_bus_read(struct ops_i2c_dev *i2c_bus,struct i2c_dev_message *msg);

    5.模拟i2c总线实现

    此部分实现源码为:i2c_hw.c  i2c_hw.h

    以stm32f1为硬件平台,采用上述模拟i2c封装,实现一根模拟i2c总线。

    1)实现struct ops_i2c_dev函数实体

    除了“delayus”函数外,其余为io翻转,以“set_sda”和“delayus”为例,实现如下:

    static void gpio_set_sda(int8_t state)
    {
            if (state)
                    I2C1_SDA_PORT->BSRR = I2C1_SDA_PIN;
            else
                    I2C1_SDA_PORT->BRR = I2C1_SDA_PIN;
    }
    static void gpio_delayus(uint32_t us)
    {
    #if 0  
            volatile int32_t i;
    	
            for (; us > 0; us--)
            {
                    i = 30;  //mini 17
                    while(i--);
            }
    #else
            Delayus(us);
    #endif
    }

    a)为例提高速率,上诉代码采用寄存器方式操作,可以用库函数操作io口;

    b)延时可以用硬件定时器延时,或者软件延时,具体根据cpu时钟计算;

    c)其他源码看附件中“i2c_hw.c”

    2)初始化一根模拟i2c总线

    void stm32f1xx_i2c_init(void)
    {
    	GPIO_InitTypeDef GPIO_InitStructure;										
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);		
    
    	GPIO_InitStructure.GPIO_Pin = I2C1_SDA_PIN | I2C1_SCL_PIN;
      	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;	   		
      	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	   		
      	GPIO_Init(I2C1_SDA_PORT, &GPIO_InitStructure);								   				
    	I2C1_SDA_PORT->BSRR = I2C1_SDA_PIN;												
    	I2C1_SCL_PORT->BSRR = I2C1_SCL_PIN;
    	
    	//device init
    	ops_i2c1_dev.set_sda = gpio_set_sda;
    	ops_i2c1_dev.get_sda = gpio_get_sda;
    	ops_i2c1_dev.set_scl = gpio_set_scl;
    	ops_i2c1_dev.get_scl = gpio_get_scl;
    	ops_i2c1_dev.delayus = gpio_delayus;
    		
    	i2c1_dev.i2c_phy 	 = &ops_i2c1_dev;
    	i2c1_dev.xfer 		 = ops_i2c_bus_xfer; 
    }

    a)i2c io初始化;

    b)i2c设备实例化,其中“ops_i2c1_dev”和“i2c1_dev”即是我们定义的总线设备,后面使用该总线时主要通过“i2c1_dev”实现对底层的调用。

    6.驱动EEPROM(AT24C16)

    此部分实现源码为:24clxx.c  24clxx.h

    上面总线完成后,驱动一个i2c外设可以说就是信手拈来的事情了,而且模拟i2c总线抽象出来后,不需在做重复调试时序的工作。

    假设初始化的i2c设备为i2c1_dev。

    1)  写EEPROM。写一个字节,页写算法详细见源码附件(24clxx.c):

    char ee_24clxx_writebyte(u16 addr,u8 data)
    {
         struct i2c_dev_message ee24_msg[1];
         u8	buf[3];
         u8  slave_addr;
         if(EEPROM_MODEL > 16)
         {					  
    	  slave_addr =EE24CLXX_SLAVE_ADDR;
    	  buf[0] = (addr >>8)& 0xff;   
    	  buf[1] = addr & 0xff;
    	  buf[2] = data;
              ee24_msg[0].size  = 3;
         }
         else
         {
              slave_addr = EE24CLXX_SLAVE_ADDR | (addr>>8);
    	  buf[0] = addr & 0xff;
    	  buf[1] = data;
    	  ee24_msg[0].size = 2;
         }
         ee24_msg[0].addr = slave_addr;
         ee24_msg[0].flags = I2C_BUS_WR;
         ee24_msg[0].buff = buf;
         i2c_bus_xfer(&i2c1_dev,ee24_msg,1);
    		
         return 0;
    }

    2)读EEPROM

    voidee_24clxx_readbytes(u16 read_ddr, char* pbuffer, u16 read_size)
    { 
         struct i2c_dev_message ee24_msg[2];
         u8     buf[2];
         u8     slave_addr;
         if(EEPROM_MODEL > 16)
         {
              slave_addr =EE24CLXX_SLAVE_ADDR;
              buf[0] = (read_ddr>>8)& 0xff;
              buf[1] = read_ddr& 0xff;
              ee24_msg[0].size  = 2;
         }
         else
         {
              slave_addr =EE24CLXX_SLAVE_ADDR | (read_ddr>>8);
              buf[0] = read_ddr & 0xff;
              ee24_msg[0].size  = 1;
         }
         ee24_msg[0].buff  = buf;
         ee24_msg[0].addr  = slave_addr;
         ee24_msg[0].flags = I2C_BUS_WR;
         ee24_msg[1].addr  = slave_addr;
         ee24_msg[1].flags = I2C_BUS_RD;
         ee24_msg[1].buff  = (u8*)pbuffer;
         ee24_msg[1].size  = read_size;
         i2c_bus_xfer(&i2c1_dev,ee24_msg,2);
    }

    3)注意事项

    驱动一个外设相对容易了,注意的事项就是标识位部分。

    a)此处外设地址(addr),是实际地址,不含读写位(7bit),比如AT24C16外设地址为0x50,可能大家平常用的是0xA0,因为包括读写位;

    b)写数据时,如果以2帧i2c_dev_message消息发送,需要注意“I2C_BUS_NO_START”宏,此宏标识意思是不需要再次启动i2c了,一般看i2c外设手册时序图可知道。如写EEPROM是先写地址,然后写数据这个过程是连续的,此时就需用到“I2C_BUS_NO_START”标识。程序可改成这样:

    char ee_24clxx_writebyte(u16 addr,u8 data)
    {
         struct i2c_dev_message ee24_msg[2];
         u8     buf[2];
         u8 slave_addr;
         if(EEPROM_MODEL > 16)
         {                                   
              slave_addr =EE24CLXX_SLAVE_ADDR;
              buf[0] = (addr>>8)& 0xff;  
              buf[1] = addr &0xff;
              ee24_msg[0].size  = 2;
         }
         else
         {
               slave_addr =EE24CLXX_SLAVE_ADDR | (addr>>8);
               buf[0] = addr &0xff;
               ee24_msg[0].size  = 1;
         }
         ee24_msg[0].addr = slave_addr;
         ee24_msg[0].flags = I2C_BUS_WR;
         ee24_msg[0].buff  = buf;
         ee24_msg[1].addr = slave_addr;
         ee24_msg[1].flags = I2C_BUS_WR |I2C_BUS_NO_START;
         ee24_msg[1].buff  = &data;
         ee24_msg[1].size  = 1;
         i2c_bus_xfer(&i2c1_dev,ee24_msg,2);
              
         return 0;
    }

    4)其他

    理解之后,或者使用过Linux、RT-Thread的驱动框架的,再驱动其他i2c外设,就是很容易的事情了,剩下的就是配置寄存器、应用算法的问题了。

    7.总结

    1)整体思路比较易理解,本质就是函数指针,将与硬件底层无关的部分抽象出来,相关联的地方分层明确,通过函数指针的方式进行调用。

    2)事务分离,通用、重复的事情交给总线处理,特殊任务留给外设驱动。

    8.相关例子

    【1】LM75A温度传感器使用:

     https://blog.csdn.net/qq_20553613/article/details/79140266

    【2】LP55231 LED驱动使用:

    https://blog.csdn.net/qq_20553613/article/details/78933482

    9.源码

    【1】  https://github.com/Prry/drivers-for-mcu

    10.参考

    【1】  https://github.com/RT-Thread/rt-thread

    【2】  https://blog.csdn.net/qq_20553613/article/details/78550427

    展开全文
  • I2C协议---I2C时序图解析

    万次阅读 多人点赞 2018-08-08 19:55:57
    一、I2C协议简介   I2C 通讯协议(Inter-Integrated Circuit)是由 Phiilps 公司开发的,由于它引脚...  关于I2C协议的更多内容,可阅读《I2C总线协议》,本博文主要分析I2C波形图,对于I2C的基础知识不在做介...
  • I2C库函数

    千次阅读 2018-08-08 17:10:35
    1.void I2C_DeInit(I2C_TypeDef* I2Cx) 功能:将I2Cx外设寄存器重设为默认值 注释:该函数调用了RCC_APB1PeriphResetCmd来进行挂载于APB上外设的寄存器的复位 例如:I2C_DeInit();   2.void I2C_Init(I2C_...
  • I2C协议

    万次阅读 多人点赞 2018-11-01 19:50:16
    [I2C]I2C总线协议图解 转自:http://blog.csdn.net/w89436838/article/details/38660631 1 I2C总线物理拓扑结构    I2C 总线在物理连接上非常简单,分别由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成。...
  • Linux I2C驱动框架(超详细)

    万次阅读 多人点赞 2019-06-07 17:04:26
    Linux I2C驱动框架 一、总览全局 在讨论I2C驱动框架前,先讨论几个重要的概念 1、I2C总线 struct bus_type i2c_bus_type = { .name = "i2c", .match = i2c_device_match, .probe = i2c_device_probe, .remove...
  • i2c时序图的详细讲解

    万次阅读 多人点赞 2018-04-25 21:25:22
    i2c简易时序图 启动信号: SCL为高电平的时候,SDA由高电平向低电平跳变。结束信号:SCL为高电平的时候,SDA由低电平向高电平跳变。 应答信号: I2C总线上的所有数据都是以8位字节传送的,发送器每发送一个字节...
  • I2C总线介绍

    万次阅读 多人点赞 2018-12-06 16:01:22
    1.1 I2C总线知识 1.1.1 I2C总线物理拓扑结构   I2C总线在物理连接上非常简单,分别由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成。通信原理是通过对SCL和SDA线高低电平时序的控制,来产生I2C总线协议所...
  • I2C通信全面解析

    万次阅读 多人点赞 2020-02-19 18:03:25
    (1)SCL(serial clock):时钟线,传输CLK信号,一般是I2C主设备向从设备提供时钟的通道。 (2)SDA(serial data):数据线,通信数据都通过SDA线传输 2. 通信特征:串行、同步、非差分、低速率 (1)I2C属于...
  • 利用USB-I2C实现从机I2C收发数据

    千次阅读 2018-10-17 14:05:33
    Ginkgo USB-I2C适配器固件从V2.8.17版本开始支持I2C从机功能,下面就针对这个功能的使用做简单介绍。实现目的:1、I2C从机接收数据,也就是接收I2C主机的数据并显示出来;2、I2C从机发送数据,也就是把数据传输到...
  • I2C调试工具

    千次阅读 2019-05-06 19:55:56
    i2c-tools工具是开源I2C调试工具, 具有获取I2C总线挂载的设备列表及设备地址,可对指定设备指定寄存器进行读写的功能。 ubuntu安装: apt-get install libi2c-dev i2c-tools 源码下载地址: ...
  • i2c 驱动五:gpio模拟i2c

    千次阅读 2016-11-16 18:45:10
    介绍在linux中 gpio 模拟的 i2c 程序的编写
  • I2C接口

    万次阅读 多人点赞 2018-06-13 19:45:25
    I2C总线引脚定义SDA (I2C数据引脚)CLK (I2C数据引脚) 2. I2C总线物理连接I2C总线物理连接如下图所示,SDA和CLK连接线上连有两个上拉电阻,当总线空闲时,两根线均为高电平。连到总线上的任一器件输出的低电平,都...
  • 所谓模拟I2C是指使用普通GPIO口的输入输出功能来模拟I2C总线的时序,用来通过I2C总线进行通信。 I2C的基本知识: 1、I2C总线有两条线:SCL是时钟线,SDA是数据线; 2、I2C总线通信方式是主从模式,即由主设备发起...
  • I2C驱动之总线接口i2c_transfer

    千次阅读 2015-01-16 14:52:29
     函数本身不具备驱动适配器物理硬件完成消息交互的能力,它只是寻找到i2c_adapter对应的i2c_algorithm,并使用i2c_algorithm的master_xfer()函数真正驱动硬件流程. 成功返回0 int i2c_transfer(struct i2c_adapter...
  • I2C总线传输协议

    万次阅读 多人点赞 2017-08-20 19:50:10
    I2C总线支持设备之间的短距离通信,它只需要两根信号线来完成信息交换。I2C最早是飞利浦在1982年开发设计并用于自己的芯片上,一开始只允许100kHz、7-bit标准地址。1992年,I2C的第一个公共规范发行,增加了400kHz的...
  • HAL_I2C_Mem_Write与HAL_I2C_Master_Transmit

    万次阅读 2019-11-25 18:28:17
    HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout) 参数...
  • I2C设备驱动(三)--linux i2c驱动框架

    千次阅读 2017-06-10 15:55:13
    1 体系结构linux的i2c体系由以下三部分组成:(1)i2c核心由linux内核提供,定义基本数据结构,实现i2c驱动和设备的注册、注销,通信方法等。与设备无关。(2)i2c控制器驱动一般由soc设备厂商提供,主要实现i2c_...
  • Linux I2C工具查看配置I2C设备

    千次阅读 2017-11-28 15:11:52
     通过i2cdetect -l指令可以查看树莓派上的I2C总线,从返回的结果来看树莓派含有两个I2C总线,通过阅读相关的资料,树莓派1代使用I2C0,而树莓派2代使用I2C1。 [plain] view plain copy
  • i2cdetect i2cdump i2cget i2cset用法

    万次阅读 多人点赞 2016-12-14 11:58:27
    本博客转载自台湾朋友的文章:...幸好linux上也有這樣的工具 – i2c tools。先到lm-sensors下載soure code,然後cross compile成arm的執行檔,就可以放到板子來試試看了。 i2c-tools中含有四個執行檔i2cdetect –
  • 很清晰的解读i2c协议

    万次阅读 多人点赞 2017-06-17 02:15:29
    很清晰的解读i2c协议。 I2C协议:2条双向串行线,一条数据线SDA,一条时钟线SCL。 SDA传输数据是大端传输,每次传输8bit,即一字节。 支持多主控(multimastering),任何时间点只能有一个主控。 i2c起始信号、结束...
  • 树莓派之I2C编程

    千次阅读 2017-08-21 16:35:14
    树莓派之I2C编程一、启动I2C 使用: ls /dev/命令可以查看I2C设备是启动。 如果没有启动执行 sudo raspi-config选择 interfacing Options->I2C->yes启动i2c内核驱动。 使用 lsmod 命令可以看到i2c_bcm2708,并且/dev...
  • i2c-tools使用及调试

    万次阅读 2018-05-29 09:32:21
    i2c-tools工具是一个专门调试i2c的,开源,可获取挂载的设备及设备地址,还可以在对应的设备指定寄存器设置值或者获取值等功能。 一、下载i2c-tools,交叉编译 1、从开源网站...
  • STM32的I2C通信

    万次阅读 多人点赞 2017-08-07 12:49:35
    STM32的两个GPIO引脚,分别用于SCL和SDA,按照I2C规约的时序,像控制LED灯那样控制引脚输出,若是接收数据时则读取SDA线上的电平,那就可以实现I2C通信了,这也是我们在51单片机上的“软件模拟协议”做法。...
  • i2c_client,i2c_adapter和I2C-core的简介

    万次阅读 2013-09-24 15:15:05
    I2C的主要有两大数据结构,struct i2c_client 和 struct i2c_adapter。 2.1 i2c_client struct i2c_client { unsigned short flags; unsigned short addr; char name[I2C_NAME_SIZE]; struct i2c_...
  • GPIO模拟I2C通信协议(一)

    万次阅读 多人点赞 2018-11-07 20:19:38
    本博客是GPIO模拟I2C通信协议系列的第1篇,本文将首先介绍I2C协议的基本时序,然后给出用GPIO模拟实现I2C功能的C代码,最后介绍驱动开发的一些思路。本文的主要内容包括I2C协议简介和I2C协议的C代码实现两个部分,每...
  • I2C总线协议详解

    万次阅读 多人点赞 2014-08-18 14:49:23
    1.1 I2C总线知识 1.1.1 I2C总线物理拓扑结构    I2C 总线在物理连接上非常简单,分别由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成。通信原理是通过对SCL和SDA线高低电平时序的控制,来 产生I2C总线...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,107,378
精华内容 2,042,951
关键字:

i2c