找回密码
 马上注册

QQ登录

只需一步,快速开始

查看: 12589|回复: 22

求晓舟版主指导一下I2C读写模块的具体使用方法

[复制链接]
发表于 2012-5-16 10:54:03 | 显示全部楼层 |阅读模式
悬赏5乐币已解决
买了一片L3G4200D陀螺,无论是用LABVIEW,NXT-G和NXC都读不出数据来......
(PCB上的时钟线和数据线上拉是10K,没有更换成82K)

昨天我的Arduino 2560到了,使用了一个老外的开源库文件,瞎搞了二个小时,居然通过串口能连续读出三轴读数了!但这个东西最终我是想放到乐高上用的,再次研读晓舟版主的I2C读写BLOCK,一直搞到晚上1点多,仍然无果.......

所以想请晓舟版主给我讲解一下模块的三个输入参数的具体定义!!
(我看了一下ARDUINO下L3G4200的库文件,里面对于器件地址还涉用到什么右移一位什么的,但我在晓舟版主的I2C读写模块是找不到类似的......当然我是初学,一切全是从零开始的,正因为如此,我才想请教)

最佳答案

查看完整内容

注意你的电路连接线,接那个电阻很有必要,这样才能保证你的电压正确。

本帖被以下淘专辑推荐:

  • · DIY|主题: 1, 订阅: 1
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
发表于 2012-5-16 10:54:04 | 显示全部楼层
注意你的电路连接线,接那个电阻很有必要,这样才能保证你的电压正确。
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

发表于 2012-5-16 13:53:37 | 显示全部楼层
I2C总线 你需要上拉电阻,至少2.2k不然是无法通信,还有要看你是软件模拟I2c还是硬件接口,但是要注意I2c是主机控制模式,无论啥米操作都是主机过去的,这个你不用看老外的 国内很多单片机书上都有。。。。。
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

 楼主| 发表于 2012-5-16 16:48:39 | 显示全部楼层
哇,先谢谢楼上二位!
明天去买二个电阻,再试!
(ARDUINO是开源的,玩的人多,乐高就比较少了,ARDUINO各类传感器的库文件应有的全有,一些论坛上主要不是讨论如何制作传感器了,是讨论一些具体算法和实现,相比乐高,好象不是特别热衷于电子积木的开发.......)
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

发表于 2012-5-16 17:07:44 | 显示全部楼层
糖伯虎 发表于 2012-5-16 12:58
注意你的电路连接线,接那个电阻很有必要,这样才能保证你的电压正确。

他的不是没接电阻,接的是10K,而不是82K,这个我觉得没有问题的,我试验过。
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

发表于 2012-5-16 17:08:18 | 显示全部楼层
你的传感器到底是什么通讯协议?我被你说晕了。
能把资料发一下么?
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

