AM2320: negative temperature fix... (#312)

* switched the library, now uses a library which correctly handles negative temperatures

* minor change
This commit is contained in:
krikk
2017-05-27 17:55:13 +02:00
committed by DatuX
parent a8e39b1899
commit 1cefa5eb1b
8 changed files with 121 additions and 520 deletions
-2
View File
@@ -1,2 +0,0 @@
.DS_Store
+53 -124
View File
@@ -1,130 +1,59 @@
/**
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Copyright 2016 Ratthanan Nalintasnai
**/
#include "AM2320.h"
#include <Wire.h>
//
// AM2321 Temperature & Humidity Sensor library for Arduino
// Сделана Тимофеевым Е.Н. из AM2320-master
AM2320::AM2320() {
// do nothing
unsigned int CRC16(byte *ptr, byte length)
{
unsigned int crc = 0xFFFF;
uint8_t s = 0x00;
while(length--) {
crc ^= *ptr++;
for(s = 0; s < 8; s++) {
if((crc & 0x01) != 0) {
crc >>= 1;
crc ^= 0xA001;
} else crc >>= 1;
}
}
return crc;
}
AM2320::AM2320()
{
}
void AM2320::begin() {
Wire.begin();
int AM2320::Read()
{
byte buf[8];
for(int s = 0; s < 8; s++) buf[s] = 0x00;
Wire.beginTransmission(AM2320_address);
Wire.endTransmission();
// запрос 4 байт (температуры и влажности)
Wire.beginTransmission(AM2320_address);
Wire.write(0x03);// запрос
Wire.write(0x00); // с 0-го адреса
Wire.write(0x04); // 4 байта
if (Wire.endTransmission(1) != 0) return 1;
delayMicroseconds(1600); //>1.5ms
// считываем результаты запроса
Wire.requestFrom(AM2320_address, 0x08);
for (int i = 0; i < 0x08; i++) buf[i] = Wire.read();
// CRC check
unsigned int Rcrc = buf[7] << 8;
Rcrc += buf[6];
if (Rcrc == CRC16(buf, 6)) {
unsigned int temperature = ((buf[4] & 0x7F) << 8) + buf[5];
t = temperature / 10.0;
t = ((buf[4] & 0x80) >> 7) == 1 ? t * (-1) : t;
unsigned int humidity = (buf[2] << 8) + buf[3];
h = humidity / 10.0;
return 0;
}
return 2;
}
#ifdef ESP8266
void AM2320::begin(int sda, int scl) {
Wire.begin(sda, scl);
}
#endif
float AM2320::getTemperature() {
return _temperature;
}
float AM2320::getHumidity() {
return _humidity;
}
bool AM2320::measure() {
_errorCode = 0;
if ( ! _read_registers(0x00, 4)) {
_errorCode = 1;
return false;
}
unsigned int receivedCrc = 0; // allocate 16 bits for storing crc from sensor
receivedCrc = ((receivedCrc | _buf[7]) << 8 | _buf[6]); // pack high and low byte together
if (receivedCrc == crc16(_buf, 6)) {
int humudity = ((_buf[2] << 8) | _buf[3]);
_humidity = humudity / 10.0;
int temperature = ((_buf[4] & 0x7F) << 8) | _buf[5];
if ((_buf[2] & 0x80) >> 8 == 1) { // negative temperature
_temperature = (temperature / 10.0) * -1; // devide data by 10 according to the datasheet
}
else { // positive temperature
_temperature = temperature / 10.0; // devide data by 10 according to the datasheet
}
return true;
}
else {
_errorCode = 2;
return false;
}
}
int AM2320::getErrorCode() {
return _errorCode;
}
bool AM2320::_read_registers(int startAddress, int numByte) {
_wake(); // wake up sensor
Wire.beginTransmission(AM2320_ADDR);
Wire.write(0x03); // function code: 0x03 - read register data
Wire.write(startAddress); // begin address
Wire.write(numByte); // number of bytes to read
// send and check result if not success, return error code
if (Wire.endTransmission(true) != 0) {
return false; // return sensor not ready code
}
delayMicroseconds(1500); // as specified in datasheet
Wire.requestFrom(AM2320_ADDR, numByte + 4); // request bytes from sensor
// see function code description in datasheet
for ( int i = 0; i < numByte + 4; i++) { // read
_buf[i] = Wire.read();
}
return true;
}
void AM2320::_wake() {
Wire.beginTransmission(AM2320_ADDR);
Wire.endTransmission();
}
unsigned int crc16(byte *byte, unsigned int numByte) {
unsigned int crc = 0xFFFF; // 16-bit crc register
while (numByte > 0) { // loop until process all bytes
crc ^= *byte; // exclusive-or crc with first byte
for (int i = 0; i < 8; i++) { // perform 8 shifts
unsigned int lsb = crc & 0x01; // extract LSB from crc
crc >>= 1; // shift be one position to the right
if (lsb == 0) { // LSB is 0
continue; // repete the process
}
else { // LSB is 1
crc ^= 0xA001; // exclusive-or with 1010 0000 0000 0001
}
}
numByte--; // decrement number of byte left to be processed
byte++; // move to next byte
}
return crc;
}
+11 -57
View File
@@ -1,63 +1,17 @@
/**
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Copyright 2016 Ratthanan Nalintasnai
**/
#ifndef AM2303_H
#define AM2303_H
#ifndef AM2320_H
#define AM2320_H
#include <Arduino.h>
// address of AM2320
#define AM2320_ADDR 0x5C
// maximum number of bytes that can be read consequtively before
// sensor splits out error
#define MAX_BYTES_READ 10
class AM2320 {
public:
AM2320();
// initialize AM2320
void begin();
// initialize AM2320 for ESP8266 (ESP-01) which requires manual
// specification of sda and scl pins
#ifdef ESP8266
void begin(int sda, int scl);
#endif
bool measure();
float getTemperature();
float getHumidity();
int getErrorCode();
private:
byte _buf[ MAX_BYTES_READ ];
float _temperature;
float _humidity;
int _errorCode;
void _wake();
bool _read_registers(int startAddress, int numByte);
#define AM2320_address (0xB8 >> 1)
class AM2320
{
public:
AM2320();
float t;
float h;
int Read(void);
};
// compute CRC16
unsigned int crc16(byte *byte, unsigned int numByte);
#endif
#endif
-250
View File
@@ -1,250 +0,0 @@
# AM2320
Arduino library for Aosong AM2320 temperature and humidity sensor.
# Downloads
[Latest Version](https://github.com/hibikiledo/AM2320/releases)
# API Reference
## Constructor
A constructor should be called first. This is where you can obtain a variable of the sensor library.
### Signature
```cpp
AM2320();
```
### Parameters
None
### Usage Example
```cpp
#include "AM2320.h"
// create a variable of sensor library
AM2320 sensor;
```
---
## Initialize the sensor
This should be called once in `void setup()` of an Arduino sketch.
### Signature
```cpp
void begin(void);
```
### Parameters
None
### Return Value
None
### Usage Example
```cpp
#include "AM2320.h"
AM2320 sensor;
void setup() {
// initialize sensor library
sensor.begin();
}
void loop() {
}
```
---
## Initialize the sensor with specific SDA and SCL pin numbers
Same as [Initialize the sensor](#initialize-the-sensor) with support for ESP8266 Arduino core.
This is useful on ESP-01 where SDA and SCL pins aren't default ones.
### Signature
```cpp
void begin(int sda, int scl);
```
### Parameters
- `int sda` - pin number of sda line of I<sup>2</sup>C bus
- `int scl` - pin number of scl line of I<sup>2</sup>C bus
### Return Value
None
#### Example
```cpp
#include "AM2320.h"
AM2320 sensor;
void setup() {
// initialize sensor library with SDA and SCL pins
// https://github.com/esp8266/Arduino/blob/master/doc/libraries.md#i2c-wire-library
sensor.begin(0, 2);
}
void loop() {
}
```
---
## Measure temperature and humidity (%RH)
Tell sensor to perform both temperature and humidity acquisitions.
### Signature
```cpp
bool measure();
```
### Parameters
None
### Return Value
- `true` - the operation is successful
- `false` - an error occurs. use `getErrorCode()` to get an error code. [More info](#error-codes)
### Usage Example
You are encouraged to check a returned value of `measure()`.
Chances are that the call to `measure()` hits the sensor when it is sleeping.
This is normal behavior of AM2320 to prevent measurement errors from self-heating.
By checking the returned value, you can decide what to do.
See [**Example**](#example)
---
## Get the temperature
Retrieve the latest temperature measurement from the call to `measure()`
### Signature
```cpp
float getTemperature();
```
### Parameters
None
### Return Value
Floating point number representing the temperature in degree celcius.
### Usage Example
See [**Example**](#example)
---
## Get the humidity
Retrieve the latest humudity measurement from the call to `measure()`
### Signature
```cpp
float getHumidity();
```
### Parameters
None
### Return Value
Floating point number representing the humudity in % RH (Relative Humidity).
### Usage Example
See [**Example**](#example)
---
## Get error code
Retrieve the error code of latest call to `measure()`. Error code provides more detail on the errors.
### Signature
```cpp
int getErrorCode();
```
#### Summary
Return error code from latest operation.
#### Parameters
None
#### Return Value
Integer representing an error code. [More info](#error-codes)
### Usage Example
See [**Example**](#example)
# Error Codes
### Code 0
**This indicates no error.** Everything works fine.
### Code 1
**Sensor is offline.** This happens when Arduino cannot connect to the sensor.
If this happens all the time from call to `measure()`. It is likely the the sensor is connected incorrectly or
the sensor does not functional properly.
If this happens occasionally, It is possible that the call to `measure()` hits the sensor when it is sleeping.
Try to slow down the call to `measure()`.
### Code 2
**CRC validation failed.** This happends when data transmitted from the sensor is received with errors.
Possible causes may be bad connections, lengthy cable, etc.
# Example
```cpp
// Include library into the sketch
#include <AM2320.h>
// Create an instance of sensor
AM2320 sensor;
void setup() {
// enable serial communication
// Include library into the sketch
#include <AM2320.h>
// Create an instance of sensor
AM2320 sensor;
void setup() {
// enable serial communication
Serial.begin(115200);
// call sensor.begin() to initialize the library
sensor.begin();
}
void loop() {
// sensor.measure() returns boolean value
// - true indicates measurement is completed and success
// - false indicates that either sensor is not ready or crc validation failed
// use getErrorCode() to check for cause of error.
if (sensor.measure()) {
Serial.print("Temperature: ");
Serial.println(sensor.getTemperature());
Serial.print("Humidity: ");
Serial.println(sensor.getHumidity());
}
else { // error has occured
int errorCode = sensor.getErrorCode();
switch (errorCode) {
case 1: Serial.println("ERR: Sensor is offline"); break;
case 2: Serial.println("ERR: CRC validation failed."); break;
}
}
delay(500);
}
```
# Contributions
Open an issue if something doesn't work right. Submit pull request if you want to improve someting.
# The Story
I wrote blog posts about the process of writing this library. You can find it here.
[Part 1](https://hibikiledo.xyz/2016/11/04/writing-am2320-arduino-library-1/)
Part 2 .. working on it
@@ -0,0 +1,29 @@
#include <Wire.h>
#include <AM2320.h>
AM2320 th;
void setup() {
Serial.begin(9600);
Wire.begin();
}
void loop() {
switch(th.Read()) {
case 2:
Serial.println("CRC failed");
break;
case 1:
Serial.println("Sensor offline");
break;
case 0:
Serial.print("humidity: ");
Serial.print(th.h);
Serial.print("%, temperature: ");
Serial.print(th.t);
Serial.println("*C");
break;
}
delay(200);
}
@@ -1,52 +0,0 @@
/**
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Copyright 2016 Ratthanan Nalintasnai
**/
// Include library into the sketch
#include <AM2320.h>
// Create an instance of sensor
AM2320 sensor;
void setup() {
// enable serial communication
Serial.begin(115200);
// call sensor.begin() to initialize the library
sensor.begin();
}
void loop() {
// sensor.measure() returns boolean value
// - true indicates measurement is completed and success
// - false indicates that either sensor is not ready or crc validation failed
// use getErrorCode() to check for cause of error.
if (sensor.measure()) {
Serial.print("Temperature: ");
Serial.println(sensor.getTemperature());
Serial.print("Humidity: ");
Serial.println(sensor.getHumidity());
}
else { // error has occured
int errorCode = sensor.getErrorCode();
switch (errorCode) {
case 1: Serial.println("ERR: Sensor is offline"); break;
case 2: Serial.println("ERR: CRC validation failed."); break;
}
}
delay(500);
}
+4 -7
View File
@@ -1,7 +1,4 @@
AM2320 KEYWORD1
begin KEYWORD2
measure KEYWORD2
measureTemperature KEYWORD2
measureHumidity KEYWORD2
getTemperature KEYWORD2
getHumidity KEYWORD2
AM2320 KEYWORD1
getTemperature KEYWORD2
getHumidity KEYWORD2
CRCCheck KEYWORD2
+24 -28
View File
@@ -4,8 +4,9 @@
//
// Temperature and Humidity Sensor AM2320
// written by https://github.com/krikk
// based on this library: https://github.com/hibikiledo/AM2320
// this code is based on version 1.0 of the above library
// based on this library: https://github.com/thakshak/AM2320
// this code is based on git-version https://github.com/thakshak/AM2320/commit/ddaabaf37952d4c74f3ea70af20e5a95cfdfcadb
// of the above library
//
#ifdef PLUGIN_BUILD_TESTING
@@ -70,35 +71,30 @@ boolean Plugin_051(byte function, struct EventStruct *event, String& string)
case PLUGIN_READ:
{
AM2320 sensor;
sensor.begin(Settings.Pin_i2c_sda, Settings.Pin_i2c_scl);
AM2320 th;
// sensor.measure() returns boolean value
// - true indicates measurement is completed and success
// - false indicates that either sensor is not ready or crc validation failed
// use getErrorCode() to check for cause of error.
if (sensor.measure()) {
UserVar[event->BaseVarIndex] = sensor.getTemperature();
UserVar[event->BaseVarIndex + 1] = sensor.getHumidity();
switch(th.Read()) {
case 2:
addLog(LOG_LEVEL_ERROR, F("AM2320: CRC failed"));
break;
case 1:
addLog(LOG_LEVEL_ERROR, F("AM2320: Sensor offline"));
break;
case 0:
UserVar[event->BaseVarIndex] = th.t;
UserVar[event->BaseVarIndex + 1] = th.h;
String log = F("AM2320: Temperature: ");
log += UserVar[event->BaseVarIndex];
addLog(LOG_LEVEL_INFO, log);
log = F("AM2320: Humidity: ");
log += UserVar[event->BaseVarIndex + 1];
addLog(LOG_LEVEL_INFO, log);
success = true;
break;
}
else { // error has occured
int errorCode = sensor.getErrorCode();
switch (errorCode) {
case 1: addLog(LOG_LEVEL_ERROR, F("AM2320: Sensor is offline")); break;
case 2: addLog(LOG_LEVEL_ERROR, F("AM2320: CRC validation failed.")); break;
}
success = false;
break;
String log = F("AM2320: Temperature: ");
log += UserVar[event->BaseVarIndex];
addLog(LOG_LEVEL_INFO, log);
log = F("AM2320: Humidity: ");
log += UserVar[event->BaseVarIndex + 1];
addLog(LOG_LEVEL_INFO, log);
success = true;
break;
}
}
}
return success;