你有没有想过你的智能手机是如何知道哪个方向向上的?这是当今智能手机最具创新性的功能之一。它们都有一个内置在电路中的称为加速度计的微型设备,可以检测何时将设备从一侧倾斜到另一侧。这就是智能手机知道何时从纵向模式切换到横向模式的方式。
让我们看一下它们是什么,它们做什么,以及它们是如何工作的。
要了解加速度计的工作原理,请想象一个 3D 立方体内的球。
假设立方体在外太空,一切都是失重的,球将简单地漂浮在立方体的中心。
现在假设每面墙代表一个特定的轴。
如果我们突然以加速度 1g 将盒子向左移动( 1g 相当于重力加速度 9.8 m/s2),球无疑会撞到墙 X。如果我们测量球在墙 X 上施加的力,我们可以沿 X 轴获得 1g 的输出值。
让我们看看当我们把这个立方体放在地球上会发生什么。球将简单地落在 Z 墙上,施加 1g 的力,如下图所示:
在这种情况下,盒子没有移动,但我们仍然在 Z 轴上得到 1g 的读数。这是因为重力(实际上是一种加速度形式)以1g的力将球向下拉。
虽然此模型不能完全代表实际加速度计传感器的构建方式,但它通常有助于理解为什么加速度计的输出信号通常以 ±g 为单位,或者为什么加速度计在静止时在 z 轴上读取 1g,或者在不同方向上可以预期的加速度计读数。
在现实世界中,加速度计基于微机电系统(MEMS制造技术)。那么,让我们来了解一下MEMS加速度计的工作原理。
MEMS(微机电系统)加速度计是一种建立在硅晶圆之上的微机械结构。
这种结构由多晶硅弹簧悬挂。它允许结构在沿 X、Y 和/或 Z 轴加速时偏转。
由于偏转,固定板和连接到悬挂结构的板之间的电容会发生变化。电容的这种变化与沿该轴的加速度成正比。
传感器处理电容的这种变化,并将其转换为模拟输出电压。
该模块的核心是ADI公司的小型、低功耗、低噪声三轴MEMS加速度计ADXL335。它不仅可以测量重力引起的静态加速度,还可以测量由运动、冲击或振动引起的动态加速度。
这款试验板模块将ADXL335的每个引脚分成一个6引脚、0.1′间距接头,包括3个用于X、Y和Z轴测量的模拟输出、2个电源引脚和一个自检引脚。
ADXL335采用1.8V至3.6VDC (典型值为3.3V)工作。然而,板载 3.3V 稳压器使其成为与 Arduino 等 5V 微控制器接口的理想选择。
传感器在正常工作期间仅消耗 350μA 电流。
ADXL335具有±3g的全检测范围。这意味着ADXL335可以精确测量并表示为输出的最大加速度为±3g。例如,如果以4g加速,加速度计不会损坏,但输出可能不正常。
ADXL335的绝对最大加速度为10,000g。当加速度大于10,000g时,ADXL335可能会失效。
ADXL335输出是比率式的,因此输出电压在整个范围内随加速度线性增加。这意味着0g测量输出始终处于3.3V电源电压(1.65V)的一半,-3g为0V,+3g为3.3V,两者之间有完全缩放。
以下是规格。
工作电压 | 1.8V – 3.6V |
---|---|
工作电流 | 350μA(典型值) |
感应距离 | ±3g(满量程) |
温度范围 | −40 至 +85°C |
感应轴 | 3轴 |
敏感性 | 270 至 330mV/g(比率式) |
抗冲击性 | 高达 10,000g |
尺寸 | 4 毫米 x 4 毫米 x 1.45 毫米 |
有关更多信息,请参阅下面的数据表。
在我们进入连接和示例代码之前,让我们看一下它的 Pinout。
VCC为模块供电。将其连接到Arduino的5V输出。
X_OUT输出与沿 X 轴加速度成比例的模拟电压。
Y_OUT输出与沿 Y 轴加速度成比例的模拟电压。
Z_OUT输出与沿 Z 轴加速度成比例的模拟电压。
GND是接地引脚。
ST(Self-Test)PIN 控制自检功能,允许您在最终应用中测试传感器的功能。本教程末尾将深入讨论此功能。
现在我们知道了ADXL335加速度计的工作原理,我们可以继续将其连接到Arduino。
连接非常简单。首先将加速度计安装在试验板上。将VCC引脚连接到Arduino的5V引脚,将GND引脚连接到Arduino的接地引脚。将 X、Y 和 Z 输出连接到 Arduino 的模拟引脚 A0、A1 和 A2。
为了获得准确的结果,我们需要更改Arduino上的模拟参考(AREF)电压。这是通过将Arduino的3.3V引脚连接到AREF引脚来实现的。
下图显示了接线。
草图很简单。它只是在串行接口的每个轴上显示校准的传感器输出。在我们进入细节之前先尝试草图。
const int xInput = A0;
const int yInput = A1;
const int zInput = A2;
// initialize minimum and maximum Raw Ranges for each axis
int RawMin = 0;
int RawMax = 1023;
// Take multiple samples to reduce noise
const int sampleSize = 10;
void setup()
{
analogReference(EXTERNAL);
Serial.begin(9600);
}
void loop()
{
//Read raw values
int xRaw = ReadAxis(xInput);
int yRaw = ReadAxis(yInput);
int zRaw = ReadAxis(zInput);
// Convert raw values to 'milli-Gs"
long xScaled = map(xRaw, RawMin, RawMax, -3000, 3000);
long yScaled = map(yRaw, RawMin, RawMax, -3000, 3000);
long zScaled = map(zRaw, RawMin, RawMax, -3000, 3000);
// re-scale to fractional Gs
float xAccel = xScaled / 1000.0;
float yAccel = yScaled / 1000.0;
float zAccel = zScaled / 1000.0;
Serial.print("X, Y, Z :: ");
Serial.print(xRaw);
Serial.print(", ");
Serial.print(yRaw);
Serial.print(", ");
Serial.print(zRaw);
Serial.print(" :: ");
Serial.print(xAccel,0);
Serial.print("G, ");
Serial.print(yAccel,0);
Serial.print("G, ");
Serial.print(zAccel,0);
Serial.println("G");
delay(200);
}
// Take samples and return the average
int ReadAxis(int axisPin)
{
long reading = 0;
analogRead(axisPin);
delay(1);
for (int i = 0; i < sampleSize; i++)
{
reading += analogRead(axisPin);
}
return reading/sampleSize;
}
下图显示了不同方向的加速度计读数。
代码首先声明了 Arduino 的模拟输入引脚,传感器的 X、Y 和 Z 输出引脚连接到这些引脚。
const int xInput = A0;
const int yInput = A1;
const int zInput = A2;
接下来,定义两个变量 RawMin
andRawMax
。由于Arduino具有10位ADC(210= 1024),因此它将ADXL335的输出电压(范围为0至3.3 V)映射到0至1023之间的整数值。这就是为什么设置RawMin
为 0 并且设置RawMax
为 1023。
// initialize minimum and maximum Raw Ranges for each axis
int RawMin = 0;
int RawMax = 1023;
变量sampleSize
指定 Arduino 在每次转换期间应采集的样本数。在我们的例子中,我们设置sampleSize
为 10 以获得更准确的结果。
// Take multiple samples to reduce noise
const int sampleSize = 10;
在设置部分,我们首先通过调用将模拟引用设置为 EXTERNAL。然后,我们启动与PC的串行通信。analogReference(EXTERNAL)
警告:
这是必需的,因为我们已经将 3.3V 连接到 Arduino 的 AREF 引脚。如果没有调用analogReference(EXTERNAL)
,则会将内部生成的有源参考电压和 AREF 引脚短接在一起,从而可能损坏 Arduino。
您可以在Arduino的官方网站上了解有关analogReference()
功能的更多信息。
analogReference(EXTERNAL);
Serial.begin(9600);
在循环部分,我们每200ms读取一次传感器的模拟输出。请注意,我们调用自定义函数ReadAxis()
而不是analogRead()
函数。该函数获取10个ADC转换样本并返回平均值。
//Read raw values
int xRaw = ReadAxis(xInput);
int yRaw = ReadAxis(yInput);
int zRaw = ReadAxis(zInput);
以下代码片段是该程序最重要的部分。它将传感器的模拟输出电压映射并转换为重力加速度(G)。
映射由 IDE 的内置函数map()
处理。当我们调用map(xRaw, RawMin, RawMax, -3000, 3000)
时,值RawMin
映射到 -3000,值RawMax
映射到 3000,介于两者之间的值映射到介于两者之间的值。
数字 -3000 和 3000 不是随机的。它们实际上代表传感器以milli-g
为单位测量的重力加速度,即±3g(-3000milli-g
至3000milli-g
)。
例如
map()
函数将返回 -3000,对应于 -3g。map()
函数将返回 0,对应于 0g。map()
函数将返回 3000,对应于 +3g。术语比率更有意义,因为输出电压在整个范围内随加速度线性增加。
// Convert raw values to 'milli-Gs"
long xScaled = map(xRaw, RawMin, RawMax, -3000, 3000);
long yScaled = map(yRaw, RawMin, RawMax, -3000, 3000);
long zScaled = map(zRaw, RawMin, RawMax, -3000, 3000);
最后,传感器的输出通过除以1000将其缩小到小数Gs,并显示在串行监视器上。
// re-scale to fractional Gs
float xAccel = xScaled / 1000.0;
float yAccel = yScaled / 1000.0;
float zAccel = zScaled / 1000.0;
Serial.print("X, Y, Z :: ");
Serial.print(xRaw);
Serial.print(", ");
Serial.print(yRaw);
Serial.print(", ");
Serial.print(zRaw);
Serial.print(" :: ");
Serial.print(xAccel,0);
Serial.print("G, ");
Serial.print(yAccel,0);
Serial.print("G, ");
Serial.print(zAccel,0);
Serial.println("G");
ADXL335加速度计具有自检功能,允许您在最终应用中测试传感器的功能。模块上的 ST(自检)引脚控制此功能。
当ST引脚连接到3.3V时,在内部对加速度计光束施加静电力。由此产生的波束运动允许用户确定加速度计是否正常工作。
输出的预期变化为
在正常工作期间,ST 引脚可能保持开路或连接到 GND。
警告:
将ST引脚连接高于3.6V的电压下可能会永久损坏加速度计。