Edited at

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

More than 1 year has passed since last update.


概要

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");
}
}