exvib.lua 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. --[[
  2. @module exvib
  3. @summary exvib 三轴加速度传感器扩展库
  4. @version 1.0
  5. @date 2025.08.10
  6. @author 李源龙
  7. @usage
  8. -- 用法实例
  9. 注意:
  10. 1. exvib.lua可适用于合宙内部集成了G-Sensor加速度传感器DA221的模组型号,
  11. 目前仅有Air8000系列模组内置了DA221,Air7000推出时也会内置该型号G-Sensor;
  12. 2. DA221在Air8000内部通过I2C1与之通信,并通过WAKEUP2接收运动监测中断,
  13. 如您使用合宙其它型号模组外接DA221时,比如Air780EGH,建议与Air8000保持一致也选用I2C1和WAKEUP2
  14. (该管脚即为Air780EGH的PIN79:USIM_DET),这样便可以无缝使用本扩展库,DA221的供应商为苏州明皜
  15. 如需采购DA221或者其他更高端的加速度传感器可以联系他们;
  16. 3. DA221作为加速度传感器,LuatOS仅支持运动检测这一功能,主要用于震动检测,运动检测,跌倒检测,
  17. 搭配GNSS实现震动然后定位的功能,其余功能请自行研究,合宙提供了三种应用场景,如果需要适配自己的场景需求,
  18. 请参考手册参数自行修改代码,调试适合自己场景的传感器值,合宙不提供DA221任何其它功能的任何形式的技术支持;
  19. 关于exvib库的三种模式主要用于以下场景:
  20. 1,微小震动检测,用于检测轻微震动的场景,例如用手敲击桌面;加速度量程2g;
  21. 2,运动检测,用于电动车或汽车行驶时的检测和人行走和跑步时的检测;加速度量程4g;
  22. 3,跌倒检测,用于人或物体瞬间跌倒时的检测;加速度量程8g;
  23. exvib=require("exvib")
  24. local intPin=gpio.WAKEUP2 --中断检测脚,内部固定wakeup2
  25. local tid --获取定时打开的定时器id
  26. local num=0 --计数器
  27. local ticktable={0,0,0,0,0} --存放5次中断的tick值,用于做有效震动对比
  28. local eff=false --有效震动标志位,用于判断是否触发定位
  29. --有效震动模式
  30. --tick计数器,每秒+1用于存放5次中断的tick值,用于做有效震动对比
  31. -- local function tick()
  32. -- num=num+1
  33. -- end
  34. -- --每秒运行一次计时
  35. -- sys.timerLoopStart(tick,1000)
  36. -- --有效震动判断
  37. -- local function ind()
  38. -- log.info("int", gpio.get(intPin))
  39. -- if gpio.get(intPin) == 1 then
  40. -- --接收数据如果大于5就删掉第一个
  41. -- if #ticktable>=5 then
  42. -- log.info("table.remove",table.remove(ticktable,1))
  43. -- end
  44. -- --存入新的tick值
  45. -- table.insert(ticktable,num)
  46. -- log.info("tick",num,(ticktable[5]-ticktable[1]<10),ticktable[5]>0)
  47. -- log.info("tick2",ticktable[1],ticktable[2],ticktable[3],ticktable[4],ticktable[5])
  48. -- --表长度为5且,第5次中断时间间隔减去第一次间隔小于10s,且第5次值为有效值
  49. -- if #ticktable>=5 and (ticktable[5]-ticktable[1]<10 and ticktable[1]>0) then
  50. -- log.info("vib", "xxx")
  51. -- --是否要去触发有效震动逻辑
  52. -- if eff==false then
  53. -- sys.publish("EFFECTIVE_VIBRATION")
  54. -- end
  55. -- end
  56. -- end
  57. -- end
  58. -- --设置30s分钟之后再判断是否有效震动函数
  59. -- local function num_cb()
  60. -- eff=false
  61. -- end
  62. -- local function eff_vib()
  63. -- --触发之后eff设置为true,30分钟之后再触发有效震动
  64. -- eff=true
  65. -- --30分钟之后再触发有效震动
  66. -- sys.timerStart(num_cb,180000)
  67. -- end
  68. -- sys.subscribe("EFFECTIVE_VIBRATION",eff_vib)
  69. --持续震动模式
  70. --持续震动模式中断函数
  71. local function ind()
  72. log.info("int", gpio.get(intPin))
  73. --上升沿为触发震动中断
  74. if gpio.get(intPin) == 1 then
  75. local x,y,z = exvib.read_xyz() --读取x,y,z轴的数据
  76. log.info("x", x..'g', "y", y..'g', "z", z..'g')
  77. end
  78. end
  79. local function vib_fnc()
  80. -- 1,微小震动检测,用于检测轻微震动的场景,例如用手敲击桌面;加速度量程2g;
  81. -- 2,运动检测,用于电动车或汽车行驶时的检测和人行走和跑步时的检测;加速度量程4g;
  82. -- 3,跌倒检测,用于人或物体瞬间跌倒时的检测;加速度量程8g;
  83. --打开震动检测功能
  84. exvib.open(1)
  85. --设置gpio防抖100ms
  86. gpio.debounce(intPin, 100)
  87. --设置gpio中断触发方式wakeup2唤醒脚默认为双边沿触发
  88. gpio.setup(intPin, ind)
  89. end
  90. sys.taskInit(vib_fnc)
  91. ]]
  92. local exvib={}
  93. local i2cId=0
  94. local bsp=rtos.bsp()
  95. if bsp:find("780") then
  96. i2cId = 1
  97. end
  98. local da221Addr = 0x27
  99. local soft_reset = {0x00, 0x24} -- 软件复位地址
  100. local chipid_addr = 0x01 -- 芯片ID地址
  101. local rangeaddr = {0x0f, 0x00} -- 设置加速度量程,默认2g
  102. -- local rangeaddr = {0x0f, 0x01} -- 设置加速度量程,默认4g
  103. -- local rangeaddr = {0x0f, 0x10} -- 设置加速度量程,默认8g
  104. local int_set1_reg = {0x16, 0x87} --设置x,y,z发生变化时,产生中断
  105. local int_set2_reg = {0x17, 0x10} --使能新数据中断,数据变化时,产生中断,本程序不设置
  106. local int_map1_reg = {0x19, 0x04} --运动的时候,产生中断
  107. local int_map2_reg = {0x1a, 0x01}
  108. local active_dur_addr = {0x27, 0x01} -- 设置激活时间,默认0x01
  109. local active_ths_addr = {0x28, 0x33} -- 设置激活阈值,灵敏度最高
  110. -- local active_ths_addr = {0x28, 0x80} -- 设置激活阈值,灵敏度适中
  111. -- local active_ths_addr = {0x28, 0xFE} -- 设置激活阈值,灵敏度最低
  112. local odr_addr = {0x10, 0x08} -- 设置采样率 100Hz
  113. local mode_addr = {0x11, 0x00} -- 设置正常模式
  114. local int_latch_addr = {0x21, 0x02} -- 设置中断锁存
  115. local x_lsb_reg = 0x02 -- X轴LSB寄存器地址
  116. local x_msb_reg = 0x03 -- X轴MSB寄存器地址
  117. local y_lsb_reg = 0x04 -- Y轴LSB寄存器地址
  118. local y_msb_reg = 0x05 -- Y轴MSB寄存器地址
  119. local z_lsb_reg = 0x06 -- Z轴LSB寄存器地址
  120. local z_msb_reg = 0x07 -- Z轴MSB寄存器地址
  121. local active_state = 0x0b -- 激活状态寄存器地址
  122. local active_state_data
  123. local rangemode=1
  124. local x_accel
  125. local y_accel
  126. local z_accel
  127. --[[
  128. 获取da221的xyz轴数据
  129. @api exvib.read_xyz()
  130. @return number x轴数据,number y轴数据,number z轴数据
  131. @usage
  132. local x,y,z = exvib.read_xyz() --读取x,y,z轴的数据
  133. log.info("x", x..'g', "y", y..'g', "z", z..'g')
  134. ]]
  135. function exvib.read_xyz()
  136. -- da221是LSB在前,MSB在后,每个寄存器都是1字节数据,每次读取都是6个寄存器数据一起获取
  137. -- 因此直接从X轴LSB寄存器(0x02)开始连续读取6字节数据(X/Y/Z各2字节),避免出现数据撕裂问题
  138. i2c.send(i2cId, da221Addr, x_lsb_reg, 1)
  139. local recv_data = i2c.recv(i2cId, da221Addr, 6)
  140. -- LSB数据格式为: D[3] D[2] D[1] D[0] unused unused unused unused
  141. -- MSB数据格式为: D[11] D[10] D[9] D[8] D[7] D[6] D[5] D[4]
  142. -- 数据位为12位,需要将MSB数据左移4位,LSB数据右移4位,最后进行或运算
  143. -- 解析X轴数据 (LSB在前,MSB在后)
  144. local x_data = (string.byte(recv_data, 2) << 4) | (string.byte(recv_data, 1) >> 4)
  145. -- 解析Y轴数据 (LSB在前,MSB在后)
  146. local y_data = (string.byte(recv_data, 4) << 4) | (string.byte(recv_data, 3) >> 4)
  147. -- 解析Z轴数据 (LSB在前,MSB在后)
  148. local z_data = (string.byte(recv_data, 6) << 4) | (string.byte(recv_data, 5) >> 4)
  149. -- 转换为12位有符号整数
  150. -- 判断X轴数据是否大于2047,若大于则表示数据为负数
  151. -- 因为12位有符号整数的范围是 -2048 到 2047,原始数据为无符号形式,大于2047的部分需要转换为负数
  152. -- 通过减去4096 (2^12) 将无符号数转换为对应的有符号负数
  153. if x_data > 2047 then x_data = x_data - 4096 end
  154. -- 判断Y轴数据是否大于2047,若大于则进行同样的有符号转换
  155. if y_data > 2047 then y_data = y_data - 4096 end
  156. -- 判断Z轴数据是否大于2047,若大于则进行同样的有符号转换
  157. if z_data > 2047 then z_data = z_data - 4096 end
  158. -- 转换为加速度值(单位:g)
  159. if rangemode == 1 then
  160. x_accel = x_data / 1024
  161. y_accel = y_data / 1024
  162. z_accel = z_data / 1024
  163. elseif rangemode == 2 then
  164. x_accel = x_data / 512
  165. y_accel = y_data / 512
  166. z_accel = z_data / 512
  167. elseif rangemode == 3 then
  168. x_accel = x_data / 256
  169. y_accel = y_data / 256
  170. z_accel = z_data / 256
  171. else
  172. x_accel = x_data / 1024
  173. y_accel = y_data / 1024
  174. z_accel = z_data / 1024
  175. end
  176. -- 输出加速度值(单位:g)
  177. return x_accel, y_accel, z_accel
  178. end
  179. --初始化da221
  180. local function da221_init()
  181. if bsp:find("780") then
  182. gpio.setup(23, 1, gpio.PULLUP) -- gsensor 开关
  183. else
  184. gpio.setup(24, 1, gpio.PULLUP) -- gsensor 开关
  185. end
  186. --关闭i2c
  187. i2c.close(i2cId)
  188. --重新打开i2c,i2c速度设置为低速
  189. i2c.setup(i2cId, i2c.SLOW)
  190. sys.wait(50)
  191. i2c.send(i2cId, da221Addr, soft_reset, 1) --复位da221
  192. sys.wait(50)
  193. i2c.send(i2cId, da221Addr, chipid_addr, 1) --读取芯片id
  194. local chipid = i2c.recv(i2cId, da221Addr, 1) --接收返回的芯片id
  195. log.info("i2c", "chipid",chipid:toHex())
  196. if string.byte(chipid) == 0x13 then
  197. log.info("exvib init success")
  198. else
  199. log.info("exvib init fail")
  200. end
  201. -- 设置寄存器
  202. i2c.send(i2cId, da221Addr, rangeaddr, 1) --设置加速度量程,默认2g
  203. sys.wait(5)
  204. i2c.send(i2cId, da221Addr, int_set1_reg, 1) --设置x,y,z发生变化时,产生中断
  205. sys.wait(5)
  206. i2c.send(i2cId, da221Addr, int_map1_reg, 1)--运动的时候,产生中断
  207. sys.wait(5)
  208. i2c.send(i2cId, da221Addr, active_dur_addr, 1)-- 设置激活时间,默认0x00
  209. sys.wait(5)
  210. i2c.send(i2cId, da221Addr, active_ths_addr, 1)-- 设置激活阈值
  211. sys.wait(5)
  212. i2c.send(i2cId, da221Addr, mode_addr, 1)-- 设置模式
  213. sys.wait(5)
  214. i2c.send(i2cId, da221Addr, odr_addr, 1)-- 设置采样率
  215. sys.wait(5)
  216. i2c.send(i2cId, da221Addr, int_latch_addr, 1)-- 设置中断锁存 中断一旦触发将保持,直到手动清除
  217. sys.wait(5)
  218. end
  219. --[[
  220. 打开da221
  221. @api exvib.open(mode)
  222. @number da221模式设置,1,微小震动检测,用于检测轻微震动的场景,例如用手敲击桌面;加速度量程2g;
  223. 2,运动检测,用于电动车或汽车行驶时的检测和人行走和跑步时的检测;加速度量程4g;
  224. 3,跌倒检测,用于人或物体瞬间跌倒时的检测;加速度量程8g;
  225. @return nil 无返回值
  226. @usage
  227. exvib.open(1)
  228. ]]
  229. function exvib.open(mode)
  230. rangemode=mode
  231. if mode==1 or tonumber(mode)==1 then
  232. --轻微检测
  233. log.info("轻微检测")
  234. rangeaddr = {0x0f, 0x00} -- 设置加速度量程,默认2g
  235. active_ths_addr = {0x28, 0x33} -- 设置激活阈值
  236. odr_addr = {0x10, 0x04} -- 设置采样率 15.63Hz
  237. active_dur_addr = {0x27, 0x01} -- 设置激活时间
  238. elseif mode==2 or tonumber(mode)==2 then
  239. --常规检测
  240. log.info("运动检测")
  241. rangeaddr = {0x0f, 0x01} -- 设置加速度量程,默认4g
  242. active_ths_addr = {0x28, 0x26} -- 设置激活阈值
  243. odr_addr = {0x10, 0x08} -- 设置采样率 250Hz
  244. active_dur_addr = {0x27, 0x14} -- 设置激活时间
  245. elseif mode==3 or tonumber(mode)==3 then
  246. log.info("高动态检测")
  247. --高动态检测
  248. rangeaddr = {0x0f, 0x02} -- 设置加速度量程,默认8g
  249. active_ths_addr = {0x28, 0x80} -- 设置激活阈值
  250. odr_addr = {0x10, 0x0F} -- 设置采样率 1000Hz
  251. active_dur_addr = {0x27, 0x04} -- 设置激活时间
  252. end
  253. sys.taskInit(da221_init)
  254. end
  255. --[[
  256. 关闭da221
  257. @api exvib.close()
  258. @return nil 无返回值
  259. @usage
  260. exvib.close()
  261. ]]
  262. function exvib.close()
  263. if bsp:find("780") then
  264. gpio.close(23) -- gsensor供电关闭
  265. else
  266. gpio.close(24) -- gsensor供电关闭
  267. end
  268. gpio.close(24) -- gsensor供电关闭
  269. log.info("exvib close..")
  270. end
  271. return exvib