探索MEMS传感器:加速度计、陀螺仪和磁力计在Arduino项目中的应用
本教程将讲解MEMS加速度计、陀螺仪和磁力计的工作原理,以及如何配合Arduino开发板使用。同时我们将利用Processing IDE制作一些传感器实战应用。您可以观看以下视频或阅读下方文字教程。 MEMS是尺寸极小的系统或器件,由尺寸在0.001mm至0.1mm范围的微型组件组成。这些组件由硅、聚合物、金属和/或陶瓷制成,通常与CPU(微控制器)结合形成完整系统。 下面简要解释各类微机电系统(MEMS)传感器的工作原理。 通过测量电容变化来测量加速度。其微观结构类似:一个连接弹簧的质量块,只能沿一个方向运动,两侧有固定外板。当特定方向施加加速度时,质量块移动,导致质量块与外板间电容变化。测量该电容变化经处理后对应特定加速度值。 陀螺仪利用科里奥利效应测量角速率。当一个质量以特定速度沿特定方向运动时,若施加外部角速率(绿箭头),会产生一个力(蓝红箭头),导致质量块发生垂直位移。与加速度计类似,这种位移引起电容变化,经测量处理后对应特定角速率。 陀螺仪微观结构:一个持续振荡的质量块,当外部角速率施加时,质量块的柔性部分移动产生垂直位移。 利用霍尔效应或磁阻效应测量地磁场。市场上约90%的传感器使用霍尔效应,原理如下: 若有一导电板,电流流过时电子从一侧直线流向另一侧。若靠近磁场,电子流偏向板一侧,正极偏向另一侧。此时在两侧间测量可得电压,其大小取决于磁场强度和方向。 其余10%传感器使用磁阻效应,采用对磁场敏感的材料(通常为铁Fe和镍Ni组成),暴露于磁场时电阻发生变化。 现在将这些传感器连接到Arduino并加以利用。示例使用GY-80扩展板,包含:ADXL345三轴加速度计、L3G4200D三轴陀螺仪、MC5883L三轴磁力计,以及气压计和温度计(本教程不使用)。 您可以从以下网站获取组件: 该板使用I2C通信协议,仅需两根线即可与所有传感器通信。需要知道各传感器的唯一设备地址及内部寄存器地址以读取数据,这些地址可从数据手册获取: I2C通信详情请参考我的I2C通信协议教程。 下面看如何从传感器获取数据。先从加速度计开始,每段代码前有解释,代码注释也有额外说明。 首先包含Arduino Wire库并定义传感器寄存器地址。setup()中初始化Wire库和串口通信(用串口监视器显示结果)。通过向Power_CTL寄存器发送适当字节激活传感器启用测量。使用Wire.beginTransmission()选择与哪个传感器通信(三轴加速度计),Wire.write()指定内部寄存器,发送启用测量的字节,Wire.endTransmission()结束传输。 loop()中读取各轴数据。以X轴为例:选择X轴两个内部寄存器,用Wire.requestFrom()请求两字节数据。Wire.available()返回可用字节数,若匹配请求的2字节,用Wire.read()读取两个寄存器的字节。输出数据为二进制补码,X0为低字节,X1为高字节,需转换为-1到+1的浮点值,表示X轴相对于地球重力加速度的方向。对Y、Z轴重复相同过程,最后在串口监视器打印。 获取陀螺仪数据代码结构类似。先定义寄存器地址和变量。setup()中使用CTRL_REG1唤醒传感器并设为正常模式,选择灵敏度(本例选2000dps模式)。loop()中读取X、Y、Z轴原始数据并转换为角度值。根据数据手册,2000dps模式对应70 mdps/digit,即原始数据乘0.07得角速度(度/秒)。角速度乘时间得角度值。用millis()计算每次循环时间间隔dt,每次循环累加角度。三轴同理,最后串口打印结果。 同样技术。定义寄存器地址,setup()设置连续测量模式。loop()中获取各轴原始数据。需将原始数据转换为磁场值(高斯单位)。数据手册显示默认灵敏度0.92mG/digit,即原始数据乘0.00092得高斯值。地磁场约0.25-0.65高斯,读数应在此范围。最后串口打印。 这是一个使用Processing IDE制作的MEMS数字指南针酷炫应用。更多详情和源码请访问以下链接:什么是MEMS?
MEMS加速度计

MEMS陀螺仪


MEMS磁力计


Arduino与MEMS传感器

