极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 25292|回复: 10

【已解决】L3G4200D I2C方式能否一次读取两个字节?

[复制链接]
发表于 2012-3-19 19:28:05 | 显示全部楼层 |阅读模式
我自己写的读取姿态传感器的函数,发现一次读取的话,加速度计和数字罗盘都能正确读取,唯独陀螺仪读出来的数据不对,离散性的乱跳,下边是代码:[code=cpp]int gDat(int deviceAddress, int axis) {
            // 读寄存器
    int v;                                             // 返回值
    byte vL, vH, address;
    if (deviceAddress == ADXAddress) address = 0x32;   // ADXL345读数地址
    if (deviceAddress == L3GAddress) address = 0x28;   // L3G4200D读数地址
    if (deviceAddress == HMCAddress) address = 0x03;   // HMC5883L读数地址
    address = address + axis * 2;                      // 坐标轴选择

    Wire.beginTransmission(deviceAddress);
    Wire.send(address);
    Wire.endTransmission();
    Wire.requestFrom(deviceAddress, 2);

    while(!Wire.available()) {}
    vL = Wire.receive();
    while(!Wire.available()) {}
    vH = Wire.receive();                                // 能否一次读取两个字节???

    if (deviceAddress == HMCAddress)
        v = (vL << 8) | vH;
    else
        v = (vH << 8) | vL;
    return v;
}[/code]如果分两次读取的话就没问题:[code=cpp]int gDat(int deviceAddress, int axis) {
            // 读寄存器
    int v;                                             // 返回值
    byte vL, vH, address;
    if (deviceAddress == ADXAddress) address = 0x32;   // ADXL345读数地址
    if (deviceAddress == L3GAddress) address = 0x28;   // L3G4200D读数地址
    if (deviceAddress == HMCAddress) address = 0x03;   // HMC5883L读数地址
    address = address + axis * 2;                      // 坐标轴选择

    Wire.beginTransmission(deviceAddress);
    Wire.send(address);
    Wire.endTransmission();
    Wire.requestFrom(deviceAddress, 1);
    while(!Wire.available()) {}
    vL = Wire.receive();

    Wire.beginTransmission(deviceAddress);
    Wire.send(address + 1);
    Wire.endTransmission();
    Wire.requestFrom(deviceAddress, 1);
    while(!Wire.available()) {}
    vH = Wire.receive();

    if (deviceAddress == HMCAddress)
        v = (vL << 8) | vH;
    else
        v = (vH << 8) | vL;
    return v;
}[/code]DX们指点一下,是哪里搞错了捏?
回复

使用道具 举报

 楼主| 发表于 2012-3-20 16:04:59 | 显示全部楼层
终于自己搞定了,真不容易,读书的地址不能用0x28,得用0xA8,最高位要标1,这样每次寄存器指针才会自动+1
回复 支持 反对

使用道具 举报

发表于 2012-3-20 16:46:07 | 显示全部楼层
看到寄存器就头大
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-3-20 17:18:25 | 显示全部楼层
弘毅 发表于 2012-3-20 16:46
看到寄存器就头大

主要是原生资料基本都是英文的,看着有点累,说的倒是够详细……有点太详细了,N久找不到想要的东西。

今天还犯了个错误,数组下标溢出了,状况太莫名其妙,都没这方面想,搞了好久才发现,郁闷。
回复 支持 反对

使用道具 举报

发表于 2012-5-31 13:58:23 | 显示全部楼层
黑马 发表于 2012-3-20 17:18
主要是原生资料基本都是英文的,看着有点累,说的倒是够详细……有点太详细了,N久找不到想要的东西。
...

弄好的代码能贴出来么?我用你 《我的自平衡小车D2——加速度计与陀螺仪获取姿态参数的差异》的代码调试,结果串口没有收到数据,板子的TX RX灯也不闪。。。
不知道哪里错了, 原版复制 然后把 I2C地址改成我模块的对应地址。
郁闷搞不懂啊,就算读取错误也该有错误的输出啊?
写入成功了啊。昏死
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-5-31 16:19:07 | 显示全部楼层
darkorigin 发表于 2012-5-31 13:58
弄好的代码能贴出来么?我用你 《我的自平衡小车D2——加速度计与陀螺仪获取姿态参数的差异》的代码调试, ...

http://www.geek-workshop.com/forum.php?mod=viewthread&tid=665
这个帖子里就是改过的

你用的是哪款mems?不同的片子读取的方式都有差异,最好花点时间琢磨规格书。别急,一般涉及寄存器读写的都会这样,错一点就完全莫名其妙的。
回复 支持 反对

使用道具 举报

发表于 2012-5-31 16:25:37 | 显示全部楼层
黑马 发表于 2012-5-31 16:19
http://www.geek-workshop.com/forum.php?mod=viewthread&tid=665
这个帖子里就是改过的

HMC5883 ADXL345 L3G4200D BMP085
比你这个就多个BMP085(气压传感器)
用IIC地址测定的代码测出来如下
--- I2C Bus Scanner Test ---
starting scanning of I2C bus from 1 to 127...

addr: 30         HEX: 0x3C         found!   HMC5883
addr: 83         HEX: 0xA6         found!          ADXL345
addr: 105         HEX: 0xD2         found!          L3G4200D
addr: 119         HEX: 0xEE         found!   BMP085

--- I2C Bus Scanner Complete ---

我把我改的你的代码贴下来,方便的话帮我看下,


#include <Wire.h>
#define Acc 0xA6  // ADXL345的读数地址
#define Gyr 0xD2   //陀螺仪L3G4200D
#define Mag 0x3C //HMC5883L的读数地址
#define Gry_offset -13    // 陀螺仪偏移量
#define Gyr_Gain 0.07     // 满量程2000dps时灵敏度(dps/digital)
#define pi 3.14159   

