(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(0b1011),但实际上器件是采用的7位地址,应该表述成0x5C(0b),代码中的地址也应写成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秒。

测试代码

 /*
Measurement of temperature and humidity using the AM2321 sensor
Attention:
The protocol AM2321 used is not a standard i2c.
Bit-banging is used to wake up the sensor,
and then i2c functions are used to communicate.
Connection:
AM2321 UNO
VDD <---------> 5V
GND <---------> GND
SCL <---------> SCL(A5)
SDA <---------> SDA(A4)
*/ #include <Wire.h> #define ADDRESS_AM2321 0x5C //not 0xB8
#define SIGN_WRITE 0x00
#define SDA_PIN A4
#define SCL_PIN A5 byte fuctionCode = ;
byte dataLength = ;
byte humiHigh = ;
byte humiLow = ;
byte tempHigh = ;
byte tempLow = ;
byte crcHigh = ;
byte crcLow = ; int humidity = ;
int temperature = ;
unsigned int crcCode = ; byte backupTWCR = ; void setup()
{
Serial.begin();
} void loop()
{
//step 1. wake up the sensor
SendWakeUp();
backupTWCR = TWCR; //step 2. send command
Wire.begin();
Wire.beginTransmission(ADDRESS_AM2321);
Wire.write(0x03);
Wire.write(0x00);
Wire.write(0x04);
Wire.endTransmission(); delayMicroseconds(); //step 3. read data, and recover the TWCR register
Wire.requestFrom(ADDRESS_AM2321, );
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<<) | humiLow;
temperature = (tempHigh<<) | tempLow;
crcCode = (crcHigh<<) | crcLow; Serial.print(temperature/10.0, ); Serial.println(" `C");
Serial.print(humidity/10.0, ); Serial.println(" \%RH");
CheckCRC(); //recover the TWCR register, e.g. disable the I2C bus
TWCR = backupTWCR; delay();
} void SendWakeUp()
{
//set pinmode
pinMode(SCL_PIN, OUTPUT);
pinMode(SDA_PIN, OUTPUT);
digitalWrite(SCL_PIN, HIGH);
digitalWrite(SDA_PIN, HIGH); //issue a START condition
delayMicroseconds();
digitalWrite(SDA_PIN, LOW);
delayMicroseconds();
digitalWrite(SCL_PIN, LOW);
delayMicroseconds(); //send ADDRESS+W
shiftOut(SDA_PIN, SCL_PIN, MSBFIRST, ((ADDRESS_AM2321<<) | SIGN_WRITE)); //send clock for ack
pinMode(SDA_PIN, INPUT_PULLUP);// or INPUT mode
delayMicroseconds();
digitalWrite(SCL_PIN, HIGH);
delayMicroseconds();
digitalWrite(SCL_PIN, LOW);
pinMode(SDA_PIN, OUTPUT);
digitalWrite(SDA_PIN, LOW); delayMicroseconds(); //issue a STOP condition
digitalWrite(SCL_PIN, HIGH);
delayMicroseconds();
digitalWrite(SDA_PIN, HIGH);
} void CheckCRC() //from the datesheet
{
byte backValues[] = {fuctionCode, dataLength, humiHigh, \
humiLow, tempHigh, tempLow};
unsigned int crc = 0xFFFF;
int i;
int len = ;
int j = ;
while (len--)
{
crc ^= backValues[j];
j++;
for (i=; i<; i++)
{
if (crc & 0x01)
{
crc >>= ;
crc ^= 0xA001;
}
else
{
crc >>= ;
}
}
}
if (crc == crcCode)
{
Serial.println("CRC checked.");
}
else
{
Serial.println("CRC Error!");
}
}

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

参考资料

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

Arduino I2C + 温湿度传感器AM2321的更多相关文章

  1. Arduino I2C + 温湿度传感器Si7021

      Si7021是Silicon Labs生产的温湿度传感器芯片.其主要特性: 湿度精度:误差典型值+/-2%RH,最大值+/-3%RH(0~80%RH),出厂已校正 温度精度:误差典型值+/-0.3 ...

  2. Arduino I2C + 温湿度传感器HTS221

    主要特性 HTS221是意法半导体(STMicroelectronics)生产的小体积.数字式温湿度传感器IC.该IC目前在官网仍处在“评估”状态.其主要特性: 工作电压:1.7~3.6V 数据输出频 ...

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

    AM2321是采用I2C总线或单总线通讯的国产温湿度传感器.在AM2321手册中,当采用I2C通讯时,手册指定了多处需要主机等待的时间间隔,包括: (1)唤醒传感器时,从机不回复ACK,但主机主要等待 ...

  4. Arduino和C51开发DHT11温湿度传感器

    技术:51单片机.Arduino.DHT11.温湿度传感器.传感器   概述 学习单片机离不开对传感器的学习,本文主要介绍DHT11温湿度传感器的使用方法,同学也可以了解更多的传感器,这对你以后开发产 ...

  5. Arduino连接SHT10温湿度传感器--返回值不正常解决办法

    如题目,arduino中连接温湿度传感器,用的是一个github开源项目,地址:点击打开,其实这个就是一个封装好的库,下载后把解压的文件夹复制到Arduino目录下的librarys文件夹内,重启Ar ...

  6. 基于I2C的AHT20温湿度传感器的数据采集

    关于:IC( Inter-- Integrated Circuit)总线是一种由 PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备.它是由数据线SDA和时钟SCL构成的串行总线,可 ...

  7. DH11数字温湿度传感器

    DH11数字温湿度传感器是一种集温度.湿度一体的复合传感器,它能把温度和湿度物理量通过温.湿度敏感元件和相应电路转化成方便计算机.PLC.智能仪表等数据采集设备直接读取的数字量.DHT11由电阻式感湿 ...

  8. STM32应用实例五:与SHT1X温湿度传感器通讯

    在这次项目开发中应用到了SHT1X温湿度传感器,该系列有SHT10.SHT11和SHT15,属于Sersirion温湿度传感器家族中的贴片封装系列.包括一个电容性聚合体测湿敏感元件.一个用能隙材料制成 ...

  9. 进阶之路(中级篇) - 016 温湿度传感器DHT11

    如果想使用 Arduino 开发板驱动 DHT11 来获取温湿度的时候建议使用第三方的库,这样可以加快程序的开发速度,而且不容易出错,下面的代码我已经安转了第三方的库了.详细的安装方法请参考极客先锋的 ...

随机推荐

  1. G++ 4.4.7 无法编译模板程序,Vs可以,和解?智者尾部留言,本人第一次使用vs pro,通常并且习惯在linux下写些小东西,虽然程序简单;

    vs 模板编译运行Ok \ linux g++ 4.4.7编译模板测试程序,报无法定义 template <typename or class 中的 AnyType> 类型的数据 Exam ...

  2. vue组件重新加载(刷新)

    vue组件重新加载(刷新) 第一种方法:利用v-if控制router-view,在根组件APP.vue中实现一个刷新方法 <template> <router-view v-if=& ...

  3. directshow 虚拟摄像头 实例 代码解读

    directshow 虚拟摄像头 实例 代码解读 本文只介绍这个源码的大致构成以及怎么修改,因为其他的我也不会啊哈哈哈,我就是用QQ调用虚拟摄像头读取我自己的视频或者图片播放给别人让别人以为这就是实时 ...

  4. centos7+tomcat部署JavaWeb项目超详细步骤

    我们平时访问的网站大多都是发布在云服务器上的,比如阿里云.腾讯云等.对于新手,尤其是没有接触过linux系统的人而言是比较有困难的,而且至今使用云服务器也是有成本的,很多时候我们可以通过虚拟机自己搭建 ...

  5. jquery中ready函数,$(function(){})与自执行函数的区别

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  6. Excel VBA入门(七)注释、宏按钮及错误处理

    系统性的知识前面已经讲完,从本章开始,本系列教程涉及的将会是一些相对凌散的内容. 1. 注释 代码注释是一件利人利己的事,为了方便自己在代码需要更新修改时,依然能够快速地看懂自己完的每一行代码到底是什 ...

  7. C#根据url生成唯一的key

    根据url生成唯一的idkey,记录并分享: public class UrlToUniqueKey { ); , ] { { 0L, 0L }, { -4611686018427387904L, - ...

  8. K.O. ----- 配置文件没有提示

    ---------------siwuxie095 K.O. ----- 配置文件没有提示 1.解决方法一:联网 只要 PC 联网,配置文件中就有提示 2.解决方法二:手动导入约束文件 约束文件:hi ...

  9. java-tip-Collections.synchronized系列生成的容器

    这个系列的容器,和Vector或者HashTable之流的差不多, 区别是: Vector和HashTable是在关键方法上加synchronized关键字 而 Collections.synchro ...

  10. Java-精确计算工具类

    import java.math.BigDecimal; import java.math.RoundingMode; /** * 精确计算工具类(加,减,乘,除,返回较大值,返回较小值) */ pu ...