首页 > 代码库 > Arduino调试温湿度传感器AM2321

Arduino调试温湿度传感器AM2321

AM2321是广州奥松电子生产的数字式温湿度传感器。虽是国产品牌,其精度也可以与国外的主流温湿度传感IC媲美。

技术分享

  • 尺寸:11.3x7.8x4mm(长x宽x高)
  • 封装:0.05 pitch PTH
  • 工作电压:2.6~5V
  • 接口:I2C,最大速率100kbps,有特殊时序要求
  • 分辨率:温度0.1°C,相对湿度0.1%RH
  • 精度:室温时温度误差+/-0.3°C,相对湿度误差+/-3%RH
  • 重复性:温度+/-0.2°C,相对湿度+/-0.1%RH

美中不足:与国外同精度产品相比,AM2321的重复性和漂移指标偏大;只能手动焊接,量产时会很不方便。

电路连接

AM2321支持5V工作,将电源、地、SCL、SDA四个管脚直接与UNO板子的对应管脚相连。对于Arduino UNO,I2C总线的SDA信号线对应A4管脚,SCL时钟线对应A5管脚。之后,SCL、SDA线需要通过上拉电阻连接到5V电源,电阻值可取4.7k或10k。

 技术分享

功能调试

第一次调试花了不少时间,最终借助示波器才搞定。需留意的几个问题:

1. I2C地址问题。虽然手册里写的地址是0xB8(0b10111000),但实际上器件是采用的7位地址,应该表述成0x5C(0b1011100),代码中的地址也应写成0x5C,否则无法通信。

2. 唤醒AM2321时的时序问题。器件不回ACK,且最后一个时钟下降沿到发stop信号需间隔0.8~3ms。这个时序条件在Arduino的Wire库中没有处理的函数,因此只能将A4、A5设置成GPIO,利用bit-banging实现。shiftOut()函数可以实现字节的串行输出,且速率刚好也是100kbps左右。

3. A4、A5管脚在GPIO和硬件I2C之间的功能切换问题。在调用的Wire.begin()函数之后,再使用pinMode()或digitalWrite()函数就无效了。发现在Wire.begin()函数中设置了I2C的控制寄存器TWCR,需将TWCR恢复到调用Wire.begin()前的状态,才可以用GPIO的方式操作A4、A5。

4. 读返回数据时的时序问题。手册要求发送地址后,需要等待至少30μs后才能读取数据。这个功能在Wire库里也不支持,但直接用库里的函数(间隔约10μs)读取,没有发现有通信错误的问题。

参考代码:

  1 /*  2 Measurement of temperature and humidity using the AM2321 sensor  3 Attention:   4     The protocol AM2321 used is not a standard i2c.  5     Bit-banging is used to wake up the sensor,   6     and then i2c functions are used to communicate.  7 Connection:  8 AM2321             UNO  9 VDD <---------->   GND 10 GND <---------->   GND 11 SCL <----------> SCL(A5) 12 SDA <----------> SDA(A4) 13 */ 14  15 #include <Wire.h> 16  17 #define ADDRESS_AM2321 0x5C //not 0xB8 18 #define SIGN_WRITE 0x00 19 #define SDA_PIN A4 20 #define SCL_PIN A5 21  22 byte fuctionCode = 0; 23 byte dataLength = 0; 24 byte humiHigh = 0; 25 byte humiLow = 0; 26 byte tempHigh = 0; 27 byte tempLow = 0; 28 byte crcHigh = 0; 29 byte crcLow = 0; 30  31 int humidity = 0; 32 int temperature = 0; 33 unsigned int crcCode = 0; 34  35 byte backupTWCR = 0; 36  37 void setup() 38 { 39     Serial.begin(115200); 40 } 41  42 void loop() 43 { 44     //step 1. wake up the sensor 45     SendWakeUp();  46     backupTWCR = TWCR; 47  48     //step 2. send command  49     Wire.begin(); 50     Wire.beginTransmission(ADDRESS_AM2321); 51     Wire.write(0x03); 52     Wire.write(0x00); 53     Wire.write(0x04); 54     Wire.endTransmission(); 55  56     delayMicroseconds(1500); 57  58     //step 3. read data, and recover the TWCR register 59     Wire.requestFrom(ADDRESS_AM2321, 8); 60     fuctionCode = Wire.read(); 61     dataLength = Wire.read(); 62     humiHigh = Wire.read(); 63     humiLow = Wire.read(); 64     tempHigh = Wire.read(); 65     tempLow = Wire.read(); 66     crcLow = Wire.read(); 67     crcHigh = Wire.read(); 68  69     //get the result 70     humidity = (humiHigh<<8) | humiLow; 71     temperature = (tempHigh<<8) | tempLow; 72     crcCode = (crcHigh<<8) | crcLow; 73  74     Serial.print(temperature/10.0, 1);    Serial.println(" `C"); 75     Serial.print(humidity/10.0, 1);    Serial.println(" \%RH"); 76     CheckCRC(); 77  78     //recover the TWCR register 79     TWCR = backupTWCR;  80  81     delay(4000); 82 } 83  84 void SendWakeUp() 85 { 86     //set pinmode 87     pinMode(SCL_PIN, OUTPUT); 88     pinMode(SDA_PIN, OUTPUT); 89     digitalWrite(SCL_PIN, HIGH); 90     digitalWrite(SDA_PIN, HIGH); 91  92     //issue a START condition 93     delayMicroseconds(5); 94     digitalWrite(SDA_PIN, LOW);  95     delayMicroseconds(5); 96     digitalWrite(SCL_PIN, LOW);  97     delayMicroseconds(5); 98  99     //send ADDRESS+W100     shiftOut(SDA_PIN, SCL_PIN, MSBFIRST, ((ADDRESS_AM2321<<1) | SIGN_WRITE));101 102     //send clock for ack103     pinMode(SDA_PIN, INPUT_PULLUP);// or INPUT mode104     delayMicroseconds(5);105     digitalWrite(SCL_PIN, HIGH);106     delayMicroseconds(5);107     digitalWrite(SCL_PIN, LOW);108     pinMode(SDA_PIN, OUTPUT);109     digitalWrite(SDA_PIN, LOW);110     111     delayMicroseconds(1000);112 113     //issue a STOP condition114     digitalWrite(SCL_PIN, HIGH);115     delayMicroseconds(5);116     digitalWrite(SDA_PIN, HIGH);117 }118 119 void CheckCRC() //from the datesheet120 {121     byte backValues[] = {fuctionCode, dataLength, humiHigh, 122         humiLow, tempHigh, tempLow};123     unsigned int crc = 0xFFFF;124     int i;125     int len = 6;126     int j = 0;127     while (len--)128     {129         crc ^= backValues[j];130         j++;131         for (i=0; i<8; i++)132         {133             if (crc & 0x01)134             {135                 crc >>= 1;136                 crc ^= 0xA001;137             }138             else139             {140                 crc >>= 1;141             }142         }143     } 144     if (crc == crcCode)145     {146         Serial.println("CRC checked.");147     }148     else149     {150         Serial.println("CRC Error!");151     }152 }

 

参考资料

奥松官网信息 - AM2321数字温湿度传感器
TI - Troubleshooting I2C Bus Protocol 关于I2C调试问题处理的文档,推荐

Arduino调试温湿度传感器AM2321