이전 글에서 처럼 TSL2561 조도 센서를 테스트 했다. 직원에게 얻었기에 가격은 모르겠고,  adafru.it에서 구매한 것 같다.


사진의 우하단에 있는 모듈로 T-package type. 




TSL2561 모듈에서 BBB 보드로 연결:

  • Pin 1(GND) --> P9.1 (GND)
  • Pin 2(ADDR) --> open
  • Pin 4(SCL) --> P9.19 (I2C2_SCL) with pull-up 10Kohm
  • Pin 5(SDA) --> P9.20(I2C2_SDA) with pull-up 10Kohm
  • Pin 6(VCC) --> P9.3 (3.3V)


결선 후 칩이 정상 작동하는지 확인하는 과정


# apt-get install i2c-tools 

...

# i2cdetect -y -r 1

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f

00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 

10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 

20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 

30: -- -- -- -- -- -- -- -- -- 39 -- -- -- -- -- -- 

40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 

50: -- -- -- -- UU UU UU UU -- -- -- -- -- -- -- -- 

60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 

70: -- -- -- -- -- -- -- --                         


i2cdetect로 확인한 결과 0x39에 장치가 발견되었다. TSL2561 datasheet를 확인해 보니 slave address가 일치한다.


TSL2561 datasheet에는 조도 계산하는 소스가 포함되어 있다. 그것을 참조로 프로그래밍.


실행결과

# lux

2013-12-13 16:17:46 lux=298

2013-12-13 16:17:47 lux=296

2013-12-13 16:17:48 lux=298

2013-12-13 16:17:49 lux=297

2013-12-13 16:17:50 lux=297

2013-12-13 16:17:51 lux=57

2013-12-13 16:17:52 lux=38

2013-12-13 16:17:53 lux=36

2013-12-13 16:17:54 lux=39

2013-12-13 16:17:55 lux=288

2013-12-13 16:17:56 lux=299

2013-12-13 16:17:57 lux=297

2013-12-13 16:17:58 lux=297

^C


중간에 조도가 바뀌는 부분은 손바닥으로 센서를 가린 것이다. 반도체의 제조 공정에 따른 칩의 편차는 크지 않을 것으로 보이며, 이 조도 값은 믿을만 해 보인다.


아래는 작업한 소스


Makefile

.SILENT: 


CC = gcc

STRIP = strip

INCLUDES = 

LIBS = 

CFLAGS = -Wall -O2 

LFLAGS = 


COMPILE = $(CC) $(INCLUDES) $(CFLAGS)

LINK = $(CC) $(LFLAGS)


BIN = lux


all: $(BIN)


clean:

rm -fr *.o $(BIN)


.c.o:

@echo compiling $< ...

$(COMPILE) -c -o $@ $<


lux: lux.o

@echo link $@

$(LINK) -o $@ lux.o

$(STRIP) $@

lux.o: lux.c



lux.c

#include <errno.h>

#include <string.h>

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <linux/i2c-dev.h>

#include <sys/ioctl.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <time.h>


#define I2C_DEV "/dev/i2c-1" // device driver name

#define TSL2561_ADDR 0x39


#define LUX_SCALE   14    // scale by 2^14

#define RATIO_SCALE 9     // scale ratio by 2^9


#define CH_SCALE          10    // scale channel values by 2^10

#define CHSCALE_TINT0     0x7517 // 322/11 * 2^CH_SCALE

#define CHSCALE_TINT1     0x0fe7 // 322/81 * 2^CH_SCALE


//---------------------------------------------------

// T Package coefficients

//---------------------------------------------------

// For Ch1/Ch0=0.00 to 0.50

// Lux/Ch0=0.0304-0.062*((Ch1/Ch0)^1.4)

// piecewise approximation

// For Ch1/Ch0=0.00 to 0.125: Lux/Ch0=0.0304-0.0272*(Ch1/Ch0)

// For Ch1/Ch0=0.125 to 0.250: Lux/Ch0=0.0325-0.0440*(Ch1/Ch0)

// For Ch1/Ch0=0.250 to 0.375: Lux/Ch0=0.0351-0.0544*(Ch1/Ch0)

// For Ch1/Ch0=0.375 to 0.50: Lux/Ch0=0.0381-0.0624*(Ch1/Ch0)

//

// For Ch1/Ch0=0.50 to 0.61: Lux/Ch0=0.0224-0.031*(Ch1/Ch0)

// For Ch1/Ch0=0.61 to 0.80: Lux/Ch0=0.0128-0.0153*(Ch1/Ch0)

// For Ch1/Ch0=0.80 to 1.30: Lux/Ch0=0.00146-0.00112*(Ch1/Ch0)

// For Ch1/Ch0>1.3: Lux/Ch0=0

//---------------------------------------------------


#define K1T  0x0040       // 0.125 * 2^RATIO_SCALE

#define B1T  0x01f2       // 0.0304 * 2^LUX_SCALE

#define M1T  0x01be       // 0.0272 * 2^LUX_SCALE

#define K2T  0x0080       // 0.250 * 2^RATIO_SCALETSL2560, TSL2561

