跳转至

I2C

一、简介

I2C 总线(Inter-Integrated Circuit)是由 Philips 公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。

Air724UG 模块提供 2 个 I2C 接口,速率支持 FAST(400KHz)、SLOW(100KHz)、3500KHz。外设地址支持 0x00-0x7f。

1.1 特性

  • 支持 Fast mode (400Kbps)和 Slow mode(100Kbps)
  • 只支持 I2C master 模式
  • 可通过软件来配置内部的上拉电阻,1.8K 或者 20K
  • 模块最多支持 2 路独立的 I2C 接口
  • 理论上最多可以支持 127 个从设备

1.2 模块 I2C 功能列表

接口
名称
复用
Air724UG引脚序号
作用
I2C1
CAMI2C_SCL1
I2C1_SCL
51
I2C1 时钟信号
I2C1
CAMI2C_SDA1
I2C1_SDA
50
I2C1 数据信号
I2C2
I2C2_SCL
I2C2_SCL
32
I2C2 时钟信号
I2C2

I2C2_SDA
I2C2_SDA
31
I2C2 数据信号

注意: 请优先使用I2C2,I2C1预留给摄像头使用。

二、演示功能概述

本教程教你如何用 Air724 开发板,演示 I2C 功能,AHT10 数字型温湿度传感器读取温湿度并通过日志观察实验结果。

三、准备硬件环境

3.1 开发板准备

使用 EVB_Air724 开发板,如下图所示:

淘宝购买链接:Air724UG-NFM 开发板淘宝购买链接

此开发板的详细使用说明参考:Air724UG 产品手册 中的《EVB_Air724UG_AXX 开发板使用说明》,写这篇文章时最新版本的使用说明为:《EVB_Air724UG_A14 开发板使用说明》;开发板使用过程中遇到任何问题,可以直接参考这份使用说明文档。

api:https://doc.openluat.com/wiki/21?wiki_page_id=2068

3.2 AHT10 模块

AHT10 数字型温湿度传感器模块购买链接:点击此处

3.3 数据通信线

USB 数据线一根(micro USB)。

3.4 PC 电脑

WIN7 以及以上版本的 WINDOWS 系统。

3.5 SIM 卡

中国大陆环境下,可以上网的 SIM 卡。一般来说,使用移动,电信,联通的物联网卡或者手机卡都行。

3.6 组装硬件环境

USB 数据线插入 USB 口,另一端与电脑相连,拨码开关全部拨到 ON,串口切换开关选择 UART1,USB 供电的 4V 对应开关拨至 ON 档,SIM 卡放到 SIM 卡槽中锁紧,如下图所示。

3.7 主板和传感器连接

确保 SDA、SCL、GND、VIN 分别连接主板和传感器,如下图所示。

四、准备软件环境

4.1 下载调试工具

使用说明参考:Luatools 下载和详细使用

4.2 源码及固件

1.底层 core 下载

下载底层固件,并解压

链接:https://docs.openluat.com/air724ug/luatos/firmware/

如下图所示,红框的是我们要使用到的。

2.本教程使用的 demo:

https://gitee.com/openLuat/LuatOS-Air724UG/tree/master/script_LuaTask/demo/peripheral/%E6%B8%A9%E6%B9%BF%E5%BA%A6%E4%BC%A0%E6%84%9F%E5%99%A8/AHT10

4.3 下载固件和脚本到开发板中

打开 Luatools,开发板上电开机,如开机成功 Luatools 会打印如下信息。

点击项目管理测试选项。

进入管理界面,如下图所示。

  • 点击选择文件,选择底层固件,我的文件放在 D:\luatOS\Air724 路径中

  • 点击增加脚本或资源文件,选择 之前下载的程序源码,如下图所示。

  • 点击下载底层和脚本,下载完成如下图所示。

五、代码示例介绍

5.1 API 说明

5.1.1 i2c.setup( id, speed [,slaveaddr] [,isbaud] [,reg16bit])

打开 i2c 接口

参数

参数
类型
释义
取值
id
number
i2c 接口 id
core 0025 版本之前,0、1、2 都表示 i2c2core 0025 以及之后的版本,1、2、3 分别表示 i2c 1、2、3
speed
number
时钟频率
0~3500000
[,slaveaddr]
number
可选,i2c 外设地址
0x00-0x7f
[,isbaud]
number
可选自定义波特率开关 0/1-关闭/开启
0/1
[,reg16bit]

