温湿度センサー AM2320 (ONE-Wire / I2C 両用)
3.3~5V / ONE-Wire と I2Cのどちらでも使える汎用性の高い温湿度センサーです。Amazonだと高い & 中国発送(時間がかかる&偽物の可能性大)ですので
秋月電子やマルツオンラインなどの国内小売店での購入をお勧めします。
ONE-Wire(単線通信)での使い方
以下の手順で通信を行います■通信の開始
ホスト側から:18m秒間LOW信号を出力
■通信開始の応答
デバイス側から:80μ秒LOW - 80μ秒HIGH
■データ:'0'
デバイス側から;50μ秒LOW-28μ秒HIGH
■データ'1'
デバイス側から:50μ秒LOW-70μ秒HIGH
■ 通信終了
デバイス側から:50μ秒LOW の後HIGH
■ デバイスから送信されるデータ
下記表の順番に40Bit(5Byte)が送信される
内容 | 範囲 | 長さ |
---|---|---|
湿度 HIGH | 0x00 ~ 0x0F | 8Bit(1Byte) |
湿度 LOW | 0x00 ~ 0xFF | 8Bit(1Byte) |
温度 HIGH | 0x80 ~ 0x8F | 8Bit(1Byte) |
温度 LOW | 0x00 ~ 0xFF | 8Bit(1Byte) |
Check SUM | 0x00 ~ 0xFF | 8Bit(1Byte) |
Ex. 0x00 0x65 = 10.1℃ / 0x80 0x65 = -10.1℃
ONE-Wire(単線通信)でデータの受信方法
■ 内蔵のPULL-UP抵抗を有効にするpinMode(DATAPIN, INPUT_PULLUP);
■ データ送信要求 を送信して 入力がLOWになるのを待つ
pinMode(DATAPIN, OUTPUT); //開始信号
delay(2); // ※通常1m秒なので、念のため(?)2m秒待つ
pinMode(DATAPIN, INPUT); // 入力に切り替え
while(digitalRead(DATAPIN) == LOW) { // 入力値がLOWになるまで待つ
delayMicroseconds(5) ;
}
■ 入力値が変化するまでdigitalRead()を繰り返す
※DHT11と同じ割り込み利用方法も可能。メリットがないと思われるので割愛
※AM2320の信号ピンは何処につないでも良い
AM2320-Wire.zip
※ <>を全角<>に置き換えています。コピペの際は注意してください。
// 温湿度センサー AM2320 ONE-WIRE アクセステスト
#define BAUDRATE 9600
#define DATAPIN 2 // コレは何番ピンでも良い
char str[120] ;
// ----- Senser Data
struct AM2320_s {
uint8_t humidityH ; // 湿度の HIGH Byte
uint8_t humidityL ; // 湿度の LOW BYTE
uint8_t temperatureH; // 温度の HIGH Byte
uint8_t temperatureL; // 温度の LOW Byte
} am2320 ;
bool readAM2320( ) {
uint8_t readData[5] ;
uint8_t checkSum = 0 ;
int setPos = 0 ;
int bitLen = 0 ;
int stat = HIGH ;
uint8_t bitData ;
unsigned long beginTime ;
unsigned long passTime ;
unsigned long zeroTime = 35 ; // 35μ秒以下なら0 以上なら1と判定 ※仕様では0は26~28μ秒
bool flagStart = false;
for (int i=0;i<5;i++) {
readData[i] = 0 ;
}
// ----- データ送信要求 -----
pinMode(DATAPIN, OUTPUT); //開始信号
delay(2); // 0.8~20mS Typ:1mS
pinMode(DATAPIN, INPUT);
while(digitalRead(DATAPIN) == LOW) {
delayMicroseconds(5) ;
}
// ----- ACSEPT -----
flagStart = false;
passTime = 0 ;
beginTime = micros();
while (passTime < 1000) {
passTime = micros() - beginTime ;
if (digitalRead(DATAPIN) != stat) {
if (stat == HIGH) {
stat = LOW ;
if (flagStart) {
break ;
}
} else {
beginTime = micros();
flagStart = true ;
stat = HIGH ;
}
}
}
// ----- データ受信 -----
bitData = 0x80 ;
flagStart = false;
passTime = 0 ;
beginTime = micros();
while (bitLen < 40 && passTime < 1000) {
passTime = micros() - beginTime ;
if (digitalRead(DATAPIN) != stat) {
if (stat == HIGH) {
stat = LOW ;
if (flagStart) {
// ----- 1Bit 受信 -----
if (passTime > zeroTime) {
readData[setPos] |= bitData ;
}
if (bitData != 0x01) {
bitData >>= 1 ;
} else {
bitData = 0x80 ;
setPos ++ ;
}
// ----- ステート変数リセット -----
beginTime = micros();
flagStart = false;
bitLen ++ ;
}
} else {
beginTime = micros();
flagStart = true ;
stat = HIGH ;
}
}
}
// ----- 取得データ格納 -----
am2320.humidityH = readData[0] ; // 湿度の HIGH Byte
am2320.humidityL = readData[1] ; // 湿度の LOW Byte
am2320.temperatureH = readData[2]; // 温度の HIGH Byte
am2320.temperatureL = readData[3]; // 温度の LOW Byte
checkSum = readData[0] + readData[1] + readData[2] + readData[3] ;
return (bitLen == 40 && checkSum == readData[4]) ;
}
void setup() {
Serial.begin(BAUDRATE);
Serial.println("\nAM2320 - Read") ;
pinMode(DATAPIN, INPUT_PULLUP);
}
void loop() {
if (readAM2320( )) {
int hum = (am2320.humidityH << 8) + am2320.humidityL ;
int tem = ((am2320.temperatureH & 0x7F) << 8) + am2320.temperatureL ;
if ((am2320.temperatureH & 0x80) != 0) tem *= -1 ;
sprintf(str,"湿度:%2d.%d%% 気温:%2d.%d℃", hum / 10 , hum % 10 , tem / 10 , tem % 10) ;
Serial.println(str) ;
}
delay(3000) ;
}
I2C接続でのデータ受信方法
I2Cアドレスは0x5CI2Cコマンドは Wakeupと読み出し、書き込み ※ユーザー領域がありますが、使う意義が分からないので割愛
センサー値の読みだ債は3秒以上の間隔を開ける必要があります。
各コマンドの間隔もそれぞれの待ち時間を入れる必要があります。
I2Cでセンサー値を取得した場合は、チェックサムではなくCRC-16になっています。
※リトルインディアンの2バイト値なので上位バイトと下位バイトが反転しています。
CRC-16の算出式はデータシートに記載されているリストをそのまま使用しています。
レジスタアドレス | レジスタ値 |
---|---|
0x00 | 湿度 上位バイト |
0x01 | 湿度 下位バイト |
0x02 | 温度 上位バイト |
0x03 | 温度 下位バイト |
湿度・気温の値は12ビットの整数です。
気温は最上位ビットがマイナスフラグになっています。
気温の値が 0x00 0x65 の場合は 10.1℃ 、 0x80 0x65の場合は-10.1℃になります。
AM2320-I2C.zip
※ <>を全角<>に置き換えています。コピペの際は注意してください。
// 温湿度センサー AM2320 I2C アクセステスト
#include <Wire.h>
#define BAUDRATE 9600
#define AM2320ADDR 0x5C
// ----- Senser Data
struct AM2320_s {
uint8_t humidityH ; // 湿度の HIGH Byte
uint8_t humidityL ; // 湿度の LOW BYTE
uint8_t temperatureH; // 温度の HIGH Byte
uint8_t temperatureL; // 温度の LOW Byte
} am2320 ;
char str[120] ;
bool readAM2320( ) {
uint8_t readData[8] ;
// wake up
Wire.beginTransmission(AM2320ADDR);
Wire.write(0x00);
Wire.endTransmission();
delay(10); // wait 10 ms
Wire.beginTransmission(AM2320ADDR);
Wire.write(0x03);
Wire.write(0x00);
Wire.write(0x04);
Wire.endTransmission();
delay(2); // wait 2 ms
// 4Byte + CRC Read
Wire.requestFrom(AM2320ADDR, 8);
int len = 0 ;
while( len < 8) {
if (Wire.available() > 0) {
readData[len] = Wire.read();
len ++ ;
}
}
// ----- CRC16 -----
int readLen = 6 ;
uint16_t rCrc = readData[7] << 8 | readData[6] ;
uint16_t crc = 0xffff;
for (int i = 0; i < readLen ; i++) {
uint8_t b = readData[i];
crc ^= b;
for (int x = 0; x < 8; x++) {
if (crc & 0x0001) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
// ----- 取得データ格納 -----
am2320.humidityH = readData[2] ; // 湿度の HIGH Byte
am2320.humidityL = readData[3] ; // 湿度の LOW Byte
am2320.temperatureH = readData[4]; // 温度の HIGH Byte
am2320.temperatureL = readData[5]; // 温度の LOW Byte
return (rCrc == crc) ;
}
void setup() {
Serial.begin(BAUDRATE);
Serial.println("\nAM2320 - Read") ;
Wire.begin();
}
void loop() {
if (readAM2320( )) {
int hum = (am2320.humidityH << 8) + am2320.humidityL ;
int tem = ((am2320.temperatureH & 0x7F) << 8) + am2320.temperatureL ;
if ((am2320.temperatureH & 0x80) != 0) tem *= -1 ;
sprintf(str,"湿度:%2d.%d%% 気温:%2d.%d℃", hum / 10 , hum % 10 , tem / 10 , tem % 10) ;
Serial.println(str) ;
}
delay(3000) ;
}
温湿度計デモ
温湿度計デモ:ディスプレイにはSSD1306 または SSD1315 を使用。ボタンは数値表示/グラフ表示切替用 なのでなくても良い。
AM2320-DEMO.zip Arduino用
AM2320-DEMO-Pico.zip RaspberryPi Pico用:mbedベースのボードライブラリを想定
※メモリ容量の都合でフォントの定数定義(cont と static)が異なるだけでロジックは同じものです。)