#define B2T  0x0214       // 0.0325 * 2^LUX_SCALE

#define M2T  0x02d1       // 0.0440 * 2^LUX_SCALE

#define K3T  0x00c0       // 0.375 * 2^RATIO_SCALE

#define B3T  0x023f       // 0.0351 * 2^LUX_SCALE

#define M3T  0x037b       // 0.0544 * 2^LUX_SCALE

#define K4T  0x0100       // 0.50 * 2^RATIO_SCALE

#define B4T  0x0270       // 0.0381 * 2^LUX_SCALE

#define M4T  0x03fe       // 0.0624 * 2^LUX_SCALE

#define K5T  0x0138       // 0.61 * 2^RATIO_SCALE

#define B5T  0x016f       // 0.0224 * 2^LUX_SCALE

#define M5T  0x01fc       // 0.0310 * 2^LUX_SCALE

#define K6T  0x019a       // 0.80 * 2^RATIO_SCALE

#define B6T  0x00d2       // 0.0128 * 2^LUX_SCALE

#define M6T  0x00fb       // 0.0153 * 2^LUX_SCALE

#define K7T  0x029a       // 1.3 * 2^RATIO_SCALE

#define B7T  0x0018       // 0.00146 * 2^LUX_SCALE

#define M7T  0x0012       // 0.00112 * 2^LUX_SCALE

#define K8T  0x029a       // 1.3 * 2^RATIO_SCALE

#define B8T  0x0000       // 0.000 * 2^LUX_SCALE

#define M8T  0x0000       // 0.000 * 2^LUX_SCALE

//---------------------------------------------------

// CS package coefficients

//---------------------------------------------------

// For 0 <= Ch1/Ch0 <= 0.52

// Lux/Ch0 = 0.0315-0.0593*((Ch1/Ch0)^1.4)

// piecewise approximation

// For 0 <= Ch1/Ch0 <= 0.13 : Lux/Ch0 = 0.0315-0.0262*(Ch1/Ch0)

// For 0.13 <= Ch1/Ch0 <= 0.26 : Lux/Ch0 = 0.0337-0.0430*(Ch1/Ch0)

// For 0.26 <= Ch1/Ch0 <= 0.39: Lux/Ch0 = 0.0363-0.0529*(Ch1/Ch0)

// For 0.39 <= Ch1/Ch0 <= 0.52: Lux/Ch0 = 0.0392-0.0605*(Ch1/Ch0)

// For 0.52 < Ch1/Ch0 <= 0.65: Lux/Ch0 = 0.0229-0.0291*(Ch1/Ch0)

// For 0.65 < Ch1/Ch0 <= 0.80: Lux/Ch0 = 0.00157-0.00180*(Ch1/Ch0)

// For 0.80 < Ch1/Ch0 <= 1.30: Lux/Ch0 = 0.00338-0.00260*(Ch1/Ch0)

// For Ch1/Ch0 > 1.30: Lux = 0

//---------------------------------------------------

#define K1C  0x0043 // 0.130 * 2^RATIO_SCALE

#define B1C  0x0204 // 0.0315 * 2^LUX_SCALE

#define M1C  0x01ad // 0.0262 * 2^LUX_SCALE

#define K2C  0x0085 // 0.260 * 2^RATIO_SCALE

#define B2C  0x0228 // 0.0337 * 2^LUX_SCALE

#define M2C  0x02c1 // 0.0430 * 2^LUX_SCALE

#define K3C  0x00c8 // 0.390 * 2^RATIO_SCALE

#define B3C  0x0253 // 0.0363 * 2^LUX_SCALE

#define M3C  0x0363 // 0.0529 * 2^LUX_SCALE

#define K4C  0x010a // 0.520 * 2^RATIO_SCALE

#define B4C  0x0282 // 0.0392 * 2^LUX_SCALE

#define M4C  0x03df // 0.0605 * 2^LUX_SCALE

#define K5C  0x014d // 0.65 * 2^RATIO_SCALE

#define B5C  0x0177 // 0.0229 * 2^LUX_SCALE

#define M5C  0x01dd // 0.0291 * 2^LUX_SCALE

#define K6C  0x019a // 0.80 * 2^RATIO_SCALE

#define B6C  0x0101 // 0.0157 * 2^LUX_SCALE

#define M6C  0x0127 // 0.0180 * 2^LUX_SCALE

#define K7C  0x029a // 1.3 * 2^RATIO_SCALE

#define B7C  0x0037 // 0.00338 * 2^LUX_SCALE

#define M7C  0x002b // 0.00260 * 2^LUX_SCALE

#define K8C  0x029a // 1.3 * 2^RATIO_SCALE

#define B8C  0x0000 // 0.000 * 2^LUX_SCALE

#define M8C  0x0000 // 0.000 * 2^LUX_SCALE


typedef unsigned int uint;


// lux equation approximation without floating point calculations

//////////////////////////////////////////////////////////////////////////////

// Routine:     uint CalculateLux(uint ch0, uint ch0, int iType)

//

// Description: Calculate the approximate illuminance (lux) given the raw

// channel values of the TSL2560. The equation if implemented

