Skip to content

Instantly share code, notes, and snippets.

@samm-git
Last active February 20, 2022 19:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save samm-git/61f137640a228fe9dcf97032c4935708 to your computer and use it in GitHub Desktop.
Save samm-git/61f137640a228fe9dcf97032c4935708 to your computer and use it in GitHub Desktop.
Reading AM2320 sensor value under FreeBSD
#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