TSL2561是一块小型的可编程数字光强测量芯片,外部引脚仅由3.3v电源引脚、SDA引脚、SCL引脚、中断控制引脚、地引脚组成。适合利用树莓派开发板或STM32型单片机来进行编程开发,本博客讲述如何在树莓派上对照着TSL2561用户手册编程实现对TSL2561光强的读取。
TSL2561数据传输的原理遵循IIC(I2C)总线协议,仅依靠一条时钟线和一条数据总线即可完成光强数据的传输。有关I2C总线协议的详细内容见百度百科:I2C总线
树莓派内核已对该协议进行了封装和包含,用户直接启动i2c总线传输接口即可:
sudo raspi-config
进入选项5“Interfacing Options”后,再选择i2c选项,进行配置。
直接按照以上引脚图去逐一连接芯片的四个管脚(除去INT)即可,其中电源引脚应接在3.3V引脚上
无论是利用Python语言还是C语言,在对树莓派上所接入设备进行操作时,都需要引入wiringPi库
wiringPi下载网址:wiringPi函数库下载
打开网页后,点击其中任何一个版本中的“snapshot”,即可下载。下载完成之后,将下载的压缩文件传输到树莓派开发板上,解压缩,cd进入对应的文件目录下,执行“./build”程序后,完成安装,此时可利用“gpio -v”或“gpio readall”命令来检查安装是否成功
软件包i2c-tools中包含与i2c设备操作有关的命令。若树莓派上未安装i2c-tools的软件包,则先安装:
sudo apt-get install i2c-tools
查看TSL2561设备的地址:
sudo i2cdetect -y 1
正常执行时,可以发现设备地址为0x39
查看TSL2561内部寄存器的值:
sudo i2cdump -f -y 1 0x39
多执行几次后,发现寄存器的值不改变,这是因为TSL2561还没有启动,要在后续的程序中通过写入命令控制字的方法才可以实现光强的读取。
TSL2561启动、寄存器访问、数据的读取都是通过写命令控制字的方法来实现的,TSL2561的用户手册里面给出了对应寄存器的名称、用途和访问方法:
上面是TSL2561内部所有寄存器的类型以及对应的地址,而读取光强仅需利用其中的命令寄存器(command)、控制寄存器(control)和数据寄存器(Ch,Dh,Eh,Fh)。数据寄存器中的值经过位运算和加法运算之后,便可生成对应ADC通道(ADC channel)内的采样值,即:
Channel_0 = DATA0HIGH<<8 + DATA0LOW;
Channel_1 = DATA1HIGH<<8 + DATA1LOW;
下面给出命令寄存器的操作要点:
一个命令寄存器有8位,其中最高位CMD必须设置为1才可以正常访问,ADDRESS位有3位,对应着上一张图片里面数据寄存器的地址。例如要访问数据寄存器Ch,就应该将命令寄存器设置为10001100B,即0x8c,当不需要访问数据寄存器时,ADDRESS直接写为0000B(0x0)即可。由此可见,命令寄存器在TSL2561内部的地址是0x80。
下面是有关控制寄存器的说明:
TSL2561的启动取决于控制寄存器中的POWER位,图片里面已经说明了启动方法与停止方法,就是把POWER位置为11B是启动,置为00是关闭。其他位是保留位,无需考虑操作,直接置0即可。
写入控制寄存器控制字使得TSL2561成功启动,并且正常读取到四个数据寄存器中的值之后,就可以按照用户手册中的计算公式进行光强计算了:
TSL2561有两种封装类型,本人手头上的芯片属于图中所述的第二种,所以计算光强时就使用第二种封装类型里面的公式就行了,芯片的封装类型在购买来之前的包装袋上有说明。
Python版本
#!/usr/bin/python
##File name: tsl2561.py
import wiringpi as wpi
import time
TSL2561_ADDR = 0x39
POWER_UP = 0x03
POWER_DOWN = 0x00
CONTROL_REG = 0x80
DATA0_LOW = 0x8c
DATA0_HIGH = 0x8d
DATA1_LOW = 0x8e
DATA1_HIGH = 0x8f
##Register initialization
tsl_fd = wpi.wiringPiI2CSetup(TSL2561_ADDR)
wpi.wiringPiI2CWrite(tsl_fd, CONTROL_REG)
wpi.wiringPiI2CWrite(tsl_fd, POWER_UP)
time.sleep(0.5)
##Read the values from Ch,Dh,Eh,Fh
wpi.wiringPiI2CWrite(tsl_fd, DATA0_LOW)
data0_low = wpi.wiringPiI2CRead(tsl_fd)
wpi.wiringPiI2CWrite(tsl_fd, DATA0_HIGH)
data0_high = wpi.wiringPiI2CRead(tsl_fd)
wpi.wiringPiI2CWrite(tsl_fd, DATA1_LOW)
data1_low = wpi.wiringPiI2CRead(tsl_fd)
wpi.wiringPiI2CWrite(tsl_fd, DATA1_HIGH)
data1_high = wpi.wiringPiI2CRead(tsl_fd)
##Convert the register values into sampling values(channel_0 & channel_1)
chn0=256*data0_high+data0_low
chn1=256*data1_high+data1_low
##According to the 'div', calculate the size of lux
if chn0==0:
lux = 0
elif chn0!=0:
div=float(chn1)/float(chn0)
if (div>0 and div<=0.5):
lux = (0.304*chn0-0.062*chn0*(div**1.4))
if (div>0.5 and div<=0.61):
lux = (0.0224*chn0-0.031*chn1)
if (div>0.61 and div<=0.8):
lux = (0.0128*chn0-0.0153*chn1)
if (div>0.8 and div<=1.3):
lux = (0.00146*chn0-0.00112*chn1)
if (div >1.3):
lux = 0
##Display the Lux
print '%.3f' % lux
##End of sampling
wpi.wiringPiI2CWrite(tsl_fd, CONTROL_REG)
wpi.wiringPiI2CWrite(tsl_fd, POWER_DOWN)
C版本(编译命令:gcc tsl2561.c -lwiringpi -o tsl2561)
/*File name: tsl2561.c*/
#include
#include /*This must be included but some manuals don't mention*/
#include
#include
#include
#include
#include
#include
#define CONTROL_REG 0x80
#define SENOR_ADDR 0x39
#define REG_COUNT 4
#define POWER_UP 0x03
#define POWER_DOWN 0x00
enum //Define the command control words.
{
data0_low = 0x8c,
data0_high,
data1_low,
data1_high,
};
int reg_addr[REG_COUNT] = {data0_low, data0_high, data1_low, data1_high};
int main(int argc, char **argv)
{
int tsl_fd = -1;
int i;
int chn_0 = 0;
int chn_1 = 0;
int reg_data[REG_COUNT];
double div = 0;
double lux = 0;
tsl_fd = wiringPiI2CSetup(SENOR_ADDR); //This funtion returns a fd for next reading step.
if(tsl_fd < 0)
{
printf("Fail to read the relative i2c-dev file: %s", strerror(errno));
return -1;
}
wiringPiI2CWrite(tsl_fd, CONTROL_REG);
wiringPiI2CWrite(tsl_fd, POWER_UP);
sleep(1);
for(i = 0; i0 && div<=0.5)
{
lux = 0.304*chn_0-0.062*chn_0*pow(div,1.4);
}
if(div>0.5 && div<=0.61)
{
lux = 0.0224*chn_0-0.031*chn_1;
}
if(div>0.61 && div<=0.8)
{
lux = 0.0128*chn_0-0.0153*chn_1;
}
if(div>0.8 && div<=1.3)
{
lux = 0.00146*chn_0-0.00112*chn_1;
}
if(div>1.3)
{
lux = 0;
}
end: printf("%.3f\n", lux);
wiringPiI2CWrite(tsl_fd, CONTROL_REG);
wiringPiI2CWrite(tsl_fd, POWER_DOWN);
return 0;
}
两种版本的代码逻辑是一样的,这里简要地提一下:
倘若在运行Python版本的程序时,抛出了“No module wiringpi”的错误,可以尝试用以下方法解决:
依次执行以下Linux命令:
sudo apt-get install python-dev python-pip
sudo pip install wiringpi2
可以知道,出现这种错误是因为缺少Python的wiringPi链接库,安装之后即可解决问题。