跳转至

I2C

一、I2C 概述:

I2C(Inter-Integrated Circuit)是一种广泛应用于嵌入式系统的通信协议,尤其适用于主从架构下的短距离通信。它最早由飞利浦(现在的NXP)公司开发,主要用于在集成电路内部以及设备之间的低速通信。以下是I2C协议的一些关键特性和工作原理:

物理层

  • I2C使用两根线进行数据传输:SCL(时钟线)和SDA(数据线)。

  • 两根线通过上拉电阻接到高电平,这样通信可以使用“线与”(Wired-AND)方式,方便多主多从架构。

  • SCL和SDA线分别传输时钟和数据,因此I2C通信是同步的。

架构

  • I2C采用主从(Master-Slave)结构。每次通信时只有一个主设 备,但可以有多个从设备。

  • 主设备负责生成时钟信号和启动/停止信号。

  • 从设备根据地址识别是否是目标通信对象。

通信流程

  • 起始条件(Start Condition):主设备将SDA线从高拉到低,而SCL保持高电平,表示通信的开始。

  • 地址传输:主设备发送从设备地址(7位或10位),并在末尾加入一个读/写位(0表示写,1表示读)。

  • 应答(ACK):从设备接收到地址后,如果地址匹配,就会拉低SDA线应答。

  • 数据传输:在数据传输过程中,每发送一个字节(8位)后,从设备都需要发送应答位。

  • 停止条件(Stop Condition):主设备将SDA线从低拉到高,而SCL保持高电平,表示通信结束。

二、演示功能概述

本例程将使用 I2C 协议读取传感器数据并打印出来。

三、准备硬件环境

参考:硬件环境清单第二章节内容,准备以及组装好硬件环境。

3.1 Air780EGH 核心板V1.0 及 所需测试配件 SHT20模块

3.2 Air780EGH核心板 与 sht20 接线图示意图

硬件I2C测试接线:

软件I2C测试接线:

3.2.3 注意

当您使用Air780EGH核心板,通过外扩插针的I2C1管脚,外接I2C接口的传感器时,若Air780EGH 核心板没有为I2C1/I2C0两路I2C接口加上拉电阻,需要外接的传感器模块电路上加上拉电阻。

四、软件环境

在开始实践本示例之前,先筹备一下软件环境:

1. Luatools 工具

2. 内核固件文件(底层 core 固件文件):LuatOS-SoC_V2007_Air780EGH;参考项目使用的内核固件

3. luatos需要的脚本和资源文件

脚本和资源文件点我,查看demo链接

lib脚本文件:使用Luatools烧录时,勾选 添加默认lib 选项,使用默认lib脚本文件;

准备好软件环境之后,接下来查看如何烧录项目文件到Air780GH开发板,将本篇文章中演示使用的项目文件烧录到Air780EGH核心板中。

五、使用 I2C 读取 sht20 软硬件资料

5.1 API接口介绍

5.2 I2C硬件参考资料

Air780EGH 支持 2 路通用 I2C 接口,I2C0 和 I2C1 ,其中,推荐优先选择 I2C1

通用 I2C1 接口参考:I2C 接口设计指导

I2C1 配置:

兼容 Philips I2C 标准协议。

支持 Fast mode (400Kbps)和 Slow mode(100Kbps)。

只支持 master 模式,不支持 slave 模式。

理论上最多可支持 127 个从设备。

I2C 的参考电路如下:

Air780EGH 的 I2C1 接口电压是 1.8V/3.3V 可配置。

通过 pm.ioVol(pm.IOVOL_ALL_GPIO, 3300) 设置,该函数设置所有GPIO的电压域,参数为 3300 表示 3.3V,参数为 1800 表示 1.8V。能够满足大部分外设的直接需求,但是如果要和 5V 或者以上电平的外设通信,那就必须要加电平转换电路。

5.3 sht20介绍

sht20特点:

  • 完全校准
  • 数字输出,I2C接口
  • 低功耗
  • 优异的长期稳定性
  • DFN型封装 - 可回流焊接
  • 工作电压范围是2.1~3.6V.
  • I2C速率支持400k
  • 读取温度的命令为:0xF3
  • 读取湿度的命令为:0xF5

六、代码示例介绍

6.1 IO复用配置

使用LuatIO工具配置代码例程中所用的的IO复用管脚配置,如下图所示:

保存为pins_Air780EGH.json, 注意配置文件中"model"对应键值"Air780EGH" 。

6.2 读取 SHT20 温湿度传感器

6.2.1 SHT20 简介:

SHT20 是使用 I2C 协议进行通信的温湿度传感器。

首先我们可以发送 STH20 的 7 位从机地址 +1 位读写位(写 0 读 1),然后发送 8 位的命令,0xF3 是读取温度的命令,0xF5 是读取湿度的命令。发送完后接收应答,等待 20us 之后我们发出 I2C 的结束时序。

