LoginSignup
19
24

More than 5 years have passed since last update.

Raspberry Pi で3つのi2cデバイスを同時に動かしてみた

Last updated at Posted at 2016-11-12

概要

3つのi2cデバイス
1.距離センサ(VL53L0X)
2.ジャイロ加速度センサ(MPU-6050)
3.PWMドライバ(PCA9685)
が同時動作することを確認しました。

使用プログラミング言語言語

c
c++

接続図

aaa_ブレッドボード.png

動作確認画面

キャプチャ2.png
VL53L0X:距離センサ
MPU-6050:ジャイロ加速度センサ
PCA9685:PWMドライバ

binファイルはそれぞれi2cデバイス毎に用意して3プロセスを同時に実行した。
上の画像では静止画ですが、実際は3つとも同時に動作しました。

プログラムソースコード

距離センサ(VL53L0X)

https://github.com/cassou/VL53L0X_rasp を利用させていただきました。
http://www.st.com/content/st_com/en/products/embedded-software/proximity-sensors-software/stsw-img005.html のVL53L0X APIを利用するためダウンロードと、MakeFieへのAPIパス設定が必要です。

ジャイロ加速度センサ(MPU-6050)

https://www.raspberrypi.org/forums/viewtopic.php?t=22266 を利用させていただきました。

PWMドライバ(PCA9685)

http://junkroom2cyberrobotics.blogspot.jp/2013/06/raspberry-pi-adafruit-i2c-16-channel.html を参考させていただきc++からcへ変更しました。

PCA9685.c
//gcc -Wall -O2 -lm PCA9685.c -o PCA9685
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <math.h>

#define PCA9685_SUBADR1 0x2
#define PCA9685_SUBADR2 0x3
#define PCA9685_SUBADR3 0x4

#define PCA9685_MODE1 0x0
#define PCA9685_PRESCALE 0xFE

#define LED0_ON_L 0x6
#define LED0_ON_H 0x7
#define LED0_OFF_L 0x8
#define LED0_OFF_H 0x9

#define ALLLED_ON_L 0xFA
#define ALLLED_ON_H 0xFB
#define ALLLED_OFF_L 0xFC
#define ALLLED_OFF_H 0xFD



//PCA9685
int m_nI2c;
void PCA9685_init(float freq);
uint8_t PCA9685_read(uint8_t adr);
void PCA9685_write(uint8_t adr, uint8_t dat);
void PCA9685_pwmWrite(uint8_t ch, double pulseWidth_usec);
void PCA9685_setPWM(uint8_t ch, uint16_t onTime, uint16_t offTime);

#define PWM_FREQUENCY 60                    //60Hz 16.7ms
#define PWM_PULSE_WIDTH_MAX 12000           //12ms

/**********************************************************************
*
**********************************************************************/
int main(int argc, char *argv[])
{
    char *i2cFileName = "/dev/i2c-1";
    int driverAddress = 0x40;
    int i;
    double dfVal;

    if((m_nI2c = open(i2cFileName, O_RDWR)) < 0){
        printf("m_nI2c open err\n");
        return -1;
    }

    if(ioctl(m_nI2c, I2C_SLAVE, driverAddress) < 0){
        printf("ioctl err\n");
        return -1;
    }

    PCA9685_init(PWM_FREQUENCY);

    for(i=0;i<100;i++){
        dfVal = i*200+1000;
        if(PWM_PULSE_WIDTH_MAX < dfVal)break;
        printf("%0.1lfms\n",dfVal/1000);
        PCA9685_pwmWrite(0, dfVal);
        PCA9685_pwmWrite(1, PWM_PULSE_WIDTH_MAX - dfVal);
        sleep(1);
    }

    printf("stop\n");
    sleep(5);
    PCA9685_pwmWrite(0, 0);


    return 0;
}


/**********************************************************************
*   PCA9685_init
**********************************************************************/
void PCA9685_init(float freq)
{
    float prescaleval = 25000000;

    PCA9685_write(PCA9685_MODE1, 0x0);
    usleep(100000);//100ms

    prescaleval /= 4096;
    prescaleval /= freq;
    prescaleval -= 1;
    printf("Estimated pre-scale: %f\n", prescaleval);

    uint8_t prescale = floor(prescaleval + 0.5);
    printf("Final pre-scale: %d\n", prescale); 

    uint8_t oldmode = PCA9685_read(PCA9685_MODE1);
    uint8_t newmode = (oldmode&0x7F) | 0x10; 
    PCA9685_write(PCA9685_MODE1, newmode); 
    PCA9685_write(PCA9685_PRESCALE, prescale);
    PCA9685_write(PCA9685_MODE1, oldmode);
    sleep(5);
    PCA9685_write(PCA9685_MODE1, oldmode | 0xa1);  

}


/**********************************************************************
*   PCA9685_pwmWrite
**********************************************************************/
void PCA9685_pwmWrite(uint8_t ch, double pulseWidth_usec)
{
    double pulselength;
    double pulseWidth;
    // 1秒=1000000usを60Hzで割ってパルス長を算出。
    pulselength = 1000000 / PWM_FREQUENCY;
    // 12bit(2^12=4096)分解能相当へ。1分解能当たりの時間算出。
    pulselength /= 4096;
    // PWMのパルス設定値を算出。
    pulseWidth = pulseWidth_usec / pulselength;

    // PWM値設定。
    //  setPWM(channel, on_timing, off_timing)
    //  channelで指定したチャネルのPWM出力のon(0→1)になるタイミングと
    //  off(1→0)になるタイミングを0~4095で設定する。
    PCA9685_setPWM(ch, 0, pulseWidth);
}
/**********************************************************************
*   PCA9685_setPWM
**********************************************************************/
void PCA9685_setPWM(uint8_t ch, uint16_t onTime, uint16_t offTime)
{
    uint8_t sendData[5];

    sendData[0] = LED0_ON_L + 4 * ch;
    sendData[1] = (uint8_t)(0x00ff & onTime);
    sendData[2] = (uint8_t)((0xff00 & onTime) >> 8);
    sendData[3] = (uint8_t)(0x00ff & offTime);
    sendData[4] = (uint8_t)((0xff00 & offTime) >> 8);

    if(write(m_nI2c, sendData, 5) != 5){
        printf("PCA9685_setPWM() err\n");
    }
}


/**********************************************************************
*   PCA9685_read
**********************************************************************/
uint8_t PCA9685_read(uint8_t adr)
{
    uint8_t sendData;
    uint8_t readData;

    sendData = adr;
    if(write(m_nI2c, &sendData, 1) != 1){
        printf("PCA9685_read() err1\n");
    }
    else{
        if(read(m_nI2c, &readData, 1) != 1){
            printf("PCA9685_read() err2\n");
        }
     }

    return readData;
}
/**********************************************************************
*   PCA9685_write
**********************************************************************/
void PCA9685_write(uint8_t adr, uint8_t dat)
{
    uint8_t buf[2];

    buf[0] = adr;
    buf[1] = dat;
    if(write(m_nI2c, buf, 2) != 2){
        printf("PCA9685_write() err\n");
    }
}


19
24
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
24