Last active
February 20, 2022 19:16
-
-
Save samm-git/61f137640a228fe9dcf97032c4935708 to your computer and use it in GitHub Desktop.
Reading AM2320 sensor value under FreeBSD
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <sys/ioctl.h> | |
#include <fcntl.h> | |
#include <unistd.h> | |
#include <stdint.h> | |
#include <dev/iicbus/iic.h> | |
#define I2C_DEVICE "/dev/iic0" | |
#define AM2320_ADDR 0x5C | |
static uint16_t | |
_calc_crc16(const uint8_t *buf, size_t len) { | |
uint16_t crc = 0xFFFF; | |
while(len--) { | |
crc ^= (uint16_t) *buf++; | |
for (unsigned i = 0; i < 8; i++) { | |
if (crc & 0x0001) { | |
crc >>= 1; | |
crc ^= 0xA001; | |
} else { | |
crc >>= 1; | |
} | |
} | |
} | |
return crc; | |
} | |
static uint16_t | |
_combine_bytes(uint8_t msb, uint8_t lsb) | |
{ | |
return ((uint16_t)msb << 8) | (uint16_t)lsb; | |
} | |
static int | |
write_bytes(int fd, int slave, int len, uint8_t *buf) | |
{ | |
struct iic_msg msg[2]; | |
struct iic_rdwr_data rdwr; | |
msg[0].slave = slave << 1; | |
msg[0].flags = IIC_M_WR; | |
msg[0].len = len; | |
msg[0].buf = buf; | |
rdwr.msgs = msg; | |
rdwr.nmsgs = 1; | |
return (ioctl(fd, I2CRDWR, &rdwr)); | |
} | |
static int | |
read_bytes(int fd, int slave, int off, int len, uint8_t *buf) | |
{ | |
struct iic_msg msg[2]; | |
struct iic_rdwr_data rdwr; | |
uint8_t offset[2]; | |
offset[0] = 0x15; | |
offset[1] = off; | |
msg[0].slave = slave << 1; | |
msg[0].flags = IIC_M_WR; | |
msg[0].len = sizeof( offset ); | |
msg[0].buf = offset; | |
msg[1].slave = slave << 1; | |
msg[1].flags = IIC_M_RD; | |
msg[1].len = len; | |
msg[1].buf = buf; | |
rdwr.msgs = msg; | |
rdwr.nmsgs = 2; | |
return (ioctl(fd, I2CRDWR, &rdwr)); | |
} | |
int | |
am2320(float *out_temperature, float *out_humidity) | |
{ | |
int fd; | |
uint8_t data[8] = {0}; | |
fd = open(I2C_DEVICE, O_RDWR); | |
if (fd < 0) | |
return 1; | |
/* wake AM2320 up, goes to sleep to not warm up and | |
* affect the humidity sensor | |
*/ | |
data[0] = 0; | |
write_bytes(fd, AM2320_ADDR, 1, data); | |
usleep(1000); /* at least 0.8ms, at most 3ms */ | |
/* write at addr 0x03, start reg = 0x00, num regs = 0x04 */ | |
data[0] = 0x03; | |
data[1] = 0x00; | |
data[2] = 0x04; | |
if (write_bytes(fd, AM2320_ADDR, 3, data) < 0) | |
return 3; | |
/* wait for AM2320 */ | |
usleep(1600); /* Wait atleast 1.5ms */ | |
/* | |
* Read out 8 bytes of data | |
* Byte 0: Should be Modbus function code 0x03 | |
* Byte 1: Should be number of registers to read (0x04) | |
* Byte 2: Humidity msb | |
* Byte 3: Humidity lsb | |
* Byte 4: Temperature msb | |
* Byte 5: Temperature lsb | |
* Byte 6: CRC lsb byte | |
* Byte 7: CRC msb byte | |
*/ | |
if (read_bytes(fd, AM2320_ADDR, 0, 8, data) < 0) | |
return 4; | |
close(fd); | |
// printf("[0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x]\n", data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7] ); | |
/* Check data[0] and data[1] */ | |
if (data[0] != 0x03 || data[1] != 0x04) | |
return 9; | |
/* Check CRC */ | |
uint16_t crcdata = _calc_crc16(data, 6); | |
uint16_t crcread = _combine_bytes(data[7], data[6]); | |
if (crcdata != crcread) | |
return 10; | |
uint16_t temp16 = _combine_bytes(data[4], data[5]); | |
uint16_t humi16 = _combine_bytes(data[2], data[3]); | |
//printf("temp=%u 0x%04x hum=%u 0x%04x\n", temp16, temp16, humi16, humi16); | |
/* Temperature resolution is 16Bit, | |
* temperature highest bit (Bit15) is equal to 1 indicates a | |
* negative temperature, the temperature highest bit (Bit15) | |
* is equal to 0 indicates a positive temperature; | |
* temperature in addition to the most significant bit (Bit14 ~ Bit0) | |
* indicates the temperature sensor string value. | |
* Temperature sensor value is a string of 10 times the | |
* actual temperature value. | |
*/ | |
if (temp16 & 0x8000) | |
temp16 = -(temp16 & 0x7FFF); | |
*out_temperature = (float)temp16 / 10.0; | |
*out_humidity = (float)humi16 / 10.0; | |
return 0; | |
} | |
int main(void) { | |
float temp, humi; | |
int ret = am2320(&temp, &humi); | |
if (ret) { | |
printf("Err=%d\n", ret); | |
return ret; | |
} | |
printf( "Temperature %.1f [C]\n", temp); | |
printf( "Humidity %.1f [%%]\n", humi); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment