Skocz do zawartości

Akcelerometr + Żyroskop (układ Mpu6050) - problem z dziwnymi odczytami


simba92

Pomocna odpowiedź

Witam!

Od dłuższego czasu walczę z poprawną obsługą czujnika akcelerometru + żyroskopu na module Mpu6050. Problemy z jakimi się zmierzyłem są następujące :

1) układ nie jest rozpoznawalny pod adresem 0x68 (nota katalogowa), a działa na adresie 0xD0 ?! nie rozumiem

2)błędne odczyty przyspieszeń na wszystkich osiach, które nie są zgodne ze strzałkami (kierunkiem) osi X i Y widocznych na płytce z układem (zdjęcie poniżej) ??? tzn. jeżeli moduł leży w spoczynku to oś Z powinna wskazywać 1 g ( wartość około 16567), a zamiast tego ten wynik jest na odczycie dla osi Y, wskazania dla Y wg. strzałek widoczne są dla X, oprócz tego odczyty z rejestru z przyspieszeniem Z narastają do wartości około - 4000 i nic się już z nią nie dzieje.

Dostaje zielonej gorączki z tym czujnikiem, bardzo proszę o jakąkolwiek pomoc.

Poniżej widok płytki z modułem leżącej na biurku.

Poniżej wklejam KOD pisany dla stm32f103rbt6:

#include <stdint.h>
#include <stdio.h>
#include "stm32f10x.h"
#include <math.h>
#include "delay.h"
#include "mpu6050.h"
#include "print.h"




int main(void)
{
GPIO_InitTypeDef gpio;
I2C_InitTypeDef i2c;
USART_InitTypeDef uart;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

GPIO_StructInit(&gpio);
gpio.GPIO_Pin = GPIO_Pin_5;
gpio.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &gpio);

SysTick_Config(SystemCoreClock / 1000);

/*---------------------konfiguracja UART2-----------------------*/

GPIO_StructInit(&gpio);
gpio.GPIO_Pin = GPIO_Pin_2;
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio);

gpio.GPIO_Pin = GPIO_Pin_3;
gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio);

USART_StructInit(&uart);
uart.USART_BaudRate = 9600;
uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
uart.USART_WordLength = USART_WordLength_8b;
uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
uart.USART_Parity = USART_Parity_No;
uart.USART_StopBits = USART_StopBits_1;
USART_Init(USART2, &uart);
USART_Cmd(USART2, ENABLE);
/*------------------------------------------------------------*/


/*----------------konfiguracja I2C1---------------------------*/
GPIO_StructInit(&gpio);
gpio.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; // SCL, SDA
gpio.GPIO_Mode = GPIO_Mode_AF_OD;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio);

I2C_StructInit(&i2c);
i2c.I2C_Mode = I2C_Mode_I2C;
i2c.I2C_ClockSpeed = 100000; //100kHz
i2c.I2C_Ack = I2C_Ack_Enable;
I2C_Init(I2C1, &i2c);
I2C_Cmd(I2C1, ENABLE);
/*-------------------------------------------------------------*/


MPU6050_Initialize();


printf("Wyszukiwanie mpu6050...\n");

uint8_t who_am_i = mpu6050_read_reg(MPU6050_WHO_AM_I);


 if (who_am_i == 0x68)
 {
 printf("Znaleziono mpu6050\n");
 }

 else
 {
 printf("Niepoprawna odpowiedź układu(0x%02X)\n", who_am_i);
 }


 delay_ms(100);



 GPIO_StructInit(&gpio);
 gpio.GPIO_Pin = GPIO_Pin_5;
 gpio.GPIO_Mode = GPIO_Mode_Out_PP;
 GPIO_Init(GPIOA, &gpio);

 GPIO_SetBits(GPIOA, GPIO_Pin_5);
 delay_ms(300);
 GPIO_ResetBits(GPIOA, GPIO_Pin_5);
 delay_ms(300);


while(1)
{
GPIO_SetBits(GPIOA, GPIO_Pin_5);
delay_ms(50);
GPIO_ResetBits(GPIOA, GPIO_Pin_5);
delay_ms(50);

int16_t ax = mpu6050_read_value(MPU6050_RA_ACCEL_XOUT_L);
int16_t ay = mpu6050_read_value(MPU6050_RA_ACCEL_YOUT_L);
int16_t az = mpu6050_read_value(MPU6050_RA_ACCEL_ZOUT_L);


printf("X = %d   Y = %d   Z = %d \r\n", ax, ay, az);



}

}

