일단 SenseHAT는 이렇게 라즈베리파이에 얹어서 사용할 수 있는 친구다.
축 높이가 일정하게 딱 맞아서 안정적으로 이용할 수 있다.
전원을 인가하는 순간 LED들이 반짝 켜져서 섬광탄을 연상케하지만 이후엔 예쁘장하게 들어온다.
HTS221로부터 온습도를 읽어내기 위해선 데이터시트가 필요하다.
control register로 제어하고 데이터값도 I2C를 통해 register를 읽어내는 방식으로 한다.
온도와 습도를 읽어내는 방식은 아내와 같다. 두 사진 모두 HTS221 datasheet에서 일부 발췌한 사진이다.
값을 그냥 읽어내는 것이 아니라 x좌표값 두개, 그에 상응하는 y좌표값 두개를 읽은 후, 두 점을 지나는 직선에 대한 방정식을 통해 값을 실제 센서가 읽은 값을 계산하는 방식이다.
문제는 이 계산을 전부 코딩으로 갈아 넣어야한다는 점이다.
레지스터에 저장된 x,y 좌표값 두세트는 현재 온습도에 관련없이 상수값을 지니는 듯 보인다.
아마 센서 내에 내장된 산술연산장치가 없이기에 이렇게 소프트웨어적으로 산술정보를 처리하도록 하는 듯 하다.
센서의 각 레지스터는 I2C통신으로 하기에, 읽어내는 데이터를 8-bit씩 끊어 읽어내야 하는데, 실제로 센서가 가진 값은 8-bit로 표현할 수 없다. 따라서 16bit의 경우에는 레지스터를 둘로 나누어 데이터의 low부분과 high부분을 unsigned값으로 읽어내 두 바이트를 합쳐 double형으로 저장한다. 실제 값은 2's complement이므로 부호가 중하기에 unsiigned로 받아 합치는 것이다.
코드 전문은 아래와 같다.
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>
#include <sys/ioctl.h>
static const char* I2C_DEV = "/dev/i2c-1";
static const int I2C_SLAVE = 0x0703;
static const int HTS221_ID = 0x5F;
static const int CTRL1 = 0x20;
static const int CTRL2 = 0x21;
static const int humi_x_0l = 0x36;
static const int humi_x_0h = 0x37;
static const int humi_x_1l = 0x3A;
static const int humi_x_1h = 0x3B;
static const int humi_y_0 = 0x30;
static const int humi_y_1 = 0x31;
static const int temp_x_0l = 0x3C;
static const int temp_x_0h = 0x3D;
static const int temp_x_1l = 0x3E;
static const int temp_x_1h = 0x3F;
static const int temp_y_0l = 0x32;
static const int temp_y_1l = 0x33;
static const int temp_y_01h = 0x35;
static const int temp_out_l = 0x2A;
static const int temp_out_h = 0x2B;
static const int humi_out_l = 0x28;
static const int humi_out_h = 0x29;
void getdata(int fd, double *temperature, double *humidity);
int main() {
int i2c_fd;
double temperature, humidity; //2 bytes
i2c_fd = open(I2C_DEV, O_RDWR);
ioctl(i2c_fd, I2C_SLAVE, HTS221_ID);
for(int i = 0 ; i < 10 ; i++ ) {
wiringPiI2CWriteReg8(i2c_fd, CTRL1, 0x00); //powerdown
wiringPiI2CWriteReg8(i2c_fd, CTRL1, 0x84); //active mode & register update resist
wiringPiI2CWriteReg8(i2c_fd, CTRL2, 0x01); //oneshot enable
getdata(i2c_fd, &temperature, &humidity);
printf("Temp : %.2f C\n", temperature);
printf("Humi : %.0f%% rH\n", humidity);
delay(1000);
}
wiringPiI2CWriteReg8(i2c_fd, CTRL1, 0x00); //powerdown HTS221
close(i2c_fd);
return 0;
}
void getdata(int fd, double *temperature, double *humidity) {
int result;
do {
delay(100);
result = wiringPiI2CReadReg8(fd, CTRL2);
} while (result != 0); //run untill ctrl_reg goes to zero.
//humi x & y
unsigned char HUMI_x_0l = wiringPiI2CReadReg8(fd, humi_x_0l);
unsigned char HUMI_x_0h = wiringPiI2CReadReg8(fd, humi_x_0h);
unsigned char HUMI_x_1l = wiringPiI2CReadReg8(fd, humi_x_1l);
unsigned char HUMI_x_1h = wiringPiI2CReadReg8(fd, humi_x_1h);
unsigned char HUMI_y_0_raw = wiringPiI2CReadReg8(fd, humi_y_0);
unsigned char HUMI_y_1_raw = wiringPiI2CReadReg8(fd, humi_y_1);
//temp x & y
unsigned char TEMP_x_0l = wiringPiI2CReadReg8(fd, temp_x_0l);
unsigned char TEMP_x_0h = wiringPiI2CReadReg8(fd, temp_x_0h);
unsigned char TEMP_x_1l = wiringPiI2CReadReg8(fd, temp_x_1l);
unsigned char TEMP_x_1h = wiringPiI2CReadReg8(fd, temp_x_1h);
unsigned char TEMP_y_0l = wiringPiI2CReadReg8(fd, temp_y_0l);
unsigned char TEMP_y_1l = wiringPiI2CReadReg8(fd, temp_y_1l);
unsigned char TEMP_y_01h = wiringPiI2CReadReg8(fd, temp_y_01h);
//use unsinged char. becuase of 2's complement.
//and A register has only 8-bit.
//if use just char, 2 byte date short = (2's comp)(2's comp) is not correct
//in code, 2byte datas are 2's complement.
//humi-y, msb-data, temp-y are unsinged type.
unsigned char TEMP_out_l = wiringPiI2CReadReg8(fd, temp_out_l);
unsigned char TEMP_out_h = wiringPiI2CReadReg8(fd, temp_out_h);
unsigned char HUMI_out_l = wiringPiI2CReadReg8(fd, humi_out_l);
unsigned char HUMI_out_h = wiringPiI2CReadReg8(fd, humi_out_h);
//bit setting - cartesian-X
short HUMI_x_0 = HUMI_x_0h << 8 | HUMI_x_0l;
short HUMI_x_1 = HUMI_x_1h << 8 | HUMI_x_1l;
short TEMP_x_0 = TEMP_x_0h << 8 | TEMP_x_0l;
short TEMP_x_1 = TEMP_x_1h << 8 | TEMP_x_1l;
//bit setting - cartesian-Y
double HUMI_y_0 = HUMI_y_0_raw / 2.0;
double HUMI_y_1 = HUMI_y_1_raw / 2.0;
double TEMP_y_0 = ((TEMP_y_01h & 0b11) << 8 | TEMP_y_0l) / 8.0;
double TEMP_y_1 = (((TEMP_y_01h & 0b1100) >> 2 ) << 8 | TEMP_y_1l) / 8.0;
//bit setting output data
short TEMP_out = TEMP_out_h << 8 | TEMP_out_l;
short HUMI_out = HUMI_out_h << 8 | HUMI_out_l;
//gradient & central data by cartesian
double gradient_temp = (TEMP_y_1 - TEMP_y_0) / (TEMP_x_1 - TEMP_x_0);
double gradient_humi = (HUMI_y_1 - HUMI_y_0) / (HUMI_x_1 - HUMI_x_0);
*temperature = gradient_temp * (TEMP_out - TEMP_x_1) + TEMP_y_1;
*humidity = gradient_humi * (HUMI_out - HUMI_x_1) + HUMI_y_1;
}
gradient로 기울기를 읽고, 한 점을 지나고 기울기를 아는 직선의 방정식을 이용해 현재 값을 읽어낸다.
'SW > Jetson nano & Raspberry Pi' 카테고리의 다른 글
Jetson Nano 세팅하기 (0) | 2023.07.21 |
---|---|
라즈베리파이4 model B (Raspberrypi4 model B) (0) | 2023.01.22 |