前回は、Rabbit4000(モジュールはRCM4010)のオープンドレインで使用可能なピンを見つけて、16文字x2行のキャラクタディスプレイAQM1602をソフトI2C接続いたしました。今回は同じ「I2C」バスにAHT21B温湿度センサを取り付けてみます。今回はライトオンリの前回とは違って読み書き双方向が必要です。
※「うさちゃんと一緒」投稿順indexはこちら
AHT21B温湿度センサのRabbit4000への接続
AHT21B温湿度センサについては別シリーズでRaspberry Pi 3に取り付けているので以下をご参照ください。
Rabbit4000(RCM4010)からのソフトI2Cバスの引き出しについては前回やってますので以下をご参照ください。
回路図的には以下のようになります。
ぶっちゃけ、前回引き出したソフト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に書き込んで実行したところが以下に。
温度28℃、相対湿度56%とな。エコだけれどもちょいと暑いデス。CRCはOKだからデータは大丈夫だよね。ホントか。