为什么输出通过I2C在Atmega8上显示MPU-6050的常量值?

时间:2014-05-27 10:14:41

标签: c embedded avr gyroscope i2c


大家好!

我试图通过I2C连接MPU-6050(ITG / MPU分线板)和ATmega8(在面包板上 - 非arduino)。

当我尝试读取其中一个传感器值时,TWSR值显示完美的I2C通信,例如TWSR值,例如:Start,Slave + W,Address ACK,Register AddressACK,Slave + R,Data to TWDR,NACK by master,Stop等都与atmega8的数据表相匹配(我将PORTD的8个引脚连接到8个LED,并在每次执行TWSR检查操作时将TWSR设置为在此PORT上显示)。

但是我在TWDR中收到的值都是恒定的,并且不会因传感器的任何移动而改变(我尝试在8-LEDS布置上以及在LCD上显示感测值)。

我通过以下方式在I2C上进行通信:
    发送开始,
    检查TWSR,
    通过写位发送从机地址,
    等待N / ACK,
    检查TWSR,
    发送传感器寄存器地址,
    等待N / ACK,
    检查TWSR,
    发送开始(重复开始)
    检查TWSR,
    发送带有读取的从站地址,
    等待N / ACK,
    检查TWSR,
    将TWDR数据复制到数组的元素,
    发送" NACK",
    检查TWSR
    停止。

我会在所有步骤中持续监控TWINT标志。对于不同的传感器寄存器,这些步骤会一再重复 我也启用了中断(通过包含sei();)但我没有在中断向量中添加任何内容。

我的问题是:

为什么这个数据不变?

我的I2C通信方法有问题吗?

或者是MPU在3V3上运行而AVR在5V上运行会导致检测到的数据? (我使用4K7上拉至5V)

在实际的寄存器寻址和数据读取之前,还是要配置任何其他寄存器(我按照这个顺序尝试了PWR_MGMT_1,USER_CTRL,CONFIG,SMPRT_DIV,GYRO_CONFIG,ACCEL_CONFIG)?

还是其他一些问题?

如果之前讨论过类似的经历或讨论可能会有所帮助,请重定向。

感谢。

以下是我的代码:

#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "defandfunc4.c"    // contains I2C functions
#include "lcdincluder.c"    // contains LCD functions
#include "myheader.h"       // contains definitions and prototype decl.

int main (void)
{
//------------------ Variable initialisations
unsigned char SLA_W[10], SLA_R[10], RCVD_L[10], RCVD_M[10];
int INTRMDT[10], GYRO_Z[10], MSB[10], LSB[10];
int i = 0, j = 0;
sei();
DDRD = 0XFF;
DDRB = 0XFF;
//------------------ Clear LCD
Send_a_command (0X01);          // Clear screen
_delay_ms(2);               // takes 1.53 ms
//------------------ Address setting
SLA_W = ((SL_ADD<<1) | 0);      // Slave + Write bit (0)
SLA_R = ((SL_ADD<<1) | 1);      // Slave + Read bit (1)
//------------------------ Actual TWI communication begins
TWSR = 0X00;                // Set prescaler to be 0
TWBR = 0X0C;                // setting bit-rate division factor to be 12
_delay_us(10);
j = 1;
for (i=0;i<10;++i)
{
start_condn();              // start condition
//------------------------ First TWI : Send Register Addr
CHECK_TWSR_FOR (START);  // If status mismatches error routine is followed
clear_go(); //a prgram that glows an led for few milli sec
TWDR = SLA_W;               // Load TWDR with Slave + write
charge ();              // Clear TWINT
wait_for_TWINT();           // Wait for TWINT
CHECK_TWSR_FOR (MT_SLA_ACK);        // check TWSR for successful TXn of slave address. If status mismatches error routine is followed
clear_go(); //a prgram that glows an led for few milli sec
TWDR = GYRO_XOUT_H;         // Load TWDR with Data(register address)
charge ();              // Clear TWINT
wait_for_TWINT();           // Wait for TWINT
CHECK_TWSR_FOR (MT_DATA_ACK);       // check TWSR for successful TXn of Data and ACK RCVD. If status mismatches error routine is followed
clear_go(); //a prgram that glows an led for few milli sec
//------------------------ Second TWI : Read data
start_condn();              // Repeated start condition
wait_for_TWINT();           // Wait for TWINT
CHECK_TWSR_FOR (R_START);       // check TWSR for successful TXn of Repeated Start, If status mismatches error routine is followed
clear_go(); //a prgram that glows an led for few milli sec
TWDR = SLA_R;               // Load TWDR with Slave + read
charge ();              // Clear TWINT
wait_for_TWINT();           // Wait for TWINT
CHECK_TWSR_FOR (MR_SLA_ACK);        // check TWSR for successful TXn of ADDr + R, If status mismatches error routine is followed
clear_go(); //a prgram that glows an led for few milli sec
wait_for_TWINT();           // Wait for TWINT
RCVD_M[i] =  TWDR;
TWCR = (1<<TWINT)|(1<<TWEN);        //send NACK
wait_for_TWINT();           // Wait for TWINT
CHECK_TWSR_FOR (DATA_RCVD_NACK);    // check TWSR for Data RXd NACK sent, If status mismatches error routine is followed
clear_go(); //a prgram that glows an led for few milli sec
stop_condn ();              // Transmit STOP
//------------------------ Third TWI : Send Register Addr
start_condn();              // Repeated start condition
wait_for_TWINT();           // Wait for TWINT
CHECK_TWSR_FOR (START);         // check value of TWSR for successful TXn of Start, If status mismatches error routine is followed
clear_go(); //a prgram that glows an led for few milli sec
TWDR = SLA_W;               // Load TWDR with Slave + write
charge ();              // Clear TWINT
wait_for_TWINT();           // Wait for TWINT
CHECK_TWSR_FOR (MT_SLA_ACK);        // check TWSR for successful TXn of slave address, If status mismatches error routine is followed
clear_go(); //a prgram that glows an led for few milli sec
TWDR = GYRO_XOUT_L;         // Load TWDR with Data(register address)
charge ();              // Clear TWINT
wait_for_TWINT();           // Wait for TWINT
CHECK_TWSR_FOR (MT_DATA_ACK);       // check TWSR for successful TXn of Data and ACK RCVD, If status mismatches error routine is followed
clear_go(); //a prgram that glows an led for few milli sec

PORTD = 0X00;               // Switching off portD
//------------------------ Fourth TWI : Read data
start_condn();              // Repeated start condition
wait_for_TWINT();           // Wait for TWINT
CHECK_TWSR_FOR (R_START);       // check TWSR for successful TXn of Repeated Start, If status mismatches error routine is followed
clear_go(); //a prgram that glows an led for few milli sec
TWDR = SLA_R;               // Load TWDR with Slave + read
charge ();              // Clear TWINT
wait_for_TWINT();           // Wait for TWINT
CHECK_TWSR_FOR (MR_SLA_ACK);        // check TWSR for successful TXn of ADDr + R, If status mismatches error routine is followed
clear_go(); //a prgram that glows an led for few milli sec
wait_for_TWINT();           // Wait for TWINT
RCVD_L[i] =  TWDR;          
TWCR = (1<<TWINT)|(1<<TWEN);        //send NACK
wait_for_TWINT();           // Wait for TWINT
CHECK_TWSR_FOR (DATA_RCVD_NACK);    // check TWSR for Data RXd NACK sent, If status mismatches error routine is followed
clear_go(); //a prgram that glows an led for few milli sec
stop_condn ();              // Transmit STOP
//------------------ Making a word
LSB[i] = 0XFF & RCVD_L[i];
MSB[i] = 0XFF & RCVD_M[i];
INTRMDT[i] = ((MSB[i] << 8) | LSB[i]);
GYRO_Z[i] = INTRMDT[i];

// On to LCD
Send_a_character (GYRO_Z[i]);       // Displays it on LCD
_delay_us(50);              // takes 39 micro seconds
j++;
}
//------------------------ TWI complete ------------------------//
return 0;
}

