用于 sparkfun redboard turbo 的 ADXL345 库给出错误的读数
ADXL345 library for sparkfun redboard turbo giving wrong readings
我是 运行 在 sparkfun redboard turbo(处理器 samd21g18)和旧的 arduino uno(处理器 mega16u2)上使用 I2C 的 ADXL345。我在两块板上使用的库和草图是相同的,除了串行端口更改为 SerialUSB 以适应红板。
问题似乎是 uno 将 xyz 寄存器(寄存器 0x32 - 0x37 中每轴 2 个字节)解释为 16 位二进制补码(根据数据表),而红板则不然。 uno的输出是正确的,红板的输出是错误的,都是正整数输出。
下图显示了 ADXL345 相同相对位置下左侧红板和右侧 uno 的输出。
我认为有问题的代码在以下库代码中。
/*********************** READING ACCELERATION ***********************/
/* Reads Acceleration into Three Variables: x, y and z */
void ADXL345::readAccel(int *xyz){
readAccel(xyz, xyz + 1, xyz + 2);
}
void ADXL345::readAccel(int *x, int *y, int *z) {
readFrom(ADXL345_DATAX0, ADXL345_TO_READ, _buff); // Read Accel Data from ADXL345
// Each Axis @ All g Ranges: 10 Bit Resolution (2 Bytes)
*x = (((int)_buff[1]) << 8) | _buff[0];
*y = (((int)_buff[3]) << 8) | _buff[2];
*z = (((int)_buff[5]) << 8) | _buff[4];
}
草图代码如下:
#include <SparkFun_ADXL345.h>
/*********** COMMUNICATION SELECTION ***********/
/* Comment Out The One You Are Not Using */
//ADXL345 adxl = ADXL345(10); // USE FOR SPI COMMUNICATION, ADXL345(CS_PIN);
ADXL345 adxl = ADXL345(); // USE FOR I2C COMMUNICATION
/****************** INTERRUPT ******************/
/* Uncomment If Attaching Interrupt */
//int interruptPin = 2; // Setup pin 2 to be the interrupt pin (for most Arduino Boards)
/******************** SETUP ********************/
/* Configure ADXL345 Settings */
void setup(){
SerialUSB.begin(9600); // Start the SerialUSB terminal
SerialUSB.println("SparkFun ADXL345 Accelerometer Hook Up Guide Example");
SerialUSB.println();
adxl.powerOn(); // Power on the ADXL345
adxl.setRangeSetting(2); // Give the range settings
// Accepted values are 2g, 4g, 8g or 16g
// Higher Values = Wider Measurement Range
// Lower Values = Greater Sensitivity
}
/****************** MAIN CODE ******************/
/* Accelerometer Readings and Interrupt */
void loop(){
// Accelerometer Readings
int x,y,z;
adxl.readAccel(&x, &y, &z); // Read the accelerometer values and store them in variables declared above x,y,z
// Output Results to SerialUSB
/* UNCOMMENT TO VIEW X Y Z ACCELEROMETER VALUES */
SerialUSB.print(x);
SerialUSB.print(", ");
SerialUSB.print(y);
SerialUSB.print(", ");
SerialUSB.println(z);
adxl.printAllRegister();
delay(10);
}
头文件.h中声明_buff[]的代码:
private:
void writeTo(byte address, byte val);
void writeToI2C(byte address, byte val);
void writeToSPI(byte address, byte val);
void readFrom(byte address, int num, byte buff[]);
void readFromI2C(byte address, int num, byte buff[]);
void readFromSPI(byte address, int num, byte buff[]);
void setRegisterBit(byte regAdress, int bitPos, bool state);
bool getRegisterBit(byte regAdress, int bitPos);
byte _buff[6] ; // 6 Bytes Buffer
int _CS = 10;
bool I2C = true;
unsigned long SPIfreq = 5000000;
我认为需要修改红板库以将输出寄存器 0x32-0x37 读取为 16 位二进制补码。我是这个编程环境的新手,所以感谢任何帮助。
谢谢 - 杰瑞
我从 Sparkfun board notes (https://www.sparkfun.com/products/14812) 怀疑问题是 Redboard Turbo 是一个 32 位处理器,具有 32 位 int 而不是 16 位 int。在这样的处理器上,存储在 int 中的所有 16 位值都是正值。
为了检验我的理论,运行 Redboard Turbo 上的以下草图:
void setup() {
Serial.begin(9600);
while (!Serial) {}
Serial.print("sizeof(int) = ");
Serial.println(sizeof(int));
}
void loop() {
}
在我的 Arduino Uno - 一个 16 位环境 - 输出表明一个 int 是两个字节(16 位)
sizeof(int) = 2
如果你的 Redboard Turbo 打印出来
sizeof(int) = 4
那么它的int是4个字节(32位)。
我怀疑该库不是为 32 位处理器编写的,并且可能会在 Redboard Turbo 上显示一些问题。要修复特定的 readAccel() 函数,请重写它以将 16 位数字符号扩展为 32 位:
int16_t i16; // the 16-bit result, signed.
i16 = (int16_t) ((((uint16_t)_buff[1]) << 8) | _buff[0]);
*x = (int) i16;
i16 = (int16_t) ((((uint16_t)_buff[3]) << 8) | _buff[2]);
*y = (int) i16;
i16 = (int16_t) ((((uint16_t)_buff[5]) << 8) | _buff[4]);
*z = (int) i16;
顺便说一句,在上面的 readAccel() 重写中,我使用了 uint16_t 来确保字节移位发生在无符号值上,因为左移有符号数可能会产生意想不到的结果一些处理器。
我是 运行 在 sparkfun redboard turbo(处理器 samd21g18)和旧的 arduino uno(处理器 mega16u2)上使用 I2C 的 ADXL345。我在两块板上使用的库和草图是相同的,除了串行端口更改为 SerialUSB 以适应红板。
问题似乎是 uno 将 xyz 寄存器(寄存器 0x32 - 0x37 中每轴 2 个字节)解释为 16 位二进制补码(根据数据表),而红板则不然。 uno的输出是正确的,红板的输出是错误的,都是正整数输出。
下图显示了 ADXL345 相同相对位置下左侧红板和右侧 uno 的输出。
我认为有问题的代码在以下库代码中。
/*********************** READING ACCELERATION ***********************/
/* Reads Acceleration into Three Variables: x, y and z */
void ADXL345::readAccel(int *xyz){
readAccel(xyz, xyz + 1, xyz + 2);
}
void ADXL345::readAccel(int *x, int *y, int *z) {
readFrom(ADXL345_DATAX0, ADXL345_TO_READ, _buff); // Read Accel Data from ADXL345
// Each Axis @ All g Ranges: 10 Bit Resolution (2 Bytes)
*x = (((int)_buff[1]) << 8) | _buff[0];
*y = (((int)_buff[3]) << 8) | _buff[2];
*z = (((int)_buff[5]) << 8) | _buff[4];
}
草图代码如下:
#include <SparkFun_ADXL345.h>
/*********** COMMUNICATION SELECTION ***********/
/* Comment Out The One You Are Not Using */
//ADXL345 adxl = ADXL345(10); // USE FOR SPI COMMUNICATION, ADXL345(CS_PIN);
ADXL345 adxl = ADXL345(); // USE FOR I2C COMMUNICATION
/****************** INTERRUPT ******************/
/* Uncomment If Attaching Interrupt */
//int interruptPin = 2; // Setup pin 2 to be the interrupt pin (for most Arduino Boards)
/******************** SETUP ********************/
/* Configure ADXL345 Settings */
void setup(){
SerialUSB.begin(9600); // Start the SerialUSB terminal
SerialUSB.println("SparkFun ADXL345 Accelerometer Hook Up Guide Example");
SerialUSB.println();
adxl.powerOn(); // Power on the ADXL345
adxl.setRangeSetting(2); // Give the range settings
// Accepted values are 2g, 4g, 8g or 16g
// Higher Values = Wider Measurement Range
// Lower Values = Greater Sensitivity
}
/****************** MAIN CODE ******************/
/* Accelerometer Readings and Interrupt */
void loop(){
// Accelerometer Readings
int x,y,z;
adxl.readAccel(&x, &y, &z); // Read the accelerometer values and store them in variables declared above x,y,z
// Output Results to SerialUSB
/* UNCOMMENT TO VIEW X Y Z ACCELEROMETER VALUES */
SerialUSB.print(x);
SerialUSB.print(", ");
SerialUSB.print(y);
SerialUSB.print(", ");
SerialUSB.println(z);
adxl.printAllRegister();
delay(10);
}
头文件.h中声明_buff[]的代码:
private:
void writeTo(byte address, byte val);
void writeToI2C(byte address, byte val);
void writeToSPI(byte address, byte val);
void readFrom(byte address, int num, byte buff[]);
void readFromI2C(byte address, int num, byte buff[]);
void readFromSPI(byte address, int num, byte buff[]);
void setRegisterBit(byte regAdress, int bitPos, bool state);
bool getRegisterBit(byte regAdress, int bitPos);
byte _buff[6] ; // 6 Bytes Buffer
int _CS = 10;
bool I2C = true;
unsigned long SPIfreq = 5000000;
我认为需要修改红板库以将输出寄存器 0x32-0x37 读取为 16 位二进制补码。我是这个编程环境的新手,所以感谢任何帮助。
谢谢 - 杰瑞
我从 Sparkfun board notes (https://www.sparkfun.com/products/14812) 怀疑问题是 Redboard Turbo 是一个 32 位处理器,具有 32 位 int 而不是 16 位 int。在这样的处理器上,存储在 int 中的所有 16 位值都是正值。
为了检验我的理论,运行 Redboard Turbo 上的以下草图:
void setup() {
Serial.begin(9600);
while (!Serial) {}
Serial.print("sizeof(int) = ");
Serial.println(sizeof(int));
}
void loop() {
}
在我的 Arduino Uno - 一个 16 位环境 - 输出表明一个 int 是两个字节(16 位)
sizeof(int) = 2
如果你的 Redboard Turbo 打印出来
sizeof(int) = 4
那么它的int是4个字节(32位)。
我怀疑该库不是为 32 位处理器编写的,并且可能会在 Redboard Turbo 上显示一些问题。要修复特定的 readAccel() 函数,请重写它以将 16 位数字符号扩展为 32 位:
int16_t i16; // the 16-bit result, signed.
i16 = (int16_t) ((((uint16_t)_buff[1]) << 8) | _buff[0]);
*x = (int) i16;
i16 = (int16_t) ((((uint16_t)_buff[3]) << 8) | _buff[2]);
*y = (int) i16;
i16 = (int16_t) ((((uint16_t)_buff[5]) << 8) | _buff[4]);
*z = (int) i16;
顺便说一句,在上面的 readAccel() 重写中,我使用了 uint16_t 来确保字节移位发生在无符号值上,因为左移有符号数可能会产生意想不到的结果一些处理器。