24 Nisan 2019 Çarşamba

STM32F4 I2C Kullanımı Standart Peripheral Library (SPL) MPU6050 İvme ve Gyro Sensörü - GY-521

    I2C iletişim protokolünde veri aktarımı için SDA (Serial Data Line) ve SCL (Serial Clock) olmak üzere iki adet haberleşme hattı bulunur. SDA, cihazlar arasındaki veri aktarımının sağlandığı hattır. Bu hatta çift yönlü veri aktarımı olur. Hatta aktarılan verilerin senkronizasyonu, SCL hattı ile gerçekleştirilir. . SDA hattındaki veri iletimi, SCL sinyaline göre düzenlenir. SDA ve SCL hatları, pull-up dirençlerle VCC hattına bağlanmalıdır. I2C haberleşen cihazların GNDlerinin ortak olması  gerekmektedir.

    İletişim başlaması için ilk olarak  master cihazı slave cihaza start komutunu gönderir. Ardından adres bilgisini ve veri göndereciğini yada veri alacağını belirten bilgi datasını göndermesi gerekir. Master slave'e ait adresi göndermişse slave master'a ack bilgisini gönderir. Eğer veri gönderilecekse master ACK bilgisini aldıktan sonra 8 bitlik data gönderir ve slave cihazdan verinin alındığına dair bir ACK bilgisi bekler. Gönderilmesi gereken data bitene kadar data iletimi 8 bit data-ACK-8 bit data-ACK şeklinde gönderilir . En son alınan ACK mesajından sonra master  stop komutunu gönderir ve haberleşmeyi bitirir. Veri alımı yapılacak ise master slave adresini gönderdikten sonra veri alacağını slave'e gönderir slave adresi doğrulamak için ACK mesajını yollar ve ardından 8 bit datayı master'a yollar bu kez master slave'a  ACK masajını gönderir ve veri iletimi bu şekilde devam eder. Master veri alamazssa  slave'e NACK biti gönderir. Veri iletimi tamamlandığında master stop komutu gönderir ve haberleşmeyi bitirir.










    STM32F4 kartı ile MPU6050  İvme ve Gyro Sensörü I2C iletişiminde STM32F4 master MPU6050 ise slave cihaz olacak. MPU6050'nin adresi AD0 pinine göre 68 veya 69 olarak seçilebilir. AD0 Low olursa 0x68 Hıgh olursa 0x69 kullanılır. I2C konfigürasyon aşarları ayarlamaları şu şekildedir.



void init_I2C1(void){
 
 GPIO_InitTypeDef GPIO_InitStruct;
 I2C_InitTypeDef I2C_InitStruct;
 
 // enable APB1 clock bus for I2C1
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
 // enable AHB1 clock bus for SCL and SDA pins
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
 
 /*
  SCL on PB6 and SDA on PB7 
  SCL on PB8 and SDA on PB9
  */
 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //PB6 and PB7
 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;   // set to alternate function
 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;  
 GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;   //set to open drain 
 GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;   // pull up resistors
 GPIO_Init(GPIOB, &GPIO_InitStruct);     
 
 GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1); // SCL
 GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1); // SDA
 
 // I2C1 
 I2C_InitStruct.I2C_ClockSpeed = 100000;   
 I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;   
 I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; 
 I2C_InitStruct.I2C_OwnAddress1 = 0x00;   // own address
 I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;  // enable acknowledge 
 I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // 7 bit address length 
 I2C_Init(I2C1, &I2C_InitStruct);   
 
 // enable I2C1
 I2C_Cmd(I2C1, ENABLE);
}



 
Veri gönderme ve alma fonksiyonları bu şekildedir.





