大家好!
我试图通过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
谢谢!
答案 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的随机或不可打印的,而不是您期望的数字字符串。