一、简介

TSL2591 是一款高灵敏度的光到数字转换器,可将光强转换为数字信号输出,并支持直接通过 I²C 接口进行通信。该器件在一个 CMOS 集成电路上集成了一个宽带光电二极管(可见光加红外)和一个对红外有响应的光电二极管。两个集成式 ADC(模数转换器)将光电二极管的电流转换为数字输出,该输出表示每个通道上测量的辐照度。这一数字输出可输入到微处理器中,并通过经验公式将其转换为照度(环境光水平,单位为lux),以近似人眼的响应。

该设备通过标准的两线I²C串行总线进行通信。因此,TSL2591可以很容易地连接到微控制器或嵌入式控制器。无需外部电路进行信号调理。由于该设备输出的是数字信号,与模拟信号相比,其输出对噪声具有很强的抗干扰能力。

TSL2591还支持中断功能,这有助于简化系统并提高系统效率,从而无需持续轮询传感器以获取光强值。中断功能的主要目的是检测光强的显著变化。用户可以通过设置光强变化的程度和持续时间来定义“显著变化”的概念。该设备能够设置两组阈值,分别对应于当前光强的上限和下限。当转换结果超出这些阈值之一时,将产生中断。一组阈值可以配置为仅在环境光持续超过某个可配置时间(即持续性)时触发中断,而另一组阈值则可以配置为在立即超过阈值时触发中断。

在这里插入图片描述

二、模组引脚功能

VIN电源 5V
GND电源地
3VO电源 3.3V
INT中断输出引脚 低电平有效
SCL时钟线
SDA数据线

三、寄存器介绍

1.Enable Register (0x00)

控制 TSL2591 启动、关闭、功能启用

Bit 位名称说明
7NPIEN当该位被置位(为1)时,只要光照超过中断阈值,就会立刻触发中断,忽略“持久性过滤器”
6SAI当该位被置位(为1)时,一旦生成了中断,设备将在当前 ALS(光强采样)周期结束后自动进入休眠(省电)模式
5Reserved*保留,0
4AIEN当该位被置位(设为1)时,允许产生 ALS 中断,受“持久性过滤器(Persist Filter)”限制
3:2Reserved保留,0
1AEN使能 ALS(光强感应)功能,1=开启,0=关闭
0PON打开内部振荡器(总开关),使计时器和 ADC 通道工作,1=上电,0=下电

2.Control Register (0x01)

位名称说明
7SRESET系统复位位,写1触发复位,自动清零
6保留位保留,0
5:4AGAIN增益设置:
00 - 低增益
01 - 中增益
10 - 高增益
11 - 最大增益
3保留位保留,0
2:0ATIME采样时间设置:
000 - 100 ms(最大计数36863)
001 - 200 ms(最大计数65535)
010 - 300 ms(最大计数65535)
011 - 400 ms(最大计数65535)
100 - 500 ms(最大计数65535)
101 - 600 ms(最大计数65535)

3.ALS Interrupt Threshold Register (0x04 − 0x0B)

ALS 中断阈值寄存器提供用于比较功能的高低触发点,以生成中断。当通道 0 数据(C0DATA)低于设定的低阈值,或高于设定的高阈值时,INT 引脚上会触发中断信号。

如果 C0DATA 超过了带持久阈值(寄存器地址 0x04 至 0x07)并且持续的周期数达到了 PERSIST 寄存器中配置的持久周期数,则会触发中断。

如果 C0DATA 超过了无持久阈值(寄存器地址 0x08 至 0x0B),则会在当前积分周期结束后立即触发中断。

中断状态虽然可以在 STATUS 寄存器(0x13)中查看,但只有当 ENABLE 寄存器(0x00)中的 AIEN(ALS 中断使能)或 NPIEN(无持久中断使能)被启用时,INT 引脚才会输出中断信号。

设备上电后,中断阈值寄存器的默认值为 0x00