float angleG;
unsigned long timer = 0;  // 采样时间
void setup() {
    Serial.begin(9600);  // 开启串口以便监视数据
    sensor_init();        // 配置传感器
    delay(1000);
  }

void loop() {
    long o_timer = timer;                   // 上一次采样时间(ms)
    float Y_Accelerometer = gDat(Acc, 1);   // 获取向前的加速度
    float Z_Accelerometer = gDat(Acc, 2);   // 获取向下的加速度
    float angleA = atan(Y_Accelerometer / Z_Accelerometer) * 180 / pi;
                                            // 根据加速度分量得到的角度(degree)
    timer = millis();                       // 当前时间(ms)
    int dt = timer - o_timer;               // 微分时间
    angleG = angleG + Gyr_Gain * (gDat(Gyr, 0) +  Gry_offset) * dt / 1000;
                                            // 对角速度积分得到的角度(degree)
    Serial.print(timer);
    Serial.print(",");
    Serial.print(angleA, 6);
    Serial.print(",");
    Serial.print(angleG, 6);
    Serial.print(";");                      // 输出数据
    delay(10);
  }

int gDat(int device, int axis) {
Serial.println("get data now!");
// 读九轴姿态传感器寄存器函数
// For Arduino, by 黑马
// 调用参数表
//   type    device      axis
//                    0   1   2
// ADXL345     Acc    x   y   z
// L3G4200D    Gyr    x   y   z
// HMC5883L    Mag    x   z   y
// Example
// 00 #include <Wire.h>
// 01 #define Acc 0x1D;
// 02 #define Gyr 0x69;
// 03 #define Mag 0x1E;
// 04
// 05  void setup() {
// 06    sensor_init();
// 07    delay(1000);
// 08  }
// 09
// 10  void loop() {
// 11    int Z-Gyroscope;
// 12    Z-Gyroscope = gDat(Gyr, 2);
// 13    delay(50);
// 14  }
     Serial.println("GET DATA now!");
    int v;
    byte vL, vH, address;               // 存放byte数值
    if (device == Acc) address = 0xA6;  // ADXL345的读数地址
    if (device == Gyr) address = 0xD2;  // L3G4200D的读数地址
    if (device == Mag) address = 0x3C;  // HMC5883L的读数地址
    address = address + axis * 2;       // 数据偏移-坐标轴
    Wire.beginTransmission(device);     // 开始传输数据
    Wire.send(address);                 // 发送指针
    Wire.requestFrom(device, 2);        // 请求2 byte数据
    while(Wire.available() < 2);        // 成功获取前等待
    vL = Wire.receive();
    vH = Wire.receive();                // 读取数据
    Wire.endTransmission();             // 结束传输
    if (device == Mag) v = (vL << 8) | vH;
    else v = (vH << 8) | vL;            // 将byte数据合并为Int
    return v;                           // 返回读书值
}

void sensor_init() {     // 配置九轴姿态传感器
    Serial.println("Init IMU now!");
    writeRegister(Acc, 0x2D, 0b00001000);    // 测量模式
                            // 配置ADXL345
    writeRegister(Gyr, 0x20, 0b00001111);    // 设置睡眠模式、x, y, z轴使能
    writeRegister(Gyr, 0x21, 0b00000000);    // 选择高通滤波模式和高通截止频率
    writeRegister(Gyr, 0x22, 0b00000000);    // 设置中断模式
    writeRegister(Gyr, 0x23, 0b00110000);    // 设置量程(2000dps)、自检状态、SPI模式
    writeRegister(Gyr, 0x24, 0b00000000);    // FIFO & 高通滤波
                            // 配置L3G4200D(2000 deg/sec)
    writeRegister(Mag, 0x02, 0x00);          // 连续测量
                            // 配置HMC5883L
}

void writeRegister(int device, byte address, byte val) {    // 写寄存器
    Serial.println("Write Register now!");
    Wire.beginTransmission(device);
    Wire.send(address);
    Wire.send(val);
    Wire.endTransmission();
}
回复 支持 反对

使用道具 举报

发表于 2012-5-31 16:27:50 | 显示全部楼层
本帖最后由 darkorigin 于 2012-5-31 16:37 编辑

我在每个函数里面加了1行代码在函数开头,方便看到是到哪一步了。
结果是 gDAT 输出了1次就没下文了。LOOP也没继续LOOP了,是不是哪里死锁了(不明白,应该没有冲突怎么会死锁呢)
有输出初始化,一次gDAT
回复 支持 反对

使用道具 举报

发表于 2012-5-31 16:46:06 | 显示全部楼层
之前用了MWC的代码来测试,这个模块开始是正常的,时间一久(大约3分钟以后)传感器静止不动,图形界面上的飞行器已经飞的快七荤八素了。翻转,翻腾,不亦乐乎 I2C Err的计数也是飞奔。 搞不懂,到底是模块有问题,还是咋的
IIC扫描程序都能扫描到地址。
回复 支持 反对

使用道具 举报

发表于 2013-3-28 23:00:39 | 显示全部楼层
现在我在用L3G4200D这个陀螺,DRDY这个信号设置了总是读的有问题,想请高手指点一下,在上面代码里面,while(!Wire.available()) {}中:Wire.available()的函数原型是什么?用这个判断数据更新会好一点吧
回复 支持 反对

使用道具 举报

发表于 2014-5-21 13:08:02 | 显示全部楼层
L3G4200i2c怎么设定高速模式
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-8 13:03 , Processed in 0.039121 second(s), 22 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表