Files
BR_YKC/4G/tools/resource/soc_script/v2025.12.31.22/lib/exvib.lua
2026-03-31 15:46:04 +08:00

313 lines
12 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
--[[
@module exvib
@summary exvib 三轴加速度传感器扩展库
@version 1.0
@date 2025.08.10
@author 李源龙
@usage
-- 用法实例
注意:
1. exvib.lua可适用于合宙内部集成了G-Sensor加速度传感器DA221的模组型号
目前仅有Air8000系列模组内置了DA221Air7000推出时也会内置该型号G-Sensor
2. DA221在Air8000内部通过I2C1与之通信并通过WAKEUP2接收运动监测中断
如您使用合宙其它型号模组外接DA221时比如Air780EGH建议与Air8000保持一致也选用I2C1和WAKEUP2
(该管脚即为Air780EGH的PIN79:USIM_DET)这样便可以无缝使用本扩展库DA221的供应商为苏州明皜
如需采购DA221或者其他更高端的加速度传感器可以联系他们
3. DA221作为加速度传感器LuatOS仅支持运动检测这一功能主要用于震动检测运动检测跌倒检测
搭配GNSS实现震动然后定位的功能其余功能请自行研究合宙提供了三种应用场景如果需要适配自己的场景需求
请参考手册参数自行修改代码调试适合自己场景的传感器值合宙不提供DA221任何其它功能的任何形式的技术支持
关于exvib库的三种模式主要用于以下场景
1微小震动检测用于检测轻微震动的场景例如用手敲击桌面加速度量程2g
2运动检测用于电动车或汽车行驶时的检测和人行走和跑步时的检测加速度量程4g
3跌倒检测用于人或物体瞬间跌倒时的检测加速度量程8g
exvib=require("exvib")
local intPin=gpio.WAKEUP2 --中断检测脚内部固定wakeup2
local tid --获取定时打开的定时器id
local num=0 --计数器
local ticktable={0,0,0,0,0} --存放5次中断的tick值用于做有效震动对比
local eff=false --有效震动标志位,用于判断是否触发定位
--有效震动模式
--tick计数器每秒+1用于存放5次中断的tick值用于做有效震动对比
-- local function tick()
-- num=num+1
-- end
-- --每秒运行一次计时
-- sys.timerLoopStart(tick,1000)
-- --有效震动判断
-- local function ind()
-- log.info("int", gpio.get(intPin))
-- if gpio.get(intPin) == 1 then
-- --接收数据如果大于5就删掉第一个
-- if #ticktable>=5 then
-- log.info("table.remove",table.remove(ticktable,1))
-- end
-- --存入新的tick值
-- table.insert(ticktable,num)
-- log.info("tick",num,(ticktable[5]-ticktable[1]<10),ticktable[5]>0)
-- log.info("tick2",ticktable[1],ticktable[2],ticktable[3],ticktable[4],ticktable[5])
-- --表长度为5且第5次中断时间间隔减去第一次间隔小于10s且第5次值为有效值
-- if #ticktable>=5 and (ticktable[5]-ticktable[1]<10 and ticktable[1]>0) then
-- log.info("vib", "xxx")
-- --是否要去触发有效震动逻辑
-- if eff==false then
-- sys.publish("EFFECTIVE_VIBRATION")
-- end
-- end
-- end
-- end
-- --设置30s分钟之后再判断是否有效震动函数
-- local function num_cb()
-- eff=false
-- end
-- local function eff_vib()
-- --触发之后eff设置为true30分钟之后再触发有效震动
-- eff=true
-- --30分钟之后再触发有效震动
-- sys.timerStart(num_cb,180000)
-- end
-- sys.subscribe("EFFECTIVE_VIBRATION",eff_vib)
--持续震动模式
--持续震动模式中断函数
local function ind()
log.info("int", gpio.get(intPin))
--上升沿为触发震动中断
if gpio.get(intPin) == 1 then
local x,y,z = exvib.read_xyz() --读取xyz轴的数据
log.info("x", x..'g', "y", y..'g', "z", z..'g')
end
end
local function vib_fnc()
-- 1微小震动检测用于检测轻微震动的场景例如用手敲击桌面加速度量程2g
-- 2运动检测用于电动车或汽车行驶时的检测和人行走和跑步时的检测加速度量程4g
-- 3跌倒检测用于人或物体瞬间跌倒时的检测加速度量程8g
--打开震动检测功能
exvib.open(1)
--设置gpio防抖100ms
gpio.debounce(intPin, 100)
--设置gpio中断触发方式wakeup2唤醒脚默认为双边沿触发
gpio.setup(intPin, ind)
end
sys.taskInit(vib_fnc)
]]
local exvib={}
local i2cId=0
local bsp=rtos.bsp()
if bsp:find("780") then
i2cId = 1
end
local da221Addr = 0x27
local soft_reset = {0x00, 0x24} -- 软件复位地址
local chipid_addr = 0x01 -- 芯片ID地址
local rangeaddr = {0x0f, 0x00} -- 设置加速度量程默认2g
-- local rangeaddr = {0x0f, 0x01} -- 设置加速度量程默认4g
-- local rangeaddr = {0x0f, 0x10} -- 设置加速度量程默认8g
local int_set1_reg = {0x16, 0x87} --设置x,y,z发生变化时产生中断
local int_set2_reg = {0x17, 0x10} --使能新数据中断,数据变化时,产生中断,本程序不设置
local int_map1_reg = {0x19, 0x04} --运动的时候,产生中断
local int_map2_reg = {0x1a, 0x01}
local active_dur_addr = {0x27, 0x01} -- 设置激活时间默认0x01
local active_ths_addr = {0x28, 0x33} -- 设置激活阈值,灵敏度最高
-- local active_ths_addr = {0x28, 0x80} -- 设置激活阈值,灵敏度适中
-- local active_ths_addr = {0x28, 0xFE} -- 设置激活阈值,灵敏度最低
local odr_addr = {0x10, 0x08} -- 设置采样率 100Hz
local mode_addr = {0x11, 0x00} -- 设置正常模式
local int_latch_addr = {0x21, 0x02} -- 设置中断锁存
local x_lsb_reg = 0x02 -- X轴LSB寄存器地址
local x_msb_reg = 0x03 -- X轴MSB寄存器地址
local y_lsb_reg = 0x04 -- Y轴LSB寄存器地址
local y_msb_reg = 0x05 -- Y轴MSB寄存器地址
local z_lsb_reg = 0x06 -- Z轴LSB寄存器地址
local z_msb_reg = 0x07 -- Z轴MSB寄存器地址
local active_state = 0x0b -- 激活状态寄存器地址
local active_state_data
local rangemode=1
local x_accel
local y_accel
local z_accel
--[[
获取da221的xyz轴数据
@api exvib.read_xyz()
@return number x轴数据number y轴数据number z轴数据
@usage
local x,y,z = exvib.read_xyz() --读取xyz轴的数据
log.info("x", x..'g', "y", y..'g', "z", z..'g')
]]
function exvib.read_xyz()
-- da221是LSB在前MSB在后每个寄存器都是1字节数据每次读取都是6个寄存器数据一起获取
-- 因此直接从X轴LSB寄存器(0x02)开始连续读取6字节数据(X/Y/Z各2字节),避免出现数据撕裂问题
i2c.send(i2cId, da221Addr, x_lsb_reg, 1)
local recv_data = i2c.recv(i2cId, da221Addr, 6)
-- LSB数据格式为: D[3] D[2] D[1] D[0] unused unused unused unused
-- MSB数据格式为: D[11] D[10] D[9] D[8] D[7] D[6] D[5] D[4]
-- 数据位为12位需要将MSB数据左移4位LSB数据右移4位最后进行或运算
-- 解析X轴数据 (LSB在前MSB在后)
local x_data = (string.byte(recv_data, 2) << 4) | (string.byte(recv_data, 1) >> 4)
-- 解析Y轴数据 (LSB在前MSB在后)
local y_data = (string.byte(recv_data, 4) << 4) | (string.byte(recv_data, 3) >> 4)
-- 解析Z轴数据 (LSB在前MSB在后)
local z_data = (string.byte(recv_data, 6) << 4) | (string.byte(recv_data, 5) >> 4)
-- 转换为12位有符号整数
-- 判断X轴数据是否大于2047若大于则表示数据为负数
-- 因为12位有符号整数的范围是 -2048 到 2047原始数据为无符号形式大于2047的部分需要转换为负数
-- 通过减去4096 (2^12) 将无符号数转换为对应的有符号负数
if x_data > 2047 then x_data = x_data - 4096 end
-- 判断Y轴数据是否大于2047若大于则进行同样的有符号转换
if y_data > 2047 then y_data = y_data - 4096 end
-- 判断Z轴数据是否大于2047若大于则进行同样的有符号转换
if z_data > 2047 then z_data = z_data - 4096 end
-- 转换为加速度值单位g
if rangemode == 1 then
x_accel = x_data / 1024
y_accel = y_data / 1024
z_accel = z_data / 1024
elseif rangemode == 2 then
x_accel = x_data / 512
y_accel = y_data / 512
z_accel = z_data / 512
elseif rangemode == 3 then
x_accel = x_data / 256
y_accel = y_data / 256
z_accel = z_data / 256
else
x_accel = x_data / 1024
y_accel = y_data / 1024
z_accel = z_data / 1024
end
-- 输出加速度值单位g
return x_accel, y_accel, z_accel
end
--初始化da221
local function da221_init()
if bsp:find("780") then
gpio.setup(23, 1, gpio.PULLUP) -- gsensor 开关
else
gpio.setup(24, 1, gpio.PULLUP) -- gsensor 开关
end
--关闭i2c
i2c.close(i2cId)
--重新打开i2c,i2c速度设置为低速
i2c.setup(i2cId, i2c.SLOW)
sys.wait(50)
i2c.send(i2cId, da221Addr, soft_reset, 1) --复位da221
sys.wait(50)
i2c.send(i2cId, da221Addr, chipid_addr, 1) --读取芯片id
local chipid = i2c.recv(i2cId, da221Addr, 1) --接收返回的芯片id
log.info("i2c", "chipid",chipid:toHex())
if string.byte(chipid) == 0x13 then
log.info("exvib init success")
else
log.info("exvib init fail")
end
-- 设置寄存器
i2c.send(i2cId, da221Addr, rangeaddr, 1) --设置加速度量程默认2g
sys.wait(5)
i2c.send(i2cId, da221Addr, int_set1_reg, 1) --设置x,y,z发生变化时产生中断
sys.wait(5)
i2c.send(i2cId, da221Addr, int_map1_reg, 1)--运动的时候,产生中断
sys.wait(5)
i2c.send(i2cId, da221Addr, active_dur_addr, 1)-- 设置激活时间默认0x00
sys.wait(5)
i2c.send(i2cId, da221Addr, active_ths_addr, 1)-- 设置激活阈值
sys.wait(5)
i2c.send(i2cId, da221Addr, mode_addr, 1)-- 设置模式
sys.wait(5)
i2c.send(i2cId, da221Addr, odr_addr, 1)-- 设置采样率
sys.wait(5)
i2c.send(i2cId, da221Addr, int_latch_addr, 1)-- 设置中断锁存 中断一旦触发将保持,直到手动清除
sys.wait(5)
end
--[[
打开da221
@api exvib.open(mode)
@number da221模式设置1微小震动检测用于检测轻微震动的场景例如用手敲击桌面加速度量程2g
2运动检测用于电动车或汽车行驶时的检测和人行走和跑步时的检测加速度量程4g
3跌倒检测用于人或物体瞬间跌倒时的检测加速度量程8g
@return nil 无返回值
@usage
exvib.open(1)
]]
function exvib.open(mode)
rangemode=mode
if mode==1 or tonumber(mode)==1 then
--轻微检测
log.info("轻微检测")
rangeaddr = {0x0f, 0x00} -- 设置加速度量程默认2g
active_ths_addr = {0x28, 0x33} -- 设置激活阈值
odr_addr = {0x10, 0x04} -- 设置采样率 15.63Hz
active_dur_addr = {0x27, 0x01} -- 设置激活时间
elseif mode==2 or tonumber(mode)==2 then
--常规检测
log.info("运动检测")
rangeaddr = {0x0f, 0x01} -- 设置加速度量程默认4g
active_ths_addr = {0x28, 0x26} -- 设置激活阈值
odr_addr = {0x10, 0x08} -- 设置采样率 250Hz
active_dur_addr = {0x27, 0x14} -- 设置激活时间
elseif mode==3 or tonumber(mode)==3 then
log.info("高动态检测")
--高动态检测
rangeaddr = {0x0f, 0x02} -- 设置加速度量程默认8g
active_ths_addr = {0x28, 0x80} -- 设置激活阈值
odr_addr = {0x10, 0x0F} -- 设置采样率 1000Hz
active_dur_addr = {0x27, 0x04} -- 设置激活时间
end
sys.taskInit(da221_init)
end
--[[
关闭da221
@api exvib.close()
@return nil 无返回值
@usage
exvib.close()
]]
function exvib.close()
if bsp:find("780") then
gpio.close(23) -- gsensor供电关闭
else
gpio.close(24) -- gsensor供电关闭
end
gpio.close(24) -- gsensor供电关闭
log.info("exvib close..")
end
return exvib