使用Arduino Wire Library读取温湿度传感器AM2321#

AM2321是采用I2C总线或单总线通讯的国产温湿度传感器。在AM2321手册中,当采用I2C通讯时,手册指定了多处需要主机等待的时间间隔,包括:

(1)唤醒传感器时,从机不回复ACK,但主机主要等待800us~3ms再发送STOP信号;

(2)主机发送读/写指令后,需等待至少1.5ms再发送读取时序;

(3)读返回数据时,主机发送I2C地址后,需等待至少30us以上才能发送下一个串行时钟。

由于Arduino标准库Wire中的函数不支持指定(1)和(3)中的等待间隔,因此在之前的日志中,采用关闭I2C并采用bit-banging的方式唤醒传感器。

然而,就我手头的传感器测试发现,即使(3)的等待时间降低到10us左右(即100kHz速率正常通讯),并且将(1)改成“发送STOP信号后等待800us”,器件也是可以正常工作的。

这样的话,利用Wire库自带的函数,就可以实现对AM2321的操作。我利用手头的传感器分别在5V和3.3V供电下测试,都可以正常读写。

测试代码#

/*
Measurement of temperature and humidity using the AM2321 sensor
Attention:
    Use functions in Wire library to wake up the sensor.
    Although the sequence is different with the datasheet, it indeed works.
Connection:
AM2321           UNO
VDD <--------->  5V
GND <--------->  GND
SCL <---------> SCL(A5)
SDA <---------> SDA(A4)
*/

#include <Wire.h>

#define ADDRESS_AM2321 0x5C //not 0xB8
#define SDA_PIN A4
#define SCL_PIN A5

byte fuctionCode = 0;
byte dataLength = 0;
byte humiHigh = 0;
byte humiLow = 0;
byte tempHigh = 0;
byte tempLow = 0;
byte crcHigh = 0;
byte crcLow = 0;

int humidity = 0;
int temperature = 0;
unsigned int crcCode = 0;

void setup()
{
    Wire.begin();
    Serial.begin(115200);
}

void loop()
{
    //step 1. wake up the sensor
    Wire.beginTransmission(ADDRESS_AM2321);
    Wire.endTransmission();

    delayMicroseconds(800);

    //step 2. send command
    Wire.beginTransmission(ADDRESS_AM2321);
    Wire.write(0x03);
    Wire.write(0x00);
    Wire.write(0x04);
    Wire.endTransmission();

    delayMicroseconds(1500);

    //step 3. read data
    Wire.requestFrom(ADDRESS_AM2321, 8);
    fuctionCode = Wire.read();
    dataLength = Wire.read();
    humiHigh = Wire.read();
    humiLow = Wire.read();
    tempHigh = Wire.read();
    tempLow = Wire.read();
    crcLow = Wire.read();
    crcHigh = Wire.read();

    //get the result
    humidity = (humiHigh<<8) | humiLow;
    temperature = (tempHigh<<8) | tempLow;
    crcCode = (crcHigh<<8) | crcLow;

    Serial.print(temperature/10.0, 1);    Serial.println(" `C");
    Serial.print(humidity/10.0, 1);    Serial.println(" \%RH");
    CheckCRC();

    delay(4000);
}

void CheckCRC() //from the datesheet
{
    byte backValues[] = {fuctionCode, dataLength, humiHigh, \
        humiLow, tempHigh, tempLow};
    unsigned int crc = 0xFFFF;
    int i;
    int len = 6;
    int j = 0;
    while (len--)
    {
        crc ^= backValues[j];
        j++;
        for (i=0; i<8; i++)
        {
            if (crc & 0x01)
            {
                crc >>= 1;
                crc ^= 0xA001;
            }
            else
            {
                crc >>= 1;
            }
        }
    }
    if (crc == crcCode)
    {
        Serial.println("CRC checked.");
    }
    else
    {
        Serial.println("CRC Error!");
    }
}

器件介绍、电路连接可参见之前的日志