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供電下測試,都可以正常讀寫。
測試代碼

1 /* 2 Measurement of temperature and humidity using the AM2321 sensor 3 Attention: 4 Use functions in Wire library to wake up the sensor. 5 Although the sequence is different with the datasheet, it indeed works. 6 Connection: 7 AM2321 UNO 8 VDD <---------> 5V 9 GND <---------> GND 10 SCL <---------> SCL(A5) 11 SDA <---------> SDA(A4) 12 */ 13 14 #include <Wire.h> 15 16 #define ADDRESS_AM2321 0x5C //not 0xB8 17 #define SDA_PIN A4 18 #define SCL_PIN A5 19 20 byte fuctionCode = 0; 21 byte dataLength = 0; 22 byte humiHigh = 0; 23 byte humiLow = 0; 24 byte tempHigh = 0; 25 byte tempLow = 0; 26 byte crcHigh = 0; 27 byte crcLow = 0; 28 29 int humidity = 0; 30 int temperature = 0; 31 unsigned int crcCode = 0; 32 33 void setup() 34 { 35 Wire.begin(); 36 Serial.begin(115200); 37 } 38 39 void loop() 40 { 41 //step 1. wake up the sensor 42 Wire.beginTransmission(ADDRESS_AM2321); 43 Wire.endTransmission(); 44 45 delayMicroseconds(800); 46 47 //step 2. send command 48 Wire.beginTransmission(ADDRESS_AM2321); 49 Wire.write(0x03); 50 Wire.write(0x00); 51 Wire.write(0x04); 52 Wire.endTransmission(); 53 54 delayMicroseconds(1500); 55 56 //step 3. read data 57 Wire.requestFrom(ADDRESS_AM2321, 8); 58 fuctionCode = Wire.read(); 59 dataLength = Wire.read(); 60 humiHigh = Wire.read(); 61 humiLow = Wire.read(); 62 tempHigh = Wire.read(); 63 tempLow = Wire.read(); 64 crcLow = Wire.read(); 65 crcHigh = Wire.read(); 66 67 //get the result 68 humidity = (humiHigh<<8) | humiLow; 69 temperature = (tempHigh<<8) | tempLow; 70 crcCode = (crcHigh<<8) | crcLow; 71 72 Serial.print(temperature/10.0, 1); Serial.println(" `C"); 73 Serial.print(humidity/10.0, 1); Serial.println(" \%RH"); 74 CheckCRC(); 75 76 delay(4000); 77 } 78 79 void CheckCRC() //from the datesheet 80 { 81 byte backValues[] = {fuctionCode, dataLength, humiHigh, \ 82 humiLow, tempHigh, tempLow}; 83 unsigned int crc = 0xFFFF; 84 int i; 85 int len = 6; 86 int j = 0; 87 while (len--) 88 { 89 crc ^= backValues[j]; 90 j++; 91 for (i=0; i<8; i++) 92 { 93 if (crc & 0x01) 94 { 95 crc >>= 1; 96 crc ^= 0xA001; 97 } 98 else 99 { 100 crc >>= 1; 101 } 102 } 103 } 104 if (crc == crcCode) 105 { 106 Serial.println("CRC checked."); 107 } 108 else 109 { 110 Serial.println("CRC Error!"); 111 } 112 }
器件介紹、電路連接可參見之前的日志。