与加速度计接口的C分段故障

New*_*990 1 c accelerometer segmentation-fault raspberry-pi

我使用代码将Raspberry Pi与加速度计连接:

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>
#include "LSM9DS0.h"

void readBlock(uint8_t command, uint8_t size, uint8_t *data);
void selectDevice(int file, int addr);
void readACC(int  *a);
void writeAccReg(uint8_t reg, uint8_t value);
void enableIMU();
int file;

void  readBlock(uint8_t command, uint8_t size, uint8_t *data)
{
    int result = i2c_smbus_read_i2c_block_data(file, command, size, data);
    if (result != size)
    {
        printf("Failed to read block from I2C.");
        exit(1);
    }
}

void selectDevice(int file, int addr)
{
        if (ioctl(file, I2C_SLAVE, addr) < 0) {
         printf("Failed to select I2C device.");
        }
}

void readACC(int  *a)
{
        printf("entered readACC");
        uint8_t block[6];
        selectDevice(file,ACC_ADDRESS);
        readBlock(0x80 | OUT_X_L_A, sizeof(block), block);

        *a = (int16_t)(block[0] | block[1] << 8);
        *(a+1) = (int16_t)(block[2] | block[3] << 8);
        *(a+2) = (int16_t)(block[4] | block[5] << 8);        

        printf("X axis: %4.2f, Y axis: %4.2f, Z axis: %4.2f", a, a+1, a+2);
}

void writeAccReg(uint8_t reg, uint8_t value)
{
    selectDevice(file,ACC_ADDRESS);
  int result = i2c_smbus_write_byte_data(file, reg, value);
    if (result == -1)
    {
        printf ("Failed to write byte to I2C Acc.");
        exit(1);
    }
}

void enableIMU()
{

    __u16 block[I2C_SMBUS_BLOCK_MAX];

        int res, bus,  size;


        char filename[20];
        sprintf(filename, "/dev/i2c-%d", 1);
        file = open(filename, O_RDWR);
        if (file<0) {
        printf("Unable to open I2C bus!");
                exit(1);
        }

        // Enable accelerometer.
        writeAccReg(CTRL_REG1_XM, 0b10010111); //  z,y,x axis enabled, continuos update,  100Hz data rate
        writeAccReg(CTRL_REG2_XM, 0b00100000); // +/- 16G full scale
        printf("Accelerometer is enabled\n");
}

int main(){
enableIMU();
printf("fine\n");
int *a;
readAcc(a);  
return 0; 
}
Run Code Online (Sandbox Code Playgroud)

我的输出如下:

 Accelerometer is enabled 
 fine 
 Segmentation fault
Run Code Online (Sandbox Code Playgroud)

根据输出,函数enableIMU工作正常,输出也显示"正常",这是在进入readACC之前,但我从未输入readACC,因为"输入的readACC"没有打印.相反,我得到了一个分段错误.

你知道我在这里做错了什么吗?我将衷心感谢您的帮助!

Rol*_*lig 5

您的代码中的问题是:

int *a;
readAcc(a); 

…

*a = (int16_t)(block[0] | block[1] << 8);
Run Code Online (Sandbox Code Playgroud)

在第一行中,您声明一个指向的指针int.此指针指向某处,因为它未初始化.然后,在最后一行,你在内存中的某处写入.

相反,你应该这样写:

int16_t a[3];
readAcc(a);
Run Code Online (Sandbox Code Playgroud)

这样,您可以定义函数readAcc可以写入的存储.readAcc函数的参数不应该是指向int,而是指向int16_t,因为你这样使用它.

在里面readAcc,你可以写:

a[0] = …;
a[1] = …;
a[2] = …;
Run Code Online (Sandbox Code Playgroud)

您也可以定义一个代替数组struct xyz { int16_t x, y, z; }的代码,它可以更准确地描述代码的作用.

我会这样写:

struct xyz {
    int16_t x, y, z;
};

void readACC(struct xyz *coord)
{
    printf("entered readACC\n");
    selectDevice(file, ACC_ADDRESS);

    uint8_t block[6];
    readBlock(0x80 | OUT_X_L_A, sizeof(block), block);

    coord->x = (int16_t)(block[0] | block[1] << 8);
    coord->y = (int16_t)(block[2] | block[3] << 8);
    coord->z = (int16_t)(block[4] | block[5] << 8);        

    printf("X axis: %4.2f, Y axis: %4.2f, Z axis: %4.2f\n", 
        coord->x / 256.0, coord->y / 256.0, coord->z / 256.0);
}
Run Code Online (Sandbox Code Playgroud)
  • 我定义了struct xyz使代码自我解释.
  • 我将selectDevice呼叫移到了block声明之上,因为block不需要它.
  • 我用a更好的名称替换了参数coord,它具有适当的数据类型.
  • 我更正了printf调用的参数以匹配%f转换说明符.(我希望因子256.0是正确的.)当您尝试打印int使用时%f,行为是未定义的(这是C程序中可能发生的最糟糕的事情).
  • 我在printf格式字符串的末尾添加了换行符.