oraz pliki .h i .c do obsługi modułu mpu6050 :

#ifndef MPU6050_H_
#define MPU6050_H_


#include <stdint.h>
#include "stm32f10x.h"
#include "delay.h"

#define MPU6050_ADDRESS_AD0_LOW     	0xD0 //domyslny adres czujnika MPU6050 , w nocie kalalogowej jest 0x68 ???
#define MPU6050_ADDRESS_AD0_HIGH    	0x69
#define MPU6050_DEFAULT_ADDRESS         MPU6050_ADDRESS_AD0_LOW
#define MPU6050_WHO_AM_I				0x75 //rejestr przechowujacy adres urzadzenia


#define MPU6050_CLOCK_PLL_ZGYRO         0x03  //rejestry konfiguracyjne
#define MPU6050_CLOCK_INTERNAL          0x00
#define MPU6050_RA_PWR_MGMT_1       	0x6B




#define MPU6050_GYRO_FS_250         	0x00
#define MPU6050_ACCEL_FS_2         		0x00
#define MPU6050_RA_SMPLRT_DIV       	0x19

#define MPU6050_RA_CONFIG           	0x1A
#define MPU6050_RA_GYRO_CONFIG      	0x1B
#define MPU6050_RA_ACCEL_CONFIG     	0x1C
#define MPU6050_RA_SIGNAL_PATH_RESET  	0x68


#define MPU6050_RA_ACCEL_XOUT_H     	0x3B  //rejestry danych pomiarowych
#define MPU6050_RA_ACCEL_XOUT_L     	0x3C
#define MPU6050_RA_ACCEL_YOUT_H     	0x3D
#define MPU6050_RA_ACCEL_YOUT_L     	0x3E
#define MPU6050_RA_ACCEL_ZOUT_H     	0x3F
#define MPU6050_RA_ACCEL_ZOUT_L     	0x40
#define MPU6050_RA_TEMP_OUT_H       	0x41
#define MPU6050_RA_TEMP_OUT_L       	0x42
#define MPU6050_RA_GYRO_XOUT_H      	0x43
#define MPU6050_RA_GYRO_XOUT_L      	0x44
#define MPU6050_RA_GYRO_YOUT_H      	0x45
#define MPU6050_RA_GYRO_YOUT_L      	0x46
#define MPU6050_RA_GYRO_ZOUT_H      	0x47
#define MPU6050_RA_GYRO_ZOUT_L      	0x48

extern void MPU6050_Initialize(void);
extern void mpu6050_set_reg(uint8_t reg);
extern void mpu6050_write(uint8_t reg, const void* data, int size);
extern void mpu6050_read(uint8_t reg, void* data, int size);
extern void mpu6050_write_reg(uint8_t reg, uint8_t value);
extern uint8_t mpu6050_read_reg(uint8_t reg);
extern int16_t mpu6050_read_value(uint8_t reg);



#endif


#endif /* MPU6050_H_ */
#include "mpu6050.h"




void MPU6050_Initialize(void)
{
mpu6050_write_reg(MPU6050_RA_PWR_MGMT_1, 0x80);//reset the whole module first

delay_ms(200);    //wait for 50ms for the gyro to stable

mpu6050_write_reg(MPU6050_RA_PWR_MGMT_1, 0x03);//PLL with Z axis gyroscope reference MPU6050_CLOCK_INTERNAL

mpu6050_write_reg(MPU6050_RA_CONFIG, 0x03);        //DLPF_CFG = 1: Fs=1khz; bandwidth=42hz

mpu6050_write_reg(MPU6050_RA_SMPLRT_DIV, 0x01);    //500Hz sample rate ~ 2ms

mpu6050_write_reg(MPU6050_RA_GYRO_CONFIG, MPU6050_GYRO_FS_250);    //Gyro 250 st/s scale setting

mpu6050_write_reg(MPU6050_RA_ACCEL_CONFIG, MPU6050_ACCEL_FS_2);    //Accel full scale setting

//MPU6050_Write(MPU6050_DEFAULT_ADDRESS, MPU6050_RA_INT_PIN_CFG, 1<<4);        //interrupt status bits are cleared on any read operation

//MPU6050_Write(MPU6050_DEFAULT_ADDRESS, MPU6050_RA_INT_ENABLE, 1<<0);        //interupt occurs when data is ready. The interupt routine is in the receiver.c file.

mpu6050_write_reg(MPU6050_RA_SIGNAL_PATH_RESET, 0x07);//reset gyro and accel sensor
}



