| AVR Раздел по микроконтроллерам компании Atmel - AVR / ATtiny / ATmega / ATMega128 / ATxmega, вопросы по программированию в AVR studio и все, относящееся к AVR... |
Как считать данные с гироскопа MPU-6050?
16.05.2016, 01:01
|
|
|
Частый гость
Регистрация: 16.05.2016
Адрес: Москва
Сообщений: 35
Сказал спасибо: 6
Сказали Спасибо 1 раз в 1 сообщении
|
Как считать данные с гироскопа MPU-6050?
Здравствуйте! Имею микроконтроллер мега16 и модуль гироскоп MPU-6050. Пытаюсь с ним пообщаться по шине TWI.
Общение построил по протоколу из даташита и вроде бы модуль отсылает мне бит подтверждения ACK но как дело доходит до чтения данных из регистра TWDR там одни нули! Подскажите что неправильно.
Вот протокол общения:
unsigned char MPU_I2C_R(unsigned char w,unsigned char x, unsigned char r)
{
char a;
I2C_start();//отправляем условие СТАРТ
I2C_tranciv_byte(w);//отправляем адрес модуля на запись
I2C_tranciv_byte(x);//отправляем адрес регистра откуда будем читать данные
I2C_start();//отправляем повторный СТАРТ
I2C_tranciv_byte(r);//отправляем адрес модуля на чтение
a = I2C_receiver_last_byte();//читаем данные из регистра
I2C_stop();//отправляем условие СТОП
return a;
}
Вот функция чтения чтения данных
unsigned char I2C_receiver_last_byte()
{
TWCR = (1‹‹TWINT)|(1‹‹TWEN);// включили прием данных ‹--вот после этого в отладке регистр TWDR обнуляется
while(!(TWCR&(1‹‹TWINT))); //ждем установку бита TWIN
return TWDR;
}
|
|
|
|
16.05.2016, 19:15
|
|
|
Прописка
Регистрация: 05.12.2008
Адрес: Россия, Омск
Сообщений: 145
Сказал спасибо: 39
Сказали Спасибо 29 раз(а) в 22 сообщении(ях)
|
Re: Как считать данные с гироскопа MPU-6050?
Шина подтянута к питанию?
|
|
|
|
16.05.2016, 20:20
|
|
|
Частый гость
Регистрация: 16.05.2016
Адрес: Москва
Сообщений: 35
Сказал спасибо: 6
Сказали Спасибо 1 раз в 1 сообщении
|
Re: Как считать данные с гироскопа MPU-6050?
Да подтянута. На самом модуле через два резистора на 4.7К
|
|
|
|
16.05.2016, 21:41
|
|
|
Вид на жительство
Регистрация: 11.08.2015
Сообщений: 409
Сказал спасибо: 17
Сказали Спасибо 37 раз(а) в 28 сообщении(ях)
|
Re: Как считать данные с гироскопа MPU-6050?
Попробуйте использовать прерывание от TWI. И уже в прерывании обрабатывать байт, который пришел от гироскопа.
|
|
|
|
16.05.2016, 22:02
|
|
|
Вид на жительство
Регистрация: 11.08.2015
Сообщений: 409
Сказал спасибо: 17
Сказали Спасибо 37 раз(а) в 28 сообщении(ях)
|
Re: Как считать данные с гироскопа MPU-6050?
Кстати, как вариант, может Вы подключили микроконтроллер к AUX-входу гироскопа?
|
|
|
|
20.05.2016, 12:59
|
|
|
Прописка
Регистрация: 05.12.2008
Адрес: Россия, Омск
Сообщений: 145
Сказал спасибо: 39
Сказали Спасибо 29 раз(а) в 22 сообщении(ях)
|
Re: Как считать данные с гироскопа MPU-6050?
Для начала - проверьте, читаются ли вообще данные, в частности, регистры калибровки.
Так же, рекомендую обратиться к документу: MPU6050 register map.
Если интересен код - вот мой, работает на ATMega1284p
Данные выводятся в консоль.
Пример:
Accel: X: -3024 Y: -1164 Z: 17076 Gyro: X: -434 Y: 123 Z: -19 Temperature: 30
Да, чип греется.
Нажмите, чтобы открыть спойлер
|
Код:
|
#define F_CPU 8000000UL
#include ‹avr/io.h›
#include ‹util/delay.h›
#include ‹avr/pgmspace.h›
#include ‹util/twi.h›
#include ‹avr/interrupt.h›
#include ‹stdlib.h›
#define TWBR_val 0x40
#define UART_BAUD_RATE 9600
#define BaudRate (F_CPU/UART_BAUD_RATE)/16-1;
// 11059200/115200 = 96|16 = 6-1 = 5.
volatile uint8_t tx_buffer[256];
volatile uint16_t txwrptr, txsendptr;
ISR (USART0_RX_vect) {
};
ISR (USART0_TX_vect) {
};
ISR (USART0_UDRE_vect) {
if (txsendptr ›= sizeof(tx_buffer))
txsendptr = 0;
if (txsendptr != txwrptr)
{
UDR0 = tx_buffer[txsendptr];
txsendptr++;
} else {
UCSR0B &= ~(1‹‹UDRIE0);
};
};
void console_put(const char *s) {
while (*s) // Пока по указателю на ноль (нуль-терминатор)
{
tx_buffer[txwrptr] = *s; // Записываем в буфер
txwrptr++; // Двигаем указатель
if (txwrptr ›= sizeof(tx_buffer)) // Если дослигли конца - возвращаемся в начало
txwrptr = 0;
s++; // Двигаем указатель строки.
if (txwrptr == txsendptr) // Если указатель записи буфера "наехал" на указатель передачи
{
UCSR0B|=(1‹‹UDRIE0); // Разрешаем передачу
_delay_us(100); // Ждём.
};
};
UCSR0B|=(1‹‹UDRIE0); // Разрешаем передачу
};
void console_put_hex(uint8_t s) {
char rs[3];
if ((s ›› 4) › 9)
{
rs[0] = ('7' + (s ›› 4));
} else {
rs[0] = ('0' + (s ›› 4));
};
if ((s & 0x0F) › 9) {
rs[1] = ('7' + (s & 0x0F));
} else {
rs[1] = ('0' + (s & 0x0F));
};
rs[2] = 0;
console_put(rs);
};
void console_put_BYTE(uint8_t byte, uint8_t isSigned) {
char t[4];
if (isSigned)
{
itoa(byte, t, 10);
} else {
utoa(byte, t, 10);
};
console_put(t);
};
void console_put_WORD(uint16_t word, uint8_t isSigned) {
char t[8];
if (isSigned)
{
itoa(word, t, 10);
} else {
utoa(word, t, 10);
};
console_put(t);
};
void console_put_DWORD(uint32_t dword, uint8_t isSigned) {
char t[14];
if (isSigned)
{
ltoa(dword, t, 10);
} else {
ultoa(dword, t, 10);
};
console_put(t);
};
void console_init(void) {
uint16_t i;
for (i=0;i‹sizeof(tx_buffer);i++)
{
tx_buffer[i] = 0;
};
// // Обнуляем переменные
// rxlen = 0;
txwrptr = 0;
txsendptr = 0;
// Настраиваем переферию.
PRR0 &= ~(1‹‹PRUSART0); // Enables USART0
UBRR0 = BaudRate; // Baud rate
UCSR0A = 0; // USART Status and control register
UCSR0B = (1‹‹RXCIE0)|(1‹‹RXEN0)|(1‹‹TXEN0);
// Transmitter Enabled, Receiver Enabled, RX_Complete_Int Enabled.
UCSR0C = (1‹‹UCSZ01)|(1‹‹UCSZ00); // 8 bit, no parity, 1 stop bit.
};
void I2C_init(void){
PRR0 &= ~(1‹‹PRTWI); // Разрешаем работу интерфейса TWI
TWBR = TWBR_val;
};
uint8_t I2C_start(uint8_t address){
unsigned int RetryCount = 0; // Счётчик попыток.
TWCR = 0; // reset TWI control register
TWCR = (1‹‹TWINT) | (1‹‹TWSTA) | (1‹‹TWEN); // transmit START condition
// wait for end of transmission
while( !(TWCR & (1‹‹TWINT)) ) // Ждём, пока переферия не сбросит бит занятости.
{
RetryCount++; // Считаем таймер...
if (RetryCount › 20000) break; // Если ждём слишком долго - выход.
};
// check if the start condition was successfully transmitted
if((TWSR & 0xF8) != TW_START){ return 1; }
// load slave address into data register
TWDR = address;
// start transmission of address
TWCR = (1‹‹TWINT) | (1‹‹TWEN);
// wait for end of transmission
while( !(TWCR & (1‹‹TWINT)) )
{
RetryCount++;
if (RetryCount › 20000) break;
};
// check if the device has acknowledged the READ / WRITE mode
uint8_t twst = TW_STATUS & 0xF8;
if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
return 0;
};
uint8_t I2C_write(uint8_t data){
unsigned int RetryCount = 0;
// load data into data register
TWDR = data;
// start transmission of data
TWCR = (1‹‹TWINT) | (1‹‹TWEN);
// wait for end of transmission
while( !(TWCR & (1‹‹TWINT)) )
{
RetryCount++;
if (RetryCount › 60000) break;
};
if( (TWSR & 0xF8) != TW_MT_DATA_ACK ){ return 1; }
return 0;
};
uint8_t I2C_read_ack(void){
unsigned int RetryCount = 0;
// start TWI module and acknowledge data after reception
TWCR = (1‹‹TWINT) | (1‹‹TWEN) | (1‹‹TWEA);
// wait for end of transmission
while( !(TWCR & (1‹‹TWINT)) )
{
RetryCount++;
if (RetryCount › 60000) break;
};
// return received data from TWDR
return TWDR;
};
uint8_t I2C_read_nack(void){
unsigned int RetryCount = 0;
// start receiving without acknowledging reception
TWCR = (1‹‹TWINT) | (1‹‹TWEN);
// wait for end of transmission
while( !(TWCR & (1‹‹TWINT)) )
{
RetryCount++;
if (RetryCount › 60000) break;
};
return TWDR; // return received data from TWDR
};
void I2C_stop(void){
// transmit STOP condition
TWCR = (1‹‹TWINT) | (1‹‹TWEN) | (1‹‹TWSTO);
_delay_us(5); // Без этой паузы не получается передать STOP. И в отладке всё становится грустно.
// Самое смешное, что в железе работает нормально.
TWCR = 0;
};
uint8_t I2C_WriteSpecifiedByte(unsigned char addr, unsigned char data) {
uint8_t status; // Запоминаем статус.
I2C_start(0xD0); // START + SLA + WR
status = (TWSR & 0xF8); // Читаем статус, запоминаем.
I2C_write(addr); // ADDR
I2C_write(data); // Data
I2C_stop(); // STOP
if (status == 0x18) // Если статус = (0x18 ‹‹ 3 ())
{ // SLA + W & ACK
return 0; // No ERROR
} else { // SLA + W & nACK
return 1; // ERROR
};
};
uint8_t I2C_ReadSpecifiedByte(unsigned char addr) {
unsigned char temp;
I2C_start(0xD0); // START + SLA + WR
I2C_write(addr); // ADDR
//I2C_stop(); // STOP
I2C_start(0xD1); // START + SLA + RD
temp = I2C_read_nack(); // READ
I2C_stop(); // STOP
return temp;
};
int main(void) {
uint16_t val[6];
int16_t temperature;
DDRA = 0xFF;
DDRB = 0xFF;
DDRC = 0xFF;
DDRD = 0xFF;
PORTA = 0x00;
PORTB = 0x00;
PORTC = 0;
PORTD = 0;
I2C_init();
console_init();
console_put("Init OK\r\n");
_delay_ms(100);
//I2C_WriteSpecifiedByte(0x19, 0x40);
//I2C_WriteSpecifiedByte(0x1A, 0x2A);
//I2C_WriteSpecifiedByte(0x1B, 0);
//I2C_WriteSpecifiedByte(0x1C, 0);
I2C_WriteSpecifiedByte(0x6B, 0x00);
console_put("Self test: XA=");
console_put_BYTE(I2C_ReadSpecifiedByte(0x0D) & 0x1F, 0);
console_put(" XB=");
console_put_BYTE(I2C_ReadSpecifiedByte(0x0E) & 0x1F, 0);
console_put(" XC=");
console_put_BYTE(I2C_ReadSpecifiedByte(0x0F) & 0x1F, 0);
console_put("\r\n");
sei();
while(1) {
_delay_ms(1000);
console_put("\rAccel: X: ");
val[0] = ((I2C_ReadSpecifiedByte(0x3B) ‹‹ 8) | (I2C_ReadSpecifiedByte(0x3C)));
val[1] = ((I2C_ReadSpecifiedByte(0x3D) ‹‹ 8) | (I2C_ReadSpecifiedByte(0x3E)));
val[2] = ((I2C_ReadSpecifiedByte(0x3F) ‹‹ 8) | (I2C_ReadSpecifiedByte(0x40)));
val[3] = ((I2C_ReadSpecifiedByte(0x43) ‹‹ 8) | (I2C_ReadSpecifiedByte(0x44)));
val[4] = ((I2C_ReadSpecifiedByte(0x45) ‹‹ 8) | (I2C_ReadSpecifiedByte(0x46)));
val[5] = ((I2C_ReadSpecifiedByte(0x47) ‹‹ 8) | (I2C_ReadSpecifiedByte(0x48)));
temperature = ((I2C_ReadSpecifiedByte(0x41) ‹‹ 8) | (I2C_ReadSpecifiedByte(0x42)));
temperature = temperature / 340 + 36;
console_put_WORD(val[0],1);
console_put(" Y: ");
console_put_WORD(val[1],1);
console_put(" Z: ");
console_put_WORD(val[2],1);
console_put(" Gyro: X: ");
console_put_WORD(val[3],1);
console_put(" Y: ");
console_put_WORD(val[4],1);
console_put(" Z: ");
console_put_WORD(val[5],1);
console_put(" Temperature: ");
console_put_WORD(temperature, 1);
console_put(" ");
};
}; |
|
|
|
|
20.05.2016, 22:52
|
|
|
Частый гость
Регистрация: 16.05.2016
Адрес: Москва
Сообщений: 35
Сказал спасибо: 6
Сказали Спасибо 1 раз в 1 сообщении
|
Re: Как считать данные с гироскопа MPU-6050?
Всем спасибо за ответы особенно -Alan- у меня все заработало  ! -Alan-Посмотрел ваш код в начале программы вы инициализируете регистр Register 107 – Power Management 1 PWR_MGMT_1 записав в него нули! что не было у меня. Нигде кстати про этот регистр не говорится хотя он важен. Да и хотел спросить у вас про закомментированные регистры выше, что они значат?
|
|
|
|
20.05.2016, 22:59
|
|
|
Гуру портала
Регистрация: 27.10.2008
Адрес: ЕС
Сообщений: 10,821
Сказал спасибо: 919
Сказали Спасибо 4,289 раз(а) в 2,570 сообщении(ях)
|
Re: Как считать данные с гироскопа MPU-6050?
-Alan- вам показал, как не надо писать программу. Все в кучу, одна бестолковая длинная портянка. Не делайте так. Сами же потом увязните в ней.
|
|
|
|
21.05.2016, 08:08
|
|
|
Прописка
Регистрация: 05.12.2008
Адрес: Россия, Омск
Сообщений: 145
Сказал спасибо: 39
Сказали Спасибо 29 раз(а) в 22 сообщении(ях)
|
Re: Как считать данные с гироскопа MPU-6050?
Отвечу по порядку.
Kopranych:
1. Регистр управления питанием описан в инструкции но явно не указано, что после подачи питания чип находится в режиме сна. Нашёл на Ардуино-форуме пример, где этот же регистр обнуляли.
2. По закомментированным значениям - пытался настроить чип таким способом. Естественно, не вышло =)
Easyrider83, согласен, делать так не надо. Просто я собрал кусочки из своего проекта, которые минимально необходимы именно для быстрой сборки проекта:
TWI обмен данными (адрес кристалла забит жёстко)
UART на вывод в консоль
Собственно сам камушек и всё остальное. Свои проекты я так не веду, если что. А как для примера "Чтобы только собралось и запустилось" - достаточно. Кому надо - перепишет под себя и научится
|
|
|
|
21.05.2016, 14:28
|
|
|
Гражданин KAZUS.RUN
Регистрация: 16.06.2005
Сообщений: 942
Сказал спасибо: 25
Сказали Спасибо 174 раз(а) в 123 сообщении(ях)
|
Re: Как считать данные с гироскопа MPU-6050?
Сообщение от Kopranych
|
|
Посмотрел ваш код в начале программы вы инициализируете регистр Register 107 – Power Management 1 PWR_MGMT_1 записав в него нули! что не было у меня.
|
Это тут не причём. Читай даташиты. У меги16 нет регистра повер менеджмент. А там где он есть, как в меге у Алана, после сброса по подаче питания сей регистр и так заполняется нулями.
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 12:00.
|
|