number
双字节寄存器配置开关 0/1-关闭/开启
0/1

返回值

返回值
类型
释义
取值
result
number
可以根据返回的频率值判断是否成功打开 i2c
0~3500000

例子

_--使用i2c.send和i2c.recv的setup_
if i2c.setup(i2cid,100000) ~= 100000 then
print("init fail")
return
end
_--自定义i2c波特率(不想指定地址可以将第三个参数置为-1),波特率自定义开关 第四个参数:1 打开 0 关闭_
if i2c.setup(i2cid,2400,-1,1) ~= 2400 then
print("init fail")
return
end
_--使用i2c.write和i2c.read的setup_
if i2c.setup(i2cid,100000,i2cslaveaddr) ~= 100000 then
print("init1 fail")
return
end

5.1.2 i2c.write( id, reg, data )

往指定的寄存器地址 reg 传输数据

参数

参数
类型
释义
取值
id
number
i2c 接口 id
core 0025 版本之前,0、1、2 都表示 i2c2core 0025 以及之后的版本,1、2、3 分别表示 i2c 1、2、3
reg
number
写入 i2c 从设备的寄存器起始地址

data
number
number / string / table,自动根据参数类型写数据,num 只写 1 个字节,string/table

返回值

返回值
类型
释义
取值
result
number
传输成功的字节数

例子

local cmd,i = {0x1B,0x00,0x6A,0x01,0x1E,0x20,0x21,0x04,0x1B,0x00,0x1B,0xDA,0x1B,0xDA}
for i=1,#cmd,2 do_--向从设备的寄存器地址cmd[i]中写1字节的数据cmd[i+1]_
  i2c.write(i2cid,cmd[i],cmd[i+1])
end

5.1.3 i2c.read( id, reg, num )

读取指定寄存器地址 reg 的数据内容

参数

参数
类型
释义
取值
id
number
i2c 接口 id
core 0025 版本之前,0、1、2 都表示 i2c2core 0025 以及之后的版本,1、2、3 分别表示 i2c 1、2、3
reg
number
读取 i2c 从设备的寄存器起始地址

num
number
读取数据字节数

返回值

返回值
类型
释义
取值
返回读取的数据
string
二进制数据会包含非可见字符,请使用 string.byte 打印数据流

例子

_--从从设备的寄存器地址cmd[i]中读1字节的数据,并且打印出来_
local cmd,i = {0x1B,0x00,0x6A,0x01,0x1E,0x20,0x21,0x04,0x1B,0x00,0x1B,0xDA,0x1B,0xDA}
for i=1,#cmd,2 do
_--向从设备的寄存器地址cmd[i]中写1字节的数据cmd[i+1]_
        i2c.write(i2cid,cmd[i],cmd[i+1])
        _--从从设备的寄存器地址cmd[i]中读1字节的数据,并且打印出来_
        print("testI2c.init1",string.format("%02X",cmd[i]),string.toHex(i2c.read(i2cid,cmd[i],1)))
        end

5.1.4 i2c.send( id,slave, data )

向从设备写数据

参数

参数
类型
释义
取值
id
number
i2c 接口 id
core 0025 版本之前,0、1、2 都表示 i2c2core 0025 以及之后的版本,1、2、3 分别表示 i2c 1、2、3
slave
number
i2c 外设地址
0x00-0x7f
data
number/string/table
自动根据参数类型写数据,num 只写 1 个字节,string/table 自动

返回值

返回值
类型
释义
取值
result
string
返回读取的数据,二进制数据会包含非可见字符,请使用 string.byte 打印数据流

例子

_--从从设备的寄存器地址cmd[i]中读1字节的数据,并且打印出来_
local cmd,i = {0x1B,0x00,0x6A,0x01,0x1E,0x20,0x21,0x04,0x1B,0x00,0x1B,0xDA,0x1B,0xDA}
for i=1,#cmd,2 do
_--向从设备的寄存器地址cmd[i]中写1字节的数据cmd[i+1]_
        i2c.write(i2cid,cmd[i],cmd[i+1])
        _--从从设备的寄存器地址cmd[i]中读1字节的数据,并且打印出来_
        print("testI2c.init1",string.format("%02X",cmd[i]),string.toHex(i2c.read(i2cid,cmd[i],1)))
        end

5.1.5 i2c.recv( id, slave,size )

向从设备读取数据

参数