/*--------------------------funkcje z kursu STM32 do obslugi czujnika ----------------------------------*/
void mpu6050_set_reg(uint8_t reg)
{
I2C_GenerateSTART(I2C1, ENABLE);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);
I2C_Send7bitAddress(I2C1, MPU6050_DEFAULT_ADDRESS, I2C_Direction_Transmitter);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);

I2C_SendData(I2C1, reg);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING) != SUCCESS);
}

void mpu6050_write(uint8_t reg, const void* data, int size)
{
int i;
const uint8_t* buffer = (uint8_t*)data;

mpu6050_set_reg(reg);
for (i = 0; i < size; i++) {
I2C_SendData(I2C1, buffer[i]);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING) != SUCCESS);
}
I2C_GenerateSTOP(I2C1, ENABLE);
}

void mpu6050_read(uint8_t reg, void* data, int size)
{
int i;
uint8_t* buffer = (uint8_t*)data;

mpu6050_set_reg(reg);

I2C_GenerateSTART(I2C1, ENABLE);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);

I2C_AcknowledgeConfig(I2C1, ENABLE);
I2C_Send7bitAddress(I2C1, MPU6050_DEFAULT_ADDRESS, I2C_Direction_Receiver);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS);

for (i = 0; i < size - 1; i++) {
while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS);
    buffer[i] = I2C_ReceiveData(I2C1);
   }
I2C_AcknowledgeConfig(I2C1, DISABLE);
   I2C_GenerateSTOP(I2C1, ENABLE);
   while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS);
   buffer[i] = I2C_ReceiveData(I2C1);
}

void mpu6050_write_reg(uint8_t reg, uint8_t value)
{
mpu6050_write(reg, &value, sizeof(value));
}

uint8_t mpu6050_read_reg(uint8_t reg)
{
uint8_t value = 0;
mpu6050_read(reg, &value, sizeof(value));
return value;
}

int16_t mpu6050_read_value(uint8_t reg)
{
int16_t value = 0;
mpu6050_read(reg, &value, sizeof(value));
return value;
}

/*-----------------------------------------------------------------------*/

Błędne odczyty z terminala :

Link do komentarza
Share on other sites

Nie znam się na tym zbyt dobrze, ale ile razy wykona się ta pętla:

for (i = 0; i < size - 1; i++)

dla size=sizeof(int16_t)? A ile razy powinna dla odczytu 2 bajtów?

Adresowanie na I2C jest 7-bitowe a na LSB jest wysyłany bit kierunku (R/W). Niektórzy producenci podają adresy swoich układów wprost, jakby były 7-bitowe (to ten przypadek), inni podają przesunięte zakładając, że bit R/W=0 a jeszcze inni podają dwa adresy: do odczytu i do zapisu, różniące się oczywiście o 1. Na dodatek jedna biblioteka może otrzymany adres przesuwać o 1 bit w lewo (bo zakłada, że musi zrobić miejsce na R/W) a inna nie (bo uznaje, że Ty już to zrobiłeś - to Twój przypadek). Dlatego musisz zapodać 0xD0 żeby wysłało się binarnie 1-1-0-1-0-0-0-R/W, co w innym tłumaczeniu wygląda jak (0x68 << 1) | R/W.

Link do komentarza
Share on other sites

marek1707 Pętla

for (i = 0; i < size - 1; i++) 

wykona się w tym przypadku 1 raz, ponieważ size = sizeof(int16_t) = 2.