寄存器地址名称位范围说明
0x04AILTL7:0ALS低阈值的低字节
0x05AILTH7:0ALS低阈值的高字节
0x06AIHTL7:0ALS高阈值的低字节
0x07AIHTH7:0ALS高阈值的高字节
0x08NPAILTL7:0无持久ALS低阈值的低字节
0x09NPAILTH7:0无持久ALS低阈值的高字节
0x0ANPAIHTL7:0无持久ALS高阈值的低字节
0x0BNPAIHTH7:0无持久ALS高阈值的高字节

4.PERSIST Register (0x0C)

中断持久过滤器用于设置连续多少个超出范围的 ALS 周期数,才会触发中断。

超出范围的判断依据是将通道0数据(C0DATA,寄存器地址 0x14 和 0x15)与中断阈值寄存器(0x04 至 0x07)进行比较。无持久(No Persist)ALS中断不受此持久过滤器影响。

设备上电时,中断持久过滤器寄存器的默认值为 0x00。

位范围名称说明APERS(二进制)说明
7:4Reserved保留,0
3:0APERSALS中断持久过滤器,设置连续超限次数0000 (0x0)每个ALS周期都会触发中断
0001 (0x1)任意一个值超出阈值即可触发中断
0010 (0x2)连续2次超出阈值触发
0011 (0x3)连续3次超出阈值触发
0100 (0x4)连续5次超出阈值触发
0101 (0x5)连续10次超出阈值触发
0110 (0x6)连续15次超出阈值触发
0111 (0x7)连续20次超出阈值触发
1000 (0x8)连续25次超出阈值触发
1001 (0x9)连续30次超出阈值触发
1010 (0xA)连续35次超出阈值触发
1011 (0xB)连续40次超出阈值触发
1100 (0xC)连续45次超出阈值触发
1101 (0xD)连续50次超出阈值触发
1110 (0xE)连续55次超出阈值触发
1111 (0xF)连续60次超出阈值触发

5.ALS Data Register (0x14 - 0x17)

ALS(环境光)数据以两个 16 位的值存储,每个通道各占一个 16 位数值。

当读取任一通道的低字节时,该通道的高字节会被锁存到一个影子寄存器(shadow register)中。这个影子寄存器确保读取的高、低字节来自于同一个 ALS 积分周期,即使在读取这两个字节之间发生了新的积分周期,数据仍然保持一致。

每个通道的影子寄存器是独立工作的。因此,为了最小化通道 CH0 和 CH1 之间的不同步(数据偏差),建议按顺序连续读取全部四个 ADC 字节。

寄存器地址位范围字段名说明
0x147:0C0DATALALS 通道 0(CH0)数据低字节
0x157:0C0DATAHALS 通道 0(CH0)数据高字节
0x167:0C1DATALALS 通道 1(CH1)数据低字节
0x177:0C1DATAHALS 通道 1(CH1)数据高字节

四、程序

TSL2591.C

#include "DEV_Config.h"
#include "TSL2591.h"

UBYTE TSL2591_Gain, TSL2591_Time;
/******************************************************************************
function:	Read one byte of data to TSL2591 via I2C
parameter:  
            Addr: Register address
Info:
******************************************************************************/
static UBYTE TSL2591_Read_Byte(UBYTE Addr)
{
    Addr = Addr | COMMAND_BIT;
    return I2C_Read_Byte(Addr);
}

/******************************************************************************
function:	Read one word of data to TSL2591 via I2C
parameter:
            Addr: Register address
Info:
******************************************************************************/
static UWORD TSL2591_Read_Word(UBYTE Addr)
{
    Addr = Addr | COMMAND_BIT;
    return I2C_Read_Word(Addr);
}

/******************************************************************************
function:	Send one byte of data to TSL2591 via I2C
parameter:
            Addr: Register address
           Value: Write to the value of the register
Info:
******************************************************************************/
static void TSL2591_Write_Byte(UBYTE Addr, UBYTE Value)
{
    Addr = Addr | COMMAND_BIT;
    I2C_Write_Byte(Addr, Value);
}

/******************************************************************************
function:	Enable TSL2591
parameter:
Info:
******************************************************************************/
void TSL2591_Enable(void)
{
    TSL2591_Write_Byte(ENABLE_REGISTER, \
    ENABLE_AIEN | ENABLE_POWERON | ENABLE_AEN | ENABLE_NPIEN);
}

/******************************************************************************
function:	Disable TSL2591
parameter:
Info:
******************************************************************************/
void TSL2591_Disable(void)
{
    TSL2591_Write_Byte(ENABLE_REGISTER, \
    ENABLE_POWEROFF);
}

/******************************************************************************
function:	Read TSL2591 gain
parameter:
Info:
******************************************************************************/
UBYTE TSL2591_Get_Gain(void)
{   
    /*************************************************
        LOW_AGAIN           = (0X00)        (1x)
        MEDIUM_AGAIN        = (0X10)        (25x)
        HIGH_AGAIN          = (0X20)        (428x)
        MAX_AGAIN           = (0x30)        (9876x)
    *************************************************/
    UBYTE data;
    data = TSL2591_Read_Byte(CONTROL_REGISTER);
    TSL2591_Gain = data & 0x30;
    return data & 0x30;
}

/******************************************************************************
function:	Set the TSL2591 gain
parameter:
Info:
******************************************************************************/
void TSL2591_Set_Gain(UBYTE Gain)
{
    UBYTE control=0;
    if(Gain == LOW_AGAIN || Gain == MEDIUM_AGAIN \
        || Gain == HIGH_AGAIN || Gain == MAX_AGAIN){
            control =  TSL2591_Read_Byte(CONTROL_REGISTER);
            control &= 0xCf; //0b11001111
            control |= Gain;
            TSL2591_Write_Byte(CONTROL_REGISTER, control);
            TSL2591_Gain = Gain;
    }else{
        printf("Gain Parameter Error\r\n");
    }
}

/******************************************************************************
function:	Get the TSL2591 Integral Time
parameter:
Info:
******************************************************************************/
UBYTE TSL2591_Get_IntegralTime()
{
    UBYTE control=0;
    /************************************************************
        ATIME_100MS = (0x00)      100 millis   MAX COUNT 36863 
        ATIME_200MS = (0x01)      200 millis   MAX COUNT 65535 
        ATIME_300MS = (0x02)      300 millis   MAX COUNT 65535 
        ATIME_400MS = (0x03)      400 millis   MAX COUNT 65535 
        ATIME_500MS = (0x04)      500 millis   MAX COUNT 65535 
        ATIME_600MS = (0x05)      600 millis   MAX COUNT 65535 
    ************************************************************/
    control = TSL2591_Read_Byte(CONTROL_REGISTER);
    TSL2591_Time = control & 0x07;
    return control & 0x07; //0b00000111
}

/******************************************************************************
function:	Set the TSL2591 Integral Time
parameter:
Info:
******************************************************************************/
void TSL2591_Set_IntegralTime(UBYTE Time)
{
    UBYTE control=0;
    if(Time < 0x06){
        control =  TSL2591_Read_Byte(CONTROL_REGISTER);
        control &= 0xf8; //0b11111000
        control |= Time;
        TSL2591_Write_Byte(CONTROL_REGISTER, control);
        TSL2591_Time = Time;
    }else{
        printf("Integral Time Parameter Error\r\n");
    }
}

/******************************************************************************
function:	Read channel data
parameter:
Info:
******************************************************************************/
UWORD TSL2591_Read_Channel0(void)
{
    return TSL2591_Read_Word(CHAN0_LOW);
}

UWORD TSL2591_Read_Channel1(void)
{
    return TSL2591_Read_Word(CHAN1_LOW);
}

/******************************************************************************
function:	TSL2591 Initialization
parameter:
Info:
******************************************************************************/
UBYTE TSL2591_Init(void)
{
    DEV_I2C_Init(TSL2591_ADDRESS<<1);//8-bit address
    printf("ID = 0x%X \r\n",TSL2591_Read_Byte(ID_REGISTER));
    TSL2591_Enable();
    TSL2591_Set_Gain(MEDIUM_AGAIN);//25X GAIN
    TSL2591_Set_IntegralTime(ATIME_200MS);//200ms Integration time
    TSL2591_Write_Byte(PERSIST_REGISTER, 0x01);//filter
    TSL2591_Disable();
    return 0;
}

