#概要
3つのi2cデバイス
1.距離センサ(VL53L0X)
2.ジャイロ加速度センサ(MPU-6050)
3.PWMドライバ(PCA9685)
が同時動作することを確認しました。
#使用プログラミング言語言語
c
c++
#動作確認画面
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へ変更しました。
//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");
}
}