Funkcja int16_t mpu6050_read_value(uint8_t reg) pozwala odczytać 2 bajty danych wykorzystując do tego celu mechanizm przesyłania wartości przez wskaźnik, więc to musi być ok. Najbardziej mnie martwią dziwne odczyty, które nijak mają się do rzeczywistości. Problem jest chyba po stronie konfiguracji modułu w funkcji MPU6050_Initialize(); , tak jakbym coś pominął z dokumentacji chociaż czytam już ją na okrągło 🙁

int16_t mpu6050_read_value(uint8_t reg) 
{ 
int16_t value = 0; 
mpu6050_read(reg, &value, sizeof(value)); 
return value; 
} 

void mpu6050_read(uint8_t reg, void* data, int size) 
{ 
int i; 
uint8_t* buffer = (uint8_t*)data; 

mpu6050_set_reg(reg); 

I2C_GenerateSTART(I2C1, ENABLE); 
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS); 

I2C_AcknowledgeConfig(I2C1, ENABLE); 
I2C_Send7bitAddress(I2C1, MPU6050_DEFAULT_ADDRESS, I2C_Direction_Receiver); 
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS); 

for (i = 0; i < size - 1; i++) { 
while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS); 
    buffer[i] = I2C_ReceiveData(I2C1); 
   } 
I2C_AcknowledgeConfig(I2C1, DISABLE); 
   I2C_GenerateSTOP(I2C1, ENABLE); 
   while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS); 
   buffer[i] = I2C_ReceiveData(I2C1); 
} 

Linki do dokumentacji :

mpu6050_dokumentacja

oraz adresów rejestrów :

mpu6050_adresy_rejestrów

Podsumowując w funkcji :

void MPU6050_Initialize(void)
{
mpu6050_write_reg(MPU6050_RA_PWR_MGMT_1,1<<7 );//resetuje cały układ i kasuje wszystkie rejestry

delay_ms(200);    //czekam na stabilizacje układu

mpu6050_write_reg(MPU6050_RA_PWR_MGMT_1, MPU6050_CLOCK_PLL_ZGYRO);// źródło zegara dla układu z odniesieniem do osi Z cokolwiek to znaczy , PS : dla wewn. oscylatora nic się nie zmienia w działaniu programu

mpu6050_write_reg(MPU6050_RA_CONFIG,0x01 );        //0x03DLPF_CFG = 1: Fs=1khz; bandwidth=42hz

mpu6050_write_reg(MPU6050_RA_SMPLRT_DIV, 0x01);    //500Hz sample rate ~ 2ms

mpu6050_write_reg(MPU6050_RA_GYRO_CONFIG, MPU6050_GYRO_FS_250);    //Gyro 250 st/s scale setting zakres dla żyroskopu

mpu6050_write_reg(MPU6050_RA_ACCEL_CONFIG, MPU6050_ACCEL_FS_2);    //Accel full scale setting zakres dla akcelerometru

//MPU6050_Write(MPU6050_DEFAULT_ADDRESS, MPU6050_RA_INT_PIN_CFG, 1<<4);        //interrupt status bits are cleared on any read operation

//MPU6050_Write(MPU6050_DEFAULT_ADDRESS, MPU6050_RA_INT_ENABLE, 1<<0);        //interupt occurs when data is ready. The interupt routine is in the receiver.c file.

mpu6050_write_reg(MPU6050_RA_SIGNAL_PATH_RESET, 0x07);//reset gyro and accel sensor 
}

PS : właściwie konfiguracja modułu moim zdaniem powinna się sprowadzić tylko do rejestru

MPU6050_RA_PWR_MGMT_1 i twardego resetu, co jest w tej linii kodu

mpu6050_write_reg(MPU6050_RA_PWR_MGMT_1,1<<7 );

, ponieważ po resecie mamy ustawienia domyślne, a to powinno działać 😥

Link do komentarza
Share on other sites

simba92, Mam taki czujnik MPU6050 i bardzo mi zależy żeby odczytać z niego przyspieszenia. Napisałem driver i mam już z nim komunikację po I2C i nawet poprawnie odczytuję rejestr WHO_AM_I który mi zwraca wartość adresu tego slave'a 0x68.

Mam jednak problem z odczytem przyspieszeń. Nie bardzo wiem jak mam ten czujnik skonfigurować.

Czytałem Twój post i rozpiskę rejestrów ale w dalszym ciągu mam problem.

