简体   繁体   English

8bit(两个值)数组到16bit数组(一个值)

[英]8bit (two values) array to 16bit array (one value)

I'm reading data from a sensor, that sends them as two 8bit values and user have to convert them into one signed 16bit value. 我正在从传感器读取数据,该传感器将它们作为两个8位值发送,并且用户必须将它们转换为一个带符号的16位值。 I save these values into an array of 5400 elements (the sensor is accelerometer+gyro+magnetometer, so 9 axes, so in the end I'll have 300 values of each). 我将这些值保存到一个5400个元素的数组中(传感器是加速度计+陀螺仪+磁力计,所以是9个轴,所以最后每个轴都有300个值)。 So lets say I need reading from accelerometer's X axis. 所以可以说我需要从加速度计的X轴读取数据。 In my array I save these in first two places, so my accX readings are on indexes 0,1 then 18,19 then 36,37 and so on..... Now I need to extract these into new 16bit array with 300 elements that will represent only the X axis from accelerometer. 在我的数组中,我将它们保存在前两个位置,所以我的accX读数分别位于索引0,1,然后是18,19,然后是36,37,依此类推.....现在,我需要将它们提取到具有300个元素的新16bit数组中只能代表加速度计的X轴。 What I came up is following: 我想到的是:

uint8_t rawData[5400]={0};

int16_t *AccX = malloc(300*sizeof(int16_t));

for(int i=0;i<300;i++){
    AccX[i]=(rawData[i+1+i*17]<<8 | rawData[i+0+i*17]);
}
//do some calculations
free(AccX);

Yet in my AccX array are values I do not expect to be there. 但是在我的AccX数组中有一些我不希望出现的值。 Any idea what might have gone wrong? 知道可能出了什么问题吗? The sensor is LSM9DS1. 传感器为LSM9DS1。

Edit: sorry I didn't give more info about the device. 编辑:对不起,我没有提供有关该设备的更多信息。 I know for sure this works: 我肯定知道这可行:

x_accel = (rawData[1]<<8 | rawData[0]);

also I inspected the rawData array and it contains correct data. 我还检查了rawData数组,它包含正确的数据。 It goes wrong when I try to fill that data to AccX array 当我尝试将数据填充到AccX数组时出错

Look at the datasheet . 查看数据表 Essentially, there are two separate devices in a single package. 本质上,一个封装中有两个独立的设备。

You need the accelerometer/gyroscope device registers: 您需要加速度计/陀螺仪设备寄存器:

  • 21 and 22 (0x15 and 0x16) for temperature 温度的21和22(0x15和0x16)

  • 24 and 25 (0x18 and 0x19) for gyroscope X axis 陀螺仪X轴的24和25(0x18和0x19)

  • 26 and 27 (0x1A and 0x1B) for gyroscope Y axis 用于陀螺仪Y轴的26和27(0x1A和0x1B)

  • 28 and 29 (0x1C and 0x1D) for gyroscope Z axis 陀螺仪Z轴的28和29(0x1C和0x1D)

  • 40 and 41 (0x28 and 0x29) for accelerometer X axis 加速度计X轴的40和41(0x28和0x29)

  • 42 and 43 (0x2A and 0x2B) for accelerometer X axis 加速度计X轴的42和43(0x2A和0x2B)

  • 44 and 45 (0x2C and 0x2D) for accelerometer Z axis 加速度计Z轴的44和45(0x2C和0x2D)

For the magnetic field, you need the magnetic sensor registers: 对于磁场,您需要磁传感器寄存器:

  • 40 and 41 (0x28 and 0x29) for X axis field strength X轴磁场强度为40和41(0x28和0x29)

  • 42 and 43 (0x2A and 0x2B) for Y axis field strength Y轴磁场强度的42和43(0x2A和0x2B)

  • 44 and 45 (0x2C and 0x2D) for Z axis field strength Z轴磁场强度的44和45(0x2C和0x2D)

These are all in two's complement format, with least significant byte first. 这些都是二进制补码格式,最低有效字节在前。

Since practically all microcontrollers use two's complement format for signed integers (STM32 definitely does, as do ARMs and AVRs, including all Arduinos), you can write five simple helper functions. 由于几乎所有的微控制器都对二进制整数使用二进制补码格式(STM32确实如此,ARM和AVR包括所有Arduino一样),因此您可以编写五个简单的辅助函数。 In pseudo-C: 在伪C中:

static int16_t  temperature;
static int16_t  gyro_x, gyro_y, gyro_z;
static int16_t  accel_x, accel_y, accel_z;
static int16_t  mag_x, mag_y, mag_z;
static uint8_t  buf[6];


static void update_temperature(void)
{
    /* Read 2 bytes from registers 0x15 and 0x16 (21 and 22)
       from the accelerometer/gyroscope device, to buf[] */
    temperature = (int16_t)((((unsigned int)buf[1]) << 8) | (unsigned int)(buf[0]));
}

static void update_gyro(void)
{
    /* Read 6 bytes from registers 0x18..0x1D (24 through 29)
       from the accelerometer/gyroscope device, to buf[] */
    gyro_x = (int16_t)((((unsigned int)buf[1]) << 8) | (unsigned int)(buf[0]));
    gyro_y = (int16_t)((((unsigned int)buf[3]) << 8) | (unsigned int)(buf[2]));
    gyro_z = (int16_t)((((unsigned int)buf[5]) << 8) | (unsigned int)(buf[4]));
}