/******************************************************************************
function:	Read TSL2591 data to convert to Lux value
parameter:
Info:
******************************************************************************/
UWORD TSL2591_Read_Lux(void)
{
    UWORD atime, max_counts,channel_0,channel_1;
    TSL2591_Enable();
    for(UBYTE i=0; i<TSL2591_Time+2; i++){
        DEV_Delay_ms(100);
    }
//    if(DEV_Digital_Read(INT_PIN) == 1)
//            printf("INT 0\r\n"); 
//    else
//             printf("INT 1\r\n"); 
    channel_0 = TSL2591_Read_Channel0();
    channel_1 = TSL2591_Read_Channel1();
    TSL2591_Disable();
    TSL2591_Enable();
    TSL2591_Write_Byte(0xE7, 0x13);
    TSL2591_Disable();
    
    atime = 100 * TSL2591_Time + 100;
    if(TSL2591_Time == ATIME_100MS){
        max_counts = MAX_COUNT_100MS;
    }else{
        max_counts = MAX_COUNT;
    }
    UBYTE gain_t;
    if (channel_0 >= max_counts || channel_1 >= max_counts){
            gain_t = TSL2591_Get_Gain();
            if(gain_t != LOW_AGAIN){
                gain_t = ((gain_t>>4)-1)<<4;
                TSL2591_Set_Gain(gain_t);
                channel_0 = 0;
                channel_1 = 0;
                while(channel_0 <= 0 || channel_1 <=0){
                    channel_0 = TSL2591_Read_Channel0();
                    channel_1 = TSL2591_Read_Channel1();
                }
                    DEV_Delay_ms(100);
            }else{
                printf("Numerical overflow!/r/n");
                return 0;
            }
    }
    double again;
    again = 1.0;
    if(TSL2591_Gain == MEDIUM_AGAIN){
        again = 25.0;
    }else if(TSL2591_Gain == HIGH_AGAIN){
        again = 428.0;
    }else if(TSL2591_Gain == MAX_AGAIN){
        again = 9876.0;
    }
    double Cpl;
    UWORD lux1,lux2=0;
    
    Cpl = (atime * again) / LUX_DF;
    lux1 = (int)((channel_0 - (2 * channel_1)) / Cpl);
    // lux2 = ((0.6 * channel_0) - (channel_1)) / Cpl;
    // This is a two segment lux equation where the first 
    // segment (Lux1) covers fluorescent and incandescent light 
    // and the second segment (Lux2) covers dimmed incandescent light

    if(lux1>lux2){
        return lux1;
    }else{
        return lux2;
    }
}

/******************************************************************************
function:	Set the TSL2591 interrupt
parameter:
        SET_LOW : Interrupt low threshold
        SET_HIGH: Interrupt high threshold
Info:   Is the channel 0 AD data as a comparison
******************************************************************************/
void TSL2591_SET_InterruptThreshold(UWORD SET_LOW, UWORD SET_HIGH)
{
    TSL2591_Enable();
    TSL2591_Write_Byte(AILTL_REGISTER, SET_LOW & 0xFF);
    TSL2591_Write_Byte(AILTH_REGISTER, SET_LOW >> 8);
    
    TSL2591_Write_Byte(AIHTL_REGISTER, SET_HIGH & 0xFF);
    TSL2591_Write_Byte(AIHTH_REGISTER, SET_HIGH >> 8);
    
    TSL2591_Write_Byte(NPAILTL_REGISTER, 0 );
    TSL2591_Write_Byte(NPAILTH_REGISTER, 0 );
    
    TSL2591_Write_Byte(NPAIHTL_REGISTER, 0xff );
    TSL2591_Write_Byte(NPAIHTH_REGISTER, 0xff );
    TSL2591_Disable();
}