下面demo分别通过硬件I2C和软件I2C的方式完成获取SHT20传感器的数据:

    -- LuaTools需要PROJECT和VERSION这两个信息
    PROJECT = "I2C_SHT20_TEST"
    VERSION = "001.000.000"

    --添加硬狗防止程序卡死
    if wdt then
        wdt.init(9000)--初始化watchdog设置为9s
        sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
    end

    --IO电平设置为3.3v
    pm.ioVol(pm.IOVOL_ALL_GPIO, 3300)

    -- 以下测试模块,测试时一次加载一个测试模块

    -- 硬件I2C测试模块
    require "hw_i2c_sht20_test"
    -- 软件I2C测试模块
    --require "soft_i2c_sht20_test"

    -- 用户代码已结束---------------------------------------------
    -- 结尾总是这一句
    sys.run()
    -- sys.run()之后后面不要加任何语句!!!!!

6.2.2 硬件I2C的demo 介绍

初始化硬件 i2c

    -- 使用硬件I2C通道 1
    local i2c_hwid = 1

    --初始化硬件I2C
    local ret = i2c.setup(i2c_hwid)
    log.info("i2c".. i2c_hwid, "hw i2c initial",  ret)

然后给sht20发送读取温湿度命令,接收sht20回传的数据并打印即可。

    --发送0xF3来查询温度
    i2c.send(i2c_hwid, addr, string.char(0xF3)) 
    sys.wait(100)
    --读取传感器的温度值
    tmp = i2c.recv(i2c_hwid, addr, 2)  
    log.info("SHT20", "read tem data", tmp:toHex())

    --发送0xF5来查询湿度
    i2c.send(i2c_hwid, addr, string.char(0xF5)) 
    sys.wait(100)
    --读取传感器湿度值
    hum = i2c.recv(i2c_hwid, addr, 2) 
    log.info("SHT20", "read hum data", hum:toHex())

    --提取一个按照大端字节序编码的16位无符号整数
    local _,tval = pack.unpack(tmp,'>H') 
    local _,hval = pack.unpack(hum,'>H')
    --log.info("SHT20", "tval hval", tval,hval)
    if tval and hval then
        --按照传感器手册来计算对应的温湿度
        temp = (((17572 * tval) >> 16) - 4685)/100
        hump = (((12500 * hval) >> 16) - 600)/100
        log.info("SHT20", "temp,humi",string.format("%.2f",temp),string.format("%.2f",hump))
    end

6.2.3 软件I2C的demo 介绍

指定scl和sda的GPIO,初始化软件I2C

-- 定义软件I2C-SCL
local io_scl = 16
-- 定义软件I2C-SDA
local io_sda = 17

--初始化软件I2C, 返回参数为软件I2C的实例,后续通过该实例来操作i2c的读写操作
local softI2C = i2c.createSoft(io_scl,io_sda)
log.info("i2c", "sw i2c initial",  softI2C)

然后给sht20发送读取温湿度命令,接收sht20回传的数据并打印即可。

    --发送0xF3来查询温度
    i2c.send(softI2C, addr, string.char(0xF3)) 
    sys.wait(100)
    --读取传感器的温度值
    tmp = i2c.recv(softI2C, addr, 2)  
    log.info("SHT20", "read tem data", tmp:toHex())

    --发送0xF5来查询湿度
    i2c.send(softI2C, addr, string.char(0xF5)) 
    sys.wait(100)
    --读取传感器湿度值
    hum = i2c.recv(softI2C, addr, 2) 
    log.info("SHT20", "read hum data", hum:toHex())

    --提取一个按照大端字节序编码的16位无符号整数
    local _,tval = pack.unpack(tmp,'>H') 
    local _,hval = pack.unpack(hum,'>H')
    --log.info("SHT20", "tval hval", tval,hval)
    if tval and hval then
        --按照传感器手册来计算对应的温湿度
        temp = (((17572 * tval) >> 16) - 4685)/100
        hump = (((12500 * hval) >> 16) - 600)/100
        log.info("SHT20", "temp,humi",string.format("%.2f",temp),string.format("%.2f",hump))
    end

七、功能验证

成功使用 I2C 协议读取到 sht20 传感器的温湿度数值。

硬件I2C 测试结果:

软件I2C 测试结果:

八、总结

本例程分别使用硬件i2c和软件i2c的接口读取了 sht20 传感器传输的温湿度数值。

常见问题

1、i2c 每次读写数据前都需要 setup 一次吗?

不需要

正常的业务逻辑为:

i2c.setup

…此处可以多次读写数据

i2c.close

setup 之后,只要没有 close,就可以反复读写数据

一旦执行了 close,下次读写数据前,必须再次 setup

2、i2c 通信时模块可以做从设备吗?

注意:模块 I2C 只能做主设备,(虽然有内部上拉电阻,但是暂时还未实现软件配置)使用时需要外部上拉,在配置 FAST 速率时,上拉电阻阻值不要大于 4.7K。

3、i2c 设备 7 位的地址为 0x38 ,需要我手动转换到 8 位地址吗?

这里 i2c_addr 地址是 7bit 地址

如果 i2c 外设手册中给的是 8bit 地址,需要把 8bit 地址右移 1 位,赋值给 i2c_addr 变量

如果 i2c 外设手册中给的是 7bit 地址,直接把 7bit 地址赋值给 i2c_addr 变量即可

4、I2C0 怎么使用?

I2C0和UART3,SPI1 复用,详见下图:

I2C0 使用:

1) 通过luatIO工具配置使能I2C0的pin脚,如图所示:

具体luatIO工具使用参考

2) Lua代码修改

i2c.setup(0)