本文分为三个部分:
1.光强传感器说明 2.程序解读 3.前期准备(放在最后一部分,供小白查阅借鉴,包括本文需要用到的wiringPi库函数)
一、光强传感器说明
1.TSL256x 是 TAOS 公司推出的一种高速、低功耗、宽量程、可编程灵活配置的光强传感器芯片。外部引脚仅由3.3v电源引脚、SDA引脚、SCL引脚、中断控制引脚、地引脚组成。
2.TSL256x 数据传输遵循I2C总线协议,它只需要两根线即可在连接于总线上的器件之间传送信息。I2C的具体细节,详见I2C总线介绍
3.TSL256x 有 2 种封装形式: 6LEAD CHIPSCALE 和 6LEAD TMB。封装形式不同,相应的光照度计算公式也不同,下图为这两种封装形式的引脚分布图。
脚 1 和脚 3: 分别是电源引脚和信号地。其工作电压范围是 2.7~3.5V。
脚 2: 器件访问地址选择引脚。由于该引脚电平不同,该器件有 3个不同的访问地址。具体关系如下图所示:
由上图所知:
当ADDR SEL接 GND 时I2C的访问地址为 0x29
当ADDR SEL 悬空 时I2C的访问地址为 0x39
当ADDR SEL接 VCC 时I2C的访问地址为 0x39
脚 4 和脚 6: I2C 或 SMBus 总线的时钟信号线和数据线。
脚 5: 中断信号输出引脚。当光强度超过用户编程配置的上或下阈值时,器件会输出一个中断信号。
** 树莓派的引脚图见 三、前期准备 部分**
(博客采用悬空的接法,访问地址为0x39,电源引脚接于3.3v)
4.设备检查
在接好线后开始下一步的准备工作,若树莓派上未安装i2c-tools的软件包,则先安装:
sudo apt-get install i2c-tools
观察设备地址:(按照版本不同有如下命令,在 v1 版本的树莓派上是 0,v2 版本上是 1)
sudo i2cdetect -y 0
sudo i2cdetect -y 1
或者使用 gpio 命令来调用 i2cdetect 命令,从而检测 I2C设备
gpio i2cdetect
结果如下图:可以观察到地址为0x39
我们还需要了解此命令,用来观察设备内部各个寄存器的值:(0x39要按照自己的地址更改)
sudo i2cdump -f -y 1 0x39
结果如下:( 此命令在后期调试代码的时候可能会有帮助 )
5.对TSL2561寄存器进行操作的说明
参照TSL2561的英文手册
关于命令寄存器:
红图中点标注处为重点,命令寄存器用于指定后续操作的目标寄存器的地址,所以要对其他寄存器操作时,要通过Command寄存器,由table 3与table可知,如果要对存储数据的寄存器(table 2中的DATA0LOW,DATA0HIGH,DATA1LOW,DATA1HIGH)进行读取操作,需要将命令寄存器分别设置为:0x8C,0x8D,0x8E,0x8F
关于控制寄存器:
TSL2561的开启与关闭与Control寄存器有关
由上图可知,把POWER位设置为11(即0x03)是开启,关闭是0(即0x00);
6.光照强度的计算
从数据寄存器读取到的数值还需要进行转换才能得到想要的结果
首先
CH0 = 256 * DATA0HIGH + DATA0LOW
CH1 = 256 * DATA1HIGH + DATA1LOW
接着按照产品的封装形式对应不同的计算公式,具体见自己的产品包装说明。
(此博客采用第二种计算公式)Lux为所得到的最终光强结果。
二、程序解读
strerror()需要包含库函数有
#include <errno.h>
#include <string.h>
若有疑问请点击:此链接
wiringPiSetup():
初始化 wiringPi,幵假定程序将使用 wiringPi 的管脚定义图。具体管脚映射,可以通过 gpio readall 命令来查看
int wiringPiI2CSetup(int devId);
该函数使用指定设备标示号来初始化 I2C 系统。参数 devId 是 I2C设备的地址,可以通过i2cdetect 命令可以查到该地址。该函数会获取树莓派的版本开依据此打开/dev 目录下对应的设备,函数的返回值是标准的 Linux 文件句柄,如果有错误,则返回-1
wiringPiSetup();
fd=wiringPiI2CSetup(I2C);
以下为打开TSL2561时的操作,注意要延时至少0.5s,此博客采样延时1s
wiringPiI2CWrite(fd,CONTROL);
wiringPiI2CWrite(fd,POWER_UP);
sleep(1);
以下为读取数据寄存器中的数据操作
int wiringPiI2CRead(int fd);
简单的设备读操作。一些设备可以直接读取,而不需要发送任何寄存器地址。
int wiringPiI2CWrite(int fd, int data);
for(i=0;i<datareg_num;i++)
{
wiringPiI2CWrite(fd,reg_addr[i]);
reg_data[i]=wiringPiI2CRead(fd);
}
接下来调用计算光强的函数进行计算:具体计算函数详见完整代码
Lux=cal(reg_data);
若数据读取是无效的时候,返回值是-1,而Lux的定义是double类型,在将double类型与int类型做比较时需要如下操作
if(fabs(Lux+1)<0.00000001)
{
printf("Data read error!\n");
}
else
{
printf("The light intensity is %lf\n",Lux);
}
程序结束时,需要把TSL2561关闭,同打开操作类似:
wiringPiI2CWrite(fd,CONTROL);
wiringPiI2CWrite(fd,POWER_DOWN);
以下为完整C语言代码:(仅供测试使用)
若对里面的一些操作有些疑惑,请仔细查看第一部分的介绍
宏定义最好封装在头文件里,为了读者方便理解,本文没有封装
#include <stdio.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>
#include <math.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define I2C 0x39
#define datareg_num 4
#define DATA0LOW 0x8C
#define DATA0HIGH 0x8D
#define DATA1LOW 0x8E
#define DATAHIGH 0x8F
#define CONTROL 0x80
#define POWER_UP 0x03
#define POWER_DOWN 0x00
double cal(int* reg_data); //计算光强函数声明
int main()
{
int i;
int fd;
double Lux;
int reg_data[4];
int reg_addr[datareg_num]={DATA0LOW,DATA0HIGH,DATA1LOW,DATAHIGH};
wiringPiSetup();
fd=wiringPiI2CSetup(I2C);
if(fd==-1)
{
printf("I2C initialization failed: %s",strerror(errno));
return -1;
}
wiringPiI2CWrite(fd,CONTROL); //TSL2561打开
wiringPiI2CWrite(fd,POWER_UP);
sleep(1);
for(i=0;i<datareg_num;i++) //读取数据寄存器数据
{
wiringPiI2CWrite(fd,reg_addr[i]);
reg_data[i]=wiringPiI2CRead(fd);
}
Lux=cal(reg_data); //获取光强数据
if(fabs(Lux+1)<0.00000001)
{
printf("Data read error!\n");
}
else
{
printf("The light intensity is %lf\n",Lux);
}
wiringPiI2CWrite(fd,CONTROL); //关闭TSL2561
wiringPiI2CWrite(fd,POWER_DOWN);
return 0;
}
double cal(int* reg_data) //此代码按照第二种计算公式
{
double CH0,CH1,div,Lux;
CH0=256*reg_data[1]+reg_data[0];
CH1=256*reg_data[3]+reg_data[2];
if(CH0<=0 || CH1<0)
{
return -1;
}
div=CH1/CH0;
if(0<div<=0.5)
{
Lux=0.0304*CH0-0.062*CH0*pow(div,1.4);
}
else if(0.5<div<=0.61)
{
Lux=0.0224*CH0-0.031*CH1;
}
else if(0.61<div<=0.8)
{
Lux=0.0128*CH0-0.0153*CH1;
}
else if(0.8<div<=1.3)
{
Lux=0.00146*CH0-0.00112*CH1;
}
else if(div>1.3)
{
Lux=0;
}
return Lux;
}
编译命令:(文件名为TSL2561.c)
gcc TSL2561.c -o TSL2561 -lwiringPi -lm
运行:
./TSL2561
调试代码时,可以利用以下命令去观察设备寄存器内部的值:(观察对应的数据寄存器)
sudo i2cdump -f -y 1 0x39
另附python代码:(仅供测试使用)逻辑与C相同
#!/usr/bin/python
#encoding:utf-8
import wiringpi as wp
import time
I2C =0x39
datareg_num =4
DATA0LOW =0x8C
DATA0HIGH =0x8D
DATA1LOW =0x8E
DATA1HIGH =0x8F
CONTROL =0x80
POWER_UP =0x33
POWER_DOWN =0x00
fd=wp.wiringPiI2CSetup(I2C)
wp.wiringPiI2CWrite(fd,CONTROL)
wp.wiringPiI2CWrite(fd,POWER_UP)
time.sleep(1)
##read data
wp.wiringPiI2CWrite(fd,DATA0LOW)
data0_L=wp.wiringPiI2CRead(fd)
wp.wiringPiI2CWrite(fd,DATA0HIGH)
data0_H=wp.wiringPiI2CRead(fd)
wp.wiringPiI2CWrite(fd,DATA1LOW)
data1_L=wp.wiringPiI2CRead(fd)
wp.wiringPiI2CWrite(fd,DATA1HIGH)
data1_H=wp.wiringPiI2CRead(fd)
##calulate Lux
CH0=256*data0_H+data0_L
CH1=256*data1_H+data1_L
if(CH0==0 | CH1==0):
Lux=0
else:
div=float(CH1)/float(CH0)
if div<=0.5:
Lux=0.034*float(CH0)-0.063*float(CH0)*(div**1.4)
elif div>0.5 & div<=0.61:
Lux=0.0224*float(CH0)-0.031*CH1
elif div>0.61 & div<=0.8:
Lux=0.0128*float(CH0)-0.0153*CH1
elif div>0.8 & div<=1.3:
Lux=0.00146*float(CH0)-0.00112*CH1
elif div>1.3:
Lux=0
print '%f' % Lux
wp.wiringPiI2CWrite(fd,CONTROL)
wp.wiringPiI2CWrite(fd,POWER_DOWN)
三、前期准备
1.引脚图:
关于wiringPi的部分:请看此链接的中的 三、前期准备 有详细说明
因本人水平有限,如果有误,欢迎指正,如需转载请附上本文链接并注明。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)