Odczytuję spod 0x3B - 0x40 i kalkuluję to na przyspieszenia ale dostaję same zera, tak jakby czujnik jeszcze pod te swoje rejestry przyspieszeń nic nie wpisywał (nie samplował).

Czy możesz mi doradzić jak należałoby skonfigurować ten czujnik krok po kroku abym z powodzeniem mógł czytać z tych rejestrów faktyczne przyspieszenia.

Będę ogromnie wdzięczny.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Adamos19 teraz aktualnie zajmuje się czymś innym i zamieniłem czujnik MPU6050 na tzn. minIMU9v5 firmy Pololu. Chyba znalazłem błąd i muszę to sprawdzić ponieważ program, który zamieściłem jest nie dopracowany i diabeł tkwi w szczegółach. Zobaczę co da się zrobić, spróbuj w miedzy czasie wykorzystać funkcje z kursu stm32 do i2c, bo tam coś zmieniłem i wiem, że to miało zły wpływ. Tzn pisząc program nie zmieniaj kodu z kursu to powinno działać poprawnie.

Link do komentarza
Share on other sites

Adamos19 Bardzo się cieszę, że udało Ci się to uruchomić. Sam do tego przysiadłem dzisiaj i poprawiłem kod, który w takiej postaci działa :

#include "stm32f10x.h"
#include <stdio.h>




#define MPU6050_ADDRESS_AD0_LOW         0xD0 //domyslny adres czujnika MPU6050 , w nocie kalalogowej jest 0x68 ???
#define MPU6050_ADDRESS_AD0_HIGH        0x69
#define MPU6050_DEFAULT_ADDRESS         MPU6050_ADDRESS_AD0_LOW
#define MPU6050_WHO_AM_I                0x75 //rejestr przechowujacy adres urzadzenia


#define MPU6050_CLOCK_PLL_ZGYRO         0x03  //rejestry konfiguracyjne
#define MPU6050_CLOCK_INTERNAL          0x00
#define MPU6050_RA_PWR_MGMT_1           0x6B




#define MPU6050_GYRO_FS_250             0x00
#define MPU6050_ACCEL_FS_2              0x00
#define MPU6050_RA_SMPLRT_DIV           0x19

#define MPU6050_RA_CONFIG               0x1A
#define MPU6050_RA_GYRO_CONFIG          0x1B
#define MPU6050_RA_ACCEL_CONFIG         0x1C
#define MPU6050_RA_SIGNAL_PATH_RESET    0x68


#define MPU6050_RA_ACCEL_XOUT_H         0x3B  //rejestry danych pomiarowych
#define MPU6050_RA_ACCEL_XOUT_L         0x3C
#define MPU6050_RA_ACCEL_YOUT_H         0x3D
#define MPU6050_RA_ACCEL_YOUT_L         0x3E
#define MPU6050_RA_ACCEL_ZOUT_H         0x3F
#define MPU6050_RA_ACCEL_ZOUT_L         0x40
#define MPU6050_RA_TEMP_OUT_H           0x41
#define MPU6050_RA_TEMP_OUT_L           0x42
#define MPU6050_RA_GYRO_XOUT_H          0x43
#define MPU6050_RA_GYRO_XOUT_L          0x44
#define MPU6050_RA_GYRO_YOUT_H          0x45
#define MPU6050_RA_GYRO_YOUT_L          0x46
#define MPU6050_RA_GYRO_ZOUT_H          0x47
#define MPU6050_RA_GYRO_ZOUT_L          0x48


void send_char(char c)
{
while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
USART_SendData(USART2, c);
}

int __io_putchar(int c)
{
if (c=='\n')
send_char('\r');
send_char(c);
return c;
}

volatile uint32_t timer_ms = 0;

void SysTick_Handler(){
if (timer_ms) {
timer_ms--;
}
}

void delay_ms(int time){
timer_ms = time*1000;
while (timer_ms) {
   SysTick_Handler();
}
}

void mpu6050_set_reg(uint8_t reg){
   I2C_GenerateSTART(I2C1, ENABLE); //start i2c
   while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS); //dziala ok
   I2C_Send7bitAddress(I2C1, MPU6050_DEFAULT_ADDRESS, I2C_Direction_Transmitter);
   while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS); //zatrzymuje sie tutaj, flag1 w I2C_CheckEvent wynosi 1024 zamiast 2
   I2C_SendData(I2C1,reg); //dlazcego tu jest 0x80???
   while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING) != SUCCESS);
   }