void write_i2c(I2C_TypeDef* I2Cx,uint8_t address, uint8_t data){


    // wait until I2C1 is not busy anymore
 while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));
 
  // I2C1 enable
 I2C_GenerateSTART(I2Cx, ENABLE);
   
 // wait for I2C1 EV5 --> Slave has acknowledged start condition
 while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
  
 // Send slave Address for write 
 I2C_Send7bitAddress(I2Cx, address, I2C_Direction_Transmitter);
 
 while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
 
 I2C_SendData(I2Cx, data);
 // wait for I2C1 EV8_2 --> byte has been transmitted
 while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
 
 I2C_GenerateSTOP(I2Cx, ENABLE);

}


int read_i2c(I2C_TypeDef* I2Cx,uint8_t address)
{
 // wait until I2C1 is not busy anymore
 while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));
  
 // I2C1 enable
 I2C_GenerateSTART(I2Cx, ENABLE);
   
 // wait for I2C1 EV5 --> Slave has acknowledged start condition
 while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT)); 
  
 // Send slave Address for read 
 I2C_Send7bitAddress(I2Cx, address, I2C_Direction_Receiver);
 
 
 while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
 
 I2C_AcknowledgeConfig(I2Cx, DISABLE);
 
 I2C_GenerateSTOP(I2Cx, ENABLE);
 
 // wait until one byte has been received
 while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );
 
 // read data from I2C data register 
 uint8_t data = I2C_ReceiveData(I2Cx);
 return data;

}


main fonksiyonu 



int main(void){
 
 init_I2C1(); // initialize I2C peripheral
 
 GPIO_InitTypeDef GPIO_InitStructure;
 
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);
 
 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;
 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12 |GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15 ;
 GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
 GPIO_Init(GPIOD,&GPIO_InitStructure);
 

 
 while(1){
  
   write_i2c(I2C1,ADDRESS<<1,0X6B); // PWR_MGMT_1 register 
 write_i2c(I2C1,ADDRESS<<1,0X00); // wakes up the MPU-6050

 write_i2c(I2C1,ADDRESS<<1,0X3B);//ACCEL_XOUT_H 
 xh=read_i2c(I2C1,ADDRESS<<1);
  
 write_i2c(I2C1,ADDRESS<<1,0x3C);//ACCEL_XOUT_L  
 xl=read_i2c(I2C1,ADDRESS<<1);
  
 write_i2c(I2C1,ADDRESS<<1,0x3D);//ACCEL_YOUT_H 
 yh=read_i2c(I2C1,ADDRESS<<1);
  
 write_i2c(I2C1,ADDRESS<<1,0x3E);//ACCEL_YOUT_L
 yl=read_i2c(I2C1,ADDRESS<<1);
 
  x  =((xh<<8 | xl));
  y  =((yh<<8)| yl);
   
 xm=map(x,-17000,17000,0,100);
 ym=map(y,-17000,17000,0,100);
   
   delay(10000);

  
             if(0<xm & xm<50)
        {
         GPIO_SetBits(GPIOD,GPIO_Pin_14);
       GPIO_ResetBits(GPIOD,GPIO_Pin_12);
        }
    
      if(50<=xm & xm<=100)
        {
  GPIO_SetBits(GPIOD, GPIO_Pin_12);
    GPIO_ResetBits(GPIOD, GPIO_Pin_14);
        }
   
      if(0<ym & ym<50)
               {
         GPIO_SetBits(GPIOD,  GPIO_Pin_13);
      GPIO_ResetBits(GPIOD,GPIO_Pin_15);
        }
      
      if(50<=ym & ym<100)
        {
         GPIO_SetBits(GPIOD, GPIO_Pin_15);
  GPIO_ResetBits(GPIOD,GPIO_Pin_13);
        }
   
          }
}






    Proje dosyasına buradan ulaşabilirsiniz. bu uygulamada MPU6050'ın konumuna göre STM32F4 üzerindeki ledler yanmaktadır. 














