为了扩大我对Atmega系列编程的理解和当前的知识,我已经开始了自己的小项目。我决定通过直接寻址其寄存器来对MPU6050 I2C传感器进行编程。为了测试传感器的工作和连接,我首先使用了这个预先编写的程序(使用Arduino平台提供的Wire库):
#include<Wire.h>
const int MPU=0x68;
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;
void setup(){
Wire.begin();
Wire.beginTransmission(MPU);
Wire.write(0x6B);
Wire.write(0);
Wire.endTransmission(true);
Serial.begin(9600);
}
void loop(){
Wire.beginTransmission(MPU);
Wire.write(0x3B);
Wire.endTransmission(false);
Wire.requestFrom(MPU,12,true);
AcX=Wire.read()<<8|Wire.read();
AcY=Wire.read()<<8|Wire.read();
AcZ=Wire.read()<<8|Wire.read();
GyX=Wire.read()<<8|Wire.read();
GyY=Wire.read()<<8|Wire.read();
GyZ=Wire.read()<<8|Wire.read();
Serial.print("Accelerometer: ");
Serial.print("X = "); Serial.print(AcX);
Serial.print(" | Y = "); Serial.print(AcY);
Serial.print(" | Z = "); Serial.println(AcZ);
Serial.print("Gyroscope: ");
Serial.print("X = "); Serial.print(GyX);
Serial.print(" | Y = "); Serial.print(GyY);
Serial.print(" | Z = "); Serial.println(GyZ);
Serial.println(" ");
delay(333);
}
串行监视器从传感器显示正确的读数,说明传感器已正确连接并可以正常工作。同时,我连接了我的总线海盗,该海盗窃听I2C总线并显示在传感器和atmega芯片(Atmega328p-pu)之间发送的十六进制值。尽管我无法将它们翻译成确切的含义,但是交流看起来很正常。
我上传了使用传感器和Atmega328p的数据表创建的自己的代码后,I2C总线几乎什么也不显示。这是我的代码:
#include <Arduino.h>
#define DEBUG_LED_PIN PB5
#define DEBUG_LED_BANK DDRB
#define MPU6050_ADDR_WRITE 0x68
#define MPU6050_ADDR_READ 0x69
const uint8_t led_on = 0x01;
const uint8_t led_off = 0x00;
const uint8_t twi_write = 0x00;
const uint8_t twi_read = 0x01;
const uint8_t twi_start_transmitted = 0x08;
const uint8_t twi_repeated_start_transmitted = 0x10;
const uint8_t twi_ack_received_addr = 0x18;
const uint8_t twi_not_ack_received_addr = 0x20;
const uint8_t twi_ack_received_data = 0x28;
const uint8_t twi_not_ack_received_data = 0x30;
const uint8_t twi_arbitration_lost = 0x38;
void setup_debug_led();
void setup_twi();
void setup_mpu6050();
void control_debug_led(uint8_t status);
void send_data_to_device(uint8_t device_address, uint8_t* data, uint8_t data_length);
void send_start_signal();
void send_device_address(uint8_t device_address);
void send_data(uint8_t data);
void send_stop_signal();
void send_test_data_complete_sequence();
void setup() {
setup_debug_led();
control_debug_led(led_off);
setup_twi(); // Setup i2c protocol
}
void loop() {
// Test stuff
send_test_data_complete_sequence();
}
void setup_twi()
{
TWSR = 0;
TWCR = 0;
TWBR = 0x0C; // Set SCL to 400kHz
}
void send_test_data_complete_sequence()
{
// 1.
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); // Write start condition
// 2.
while(!(TWCR & (1 << TWINT))); // Wait for TWINT flag set. Indicates START has been transmitted
// 3.
if((TWSR & 0xF8) != twi_start_transmitted) // Check value TWI status register, if equals 0x08 continue
{
// Handle exception call
}
// 4.
TWDR = 0b11010000; // Load slave address including r/w bit
// 5.
TWCR = (1 << TWINT) | (1 << TWEN); // Clear TWINT bit to start tranmission
// 6.
while(!(TWCR & (1 << TWINT))); // Wait for TWINT flag set. Inidicates SLA+W has been transmitted
// 7.
if((TWSR & 0xF8) != twi_ack_received_addr) // Check for 0x18 (SLA+W ACK has been received)
{
// Handle exception call
}
// 8.
TWDR = 0x6B; // Load data into TWDR
// 9.
TWCR = (1 << TWINT) | (1 << TWEN); // Clear TWINT bit to start data tranmission
// 10.
while(!(TWCR & (1 << TWINT))); // Wait for TWINT flag set. Inidicates data has been transmitted
// 11.
if((TWSR & 0xF8) != twi_ack_received_data) // Check for 0x28 (data ACK has been received)
{
// Handle exception
}
// 12.
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); // Write stop condition
}
总线海盗在普通总线上显示以下通信数据:[][[][][[[]]
这与我传输到缓冲区的数据完全不同。如果我等待足够长的时间,我会发现一些偶然的0x0或0x00。
我尝试更改从站的地址和写入传感器的第一个数据字节。从不触发步骤3、7和11的异常。
此代码中未触及引脚A4和A5(SCL和SDA)。我尝试将它们配置为启用了上拉电阻的输入,但也没有得到理想的结果。
传感器按照以下方案连接到arduino:
(Arduino) (MPU6050)
A4 (SDA) -> SDA
A5 (SCL) -> SCL
VCC -> VCC
GND -> GND
GND -> AD0
海盗车与SDA和SCL连接并行连接以截取其数据。
Atmega328p的数据表对完成I2C传输所需采取的所有步骤进行了简要总结。我已尝试正确复制这些步骤(第21.6节“使用TWI”,表21-2)。
我希望你们能发现我的错误或缺少代码。提前非常感谢!
似乎您没有在TWI
功能中启用setup_twi()
。
您需要按照数据手册中的说明,通过将TWEN
寄存器中的TWCR
位置1来将其打开:
TWEN位使能TWI操作并激活TWI接口。将TWEN写为1时,TWI将控制与SCL和SDA引脚相连的I / O引脚,从而启用压摆率限制器和尖峰滤波器。如果将此位写为零,则无论正在进行任何操作,TWI都将关闭,并且所有TWI传输都将终止。