static void update_accel(void)
{
    /* Read 6 bytes from registers 0x28..0x2D (40 through 45)
       from the accelerometer/gyroscope device, to buf[] */
    accel_x = (int16_t)((((unsigned int)buf[1]) << 8) | (unsigned int)(buf[0]));
    accel_y = (int16_t)((((unsigned int)buf[3]) << 8) | (unsigned int)(buf[2]));
    accel_z = (int16_t)((((unsigned int)buf[5]) << 8) | (unsigned int)(buf[4]));
}

static void update_mag(void)
{
    /* Read 6 bytes from registers 0x28..0x2D (40 through 45)
       from the magnetic sensor device, to buf[] */
    mag_x = (int16_t)((((unsigned int)buf[1]) << 8) | (unsigned int)(buf[0]));
    mag_y = (int16_t)((((unsigned int)buf[3]) << 8) | (unsigned int)(buf[2]));
    mag_z = (int16_t)((((unsigned int)buf[5]) << 8) | (unsigned int)(buf[4]));
}

static void update_all(void)
{
    update_temperature();
    update_gyro();
    update_accel();
    update_mag();
}

The assignments look funky, but the compiler should optimize them to sane machine code. 分配看起来很时髦,但是编译器应该优化它们以使机器代码合理。

You'll probably want to write a helper function to do the actual reads (or perhaps three functions; one for reading 2 bytes from the accelerometer/gyroscope device to buf[], one for reading 6 bytes from the accelerometer/gyroscope device to buf[], and one for reading 6 bytes from the magnetic sensor device to buf[], all from consecutive registers given as a parameter to the function). 您可能需要编写一个辅助函数来进行实际读取(或者可能是三个函数;一个函数用于将2个字节从加速度计/陀螺仪设备读取到buf [],一个函数将6个字节从加速度计/陀螺仪设备读取到buf [],以及一个用于从磁传感器设备向buf []读取6个字节的寄存器,所有这些都是从连续寄存器中提供的,该寄存器作为函数的参数提供)。

This approach uses 26 bytes of RAM, and should be suitable for all microcontrollers, both 8-bit (AVRs) and 32-bit (STM32, ARMs). 这种方法使用26字节的RAM,并且应适用于所有8位(AVR)和32位(STM32,ARM)微控制器。 The above code is not sensitive to the byte order (endianness) of the microcontroller. 上面的代码对微控制器的字节顺序(字节序)不敏感。


If your device sends the gyroscope, accelerometer, and magnetic sensor values via USB or serial to your computer, you need to know the byte order (endianness) of the output values is. 如果您的设备通过USB或串行方式将陀螺仪,加速度计和磁传感器值发送到计算机,则需要知道输出值的字节顺序(字节序)。

The sensor itself provides them in least significant byte first. 传感器本身首先以最低有效字节的形式提供它们。 STM32 is, as far as I know, little-endian too, so it should also provide them least significant byte first. 据我所知,STM32也是little-endian,因此它也应该首先提供最低有效字节。

So, lets assume you receive 18*N bytes from the device, with gyroscope axes first, then accelerometer axes, and finally magnetic sensor axis readings. 因此,假设您从设备接收到18*N字节,首先是陀螺仪轴,然后是加速度计轴,最后是磁传感器轴读数。 The following should convert those values to signed integers for easy manipulation: 以下应该将这些值转换为带符号的整数,以便于操作:

#include <stdlib.h>
#include <inttypes.h>

static inline void extract16toint(int *const                 to,
                                  const unsigned char *const from,
                                  const size_t               n,
                                  const size_t               stride)
{
    const unsigned char *const end = from + n * stride;
    const unsigned char       *src = from;
    int                       *dst;

    while (src < end) {
        *(dst++) = (int16_t)(  (unsigned int)(src[0])
                            | ((unsigned int)(src[1]) << 8) );
        src += stride;
    }
}

static void extract_gyroX(int *const                  to,
                          const unsigned char *const  data,
                          const size_t                n)
{
    extract16toint(to, data + 0, n, 18);
}

static void extract_gyroY(int *const                  to,
                          const unsigned char *const  data,
                          const size_t                n)
{
    extract16toint(to, data + 2, n, 18);
}

static void extract_gyroZ(int *const                  to,
                          const unsigned char *const  data,
                          const size_t                n)
{
    extract16toint(to, data + 4, n, 18);
}

static void extract_accelX(int *const                  to,
                           const unsigned char *const  data,
                           const size_t                n)
{
    extract16toint(to, data + 6, n, 18);
}

static void extract_accelY(int *const                  to,
                           const unsigned char *const  data,
                           const size_t                n)
{
    extract16toint(to, data + 8, n, 18);
}

static void extract_accelZ(int *const                  to,
                           const unsigned char *const  data,
                           const size_t                n)
{
    extract16toint(to, data + 10, n, 18);
}

static void extract_magX(int *const                  to,
                         const unsigned char *const  data,
                         const size_t                n)
{
    extract16toint(to, data + 12, n, 18);
}

static void extract_magY(int *const                  to,
                         const unsigned char *const  data,
                         const size_t                n)
{
    extract16toint(to, data + 14, n, 18);
}

static void extract_magZ(int *const                  to,
                         const unsigned char *const  data,
                         const size_t                n)
{
    extract16toint(to, data + 16, n, 18);
}

In OP's case, calling something like 在OP的情况下,调用类似

int *accelX = malloc(300 * sizeof (int));
extract_accelX(accelX, rawData, 300);

should work. 应该管用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM