• Arduino I2C + 温湿度传感器AM2321


    (2015.5.17:本日志的内容有所更新,参见《使用Arduino Wire Library读取温湿度传感器AM2321》。)

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

    • 尺寸:11.3x7.8x4mm(长x宽x高)
    • 封装:0.05 pitch PTH
    • 工作电压:2.6~5V
    • 功耗:测量时0.5mA,休眠状态10μA
    • 接口: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)读取,没有发现有通信错误的问题。

    5. 传感器发送数据之后,会触发下一次温湿度测量,测量结果供下次数据读取。因此连续读取两次才能获得当前的温湿度值,即:第一次读取的是上一次测量的值,第二次读取的才是当前测量值。两次读取的最小间隔为2秒。

    测试代码

      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 <--------->  5V
     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, e.g. disable the I2C bus
     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+W
    100     shiftOut(SDA_PIN, SCL_PIN, MSBFIRST, ((ADDRESS_AM2321<<1) | SIGN_WRITE));
    101 
    102     //send clock for ack
    103     pinMode(SDA_PIN, INPUT_PULLUP);// or INPUT mode
    104     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 condition
    114     digitalWrite(SCL_PIN, HIGH);
    115     delayMicroseconds(5);
    116     digitalWrite(SDA_PIN, HIGH);
    117 }
    118 
    119 void CheckCRC() //from the datesheet
    120 {
    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             else
    139             {
    140                 crc >>= 1;
    141             }
    142         }
    143     } 
    144     if (crc == crcCode)
    145     {
    146         Serial.println("CRC checked.");
    147     }
    148     else
    149     {
    150         Serial.println("CRC Error!");
    151     }
    152 }
    View Code

     [注] 后面发现,第一步唤醒时即使直接用Wire库中的beginTransmission()和endTransmission()函数即可,即使没有手册中要求的0.8~3ms等待时间,传感器也能正常运行。从示波器上看,传感器不回ACK,硬件I2C等待的时间仅10us左右,却不影响工作。看来手册的描述有问题。使用Wire Library标准库来读取AM2321,可以参照另一篇日志

    参考资料

    奥松官网信息 - AM2321数字温湿度传感器
    TI - Troubleshooting I2C Bus Protocol 关于I2C调试问题处理的文档,推荐
    拆解国产奥松微小型湿度传感器AM2321
    wangdong/AM2321 - GitHub

  • 相关阅读:
    cocos2dx 解释二具体的启动过程:内存管理和回调
    允许Android随着屏幕转动的控制自由转移到任何地方(附demo)
    freemarker 空白处理
    采用Duplicate target database在线恢复秩序oracle datagard图书馆设备
    activiti入门2流程引擎API和服务基础设施
    【android】ImageView的src和background以及两者之间的神奇的差异
    HDU ACM 1007 Quoit Design 分而治之的方法,最近点
    Dynamics CRM2013/2015 禁止欢迎屏幕(Disable the Welcome Screen)
    2013年第42周二明智行动的艺术
    2013第42周一睡前
  • 原文地址:https://www.cnblogs.com/zlbg/p/4177059.html
Copyright © 2020-2023  润新知