/******************************************************************************
function:	Set the TSL2591 interrupt
parameter:
        SET_LOW : Interrupt low threshold
        SET_HIGH: Interrupt high threshold
Info:   Based on Lux as a comparison
        Need to use the function TSL2591_Read_Lux() to update the data
******************************************************************************/  
void TSL2591_SET_LuxInterrupt(UWORD SET_LOW, UWORD SET_HIGH)
{
    double Cpl;
    double again;
    UWORD atime, channel_1;
    atime  = 100 * TSL2591_Time + 100;
    again = 1.0;
    if(TSL2591_Gain == MEDIUM_AGAIN){
        again = 25.0;
    }else if(TSL2591_Gain == HIGH_AGAIN){
        again = 428.0;
    }else if(TSL2591_Gain == MAX_AGAIN){
        again = 9876.0;
    }
    
    Cpl = (atime * again) / LUX_DF;
    channel_1 = TSL2591_Read_Channel1();
    
    SET_HIGH =  (int)(Cpl * SET_HIGH)+ 2*channel_1-1;
    SET_LOW = (int)(Cpl * SET_LOW)+ 2*channel_1+1;
		
    TSL2591_Enable();
    TSL2591_Write_Byte(AILTL_REGISTER, SET_LOW & 0xFF);
    TSL2591_Write_Byte(AILTH_REGISTER, SET_LOW >> 8);
    
    TSL2591_Write_Byte(AIHTL_REGISTER, SET_HIGH & 0xFF);
    TSL2591_Write_Byte(AIHTH_REGISTER, SET_HIGH >> 8);
    
    TSL2591_Write_Byte(NPAILTL_REGISTER, 0 );
    TSL2591_Write_Byte(NPAILTH_REGISTER, 0 );
    
    TSL2591_Write_Byte(NPAIHTL_REGISTER, 0xff );
    TSL2591_Write_Byte(NPAIHTH_REGISTER, 0xff );
    TSL2591_Disable();
}

UDOUBLE TSL2591_Read_FullSpectrum(void)
{
    UDOUBLE data;
    //Read the full spectrum (IR + visible) light and return its value
    TSL2591_Enable();
    // for(UBYTE i=0; i<TSL2591_Time+2; i++){
        // DEV_Delay_ms(100);
    // }
    data = (TSL2591_Read_Channel1()  << 16) | TSL2591_Read_Channel0();
    TSL2591_Disable();
    return data;
}

UWORD TSL2591_Read_Infrared()
{
    UWORD data;
    //Read the infrared light and return its value as a 16-bit unsigned number
    TSL2591_Enable();
    // for(UBYTE i=0; i<TSL2591_Time+2; i++){
        // DEV_Delay_ms(100);
    // }
    data = TSL2591_Read_Channel1();
    TSL2591_Disable();
    return data;
}

UDOUBLE TSL2591_Read_Visible()
{
    UDOUBLE full;
    UWORD Ch1,Ch0;
    TSL2591_Enable();
    // for(UBYTE i=0; i<TSL2591_Time+2; i++){
        // DEV_Delay_ms(100);
    // }
    Ch1 = TSL2591_Read_Channel1();
    Ch0 = TSL2591_Read_Channel0();
    TSL2591_Disable();
//    full = (Ch1 << 16) | Ch0;
	full = Ch0 - Ch1;
    return full;
}

main.C

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "TSL2591.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */
  

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
	printf("TSL2591_Light_Sensor Code\r\n");
	DEV_ModuleInit();
	
	TSL2591_Init();
	//TSL2591_SET_InterruptThreshold(0x000f, 0xff00);
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		printf("Lux = %d\r\n",TSL2591_Read_Lux());
		TSL2591_SET_LuxInterrupt(50,200);
		printf("Infrared light: %d\r\n", TSL2591_Read_Infrared());
		printf("Visible light: %d\r\n", TSL2591_Read_Visible());
   
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

五、实验现象

室内光照情况下输出:
在这里插入图片描述
传感模块黑暗情况下输出:
在这里插入图片描述
小光源照射情况下输出:
在这里插入图片描述
注意该程序由互联网移植修改得出,实验数据未经过仪器验证,数据不建议作为环境标准使用,仅供参考,需要资料与工程可以留言邮箱。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