うさちゃんと一緒(17) Rabbit4000にAHT21B温湿度センサをI2C接続

Joseph Halfmoon

前回は、Rabbit4000(モジュールはRCM4010)のオープンドレインで使用可能なピンを見つけて、16文字x2行のキャラクタディスプレイAQM1602をソフトI2C接続いたしました。今回は同じ「I2C」バスにAHT21B温湿度センサを取り付けてみます。今回はライトオンリの前回とは違って読み書き双方向が必要です。

AHT21B温湿度センサのRabbit4000への接続

AHT21B温湿度センサについては別シリーズでRaspberry Pi 3に取り付けているので以下をご参照ください。

Rabbit4000(RCM4010)からのソフトI2Cバスの引き出しについては前回やってますので以下をご参照ください。

回路図的には以下のようになります。

AHT21Bconnection

ぶっちゃけ、前回引き出したソフトI2CバスにAHT21Bを取り付け、別シリーズで作成済のPythonスクリプト相当のプログラムをRabbitのDynamic Cに移植すればOKという手抜きな回であります。

AHT21B読み取り実験用のDynamic Cソース

以下は、とりあえず温度と湿度を読み取って、小数点以下は割愛し、整数部分のみをStdioに表示するだけの実験用のソースです。

実験用なので、本来チェックすべきポイントでACKが返ってきているか否かなどのチェックは一切していません。とりあえず「予定バイト数」を読み取ってしまった後、CRCチェックを行ってデータ伝送に誤りが無いことを確かめているので、エラーがあればそこで分かるだろ~という無理矢理です。ま、実験だし。

#class auto
#define AHT21B		(0x70)
#define BUFSZ		(7)

#define I2CSCLBit	(4)
#define I2CSDABit	(5)

#define i2c_SCL_H() BitWrPortI(PCDDR,&PCDDRShadow,0,I2CSCLBit)
#define i2c_SCL_L() BitWrPortI(PCDDR,&PCDDRShadow,1,I2CSCLBit)
#define i2c_SDA_H() BitWrPortI(PCDDR,&PCDDRShadow,0,I2CSDABit)
#define i2c_SDA_L() BitWrPortI(PCDDR,&PCDDRShadow,1,I2CSDABit)
#define i2c_SCL()   BitRdPortI(PCDR,I2CSCLBit)
#define i2c_SDA()   BitRdPortI(PCDR,I2CSDABit)

unsigned char buf[BUFSZ];

#use "i2c_devices.lib"


void waitMs(int ms) {
    unsigned long t;
    t = MS_TIMER;
    while((long)(MS_TIMER - t) < ms);
}

int triggerAHT21B() {
    int ack;
    waitMs(10);
    i2c_startw_tx();
    ack = i2c_write_char(AHT21B);
    ack = i2c_write_char(0xAC);
    ack = i2c_write_char(0x33);
    ack = i2c_write_char(0x0);
    i2c_stop_tx();
    return ack;
}

int readMeasurementResult() {
    int ack, cnt;
    waitMs(80);
    i2c_startw_tx();
    ack = i2c_write_char(AHT21B | 0x01);
    for (cnt = 0; cnt < BUFSZ; ++cnt) {
        ack = i2c_read_char(&buf[cnt]);
        if (cnt == (BUFSIZ - 1)) {
            i2c_send_nak();
        } else {
            i2c_send_ack();
        }
    }
    i2c_stop_tx();
    return ack;
}

unsigned char calcCRC8() {
    int ack, cnt, idx;
    unsigned char poly=0x31;
    unsigned char crc=0xFF;
    for (cnt = 0; cnt < (BUFSZ - 1); ++cnt) {
        crc ^= buf[cnt];
        for (idx=0; idx < 8; ++idx) {
            if (crc & 0x80) {
                crc = (crc << 1) ^ poly;
            } else {
                crc = crc << 1;
            }
        }
    }
    return crc;
}

unsigned long calcHumidity() {
    unsigned long humInt;
    humInt = buf[1];
    humInt <<= 8;
    humInt += buf[2];
    humInt <<= 4;
    humInt += (buf[3] & 0xF0) >>4;
    humInt *= 100;
    humInt >>= 20;
    return humInt;
}

unsigned long calcTemp() {
    unsigned long tempInt;
    tempInt = buf[3] & 0x0F;
    tempInt <<=8;
    tempInt += buf[4];
    tempInt <<=8;
    tempInt += buf[5];
    tempInt *= 200;
    tempInt >>=20;
    tempInt -=50;
    return tempInt;
}

void i2c_init_PC()
{
    // No Peripheral clock control
    BitWrPortI(PCFR ,&PCFRShadow ,0,I2CSCLBit); // Set SCL, Normal
    BitWrPortI(PCFR ,&PCFRShadow ,0,I2CSDABit); // Set SDA, Normal
    BitWrPortI(PCDDR,&PCDDRShadow,0,I2CSCLBit); // Set SCL, Input
    BitWrPortI(PCDDR,&PCDDRShadow,0,I2CSDABit); // Set SDA, Input
    BitWrPortI(PCDCR,&PCDCRShadow,1,I2CSCLBit); // Set SCL, Open Drain
    BitWrPortI(PCDCR,&PCDCRShadow,1,I2CSDABit); // Set SDA, Open Drain
    BitWrPortI(PCDR ,&PCDRShadow ,0,I2CSCLBit); // Set SCL output register 0
    BitWrPortI(PCDR ,&PCDRShadow ,0,I2CSDABit); // Set SDA output register 0
    i2c_clocks_per_us = (int)(19200L*32*freq_divider/1000000L);
    if(i2c_clocks_per_us < 3)
    {
        i2c_clocks_per_us = 3;
    }
}

void main()
{
    int cnt=8;
    int idx;

    printf("AHT21B Read test\n");
    i2c_init_PC();

    while (cnt > 0) {
        triggerAHT21B();
        readMeasurementResult();
        printf("  Status: 0x%02x\n", buf[0]);
        printf("  Data: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", buf[1], buf[2], buf[3], buf[4], buf[5]);
        printf("  Humidity [RH%%]: %d\n", calcHumidity());
        printf("  Temperature[C]: %d\n", calcTemp());
        if (buf[6] == calcCRC8()) {
            printf("  CRC: OK\n");
        } else {
            printf("  CRC: NGx\n");
        }
        cnt--;
        waitMs(1000);
    }

    printf("End of AHT21B I2CRead test\n");

}
実機実行結果

Dynamic C上で上記のソースをビルドして、RCM4010のRAMに書き込んで実行したところが以下に。AHT21B_result

温度28℃、相対湿度56%とな。エコだけれどもちょいと暑いデス。CRCはOKだからデータは大丈夫だよね。ホントか。

うさちゃんと一緒(16) RCM4010にAQM1602液晶ディスプレイをI2C接続 へ戻る

うさちゃんと一緒(18) Rabbit4000のCPUレジスタを一覧にしてみた へ進む