void mpu6050_write(uint8_t reg, const void* data, int size){
   int i;
   const uint8_t* buffer = (uint8_t*)data;

   mpu6050_set_reg(reg);
   for (i = 0; i < size; i++) {
   I2C_SendData(I2C1, buffer[i]);
   while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING) != SUCCESS);
   }
   I2C_GenerateSTOP(I2C1, ENABLE);
   }

void mpu6050_read(uint8_t reg, void* data, int size){
   int i;
   uint8_t* buffer = (uint8_t*)data;

   mpu6050_set_reg(reg);

   I2C_GenerateSTART(I2C1, ENABLE);
   while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);

   I2C_AcknowledgeConfig(I2C1, ENABLE);
   I2C_Send7bitAddress(I2C1, MPU6050_DEFAULT_ADDRESS, I2C_Direction_Receiver);
   while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS);

   for (i = 0; i < size - 1; i++) {
   while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS);
        buffer[i] = I2C_ReceiveData(I2C1);
       }
   I2C_AcknowledgeConfig(I2C1, DISABLE);
       I2C_GenerateSTOP(I2C1, ENABLE);
       while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS);
       buffer[i] = I2C_ReceiveData(I2C1);
   }

void mpu6050_write_reg(uint8_t reg, uint8_t value)
{
mpu6050_write(reg, &value, sizeof(value));
}

uint8_t mpu6050_read_reg(uint8_t reg)
{
uint8_t value = 0;
mpu6050_read(reg, &value, sizeof(value));
return value;
}

int16_t mpu6050_read_value(uint8_t reg)
{
int16_t value = 0;
mpu6050_read(reg, &value, sizeof(value));
return value;



}

void MPU6050_Initialize(void)
{
   mpu6050_write_reg(MPU6050_RA_PWR_MGMT_1, 0x80);//reset the whole module first

   delay_ms(200);    //wait for 50ms for the gyro to stable

   mpu6050_write_reg(MPU6050_RA_PWR_MGMT_1, 0x03);//PLL with Z axis gyroscope reference MPU6050_CLOCK_INTERNAL

   mpu6050_write_reg(MPU6050_RA_CONFIG, 0x03);        //DLPF_CFG = 1: Fs=1khz; bandwidth=42hz

   mpu6050_write_reg(MPU6050_RA_SMPLRT_DIV, 0x01);    //500Hz sample rate ~ 2ms

   mpu6050_write_reg(MPU6050_RA_GYRO_CONFIG, MPU6050_GYRO_FS_250);    //Gyro 250 st/s scale setting

   mpu6050_write_reg(MPU6050_RA_ACCEL_CONFIG, MPU6050_ACCEL_FS_2);    //Accel full scale setting

   //MPU6050_Write(MPU6050_DEFAULT_ADDRESS, MPU6050_RA_INT_PIN_CFG, 1<<4);        //interrupt status bits are cleared on any read operation

   //MPU6050_Write(MPU6050_DEFAULT_ADDRESS, MPU6050_RA_INT_ENABLE, 1<<0);        //interupt occurs when data is ready. The interupt routine is in the receiver.c file.

   //mpu6050_write_reg(MPU6050_RA_SIGNAL_PATH_RESET, 0x07);//reset gyro and accel sensor
}