参数
类型
释义
取值
id
number
i2c 接口 id,core 0025 版本之前,0、1、2 都表示 i2c2core 0025 以及之后的版本,1、2、3 分别表示 i2c 1、2、3

slave
number
i2c 外设地址
0x00-0x7f
size
number
读取数据字节数

返回值

返回值
类型
释义
取值
result
string
返回读取的数据,二进制数据会包含非可见字符,请使用 string.byte 打印数据流

例子

_--向从设备i2cslaveaddr发送寄存器地址cmd[i]_
i2c.send(i2cid,i2cslaveaddr,cmd[i])
_--读取从设备i2cslaveaddr寄存器内的1个字节的数据,并且打印出来_
print("testI2c.init",string.format("%02X",cmd[i]),string.toHex(i2c.recv(i2cid,i2cslaveaddr,1)))

5.1.6 i2c.close( id )

关闭 I2C 接口

参数

参数
类型
释义
取值
id
number
i2c 接口 id
core 0025 版本之前,0、1、2 都表示 i2c2core 0025 以及之后的版本,1、2、3 分别表示 i2c 1、2、3

返回值

5.2 AHT10.lua 代码

打开 AHT10 传感器,读取温湿度寄存器,解释温湿度数据,打印日志。

--- 模块功能:AHT10功能测试.
-- @module i2c
-- @author openLuat
-- @license MIT
-- @copyright OpenLuat.com
-- @release 2021.8.10
local function i2c_open(id)
    if i2c.setup(id, i2c.SLOW) ~= i2c.SLOW then
        log.error("I2C.init is: ", "fail")
    end
end

function readAHT10()
    local id = 2
    i2c_open(id)
    --数值查询,发送指令0xAC, 0x22, 0x00,通过I2C发送完毕之后,AHT10返回的数值是6个字节的数组
    i2c.send(id, 0x38, {0xAC, 0x22, 0x00})
    --等待75毫秒以上
    --rtos.sleep(80)
    --1[状态位],2[湿度第一段],3[湿度第二段],4前四位[湿度第三段],4后四位[温度第一段],5[温度第二段],6[温度第三段]
    local data = i2c.recv(id, 0x38, 6)
    log.info("i2cdata", #data, data:toHex())
    i2c.close(id)
    if #data == 6 then
        local _, _, data2, data3, data4, data5, data6 = pack.unpack(data, "b6")
        local hum = bit.bor(bit.bor(bit.lshift(data2, 12), bit.lshift(data3, 4)), bit.rshift(data4, 4))/ 1048576 * 10000
        log.info("hum", hum/100 )
        local tmp = bit.bor(bit.bor(bit.lshift(bit.band(data4, 0x0f), 16), bit.lshift(data5, 8)), data6) / 1048576 * 20000 - 5000
        log.info("tmp", tmp/100)
        --前面将数据放大了100倍,方便没有float的固件保留精度,在使用float固件时直接缩小100倍还原
        --return tmp, hum
        return tmp/100, hum/100
    else
        return 0, 0
    end
end

sys.timerLoopStart(readAHT10,2000)

5.3 main.lua 代码

本代码为主程序脚本,系统启动后首先会对 4G 网络进行配置,等待网络连接成功,然后加载测试模块。

六、开机调试

6.1 开发板开机

连接好硬件并下载固件后,启动 Luatools 软件,系统运行信息将显示在界面中。红框中为开发板连接到 PC 机后正常打印的信息,如下图所示。

6.2 功能调试

系统循环打印温湿度数据。

七、常见问题

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

不需要

正常的业务逻辑为:

i2c.setup

…此处可以多次读写数据

i2c.close

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

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

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

注意:模块 I2C 只能做主设备,外部需要上拉,在配置 FAST 速率时,上拉电阻阻值不要大于 4.7K。

7.3 i2c 通信时主从机电平不一样,要做电平转换吗?

如果主从设备的参考电平不一致,请注意做电平转换。如下图:

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

这里 i2c_addr 地址是 7bit 地址

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

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

给读者的话

本篇文章由杨超开发;

本篇文章描述的内容,如果有错误、细节缺失、细节不清晰或者其他任何问题,总之就是无法解决您遇到的问题;

请登录合宙技术交流论坛,点击文档找错赢奖金-Air724UG-LuatOS-软件指南-外设驱动实现-I2C

用截图标注+文字描述的方式跟帖回复,记录清楚您发现的问题;

我们会迅速核实并且修改文档;

同时也会为您累计找错积分,您还可能赢取月度找错奖金!