I2C
一、I2C 概述
I2C(Inter-Integrated Circuit)是一种串行通信协议,广泛用于微控制器和各种外围设备之间的通信。它采用两根线(SDA 数据线和 SCL 时钟线)进行数据传输,支持多个从设备挂载在同一总线上,通过设备地址进行区分。I2C 协议具有简单、高效、低功耗等优点,是嵌入式系统中常用的通信方式之一。
I2C 配置:
兼容 Philips I2C 标准协议。
支持 Fast mode (400Kbps)和 Slow mode(100Kbps)。
只支持 master 模式,不支持 slaver 模式。
理论上最多可支持 127 个从设备。
二、演示功能概述
本 demo 主要讲述 LuatOS 的 I2C 总线的用法,包括 I2C 初始化、I2C 发送数据、I2C 接收数据等接口的相关用法。采用 SHT20 温湿度传感器来进行演示,通过 I2C 来读取温湿度,并将读取到的原始值转化为温度值以及湿度百分比,同时会搭配逻辑分析仪一步一步去分析 I2C 总线波形。
整体逻辑如下:
三、准备硬件环境
1、AIR8101 开发板准备环境:
“古人云:‘工欲善其事,必先利其器。’在深入介绍本功能示例之前,我们首先需要确保以下硬件环境的准备工作已经完成。”
参考:硬件环境清单,准备以及组装好硬件环境。
2、I2C 传感器模块:
淘宝上自行选择购买。
四、准备软件环境
“凡事预则立,不预则废。”在详细阐述本功能示例之前,我们需先精心筹备好以下软件环境。
1. Luatools 工具;
2. 内核固件文件(底层 core 固件文件):LuatOS-SoC_V1002_Air8101.soc;参考项目使用的内核固件;
3. LuatOS 需要的脚本和资源文件 脚本和资源文件:https://gitee.com/openLuat/LuatOS-Air8101/tree/master/demo/I2C
lib 脚本文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件;
准备好软件环境之后,接下来查看如何烧录项目文件到 Air8101 开发板,将本篇文章中演示使用的项目文件烧录到 Air8101 开发板中。
五、I2C 软硬件参考
5.1 API 接口介绍
本教程使用 api 接口为:
https://docs.openluat.com/air780e/luatos/api/core/i2c/
注意:luatos 的 api 接口是通用的。
5.2 I2C 硬件设计
5.2.1 I2C 硬件电路
AIR8101 可支持两路 I2C。
Air8101 用于 LuatOS 二次开发方式时的 GPIO 引脚复用表,可以点击查看 AIR8101 的引脚复用表,查看可以复用为 I2C 的管脚。
I2C 的参考电路如下:
5.2.2 软件模拟 I2C
软件模拟 I2C 是一种使用普通的 GPIO 引脚,通过软件控制引脚的电平变化,来模拟 I2C 协议的通信方式。
当芯片自带的 I2C 个数无法满足需求或者所用引脚被其他功能占用时,可以使用软件模拟 I2C 接口来实现功能。
六、代码示例介绍
本教程演示 AIR8101 通过 I2C 驱动 SHT20 温湿度传感器来读取温湿度值。在 demo 中会有硬件 I2C 驱动以及软件 I2C 两种不同的方式。本教程主要演示硬件 I2C 来驱动,代码中注释掉的部分是通过软件 I2C 来进行驱动,可以根据自己需求来选择软硬件方式。
6.1 软件代码介绍
-- LuaTools需要PROJECT和VERSION这两个信息
PROJECT = "sht20demo"
VERSION = "1.0.0"
-- sys库是标配
sys = require("sys")
--添加硬狗防止程序卡死
if wdt then
wdt.init(9000) -- 初始化watchdog设置为9s
sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
end
--本demo演示通过I2C协议去读取SHT20温湿度传感器的过程,并介绍luatos中I2C相关接口的用法。
-- 接线
--[[
SHT20 --- 模块
SDA - I2C_SDA
SCL - I2C_SCL
VCC - VDDIO
GND - GND
]]
--第一种方式,通过硬件I2C来驱动
-- 启动个task, 定时查询SHT20的数据
sys.taskInit(function()
local tmp,hum -- 原始数据
local temp,hump -- 真实值
--0100 0000 传感器七位地址
local addr = 0x40
-- 按实际修改哦
local id = 0
------------------硬件I2C---------------------------------
log.info("i2c", "initial",i2c.setup(id)) --初始化I2C
while true do
i2c.send(id, addr, string.char(0xF3)) --发送0xF3来查询温度
sys.wait(100)
tmp = i2c.recv(id, addr, 2) --读取传感器的温度值
log.info("SHT20", "read tem data", tmp:toHex())
i2c.send(id, addr, string.char(0xF5)) --发送0xF5来查询湿度
sys.wait(100)
hum = i2c.recv(id, addr, 2) --读取传感器湿度值
log.info("SHT20", "read hum data", hum:toHex())
local _,tval = pack.unpack(tmp,'>H') --提取一个按照大端字节序编码的16位无符号整数
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
sys.wait(1000)
end
------------------软件I2C---------------------------------
-- local softI2C = i2c.createSoft(20,21)
-- while true do
-- i2c.send(softI2C, addr, string.char(0xF3)) --发送0xF3来查询温度
-- sys.wait(100)
-- tmp = i2c.recv(softI2C, addr, 2) --读取传感器的温度值
-- log.info("SHT20", "read tem data", tmp:toHex())
-- i2c.send(softI2C, addr, string.char(0xF5)) --发送0xF5来查询湿度
-- sys.wait(100)
-- hum = i2c.recv(softI2C, addr, 2) --读取传感器湿度值
-- log.info("SHT20", "read hum data", hum:toHex())
-- local _,tval = pack.unpack(tmp,'>H') --提取一个按照大端字节序编码的16位无符号整数
-- 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
-- sys.wait(1000)
-- end
end)
-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后后面不要加任何语句!!!!!
6.2 效果展示
通过观察日志可以看到在循环读取 SHT20 的温湿度值:
6.3 I2C 驱动波形参考
抓取循环中某次读取的传感器温湿度值为例分析具体波形:
在 I2C 初始化后首先发送 0xF3 来查询 SHT20 的温度值,其 I2C 波形如下:
读取传感器返回的温度值:
然后发送 0xF5 来读取传感器的湿度值:
读取传感器返回的湿度值:
七、总结
至此,我们已使用 Air8101 开发板的 I2C 接口完成了对 SHT20 读写操作。
八、常见问题
1 i2c 每次读写数据前都需要 setup 一次吗?
不需要
正常的业务逻辑为:
i2c.setup
…此处可以多次读写数据
i2c.close
setup 之后,只要没有 close,就可以反复读写数据
一旦执行了 close,下次读写数据前,必须再次 setup
2 i2c 通信时模块可以做从设备吗?
注意:模块 I2C 只能做主设备,并且 SCL 和 SDA 要有上拉电阻。
3、i2c 设备 7 位的地址为 0x38 ,需要我手动转换到 8 位地址吗?
这里 i2c_addr 地址是 7bit 地址
如果 i2c 外设手册中给的是 8bit 地址,需要把 8bit 地址右移 1 位,赋值给 i2c_addr 变量
如果 i2c 外设手册中给的是 7bit 地址,直接把 7bit 地址赋值给 i2c_addr 变量即可