我正在使用以下分组板:
http://playground.arduino.cc/Main/MPU-6050
(但我没有使用Arduino)

以下是MPU-6050产品页面:
http://www.invensense.com/mems/gyro/mpu6050.html

以下是MPU-6050产品规格和注册图的链接:
http://www.invensense.com/mems/gyro/documents/PS-MPU-6000A-00v3.4.pdf
http://www.invensense.com/mems/gyro/documents/RM-MPU-6000A-00v4.2.pdf

谢谢!

2 个答案:

答案 0 :(得分:2)

问题在于访问TWDR寄存器的顺序:

  

...
  发送带有读取的从站地址,
  等待N / ACK,
  检查TWSR,
  将TWDR数据复制到数组的元素,
  发送&#34; NACK&#34;,
  检查TWSR
  ...

正确的顺序是:

  

...
  发送带有读取的从站地址,
  等待N / ACK,
  检查TWSR,
  发送&#34; NACK&#34;,
  将TWDR数据复制到数组的元素,
  检查TWSR
  ...

这背后的原因是,当主机不发送(N)ACK时,操作可能仍然处于从从机接收数据的状态。 TWDR将包含最后发送(或接收)的数据的值,在这种情况下是从站地址。

因此,必须在发送(N)ACK后复制来自TWDR的数据,确保从站的数据接收完成。但是这种复制应该在发送STOP或重复启动之前完成。

也可以在检查TWSR后复制数据,从而100%确定操作是否完成。

答案 1 :(得分:1)

对于一般注释,对设备的写入和读取顺序似乎是正确的。我假设您的函数会报告错误是否发生。

您不需要一个数组来保存SLA_W和SLA_R。您正在使用这些数组的地址作为字节,这可能会导致问题,但似乎以某种方式工作。此外,您可以进行突发读取,同时获得陀螺仪读数的高字节和低字节。如果你只是继续发送ack,那么设备将按寄存器顺序发回数据。实际上,您可以立即从设备获取所有数据;从0x3B开始读取14个字节的数据。

您正在快速循环读取设备,但只有时间显示最后一个读数,因此循环现在没有意义。 (我猜你以后会用它做些什么,也许?)

另外,请注意陀螺仪寄存器的旋转运动。如果设备仍然是,那么应该读为零。

但我怀疑你的问题在于写入LCD。陀螺仪读数是整数,而不是ascii字符。您需要使用sprintf()或手工函数将此数字转换为可读字符串。如果您只是发送一个整数,它将被截断为一个字符,这可能是LCD的随机或不可打印的,而不是您期望的数字字符串。