int main(void){

   GPIO_InitTypeDef gpio;
   I2C_InitTypeDef i2c;
   USART_InitTypeDef uart;

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

   GPIO_StructInit(&gpio);
   gpio.GPIO_Pin = GPIO_Pin_2;
   gpio.GPIO_Mode = GPIO_Mode_AF_PP;
   GPIO_Init(GPIOA, &gpio);

   gpio.GPIO_Pin = GPIO_Pin_3;
   gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
   GPIO_Init(GPIOA, &gpio);

   gpio.GPIO_Pin=GPIO_Pin_5|GPIO_Pin_4;
   gpio.GPIO_Mode=GPIO_Mode_Out_PP;
   GPIO_Init(GPIOA, &gpio);

   USART_StructInit(&uart);
   uart.USART_BaudRate = 9600;
   USART_Init(USART2, &uart);
   USART_Cmd(USART2, ENABLE);

   gpio.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; // SCL, SDA
   gpio.GPIO_Mode = GPIO_Mode_AF_OD;
   gpio.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_Init(GPIOB, &gpio);

   I2C_StructInit(&i2c);
   i2c.I2C_Ack = I2C_Ack_Enable;
   i2c.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
   i2c.I2C_Mode = I2C_Mode_I2C;
   i2c.I2C_OwnAddress1 = 0;
   I2C_Init(I2C1, &i2c);
   I2C_Cmd(I2C1, ENABLE);

   unsigned char who_am=0;

   GPIO_SetBits(GPIOA, GPIO_Pin_5);

   delay_ms(150);
   GPIO_ResetBits(GPIOA, GPIO_Pin_5);

   delay_ms(150);

   mpu6050_read(MPU6050_WHO_AM_I, &who_am, sizeof(who_am));

    if(who_am==0x68){
        printf("Znaleziono modul mpu6050.\n");
    }else{
        printf("Niepoprawna odpowiedz ukladu.\n");
    }

    MPU6050_Initialize();

   while(1){


   	/*-----------odczyty z akceleromertu xyz ----------------*/
       int8_t axL =  mpu6050_read_reg(MPU6050_RA_ACCEL_XOUT_L);
       int8_t axH =  mpu6050_read_reg(MPU6050_RA_ACCEL_XOUT_H);
       int16_t ax = (axH << 8) + axL;

       int8_t ayL =  mpu6050_read_reg(MPU6050_RA_ACCEL_YOUT_L);
       int8_t ayH =  mpu6050_read_reg(MPU6050_RA_ACCEL_YOUT_H);
       int16_t ay = (ayH << 8) + ayL;

       int8_t azL =  mpu6050_read_reg(MPU6050_RA_ACCEL_ZOUT_L);
       int8_t azH =  mpu6050_read_reg(MPU6050_RA_ACCEL_ZOUT_H);
       int16_t az = (azH << 8) + azL;

       /*-------------------------------------------------------*/

       /*-----------odczyty z zyroskopu xyz ----------------*/
       int8_t gxL =  mpu6050_read_reg(MPU6050_RA_GYRO_XOUT_L);
       int8_t gxH =  mpu6050_read_reg(MPU6050_RA_GYRO_XOUT_H);
       int16_t gx = (gxH << 8) + gxL;

       int8_t gyL =  mpu6050_read_reg(MPU6050_RA_GYRO_YOUT_L);
       int8_t gyH =  mpu6050_read_reg(MPU6050_RA_GYRO_YOUT_H);
       int16_t gy = (gyH << 8) + gyL;

       int8_t gzL =  mpu6050_read_reg(MPU6050_RA_GYRO_ZOUT_L);
       int8_t gzH =  mpu6050_read_reg(MPU6050_RA_GYRO_ZOUT_H);
       int16_t gz = (gzH << 8) + gzL;

       /*-------------------------------------------------------*/

   	 printf("aX = %d, aY = %d, aZ = %d \r\n", ax, ay, az);
   	 //printf("gX = %d, gY = %d, gZ = %d \r\n", gx, gy, gz);





   	 /*---------miganie diody wprowadzajace opoznienie o 100[ms] tzn. pomiary co 100ms--------*/
   	 GPIO_SetBits(GPIOA, GPIO_Pin_5);
   	 delay_ms(50);
   	 GPIO_ResetBits(GPIOA, GPIO_Pin_5);
   	 delay_ms(50);


   }
}

Nie wykorzystuje funkcji czytającej kilka bajtów tylko odczytuje pojedyncze bajty z rejestrów i sumuje do słowa binarnego. Wszystko działa, zwroty osi x y z są tylko odwrotne tzn. z minusem w kierunku strzałek na płytce mpu. A tu projekt mpu 6050 pod arduino z funkcja czytającą od razu wszystkie bajty z pomiarów acc + gyro funkcja_czytaj_wszystkie_pomiary Pozdrawiam!!!

Link do komentarza
Share on other sites

