Arduino代码没有正确添加数字

时间:2017-06-19 10:17:37

标签: c++ arduino sensor mpu6050

我正在尝试创建一个函数来查找Arduino上传感器值的平均值以进行校准,但总和不能正常工作,因此平均值不正确。下表显示了输出的示例。左栏应该是输出的滚动总和,它显示在右栏中(负面如何进入?)

-10782      17112        
  6334      17116       
 23642      17308        
-24802      17092        
 -7706      17096        
  9326      17032        
 26422      17096        
-21986      17128  

应该执行此操作的calibrateSensors()函数如下所示

void calibrateSensors(int16_t * accelOffsets){

  int16_t rawAccel[3];
  int sampleSize = 2000;


  Serial.println("Accelerometer calibration in progress...");

  for (int i=0; i<sampleSize; i ++){

    readAccelData(rawAccel);        // get raw accelerometer data
    accelOffsets[0] += rawAccel[0]; // add x accelerometer values
    accelOffsets[1] += rawAccel[1]; // add y accelerometer values
    accelOffsets[2] += rawAccel[2]; // add z accelerometer values
    Serial.print(accelOffsets[2]);
    Serial.print("\t\t");
    Serial.print(rawAccel[2]);
    Serial.print("   \t FIRST I:");
    Serial.println(i);
  }

  for (int i=0; i<3; i++)
  {
    accelOffsets[i] = accelOffsets[i] / sampleSize;
    Serial.print("Second I:");
    Serial.println(i);
  }

  Serial.println("Accelerometer calibration complete");
  Serial.println("Accelerometer Offsets:");
  Serial.print("Offsets (x,y,z): ");
  Serial.print(accelOffsets[0]);
  Serial.print(", ");
  Serial.print(accelOffsets[1]);
  Serial.print(", ");
  Serial.println(accelOffsets[2]);
}

readAccelData()功能如下

void readAccelData(int16_t * destination){
  // x/y/z accel register data stored here
  uint8_t rawData[6];
  // Read the six raw data registers into data array
  I2Cdev::readBytes(MPU6050_ADDRESS, ACCEL_XOUT_H, 6, &rawData[0]);  
  // Turn the MSB and LSB into a signed 16-bit value
  destination[0] = (int16_t)((rawData[0] << 8) | rawData[1]) ;  
  destination[1] = (int16_t)((rawData[2] << 8) | rawData[3]) ;  
  destination[2] = (int16_t)((rawData[4] << 8) | rawData[5]) ; 

知道我哪里错了吗?

2 个答案:

答案 0 :(得分:1)

你有两个问题:

  1. 您没有初始化数组。它们以垃圾数据开头(空间已分配,但未清除)。您可以通过执行以下操作将数组初始化为全零:
  2. int array[5] = {};

    这将产生一个最初看起来像[0,0,0,0,0]

    的数组

    您的第二个问题是您正在创建一个16位有符号整数数组。 16位整数可以存储65536个不同的值。问题是,因为您使用的是有符号类型,所以只能使用32767个正整数值。当您尝试存储大于该值的值时,您会溢出并获得负数。

    我相信arduino支持32位整数。如果您只想要正数,则使用无符号类型。

    使用显式的32位整数:

    #include <stdint.h>
    int32_t my_int = 0;
    

    有关标准变量大小的一些信息(请注意,它们可以根据代码构建的arduino模型而有不同的大小):

    https://www.arduino.cc/en/Reference/Int

      

    在Arduino Uno(以及其他基于ATMega的主板)上,一个int存储了一个   16位(2字节)值。这产生了-32,768到32,767的范围   (最小值-2 ^ 15,最大值(2 ^ 15)-1)。在   Arduino Due和基于SAMD的板(如MKR1000和Zero),一个int   存储一个32位(4字节)值。这产生了-2,147,483,648的范围   至2,147,483,647(最小值-2 ^ 31,最大值(2 ^ 31)    - 1)。

    https://www.arduino.cc/en/Reference/UnsignedInt

      

    在Uno和其他基于ATMEGA的板上,无符号整数(未签名   整数)与整数相同,因为它们存储一个2字节的值。   而不是存储负数,但它们只存储正数   值,产生0到65,535(2 ^ 16)-1的有用范围。

         

    Due存储一个4字节(32位)的值,范围从0到   4,294,967,295(2 ^ 32 - 1)。

    https://www.arduino.cc/en/Reference/UnsignedLong

      

    无符号长变量是数字的扩展大小变量   存储,并存储32位(4字节)。与标准长号未签名不同   多头不会存储负数,使其范围从0到   4,294,967,295(2 ^ 32 - 1)。

答案 1 :(得分:0)

使用此代码:

void calibrateSensors(int16_t * accelOffsets){
  int16_t rawAccel[3];
  //  [...]
  accelOffsets[0] += rawAccel[0];

有一个明显的问题:你在这里添加两个 16bit有符号整数。 16位有符号整数的典型最大值为0x7fff(第一位将用作符号位),十进制32767

鉴于前两个样本号,17112 + 17116已经34228,因此您的整数类型溢出。

中溢出有符号整数是未定义的行为,因为不同的实现可以对负数使用不同的表示。对于具有未定义行为的程序,您不能期望任何特定结果。一个非常可能的结果是价值将会回绕&#34;进入负面范围。

由于您已使用stdint.h中的类型,因此解决方案很简单:使用uint32_t作为总和,此类型的值最多可达4294967295

作为一般规则:如果您从不需要负值,只需坚持使用无符号类型即可。我在这里没有看到您使用int16_t的原因,只需使用uint16_t