源代码
Arduino加速度计代码
代码语言: Arduino (arduino)
#include <Wire.h>
//--- 加速度计寄存器地址
#define Power_Register 0x2D
#define X_Axis_Register_DATAX0 0x32
#define X_Axis_Register_DATAX1 0x33
#define Y_Axis_Register_DATAY0 0x34
#define Y_Axis_Register_DATAY1 0x35
#define Z_Axis_Register_DATAZ0 0x36
#define Z_Axis_Register_DATAZ1 0x37
int ADXAddress = 0x53; // 设备地址,包含第8位模式选择位(读模式)
int X0,X1,X_out; int Y0,Y1,Y_out; int Z1,Z0,Z_out;
float Xa,Ya,Za;
void setup() {
Wire.begin(); Serial.begin(9600); delay(100);
Wire.beginTransmission(ADXAddress);
Wire.write(Power_Register); // Power_CTL寄存器
Wire.write(8); // Bit D3置高启用测量 (0000 1000)
Wire.endTransmission();
}
void loop() {
// X轴
Wire.beginTransmission(ADXAddress);
Wire.write(X_Axis_Register_DATAX0);
Wire.write(X_Axis_Register_DATAX1);
Wire.endTransmission();
Wire.requestFrom(ADXAddress,2);
if(Wire.available()<=2) {
X0 = Wire.read(); X1 = Wire.read();
X1=X1<<8; X_out =X0+X1; Xa=X_out/256.0; // -1到+1,X轴受重力加速度
}
// Y轴
Wire.beginTransmission(ADXAddress);
Wire.write(Y_Axis_Register_DATAY0);
Wire.write(Y_Axis_Register_DATAY1);
Wire.endTransmission();
Wire.requestFrom(ADXAddress,2);
if(Wire.available()<=2) {
Y0 = Wire.read(); Y1 = Wire.read();
Y1=Y1<<8; Y_out =Y0+Y1; Ya=Y_out/256.0;
}
// Z轴
Wire.beginTransmission(ADXAddress);
Wire.write(Z_Axis_Register_DATAZ0);
Wire.write(Z_Axis_Register_DATAZ1);
Wire.endTransmission();
Wire.requestFrom(ADXAddress,2);
if(Wire.available()<=2) {
Z0 = Wire.read(); Z1 = Wire.read();
Z1=Z1<<8; Z_out =Z0+Z1; Za=Z_out/256.0;
}
// 串口监视器打印
Serial.print("Xa= "); Serial.print(Xa);
Serial.print(" Ya= "); Serial.print(Ya);
Serial.print(" Za= "); Serial.println(Za);
}Arduino陀螺仪代码
代码语言: Arduino (arduino)
#include <Wire.h>
//--- 陀螺仪寄存器地址
#define Gyro_gX0 0x28 #define Gyro_gX1 0x29
#define Gyro_gY0 0x2A #define Gyro_gY1 0x2B
#define Gyro_gZ0 0x2C #define Gyro_gZ1 0x2D
int Gyro = 0x69; // 设备地址
int gX0, gX1, gX_out; int gY0, gY1, gY_out; int gZ0, gZ1, gZ_out;
float Xg,Yg,Zg; float angleX,angleY,angleZ,angleXc,angleYc,angleZc;
unsigned long start, finished, elapsed; float dt=0.015;
void setup() {
Wire.begin(); Serial.begin(9600); delay(100);
Wire.beginTransmission(Gyro); Wire.write(0x20); Wire.write(15); Wire.endTransmission(); // CTRL_REG1 正常模式
Wire.beginTransmission(Gyro); Wire.write(0x23); Wire.write(48); Wire.endTransmission(); // CTRL_REG4 2000dps
}
void loop() {
start=millis();
// X轴
Wire.beginTransmission(Gyro); Wire.write(Gyro_gX0); Wire.endTransmission();
Wire.requestFrom(Gyro,1); if(Wire.available()<=1) gX0 = Wire.read();
Wire.beginTransmission(Gyro); Wire.write(Gyro_gX1); Wire.endTransmission();
Wire.requestFrom(Gyro,1); if(Wire.available()<=1) gX1 = Wire.read();
// Y轴
Wire.beginTransmission(Gyro); Wire.write(Gyro_gY0); Wire.endTransmission();
Wire.requestFrom(Gyro,1); if(Wire.available()<=1) gY0 = Wire.read();
Wire.beginTransmission(Gyro); Wire.write(Gyro_gY1); Wire.endTransmission();
Wire.requestFrom(Gyro,1); if(Wire.available()<=1) gY1 = Wire.read();
// Z轴
Wire.beginTransmission(Gyro); Wire.write(Gyro_gZ0); Wire.endTransmission();
Wire.requestFrom(Gyro,1); if(Wire.available()<=1) gZ0 = Wire.read();
Wire.beginTransmission(Gyro); Wire.write(Gyro_gZ1); Wire.endTransmission();
Wire.requestFrom(Gyro,1); if(Wire.available()<=1) gZ1 = Wire.read();
// 数据处理
gX1=gX1<<8; gX_out =gX0+gX1; Xg=gX_out*0.07; angleXc = Xg*dt; angleX += angleXc;
gY1=gY1<<8; gY_out =gY0+gY1; Yg=gY_out*0.07; angleYc = Yg*dt; angleY += angleYc;
gZ1=gZ1<<8; gZ_out =gZ0+gZ1; Zg=gZ_out*0.07; angleZc = Zg*dt; angleZ += angleZc;
// 打印
Serial.print("angleX= "); Serial.print(angleX);
Serial.print(" angleY= "); Serial.print(angleY);
Serial.print(" angleZ= "); Serial.println(angleZ);
delay(10);
finished=millis(); elapsed=finished-start; dt=elapsed/1000.0; start = elapsed = 0;
}Arduino磁力计代码
代码语言: Arduino (arduino)
#include <Wire.h>
//I2C Arduino库
#define Magnetometer_mX0 0x03 #define Magnetometer_mX1 0x04
#define Magnetometer_mZ0 0x05 #define Magnetometer_mZ1 0x06
#define Magnetometer_mY0 0x07 #define Magnetometer_mY1 0x08
int mX0, mX1, mX_out; int mY0, mY1, mY_out; int mZ0, mZ1, mZ_out;
float Xm,Ym,Zm;
#define Magnetometer 0x1E // HMC5883 I2C 7位地址
void setup(){
Serial.begin(9600); Wire.begin(); delay(100);
Wire.beginTransmission(Magnetometer);
Wire.write(0x02); Wire.write(0x00); // 连续测量模式
Wire.endTransmission();
}
void loop(){
// X轴
Wire.beginTransmission(Magnetometer); Wire.write(Magnetometer_mX1); Wire.endTransmission();
Wire.requestFrom(Magnetometer,1); if(Wire.available()<=1) mX0 = Wire.read();
Wire.beginTransmission(Magnetometer); Wire.write(Magnetometer_mX0); Wire.endTransmission();
Wire.requestFrom(Magnetometer,1); if(Wire.available()<=1) mX1 = Wire.read();
// Y轴
Wire.beginTransmission(Magnetometer); Wire.write(Magnetometer_mY1); Wire.endTransmission();
Wire.requestFrom(Magnetometer,1); if(Wire.available()<=1) mY0 = Wire.read();
Wire.beginTransmission(Magnetometer); Wire.write(Magnetometer_mY0); Wire.endTransmission();
Wire.requestFrom(Magnetometer,1); if(Wire.available()<=1) mY1 = Wire.read();
// Z轴
Wire.beginTransmission(Magnetometer); Wire.write(Magnetometer_mZ1); Wire.endTransmission();
Wire.requestFrom(Magnetometer,1); if(Wire.available()<=1) mZ0 = Wire.read();
Wire.beginTransmission(Magnetometer); Wire.write(Magnetometer_mZ0); Wire.endTransmission();
Wire.requestFrom(Magnetometer,1); if(Wire.available()<=1) mZ1 = Wire.read();
// 数据转换
mX1=mX1<<8; mX_out =mX0+mX1; Xm = mX_out*0.00092; // 高斯
mY1=mY1<<8; mY_out =mY0+mY1; Ym = mY_out*0.00092;
mZ1=mZ1<<8; mZ_out =mZ0+mZ1; Zm = mZ_out*0.00092;
// 打印
Serial.print("x: "); Serial.print(Xm);
Serial.print(" y: "); Serial.print(Ym);
Serial.print(" z: "); Serial.println(Zm);
delay(50);
}
制造工艺
- Arduino Nano 与 MPU-6050 构建实时陀螺仪游戏
- 互动陀螺仪 LED 显示:NeoPixel Ring + Arduino Pro Mini
- K30 CO₂ 传感器:室内空气质量实时监测
- 基于 1Sheeld 与 Arduino 的盲聋人士沟通辅助系统
- 智能存钱罐:Arduino Nano 控制硬币识别器实现余额显示
- Arduino + HC-05 蓝牙控制 LED:MIT App Inventor 手机 App 开发全攻略
- DFRobot 电容指纹传感器 (ID809) 接入 Arduino/ESP8266 完整教程
- 基于 Arduino Mega 与 Nextion 显示屏的交互式气象站
- Arduino Mega 驱动 Wii Nunchuk 控制 6 自由度机械臂
- Arduino UNO + 以太网盾板实现低成本太阳辐射测量仪(热电堆原理)
- 什么是磁力计?原理、核心物理与现实应用全景
- 可靠性互联网中的数据驾驭:高效管理策略