ODGIRON LIS3DH笔记
TS100的两个加速度计
基于IronOS固件的典型烙铁,比如TS100的PCB预留了两种加速度计焊盘,一种是NXP的MMA系列的MMA8652FC加速度计,一种是ST的LIS系列的LIS2DH12加速度计,实际出货时只焊接一个(这么做应该是和采购有关),大多数TS100仅焊接的是LIS2DH12加速度计,其封装为 LGA12(2.0x2.0x1.0 mm),焊盘之间实在距离太小了,又是LGA封装,和QFN封装能侧面爬锡不同,LGA封装仅底面开了焊盘,侧面无法爬锡,从网上找到TS100的PCB的加速度计如下:
TS100采用双PCB设计 | 小PCB通过板对板连接器与大PCB连接 |
---|---|
小PCB右加速计和STM32 | 确认型号与LC商城的LIS2DH12一致 |
---|---|
LIS3DH与LIS2DH12
ODGIRON,是我最近在开发的基于ironOS的快充T12电烙铁,由于ODGIRON双面布线,加速度盘下要走两个过孔才能布通,因此选用了封装更大的LIS3DH,封装为LGA12(3.0x3.0x1.0 mm),其焊接更友好,还更便宜,需要用到的地方与LIS2DH12几乎完全一致,要什么自行车
LIS3DH | LIS2DH12 | |
---|---|---|
尺寸 | ||
供电电压 | 1.71 V to 3.6 V | 1.71 V to 3.6 V |
50Hz正常工作电流(uA) | 11 | 11 |
量程(FS) | ±2g/±4g/±8g/±16g | ±2g/±4g/±8g/±16g |
量程特性 | dynamically selectable full scale | selectable full scales |
接口 | I2C/SPI | I2C/SPI |
可编程中断GPIO | 2 | 2 |
中断GPIO功能 | free-fall and motion detection | free-fall and motion detection |
硬件方向检测 | 6D/4D orientation detection | 6D/4D orientation detection |
数据位数(bit) | Low-power mode (8-bit data output) Normal mode (10-bit data output) High-resolution mode (12-bit data output) |
Low-power mode (8-bit data output) Normal mode (10-bit data output) High-resolution mode (12-bit data output) |
输出数据位数 | 12bit/10bit/8bit | 12bit/10bit/8bit |
片上温度传感器 | Yes | Yes |
自检 | Yes | Yes |
FIFO | 16-bit, 32-level | 10-bit, 32-level |
ADC | 多一路A/D converter 引出3路ADC GPIO |
仅一路A/D converter |
抗震性(g) | 10000 | N/A |
Datasheet一样的参数 | Mechanical characteristics Temperature sensor characteristics Electrical characteristics Communication interface characteristics Absolute maximum ratings Terminology and functionality |
|
最低价格 | 1.3包邮 | 2.3包邮 |
ironOS 加速度计读数不正常问题解决
ironOS跑了FreeRTOS,加速度计为MOVTask任务,与oled的GUITask共用 I2C1 总线,由二值信号量做 I2C1 互斥,具体实现请见ironOS源码
ironOS的LISDH12的加速度计驱动代码有BUG,它配置了一大堆非必要的加速度计寄存器,而实际上任务仅用到读取3轴数据和6D检测,我仔细跟了它原本的寄存器配置,得出LISDH12工作状态如下:
- 输出数据:12bit,即 [-2048, +2048]
- 加速度量程:±2g
- ODR:1Hz,实际上注释是想配置成25Hz,但它实际的配置数据位写错了
- 实际加速度输出频率:当ODR=1,ODR/9 = 0.111次/秒,运动检测很迟钝
- 期望的加速度输出频率:当ODR=25,ODR/9 = 2.777次/秒,运动检测较迟钝
- ODGIRON设置的加速度输出频率:ODR为100Hz,ODR/9=11.111次/秒,与MOVTask调度频率10Hz几乎同步,运动检测很灵敏
其运动检测的源代码:ironOS运动检测是由MOVTask里跑了一个阈值比较程序,它实现了运动检测,既然软件进行了运动检测,那为啥还要使能6D阈值检测的事件中断?
ironOS读取加速度计的代码如下:
1 |
|
由于12bit数据是左对齐的,可见,在 //依次赋值 的地方,未作 >> 4 运算,直接输出的xyz结果范围不是[-2048, +2048],而是有时候数据能到 ±10000以外,离谱
我补上 >> 4运算,使劲晃动时输出数据也不正常,很难到 ±2000附近:
这与arduino的Sparkfun 的LIS3DH例程非常不同,arduino的例程跑起来,若水平放置加速度计,z方向会在-1024附近,即能显示地球的重力加速度1g,奇怪的是ironOS的跑起来没有1g的加速度,读出数据如下:
这是为什么呢?排查出错原因是仅配置了LIS_CTRL_REG2的FDS位,使能了High-pass filter ,这之后输出的三轴数据,是经高通滤波后的
1 | {LIS_CTRL_REG2, 0b00001000, 0}, //default:00000000 // Highpass filter off // FDS[3:3] = 1: |
我将该配置取消掉,之后水平静置读数正常,换算z方向的加速度是正常的1g左右:
实际上,后面运动检测也可以读经过高通滤波器的值,ironOS没有将经过高通滤波器的值 做<<4运算,即实际传入运动检测程序的值大了2^4 = 16倍,这就能解释为啥我默认打印xyz读到的数据剧烈晃动时可以到±10000,能触发运动检测,但<<4后摇晃时读数稳如泰山,摇晃得很厉害也无法触发运动检测
所以,是否按ironOS的原始代码启用高通滤波器看你的喜好,个人感觉数据不过滤波器运动检测舒服一些
注意:数据经过滤波器对6D阈值无影响,6D阈值是取原始读数的
LIS3DH的滤波器还有很多高级特性供配置,可以作用于中断、敲击检测,更多请参考手册的 8.9节 CTRL_REG2 (21h)
根据加速读计旋转oled
LIS3DH带有6D阈值事件中断功能。
加速度计坐标轴
注意TS100的LIS2DH12和我ODGIRON的LIS3DH的轴向坐标不同:
LIS3DH | LIS2DH12 | |
---|---|---|
轴向 |
我对原本TS100的 LIS3DH::getOrientation() 函数进行修改,使之符合LIS3DH的坐标轴,明细请见源代码。
右手与左手的旋转与加速度计坐标关系
我根据加速度计相对烙铁的安装的位置,画了ODGIRON和TS100的加速读坐标两张纸贴在烙铁上,下文都按照左边ODGIRON贴纸上的坐标
右手模式水平静置 | 右手模式旋转 +90° |
---|---|
左手模式水平静置 | 左手模式旋转 -90° |
---|---|
INT2_THS 阈值寄存器
THS 即 threshold 阈值
ironOS 的 INT2_THS
寄存器 设置值为0x28,根据datasheet:
-
由 Table 68.
INT2_THS
description:LIS3DH工作在12bit ±2g,则 THS[6:0] 的 1LSB = 16mg,计算触发阈值:先将0x28转换为10进制:0x28 = 40DEC , 再乘以16msg 得到触发阈值为±640mg, -
由 Table 4. Mechanical characteristics的Sensitivity部分:LIS3DH工作在12bit ±2g时 ,加速度输出数据的1LSB = 1mg,则读数为±640触发临界点
测试,0x28的640mg实际旋转触发时以z轴值主导,z的阈值为±640附近,而x阈值为±830附近:
左手阈值触发临界点附近: | 右手阈值触发临界点附近: |
---|---|
将0x28改为0x20,0x20为512mg,实际旋转触发时以z轴值主导,z的阈值为±640附近,x阈值为±910附近:
左手阈值触发临界点附近: | 右手阈值触发临界点附近: |
---|---|
改为50,50为800mg,实际旋转触发时以x轴值为主导,z的阈值为±640附近,x阈值为±800附近:
左手阈值触发临界点附近: | 右手阈值触发临界点附近: |
---|---|
所以这很奇怪,INT2_THS
的值可能由z轴也可能为x轴的阈值事件触发,但最终手性的判断是OK的
那么旋转oled阈值事件到底是以x还是z轴触发判断?
设xoy面水平,即烙铁屏幕水平,当烙铁沿y轴旋转时,z轴加速度读数 与 旋转角度 存在函数关系,推导一下
规定屏幕水平向上时,沿y轴的旋转角度为0,则烙铁沿y轴旋转时,垂直于屏幕的法线与旋转角度为0时的法线存在夹角θ,令该法线通过原点,则该法线的参数方程为:
\left\{ \begin{align} x&=tcos(\frac{\pi}{2}-\theta)\\ y&=tsin(\frac{\pi}{2}-\theta)\\ \end{align} \right. \space\space\space\space,\space\space\theta∈[-\frac{\pi}{2},\frac{\pi}{2}]
如图所示,建立与x轴加速度读数有关的圆,直径是1g时,读数为1024,则半径为512,那么该的圆的方程为: $$ x^2+(y-512)^2=512^2 $$ 该圆上任一点 (x,y) 到原点 (0,0) 的距离为: $$ d=\sqrt{x^2+y^2} $$ 联立以上公式: $$ \left\{ \begin{align} x&=tcos(\frac{\pi}{2}-\theta)\\ y&=tsin(\frac{\pi}{2}-\theta)\\ x^2+(y-512)^2&=512^2\\ d&=\sqrt{x^2+y^2}\\ \end{align} \right. \space\space\space\space,\space\space\theta∈[-\frac{\pi}{2},\frac{\pi}{2}] $$ 整理后,只有一个sin: $$ d=1024\cdot sin(\frac{\pi}{2}-\theta) \space\space\space\space,\space\space\theta∈[-\frac{\pi}{2},\frac{\pi}{2}] $$ 由于z轴于屏幕显示方向刚好相反,所以 $$ z轴加速度读数=-1024\cdot sin(\frac{\pi}{2}-\theta) \space\space\space\space,\space\space\theta∈[-\frac{\pi}{2},\frac{\pi}{2}] $$ 类似地,可以写出 $$ x轴加速度读数=1024\cdot sin(\theta) \space\space\space\space,\space\space\theta∈[-\frac{\pi}{2},\frac{\pi}{2}] $$那么把旋转角度θ带入x轴加速度读数函数求得的值,再由 THS[6:0] 的 1LSB = 16mg 计算触发阈值,设置为INT2_THS
的值,就可指定旋转角度触发中断了
可以画出x轴和z轴读数随沿y轴旋转角度(-90度到90度)的图像:
发现x与z轴的事件 受INT2_THS
的值范围 会出现先后触发的情况,在x=-π/4
或x=π/4
的附近,即旋转-45
度和45
度附近,在-45
度的左边时,z轴比x轴先触发,在-45
度右边时,则相反,但实际x轴和z轴事件的先后顺序却相反,应该是加速度计片内电路判断成反序了
注意:使能了IN2中断锁存:LIR_INT2[7:7] = 1:在INT2_SRC(35h)寄存器上锁存中断请求,对此没有影响
为了最佳旋转触发,我45
度作为临界点:
然后再除以寄存器的分辨率16mg/LSB:
$$ 724.08/16≈45 $$那么将INT2_THS
设置为45即可
剩下oled驱动、旋转oled的命令不是重点,略
INT2_DURATION寄存器有没有用?
会增加一个消抖时间,可开可不开,实际效果无明显变化
1 | /*开了没开一样,没卵用?*/ {LIS_INT2_DURATION, 64, 0}, //default:00000000 // 64 = 0b01000000 // 超出阈值持续多少时间才触发INT2的中断(相当于按键延时消抖) |
运动检测
1 | currentPointer = (currentPointer + 1) % MOVFilter // 每8次MOVTask调度,currentPointer归0 |
串口打印currentPointer随MOVTAsk调度次数变化:ptr是currentPointer, time是调度次数
读到的轴数据在滑动滤波器数组里的变化情况:
1 | //第1次: |
然后每次求一次8个元素的平均值,即变量avgx,使用abs(avgx - 本次读到的x数据)
,得到x轴变化量的绝对值,以同样的方式计算y和z轴,求和为三轴的总变化值,即变量error,将error与threshold比较,若大于,则更新运动检测的时间戳,即变量lastMovementTime,详细见代码,以下节选部分:
1 | // 求三轴变化量绝对值的总和 //Sum the deltas //abs()求传入数据的绝对值 |
综合测试
一边读3轴数据,一边6D旋转阈值检测,一边运动检测的瞬间,OK:
相关链接
- 本文链接: http://oldgerman.github.io/74a960e2/
- 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!