No to fajnie, dzięki. Przeanalizowałem Twój kod i tak jak piszesz czytasz pomiary po jednym bajcie. A co się stanie jeśli przeczytasz jednego bajta (np. przyspieszenie w osi X starszy bajt) i akurat po Twoim "przeczytaniu" czujnik nadpisze obydwie wartości (starszy i młodszy bajt) nowymi danymi, a następnie Ty przeczytasz bajt młodszy przyspieszenia w osi X ?

Link do komentarza
Share on other sites

Hmm no to pomiar nie będzie precyzyjny tzn. można powiedzieć, że nawet błędny. Generalnie najlepiej byłoby odczytywać pomiary ze wskaźnikiem na pierwszy rejestr (tu _X_OUT_H 0x3B) i przesuwać adres do przodu ale i tak trzeba scalić dane w słowo binarne czyli defacto wykonać dwa pomiary po 1 bajcie co jest robione w moim kodzie. No ale ok ze wskaźnikiem pomiar wykonuje się raz i tyle, więc to rozwiązanie jest bardziej precyzyjne jak dla przykładu z arduino w moim wcześniejszym poście. BTW. pomiary wg. kodu, który zamieściłem wydają się poprawne, podglądałem je na UART i są ok. Ten czujnik ma wiele ciekawych ustawień i warto poczytać jeszcze dokumentacje. Dodaje ciekawy artykuł jeśli nie czytałeś, może się przydać mpu6050 i2c+dma

Link do komentarza
Share on other sites

Czytałem o tym czujniku, mój post miał sprowokować odpowiedź ponieważ bardzo ciekawiło mnie w jaki sposób Ty to rozwiązałeś.

Dzięki za artykuł, zaznajomię się.

Na koniec miałbym jeszcze takie pytanie, jak rozumiesz tą część dokumentacji czujnika:

The accelerometer measurement registers, along with the temperature measurement registers,

gyroscope measurement registers, and external sensor data registers, are composed of two sets of

registers: an internal register set and a user-facing read register set.

The data within the accelerometer sensors’ internal register set is always updated at the Sample

Rate. Meanwhile, the user-facing read register set duplicates the internal register set’s data values

whenever the serial interface is idle. This guarantees that a burst read of sensor registers will read

measurements from the same sampling instant. Note that if burst reads are not used, the user is

responsible for ensuring a set of single byte reads correspond to a single sampling instant by

checking the Data Ready interrupt.

Link do komentarza
Share on other sites

Adamos19

The accelerometer measurement registers, along with the temperature measurement registers,

gyroscope measurement registers, and external sensor data registers, are composed of two sets of

registers: an internal register set and a user-facing read register set.

mpu6050 wykonuje pomiary wielkości z akcelerometru + żyroskopu + temperatury z czunjnika na module mpu6050. W tym module masz wyjścia XCL i XDA do pomiaru z czujnika dołączonego z zewnątrz np. magnetometru co daje dodatkowy pomiar
a user-facing read register set
. A w
The data within the accelerometer sensors’ internal register set is always updated at the Sample

Rate. Meanwhile, the user-facing read register set duplicates the internal register set’s data values

whenever the serial interface is idle. This guarantees that a burst read of sensor registers will read

measurements from the same sampling instant. Note that if burst reads are not used, the user is

responsible for ensuring a set of single byte reads correspond to a single sampling instant by

checking the Data Ready interrupt.

Pomiary są wykonywane cały czas na czujniku pomimo stanu bezczynności na i2c. Generalnie chodzi o pomiary w każdym cyklu pomiarowym by były dokładne i tu warto chyba wykorzystać rejestry statusowe mpu6050 żeby informować mastera o aktualizacjach i zaimplementować to wszystko na przerwaniach.
Link do komentarza
Share on other sites

To nie do końca o to chodzi @Simba ale bardzo Ci dziękuję za cenne podpowiedzi. Przesyłam Ci linka do postu który założyłem i uzyskałem wiążące odpowiedzi. Proszę zaznajom się i jak będziesz miał ochotę to podyskutujemy jeszcze. Twoje porady są bardzo cenne dla mnie, mam nadzieję że i Ciebie zainteresuje to co Ci polecam przeczytać.

https://4programmers.net/Forum/C_i_C++/297105-twi_i2c_interfejs_atmega328?page=3

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.