第一章 加速度传感器基础:从原理到实现

各位同学好,我是你们的嵌入式系统讲师。今天咱们来聊聊智能手环里最核心的传感器——加速度计。说实话,我刚开始做可穿戴设备那会儿,也踩过不少坑。这一章我会把加速度传感器的工作原理、三轴概念以及数据读取方法,掰开了揉碎了讲清楚。

1.1 加速度传感器的工作原理

加速度传感器,说白了就是测量物体运动状态的芯片。它内部有一个微小的质量块,当手环运动时,这个质量块会因为惯性产生位移。传感器通过检测这个位移量,就能算出当前的加速度值。

我习惯把加速度计想象成一个弹簧振子。你想想看,当你突然加速时,质量块会向后压;减速时,它会向前冲。传感器内部用微机电系统(MEMS)技术,把这个机械位移转换成电信号。嗯,这里要注意:加速度计测的是比力,不是单纯的运动加速度。它包含重力分量,这也是为什么我们能用来测倾角。

核心公式: F = ma,其中F是惯性力,m是质量块质量,a是加速度。传感器输出的是电压或数字量,与加速度成正比。

我在项目中遇到过一个问题:有些同学以为加速度计只测运动,结果静止时发现读数不为零。其实那是重力在作怪。地球表面1g的重力加速度,约等于9.8 m/s²,传感器会一直感受到这个力。

1.2 三轴加速度计详解

三轴加速度计,就是能同时测量X、Y、Z三个方向的加速度。这三个轴互相垂直,构成一个三维坐标系。我刚开始做手环时,总搞不清哪个轴对应哪个方向。后来我总结了一个方法:把手环平放在桌面上,Z轴朝上,X轴指向手腕方向,Y轴指向手臂外侧。

方向 典型应用
X轴 手腕方向 摆臂检测
Y轴 手臂外侧 侧向运动
Z轴 垂直桌面 上下震动、步数

为什么要三轴?因为人的运动是三维的。走路时,手臂前后摆动(X轴),身体上下起伏(Z轴),偶尔还有侧向晃动(Y轴)。单轴传感器根本不够用。我记得有一次调试计步算法,只用Z轴数据,结果用户甩手时步数乱跳。后来加上X轴和Y轴的融合,才稳定下来。

个人经验: 实际项目中,Z轴数据通常最稳定,因为走路时垂直方向的加速度变化最规律。我建议新手先从Z轴入手分析。

1.3 传感器数据读取实战

好了,理论讲完了,咱们来点实际的。我以最常用的MPU6050为例,讲讲怎么用I2C接口读取加速度数据。这个芯片我用了不下五年,皮实耐用,适合入门。

首先,你需要连接硬件。VCC接3.3V,GND接地,SCL和SDA分别接到主控的I2C引脚。我习惯在SCL和SDA上各加一个4.7kΩ上拉电阻,虽然有些模块内置了,但自己加更保险。

接下来是代码。我用Python写了个简单的读取函数,用smbus库操作I2C总线。你想想看,Python做原型验证多快啊,等算法调好了再移植到C语言。

import smbus
import time

# MPU6050 I2C地址
MPU6050_ADDR = 0x68

# 加速度寄存器起始地址
ACCEL_XOUT_H = 0x3B

# 初始化I2C总线
bus = smbus.SMBus(1)

# 唤醒MPU6050(默认是睡眠模式)
bus.write_byte_data(MPU6050_ADDR, 0x6B, 0)

def read_accel():
    """读取三轴加速度原始值"""
    # 连续读取6个字节:X高、X低、Y高、Y低、Z高、Z低
    data = bus.read_i2c_block_data(MPU6050_ADDR, ACCEL_XOUT_H, 6)
    
    # 合并高低字节,注意要处理负数
    x = (data[0] << 8) | data[1]
    y = (data[2] << 8) | data[3]
    z = (data[4] << 8) | data[5]
    
    # 如果最高位为1,说明是负数
    if x & 0x8000:
        x = -((~x & 0xFFFF) + 1)
    if y & 0x8000:
        y = -((~y & 0xFFFF) + 1)
    if z & 0x8000:
        z = -((~z & 0xFFFF) + 1)
    
    return x, y, z

# 主循环:每秒读取一次
while True:
    x, y, z = read_accel()
    print(f"X: {x:6d}  Y: {y:6d}  Z: {z:6d}")
    time.sleep(1)

避坑指南: 我曾经犯过一个低级错误——忘记唤醒MPU6050。芯片默认处于睡眠模式,读出来的数据全是0。折腾了半天才发现是初始化没做。所以记住:写0x00到0x6B寄存器,这是唤醒命令。

读取到的原始值是16位有符号整数,范围是-32768到32767。要转换成物理单位,需要除以灵敏度。比如量程设为±2g时,灵敏度是16384 LSB/g。那么加速度值 = 原始值 / 16384,单位是g。

我建议你拿到数据后,先做两件事:

  • 静态校准: 把手环平放,Z轴读数应该在16384左右(1g),X和Y接近0。如果有偏差,记下来做偏移补偿。
  • 动态测试: 快速晃动一下,看数值是否跟着变化。如果纹丝不动,检查接线或I2C地址。

嗯,这里还要提一句:采样率设置。MPU6050默认采样率是1kHz,对于计步来说太高了。我一般设到100Hz,既省电又够用。设置方法是在0x19寄存器写入99(分频系数),这样采样率 = 1kHz / (1 + 99) = 10Hz?不对,我算错了。实际是:采样率 = 内部时钟频率 / (分频系数 + 1)。内部时钟默认1kHz,所以写入99得到10Hz。但计步通常用50-100Hz,我建议写入19,得到50Hz。

关键参数总结:

  • 量程:±2g(精度最高,适合计步)
  • 采样率:50-100Hz(平衡功耗和精度)
  • 灵敏度:16384 LSB/g(±2g量程下)

最后,我想说:加速度计的数据读取只是第一步。真正的挑战在于,如何从这些看似杂乱的数据中,提取出步数、活动类型、睡眠状态。下一章我们会深入探讨滤波算法,把原始数据中的噪声去掉,为计步打好基础。

好了,这一章就到这里。记住:动手实践是最好的学习方式。拿起你的开发板,把上面的代码跑一遍,看看三轴数据是怎么变化的。有任何问题,欢迎在课程群里交流。