发表于 2012-5-16 23:35:21 | 显示全部楼层
blackblue 发表于 2012-5-16 16:48
哇,先谢谢楼上二位!
明天去买二个电阻,再试!
(ARDUINO是开源的,玩的人多,乐高就比较少了,ARDUINO各类传感 ...

IIC有速率要求,这个问题LZ研究过没?
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

 楼主| 发表于 2012-5-17 12:15:53 | 显示全部楼层
本帖最后由 blackblue 于 2012-5-17 21:57 编辑

I2C有速率要求?我没有研究过啊!!!真的不懂其中的意思......

买的模块有二种通讯方式:标准I2C和XXX方式(不记得了),在ARDUINO调通用的就是I2C方式!

PCB图在附件里!

L3G4200D.pdf

171.2 KB, 下载次数: 45

如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

 楼主| 发表于 2012-5-17 22:09:18 | 显示全部楼层
本帖最后由 blackblue 于 2012-5-17 22:12 编辑

呵,瞎猫碰死耗子啦!
用NXC调出来了!X,Y轴数据蛮好的,飘移不大的,Z轴就不对了......温度更不对了.......(当然程序不是我写的,老外的,网上找来的,奇怪的是用他的NXC是行的,用同样是他写的NXT-G的BLOCK就还是读不出数值!一个常数,移动传感器它也永远不会变数值)
-----------------------------------------------------------------------------------------------------------------------------------
电阻还没有空去买,随便在一块没有用的电路上找到一只100K的0805贴片,将原来的SDA上的10K换下,NXC下就能读出X,Y,Z了!
------------------------------------------------------------------------------------------------------------------------------------
用USB连接电脑后,同样的NXC程序,就会一时读得出一时读不出??????
拔掉USB后,就能读.......又一个奇怪的事情!!!!!!
------------------------------------------------------------------------------------------------------------------------------------

用万用表量了一下,SCL和SDA的对地电压,SCL端是3.26,SDA端却是3.67!!!!这好象反了么?还是奇怪......
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

发表于 2012-5-17 23:32:38 | 显示全部楼层
我也打算用这个陀螺仪芯片,不过现在还没怎么研究深入,不过,LZ注意到没有,这个陀螺仪有两个中断引脚(INT) 我好像记得,读这颗芯片是采用中断的方式来读取的,具体就是这个芯片转换完角速度信息后,通过INT引脚来发一个信号给主机, 然后主机再来读取。

如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

发表于 2012-5-18 06:27:36 | 显示全部楼层
本帖最后由 pan_gw 于 2012-5-18 06:29 编辑

#define SensorPort IN_1
#define ADDR     0xD0
struct TriAxisData
{
int gX,gY,gZ;
};
void L3G_Init(byte port, byte i2cAddr)
{
byte cmdBuf[];
  SetSensorLowspeed(port);
  ArrayBuild(cmdBuf,i2cAddr,0xa0,0xaf,0x00,0x00,0x00,0x00,0x00);
I2CWrite(port,0,cmdBuf);
  int status = I2CCheckStatus(port);
  while (status > NO_ERR)
    status = I2CCheckStatus(port);

}
byte L3G_ReadData(byte port, byte i2cAddr,TriAxisData &triData)
{
  byte message[];
  byte buf[12];
  int count;
  byte nByteReady = 0;
byte b;
  SetSensorLowspeed(port);
  ArrayBuild(message, i2cAddr, 0xa8);
  while (I2CStatus(port, nByteReady) ==  STAT_COMM_PENDING);
  count = 6;
  if(I2CBytes(port, message, count, buf)) {
    triData.gX=buf[1]<<8;
    triData.gX |= buf[0];
    triData.gY=buf[3]<<8;
    triData.gY |= buf[2];
    triData.gZ=buf[5]<<8;
    triData.gZ |= buf[4];
}
return b;
}
task main()
{
  string msg;
  TriAxisData gData;
  string ax, ay, az;
L3G_Init(SensorPort,ADDR);

  while (true ) {
  // read the values from the sensor.
    L3G_ReadData(SensorPort, ADDR, gData);
    msg = "X:            ";
    ax = NumToStr(gData.gX);
    msg = StrReplace(msg, 2, ax);
    TextOut(0, LCD_LINE2, msg, false);
    msg = "Y:            ";
    ay = NumToStr(gData.gY);
    msg = StrReplace(msg, 2, ay);
    TextOut(0, LCD_LINE3, msg, false);
    msg = "Z:            ";
    az = NumToStr(gData.gZ);
    msg = StrReplace(msg, 2, az);
    TextOut(0, LCD_LINE4, msg, false);
    Wait(250);
  }
}
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

 楼主| 发表于 2012-5-18 08:44:25 | 显示全部楼层
哇,楼上的!
这个程序你写的?请指点一下以下语句:
1,#define ADDR     0xD0;这个D0是怎么得来的?L3G4200工厂代码是1101,后面的四位中前三位是要根据电路联接来定的,是不是?
2,整个程序里面,我没有看到你对控制寄存器和数据寄存器的读写?请指明一下,相关的是那几句?

下面贴上我抄来的:
//  Gyroscope Example
//  by dimu

#define DI_ADDR_GYRO     0xD2  /*!<  Gyro I2C address */

#define DIGYRO_REG_CTRL1     0x20  /*!< Gyro control register 1 */
#define DIGYRO_REG_CTRL2     0x21  /*!< Gyro control register 2 */
#define DIGYRO_REG_CTRL3     0x22  /*!< Gyro control register 3 */
#define DIGYRO_REG_CTRL4     0x23  /*!< Gyro control register 4 */
#define DIGYRO_REG_CTRL5     0x24  /*!< Gyro control register 5 */

#define DIGYRO_CTRL4_BLOCKDATA  0x80 /*!< Gyro block data update - output registers are not updated until MSB and LSB reading */
#define DIGYRO_CTRL4_BIGENDIAN  0x40 /*!< Gyro use big endian - MSB/LSB rather than LSB/MSB in output registers */
#define DIGYRO_CTRL4_SCALE_250  0x00 /*!< Gyro 250 degrees per second scale */
#define DIGYRO_CTRL4_SCALE_500  0x10 /*!< Gyro 500 degrees per second scale */
#define DIGYRO_CTRL4_SCALE_1000 0x20 /*!< Gyro 1000 degrees per second scale */
#define DIGYRO_CTRL4_SCALE_2000 0x30 /*!< Gyro 2000 degrees per second scale */

// These bytes set the full scale range of the gyroscope.
// it is important to define full_scale_range.  Values are below.
//0x00 - 250 dps.  Full scale range.
//0x10 - 500 dps.  Full scale range.
//0x30 - 2000 dps.  Full scale range.
#define full_scale_range DIGYRO_CTRL4_SCALE_2000

int divisor = 128;      // This will be the divisor we divide the raw value of the gryscope by
                        // to get a scaled value on output.  Default will be for 250 dps,
                        // but we'll define it again in start_gyro.

void start_gyro(byte port, byte range){
  byte I2Csnd[];

  //Write CTRL_REG1
  // Enable all axes. Disable power down.
  ArrayBuild(I2Csnd, DI_ADDR_GYRO, DIGYRO_REG_CTRL1, 0x0F);
  if (I2CWrite(port, 0, I2Csnd) != NO_ERR)
    PlayTone(TONE_A3, 500);
  Wait(MS_10);

  //Write CTRL_REG2
  // No High Pass Filter
  ArrayBuild(I2Csnd, DI_ADDR_GYRO, DIGYRO_REG_CTRL2, 0x00);
  if (I2CWrite(port, 0, I2Csnd) != NO_ERR)
    PlayTone(TONE_A3, 500);
  Wait(MS_10);

  //Write CTRL_REG3
  // No interrupts.  Data ready.
  ArrayBuild(I2Csnd, DI_ADDR_GYRO, DIGYRO_REG_CTRL3, 0x08);
  if (I2CWrite(port, 0, I2Csnd) != NO_ERR)
    PlayTone(TONE_A3, 500);
  Wait(MS_10);

  //Write CTRL_REG4
  ArrayBuild(I2Csnd, DI_ADDR_GYRO, DIGYRO_REG_CTRL4, range);
  if (I2CWrite(port, 0, I2Csnd) != NO_ERR)
    PlayTone(TONE_A3, 500);
  Wait(MS_10);

  //Write CTRL_REG5
  ArrayBuild(I2Csnd, DI_ADDR_GYRO, DIGYRO_REG_CTRL5, 0x00);
  if (I2CWrite(port, 0, I2Csnd) != NO_ERR)
    PlayTone(TONE_A3, 500);
  Wait(MS_10);

  // Set divisor so that the output of our gyro axis readings can be turned
  // into scaled values.
  ///////////////////////////////////////////////////////////////////////////
  if (range == DIGYRO_CTRL4_SCALE_250)
    divisor = 128;   // Full scale range is 250 dps.
  else if (range == DIGYRO_CTRL4_SCALE_500)
    divisor = 64;    // Full scale range is 500 dps.
  else if (range == DIGYRO_CTRL4_SCALE_1000)
    divisor = 32;    // Full scale range is 1000 dps.
  else if (range == DIGYRO_CTRL4_SCALE_2000)
    divisor = 16;    // Full scale range is 2000 dps.

}

// Gyro: axis_reading gets a byte of axis reading data
//
byte gyro_axis_reading_byte(byte port, byte reg){

  byte I2Csnd[];
  ArrayBuild(I2Csnd, DI_ADDR_GYRO, reg);

  byte I2Crec[];    // We are looking for a single byte returned.

  int count = 1;
  byte result = 0x00;
  if (I2CBytes(port, I2Csnd, count, I2Crec))
    result = I2Crec[0];
  else
    PlayTone(TONE_A4, 500);
  return result;
}

#define DIGYRO_REG_XLOW      0x28  /*!< Gyro x-axis low byte register (read only) */
#define DIGYRO_REG_XHIGH     0x29  /*!< Gyro x-axis high byte register (read only) */
#define DIGYRO_REG_YLOW      0x2A  /*!< Gyro y-axis low byte register (read only) */
#define DIGYRO_REG_YHIGH     0x2B  /*!< Gyro y-axis high byte register (read only) */
#define DIGYRO_REG_ZLOW      0x2C  /*!< Gyro z-axis low byte register (read only) */
#define DIGYRO_REG_ZHIGH     0x2D  /*!< Gyro z-axis high byte register (read only) */

// Gyro: gets a full axis reading, scaled to the full scale reading.  Returns
// float in degrees per second.
float gyro_axis_reading(byte port, byte axis){
  // byte axis definitions
  // 0x00 - x-axis
  // 0x01 - y-axis
  // 0x02 - z-axis

  if (axis > 0x02)
    return 0.0;

  byte reg_low[] = {DIGYRO_REG_XLOW, DIGYRO_REG_YLOW, DIGYRO_REG_ZLOW};
  byte reg_high[] = {DIGYRO_REG_XHIGH, DIGYRO_REG_YHIGH, DIGYRO_REG_ZHIGH};

  byte lb = gyro_axis_reading_byte(port, reg_low[axis]);
  byte hb = gyro_axis_reading_byte(port, reg_high[axis]);
//  NumOut( 0, LCD_LINE1-(axis*8), lb);
//  NumOut(40, LCD_LINE1-(axis*8), hb);
  // Assemble the final number by assembling the two bytes,
  // and dividing it by the divisor (defined in the gyro startup,
  // to get a properly scaled float.
  int ival = lb + (hb<<8);
  float val = ival/divisor;
  return val;
}

#define DIGYRO_REG_WHOAMI    0x0F  /*!< Gyro device identification register (read only) */
#define DIGYRO_REG_REFERENCE 0x25  /*!< Gyro reference register - stores the reference value used for interrupt generation */
#define DIGYRO_REG_OUTTEMP   0x26  /*!< Gyro temperature register (read only) - stores temperature data */
#define DIGYRO_REG_STATUS    0x27  /*!< Gyro status register (read only) */
#define DIGYRO_REG_FIFOCTRL  0x2E  /*!< Gyro FIFO control register */
#define DIGYRO_REG_FIFOSRC   0x2F  /*!< Gyro FIFO source register (read only) */
#define DIGYRO_REG_INT1_CFG  0x30  /*!< Gyro interrupt 1 config register */

task main(){
  SetSensorLowspeed(S1);

  start_gyro(S1, full_scale_range);  // Fire up the gyro.  Initialize it.             Only needs to be done once.
  float x_val, y_val, z_val;      // Our assembled values.

  while (true){
        ClearScreen();
        // Read the GYROSCOPE
        x_val = gyro_axis_reading(S1, 0x00);    // Get x-axis in dps.
        y_val = gyro_axis_reading(S1, 0x01);    // Get y-axis in dps.
        z_val = gyro_axis_reading(S1, 0x02);    // Get z-axis in dps.

        byte who, ref, status, temp;
        ReadI2CRegister(S1, DI_ADDR_GYRO, DIGYRO_REG_WHOAMI, who);
        ReadI2CRegister(S1, DI_ADDR_GYRO, DIGYRO_REG_REFERENCE, ref);
        ReadI2CRegister(S1, DI_ADDR_GYRO, DIGYRO_REG_STATUS, status);
        ReadI2CRegister(S1, DI_ADDR_GYRO, DIGYRO_REG_OUTTEMP, temp);
        NumOut(0, LCD_LINE1, x_val);
        NumOut(0, LCD_LINE2, y_val);
        NumOut(0, LCD_LINE3, z_val);
        NumOut(0, LCD_LINE4, who);
        NumOut(0, LCD_LINE5, ref);
        NumOut(0, LCD_LINE6, status);
        NumOut(0, LCD_LINE7, temp);

        Wait(MS_500);
  }
}
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

发表于 2012-5-18 10:20:59 | 显示全部楼层
程序是参照网上的改的, 0xD0是0x68<<1后得出的;对控制寄存器和数据寄存器的读写不会,反正好像用这个程序能读出三轴数据
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

发表于 2012-5-18 10:24:12 | 显示全部楼层
ArrayBuild(cmdBuf,i2cAddr,0xa0,0xaf,0x00);
I2CWrite(port,0,cmdBuf);
  int status = I2CCheckStatus(port);
  while (status > NO_ERR)
    status = I2CCheckStatus(port);

这几行好像是对寄存器调整
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

发表于 2012-5-18 10:26:43 | 显示全部楼层
对了,你指的飘移不大,具体的数值范围有多大?
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

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

本版积分规则

QQ|手机版|中文乐高 ( 桂ICP备13001575号-7 )

GMT+8, 2024-4-16 15:50 , Processed in 0.115103 second(s), 26 queries .

Powered by Discuz! X3.5

Copyright © 2001-2020, Tencent Cloud.

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