// as a piece-wise linear approximation.

//

// Arguments:   uint iGain - gain, where 0:1X, 1:16X

// uint tInt - integration time, where 0:13.7mS, 1:100mS, 2:402mS, 3:Manual

// uint ch0 - raw channel value from channel 0 of TSL2560

// uint ch1 - raw channel value from channel 1 of TSL2560

// uint iType - package type (T or CS)

//

//    Return:   uint - the approximate illuminance (lux)

//

//////////////////////////////////////////////////////////////////////////////


uint CalculateLux(uint iGain, uint tInt, uint ch0, uint ch1, int iType)

{

// first, scale the channel values depending on the gain and integration time 16X, 402mS is nominal.

// scale if integration time is NOT 402 msec

uint chScale = (1 << CH_SCALE);

uint channel1;

uint channel0;

uint ratio, ratio1 = 0, b = 0, m = 0, temp;

uint lux;


if (tInt == 0) // 13.7ms

chScale = CHSCALE_TINT0;

else if (tInt == 1) // 101ms

chScale = CHSCALE_TINT1;

// scale if gain is NOT 16X

chScale = (!iGain) ? chScale << 4 : chScale;  // scale 1X to 16X


// scale the channel values

channel0 = (ch0 * chScale) >> CH_SCALE;

channel1 = (ch1 * chScale) >> CH_SCALE;

// find the ratio of the channel values (Channel1/Channel0)

// protect against divide by zero


if (channel0 != 0) 

ratio1 = (channel1 << (RATIO_SCALE+1)) / channel0;


// round the ratio value

ratio = (ratio1 + 1) >> 1;

switch (iType)

{

case 0: // T package

if ((ratio >= 0) && (ratio <= K1T)) {b=B1T; m=M1T;}

else if (ratio <= K2T) {b=B2T; m=M2T;}

else if (ratio <= K3T) {b=B3T; m=M3T;}

else if (ratio <= K4T) {b=B4T; m=M4T;}

else if (ratio <= K5T) {b=B5T; m=M5T;}

else if (ratio <= K6T) {b=B6T; m=M6T;}

else if (ratio <= K7T) {b=B7T; m=M7T;}

else if (ratio > K8T) {b=B8T; m=M8T;}

break;

case 1:// CS package

if ((ratio >= 0) && (ratio <= K1C)) {b=B1C; m=M1C;}

else if (ratio <= K2C) {b=B2C; m=M2C;}

else if (ratio <= K3C) {b=B3C; m=M3C;}

else if (ratio <= K4C) {b=B4C; m=M4C;}

else if (ratio <= K5C) {b=B5C; m=M5C;}

else if (ratio <= K6C) {b=B6C; m=M6C;}

else if (ratio <= K7C) {b=B7C; m=M7C;}

break;

}

temp = ((channel0 * b) - (channel1 * m));


// do not allow negative lux value

if (temp < 0) 

temp = 0;

// round lsb (2^(LUX_SCALE-1))

temp += (1 << (LUX_SCALE-1));


// strip off fractional portion

lux = temp >> LUX_SCALE;

return(lux);

}


void msleep(int n)

{

usleep(n*1000);

}


int tsl2561_write(int fd, unsigned char adr, unsigned char data)

{

unsigned char buf[10] = { 0, };

buf[0] = (1<<7) | adr;

buf[1] = data;


if (write(fd, buf, 2) != 2) {

printf("TSL2561: write error\n");

return 0;

}

return 1;

}


int tsl2561_measure(void)

{

static int fd = -1;

unsigned char buf[10] = { 0 };

unsigned int ch0, ch1;

if (fd == -1) {

if ((fd = open(I2C_DEV,O_RDWR)) < 0) 

return 0;

if (ioctl(fd, I2C_SLAVE, TSL2561_ADDR) < 0) {

printf("TSL2561: can't set address\n");

return 0;

}


tsl2561_write(fd, 0x00, 0x03); // power up

tsl2561_write(fd, 0x01, 0x02); // low gain(1x), integration time of 402ms

}


buf[0] = 0xAC;

if (write(fd, buf, 1) != 1) {

printf("TSL2561: write error: %s\n\n", strerror(errno));

}


if (read(fd, buf, 2) != 2) {

printf("TSL2561: read error: %s\n\n", strerror(errno));

return -1;

}

ch0 = (buf[1] << 8) | buf[0];

buf[0] = 0xAE;

if (write(fd, buf, 1) != 1) {

printf("TSL2561: write error: %s\n\n", strerror(errno));

}


if (read(fd, buf, 2) != 2) {

printf("TSL2561: read error: %s\n\n", strerror(errno));

return -1;

}

ch1 = (buf[1] << 8) | buf[0];


return CalculateLux(0, 2, ch0, ch1, 0);

}


int main(int argc, char* argv[])

{

char s[256];

struct tm* tp;

time_t st = time(NULL);

while(1) {


if (time(NULL) == st) {

msleep(1);

continue;

}

st = time(NULL);


tp = localtime(&st);

strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", tp);

printf("%s lux=%d\n", s, tsl2561_measure());

}

}







,