アナログ値を測定する(C言語)

準備

初めて使用する場合は、セットアップ(ボードの取り付け)をおこないます。

AIO-32/0RA-IRCのセットアップ(ラズベリーパイ)
AIO-32/0RA-IRCのセットアップ(NVIDIA Jetson Nano 開発者キット)

プログラムの作成

「test_aio320ra.cpp」というファイル名で以下のファイルを保存します。
(または test_aio320ra.cpp からダウンロードします)

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>

#define I2C_DEVICE                  "/dev/i2c-1"
#define AIO320RA_ADS1115_ADDRESS    0x49
#define AIO320RA_PCA9554_ADDRESS    0x3e

enum PCA9554_Register {
    PCA9554_Reg_InputPort,
    PCA9554_Reg_OutputPort,
    PCA9554_Reg_PolarityInversion,
    PCA9554_Reg_Configuration
};

enum ADS1115_Register {
    ADS1115_Reg_Conversion,
    ADS1115_Reg_Config,
    ADS1115_Reg_LoThresh,
    ADS1115_Reg_HiThresh
};

enum ADS1115_SingleShotCoversion {
    ADS1115_SingleShotCoversion_NoEffect,
    ADS1115_SingleShotCoversion_Begin
};

enum ADS1115_Mux {
    ADS1115_Mux_Ain0_Ain1,
    ADS1115_Mux_Ain0_Ain3,
    ADS1115_Mux_Ain1_Ain3,
    ADS1115_Mux_Ain2_Ain3,
    ADS1115_Mux_Ain0_Gnd,
    ADS1115_Mux_Ain1_Gnd,
    ADS1115_Mux_Ain2_Gnd,
    ADS1115_Mux_Ain3_Gnd
};

enum ADS1115_PGA {
    ADS1115_PGA_6_144V,
    ADS1115_PGA_4_096V,
    ADS1115_PGA_2_048V,
    ADS1115_PGA_1_024V,
    ADS1115_PGA_0_512V,
    ADS1115_PGA_0_256V
};

enum ADS1115_Mode {
    ADS1115_Mode_Continuous,
    ADS1115_Mode_PowerDownSingleShot
};

enum ADS1115_DataRate {
    ADS1115_DataRate_8SPS,
    ADS1115_DataRate_16SPS,
    ADS1115_DataRate_32SPS,
    ADS1115_DataRate_64SPS,
    ADS1115_DataRate_128SPS,  // Default
    ADS1115_DataRate_250SPS,
    ADS1115_DataRate_475SPS,
    ADS1115_DataRate_860SPS,
};

enum ADS1115_ComparatorQueue {
    ADS1115_ComparatorQueue_Disable = 0x03
};

enum AIO320RA_PGA {
    AIO320RA_PGA_10_0352V = ADS1115_PGA_2_048V,
    AIO320RA_PGA_5_0176V = ADS1115_PGA_1_024V,
    AIO320RA_PGA_2_5088V = ADS1115_PGA_0_512V,
    AIO320RA_PGA_1_2544V = ADS1115_PGA_0_256V
};

enum AIO320RA_DataRate {
    AIO320RA_DataRate_8SPS = ADS1115_DataRate_8SPS,
    AIO320RA_DataRate_16SPS = ADS1115_DataRate_16SPS,
    AIO320RA_DataRate_32SPS = ADS1115_DataRate_32SPS,
    AIO320RA_DataRate_64SPS = ADS1115_DataRate_64SPS,
    AIO320RA_DataRate_128SPS = ADS1115_DataRate_128SPS,
    AIO320RA_DataRate_250SPS = ADS1115_DataRate_250SPS,
    AIO320RA_DataRate_475SPS = ADS1115_DataRate_475SPS,
    AIO320RA_DataRate_860SPS = ADS1115_DataRate_860SPS,
};

uint8_t multiplexerSettings;

int PCA9554_SetDirectionByte(int fd, uint8_t value) {
    uint8_t reg[] = { PCA9554_Reg_Configuration , value };
    if ((write(fd, reg, 2)) != 2) {
        perror("PCA9554_SetDirectionByte(write)");
        return 1;
    }

    return 0;
}

int PCA9554_WriteByte(int fd, uint8_t value) {
    uint8_t reg[] = { PCA9554_Reg_OutputPort, value };
    if ((write(fd, reg, 2)) != 2) {
        perror("PCA9554_WriteByte(write)");
        return 1;
    }

    return 0;
}

int16_t ADS1115_AnalogRead(int fd, ADS1115_Mux mux, ADS1115_DataRate dataRate = ADS1115_DataRate_128SPS, ADS1115_PGA pga = ADS1115_PGA_2_048V) {
    uint8_t reg[] = {
        ADS1115_Reg_Config,
        (uint8_t)(ADS1115_SingleShotCoversion_Begin << 7 | mux << 4 | pga << 1 | ADS1115_Mode_PowerDownSingleShot),
        (uint8_t)(dataRate << 5 | ADS1115_ComparatorQueue_Disable) };

    if ((write(fd, reg, 3)) != 3) {
        perror("ADS1115_AnalogRead(write)");
        return 1;
    }

    reg[0] = 0;
    while ((reg[0] & 0x80) == 0) {
        if (read(fd, reg, 1) != 1) {
            perror("ADS1115_AnalogRead(read)");
            return 1;
        }
    }

    reg[0] = ADS1115_Reg_Conversion;
    if ((write(fd, reg, 1)) != 1) {
        perror("ADS1115_AnalogRead(write)");
        return 1;
    }

    if (read(fd, reg, 2) != 2) {
        perror("ADS1115_AnalogRead(read)");
        return 1;
    }

    return (int16_t)reg[0] << 8 | reg[1];
}

