与加速度计接口时的 C 分段错误
C segmentation fault in interfacing with accelerometer
我正在使用以下代码将 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;
}
我的输出如下所示:
Accelerometer is enabled
fine
Segmentation fault
根据输出,功能 enableIMU 工作正常,输出还显示 "fine" 就在进入 readACC 之前,但我从未输入 readACC,因为 "entered readACC" 没有被打印出来。相反,我遇到了分段错误。
你知道我做错了什么吗?非常感谢您的帮助!
您的代码中的问题是:
int *a;
readAcc(a);
…
*a = (int16_t)(block[0] | block[1] << 8);
在第一行中,您声明了一个指向 int
的指针。这个指针指向某处,因为它没有被初始化。然后,在最后一行中,您在内存中的某处写入
相反,你应该这样写:
int16_t a[3];
readAcc(a);
这样,您就可以定义函数 readAcc
可以写入的存储空间。 readAcc
函数的参数不应该是指向 int
的指针,而是指向 int16_t
的指针,因为您是这样使用它的。
在readAcc
里面,你可以这样写:
a[0] = …;
a[1] = …;
a[2] = …;
除了数组,您还可以定义一个 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);
}
- 我定义了
struct xyz
以使代码不言自明。
- 我将
selectDevice
调用移到 block
声明上方,因为不需要 block
。
- 我用更好的名称
coord
替换了 a
参数,它具有合适的数据类型。
- 我更正了
printf
调用的参数以匹配 %f
转换说明符。 (我希望因子 256.0 是正确的。)当您尝试使用 %f
打印 int
时, 行为未定义(这是最糟糕的事情发生在 C 程序中)。
- 我在
printf
格式字符串的末尾添加了换行符。
我正在使用以下代码将 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;
}
我的输出如下所示:
Accelerometer is enabled
fine
Segmentation fault
根据输出,功能 enableIMU 工作正常,输出还显示 "fine" 就在进入 readACC 之前,但我从未输入 readACC,因为 "entered readACC" 没有被打印出来。相反,我遇到了分段错误。
你知道我做错了什么吗?非常感谢您的帮助!
您的代码中的问题是:
int *a;
readAcc(a);
…
*a = (int16_t)(block[0] | block[1] << 8);
在第一行中,您声明了一个指向 int
的指针。这个指针指向某处,因为它没有被初始化。然后,在最后一行中,您在内存中的某处写入
相反,你应该这样写:
int16_t a[3];
readAcc(a);
这样,您就可以定义函数 readAcc
可以写入的存储空间。 readAcc
函数的参数不应该是指向 int
的指针,而是指向 int16_t
的指针,因为您是这样使用它的。
在readAcc
里面,你可以这样写:
a[0] = …;
a[1] = …;
a[2] = …;
除了数组,您还可以定义一个 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);
}
- 我定义了
struct xyz
以使代码不言自明。 - 我将
selectDevice
调用移到block
声明上方,因为不需要block
。 - 我用更好的名称
coord
替换了a
参数,它具有合适的数据类型。 - 我更正了
printf
调用的参数以匹配%f
转换说明符。 (我希望因子 256.0 是正确的。)当您尝试使用%f
打印int
时, 行为未定义(这是最糟糕的事情发生在 C 程序中)。 - 我在
printf
格式字符串的末尾添加了换行符。