2 yorum:

  1. Dostum bende adxl345 sensörü ile verileri basmaya çalışıyorum fakat register adres değerini gönderiyorum yanıt vermiyor
    bi yardım et gözünü seveyim

    #include "stm32f4xx.h"
    #include "stm32f4_discovery.h"


    #define Max 50
    #define adxl_address 0x53<<1 //0xA6

    GPIO_InitTypeDef GPIOStructure;
    I2C_InitTypeDef I2CStructure;
    char str[Max];
    uint8_t cip=0;
    void Config(void){

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    GPIOStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //PB6 and PB7
    GPIOStructure.GPIO_Mode = GPIO_Mode_AF; // set to alternate function
    GPIOStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIOStructure.GPIO_OType = GPIO_OType_OD; //set to open drain
    GPIOStructure.GPIO_PuPd = GPIO_PuPd_UP; // pull up resistors
    GPIO_Init(GPIOB, &GPIOStructure);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1);


    I2CStructure.I2C_ClockSpeed = 100000;
    I2CStructure.I2C_Mode = I2C_Mode_I2C;
    I2CStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2CStructure.I2C_OwnAddress1 = 0x00;
    I2CStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2CStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_Init(I2C1, &I2CStructure);

    I2C_Cmd(I2C1, ENABLE);
    }
    void write_i2c(I2C_TypeDef* I2Cx,uint8_t address, uint8_t data){


    // wait until I2C1 is not busy anymore
    while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));

    // I2C1 enable
    I2C_GenerateSTART(I2Cx, ENABLE);

    // wait for I2C1 EV5 --> Slave has acknowledged start condition
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));

    // Send slave Address for write
    I2C_Send7bitAddress(I2Cx, address, I2C_Direction_Transmitter);

    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    I2C_SendData(I2Cx, data);
    // wait for I2C1 EV8_2 --> byte has been transmitted
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    I2C_GenerateSTOP(I2Cx, ENABLE);

    }


    int read_i2c(I2C_TypeDef* I2Cx,uint8_t address)
    {
    // wait until I2C1 is not busy anymore
    while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));

    // I2C1 enable
    I2C_GenerateSTART(I2Cx, ENABLE);

    // wait for I2C1 EV5 --> Slave has acknowledged start condition
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));

    // Send slave Address for read
    I2C_Send7bitAddress(I2Cx, address, I2C_Direction_Receiver);


    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

    I2C_AcknowledgeConfig(I2Cx, DISABLE);

    I2C_GenerateSTOP(I2Cx, ENABLE);

    // wait until one byte has been received
    while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );

    // read data from I2C data register
    uint8_t data = I2C_ReceiveData(I2Cx);
    return data;

    }
    uint16_t x0,x1,Y0,Y1,z0,z1;
    int main(void)
    {

    Config();

    cip=read_i2c(I2C1,adxl_address);
    write_i2c(I2C1,0x2d, 0x00);
    write_i2c(I2C1,0x2d, 0x08);
    write_i2c(I2C1,0x31, 0x01);
    while (1)
    {
    write_i2c(I2C1,adxl_address,0x32);
    x0 = read_i2c(I2C1,adxl_address);
    write_i2c(I2C1,adxl_address,0x33);
    x1 = read_i2c(I2C1,adxl_address);
    write_i2c(I2C1,adxl_address,0x34);
    Y0 = read_i2c(I2C1,adxl_address);
    write_i2c(I2C1,adxl_address,0x35);
    Y1 = read_i2c(I2C1,adxl_address);
    write_i2c(I2C1,adxl_address,0x36);
    z0 = read_i2c(I2C1,adxl_address);
    write_i2c(I2C1,adxl_address,0x37);
    z1 = read_i2c(I2C1,adxl_address);



    }
    }


    YanıtlaSil
  2. merhaba. size bu proje hakkında küçük bir soru sormak istiyorum. mpu6050 sensörürünüm hassasiyetini nasıl değiştirebilirim. yardımcı olursanız sevinirim

    YanıtlaSil