int AIO320RA_Init(int fdMux) {
    multiplexerSettings = 0xff;
    if (PCA9554_WriteByte(fdMux, multiplexerSettings) != 0)
        return 1;

    if (PCA9554_SetDirectionByte(fdMux, 0) != 0)
        return 1;

    return 0;
}

int16_t AIO320RA_AnalogRead(int fdAdc, int fdMux, int channel, AIO320RA_DataRate dataRate = AIO320RA_DataRate_128SPS, AIO320RA_PGA pga = AIO320RA_PGA_10_0352V) {
    uint8_t extMux;
    ADS1115_Mux adcMux;

    if (channel < 16) {
        extMux = (uint8_t)((multiplexerSettings & 0xf0) | channel);
        adcMux = ADS1115_Mux_Ain0_Gnd;
    }
    else if (channel < 32) {
        extMux = (uint8_t)((multiplexerSettings & 0x0f) | (channel & 0x0f) << 4);
        adcMux = ADS1115_Mux_Ain1_Gnd;
    }
    else if (channel < 48) {
        extMux = (uint8_t)((multiplexerSettings & 0xf0) | channel);
        adcMux = ADS1115_Mux_Ain0_Ain3;
    }
    else if (channel < 64) {
        extMux = (uint8_t)((multiplexerSettings & 0x0f) | (channel & 0x0f) << 4);
        adcMux = ADS1115_Mux_Ain1_Ain3;
    }
    else if (channel < 256) {
        return 0;
    }
    else {
        extMux = (uint8_t)(channel & 0xff);
        adcMux = ADS1115_Mux_Ain0_Ain1;
    }
    if (multiplexerSettings != extMux) {
        PCA9554_WriteByte(fdMux, extMux);
        multiplexerSettings = extMux;
    }

    return ADS1115_AnalogRead(fdAdc, adcMux, (ADS1115_DataRate)dataRate, (ADS1115_PGA)pga);
}

float AIO320RA_AnalogReadVolt(int fdAdc, int fdMux, int channel, AIO320RA_DataRate dataRate = AIO320RA_DataRate_128SPS, AIO320RA_PGA pga = AIO320RA_PGA_10_0352V) {
    switch (pga) {
    case AIO320RA_PGA_1_2544V:
        return (float)(0.256 * 49 / 10 / 32767 * AIO320RA_AnalogRead(fdAdc, fdMux, channel, dataRate, pga));
    case AIO320RA_PGA_2_5088V:
        return (float)(0.512 * 49 / 10 / 32767 * AIO320RA_AnalogRead(fdAdc, fdMux, channel, dataRate, pga));
    case AIO320RA_PGA_5_0176V:
        return (float)(1.024 * 49 / 10 / 32767 * AIO320RA_AnalogRead(fdAdc, fdMux, channel, dataRate, pga));
    default:
        return (float)(2.048 * 49 / 10 / 32767 * AIO320RA_AnalogRead(fdAdc, fdMux, channel, dataRate, pga));
    }
}

int main(int argc, char **argv)
{
    int fdAdc, fdMux;

    if ((fdAdc = open(I2C_DEVICE, O_RDWR)) < 0) {
        perror("adc open");
        exit(1);
    }

    if (ioctl(fdAdc, I2C_SLAVE, AIO320RA_ADS1115_ADDRESS) < 0) {
        perror("adc ioctl");
        exit(1);
    }

    if ((fdMux = open(I2C_DEVICE, O_RDWR)) < 0) {
        perror("mux open");
        exit(1);
    }

    if (ioctl(fdMux, I2C_SLAVE, AIO320RA_PCA9554_ADDRESS) < 0) {
        perror("mux ioctl");
        exit(1);
    }

    if (AIO320RA_Init(fdMux) != 0)
        exit(1);

    // アナログ入力値の読み出し(電圧値)(860SPS)  
    float volt[32];
    for (int channel = 0; channel < 32; channel++) {
        volt[channel] = AIO320RA_AnalogReadVolt(fdAdc, fdMux, channel, AIO320RA_DataRate_860SPS);
        printf("CH%d: %2.3fV\n", channel, volt[channel]);
    }

    close(fdAdc);
    close(fdMux);

    return 0;
}

動作確認

プログラムをコンパイルします。

$ g++ -o test_aio320ra test_aio320ra.cpp

プログラムを実行します。

$ ./test_aio320ra  

アナログ入力電圧が表示されます。

CH0: 5.205V
CH1: 0.000V
CH2: 0.000V
...

使用方法について

差動入力で使用する場合

AIO320RA_AnalogReadVolt関数 または AIO320RA_AnalogRead関数 で引数(channel)を以下の値にすることで、各差動入力チャネルの電圧を読み出すことが可能です。

channelの値 = 差動入力チャネル * 17 + 256

channel 差動入力チャネル 接続先
256 差動入力チャネル0 P1-1pinとP1-2pin
273 差動入力チャネル1 P1-3pinとP1-4pin
290 差動入力チャネル2 P1-5pinとP1-6pin
・・・

必ず入力信号の基準電位(0V)を、AG(P1-33pin・P1-34pinどちらかのピン)に接続してください。

参考資料

AIO-32/0RA-IRCの製品情報・ドキュメント