TSL2591STM32固件库开发
*例程链接*
- 硬件准备:
TSL2591模块
指南者开发板或者其他f103系列板子
杜邦线
- 知识准备:
TSL2591的数据手册
这个是软件翻译版的数据手册,需要结合英文原版看
STM32F10x中文参考手册
官方资料
TSL25911官方资料
- 编写程序
- 这里我们使用了指南者的USART1和I2C1,需要做好初始化
- I2C连接:PB7连接SDA ,PB6连接SCL
- USART1串口转USB连接电脑
I2C写时序代码
/*-------------------------------------------------*/
/*函数名:TSL2591_Byte_Write */
/*参 数:addr 写入寄存器的地址 Data要写入的数据 */
/*返回值:无 */
/*功 能:写入一个字节 */
/*-------------------------------------------------*/
uint32_t TSL2591_Byte_Write(uint8_t addr,uint8_t Data)
{
I2CTimeout = I2CT_FLAG_TIMEOUT;
//检测总线是否在忙
while(I2C_GetFlagStatus(TSL2591_I2C, I2C_FLAG_BUSY))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(9);
}
//发送起始信号
I2C_GenerateSTART(TSL2591_I2C, ENABLE);
//检测EV5事件
while(I2C_CheckEvent(TSL2591_I2C,I2C_EVENT_MASTER_MODE_SELECT)==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(0);
}
//EV5事件被检测到,发送设备地址
I2C_Send7bitAddress(TSL2591_I2C,TSL2591_ADDRESS,I2C_Direction_Transmitter);
//检测EV6事件
while(I2C_CheckEvent(TSL2591_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(1);
}
//检测到EV6事件
I2C_SendData(TSL2591_I2C,addr|COMMAND_BIT);
//检测EV8事件
while(I2C_CheckEvent(TSL2591_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING)==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(2);
}
//EV8事件被检测到,发送要存储的数据
I2C_SendData(TSL2591_I2C,Data);
//检测EV8_2事件
while(I2C_CheckEvent(TSL2591_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED)==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);
}
//EV8_2事件被检测到,产生停止信号
I2C_GenerateSTOP(TSL2591_I2C,ENABLE);
return 1;
}
I2C读时序代码
/*-------------------------------------------------*/
/*函数名:TSL2591_Byte_Read */
/*参 数:addr 读取寄存器的地址 Data要读取的数据 */
/*返回值:无 */
/*功 能:读取一个byte的数据 */
/*-------------------------------------------------*/
uint32_t TSL2591_Byte_Read(uint8_t addr,uint8_t *Data)
{
I2CTimeout = I2CT_LONG_TIMEOUT;
//检测总线是否在忙
while(I2C_GetFlagStatus(TSL2591_I2C, I2C_FLAG_BUSY))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(9);
}
//发送起始信号
I2C_GenerateSTART(TSL2591_I2C, ENABLE);
//检测EV5事件
while(I2C_CheckEvent(TSL2591_I2C,I2C_EVENT_MASTER_MODE_SELECT)==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(10);
}
//EV5事件被检测到,发送设备地址
I2C_Send7bitAddress(TSL2591_I2C,TSL2591_ADDRESS,I2C_Direction_Transmitter);
//检测EV6事件
while(I2C_CheckEvent(TSL2591_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(11);
}
//检测到EV6事件
I2C_SendData(TSL2591_I2C,addr|COMMAND_BIT);
//检测EV8事件
while(I2C_CheckEvent(TSL2591_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING)==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(12);
}
//EV8事件被检测到,产生停止信号
I2C_GenerateSTOP(TSL2591_I2C,ENABLE);
//第二次产生起始信号
I2CTimeout = I2CT_FLAG_TIMEOUT;
//发送起始信号
I2C_GenerateSTART(TSL2591_I2C, ENABLE);
//检测EV5事件
while(I2C_CheckEvent(TSL2591_I2C,I2C_EVENT_MASTER_MODE_SELECT)==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(13);
}
//EV5事件被检测到,发送设备地址
I2C_Send7bitAddress(TSL2591_I2C,TSL2591_ADDRESS,I2C_Direction_Receiver);
//检测EV6事件
while(I2C_CheckEvent(TSL2591_I2C,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(14);
}
//检测EV7事件
while(I2C_CheckEvent(TSL2591_I2C,I2C_EVENT_MASTER_BYTE_RECEIVED)==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);
}
//EV7事件被检测到,即数据寄存器有新的有效数据
*Data=I2C_ReceiveData(TSL2591_I2C);
//如果是最后一个就不再产生应答
I2C_AcknowledgeConfig(TSL2591_I2C,DISABLE);
//通讯完成产生停止讯号
I2C_GenerateSTOP(TSL2591_I2C,ENABLE);
// //重新产生应答信号,准备下一次的传输
// I2C_AcknowledgeConfig(TSL2591_I2C,ENABLE);
return 1;
}
根据TSL2591数据手册将寄存器宏定义
#ifndef __TSL2591_TEST_H
#define __TSL2591_TEST_H
#include "stm32f10x.h"
//写入和读取寄存器都要用寄存器地址与COMMAND_BIT进行与运算
//例 ENABLE_REGISTER|COMMAND_BIT;
#define COMMAND_BIT 0xA0
//寄存器位写1启用,写0禁用
//Register (0x00)
//使能寄存器
#define ENABLE_REGISTER 0x00
//0位pow
#define ENABLE_POWERON 0x01 //打开电源。该字段激活内部振荡器,以允许定时器和ADC通道工作。
#define ENABLE_POWEROFF 0x00 //关闭电源。
#define ENABLE_AEN 0x02 //ALS使能。此字段激活ALS功能
#define ENABLE_AIEN 0x10 //ALS中断启用。
#define ENABLE_SAI 0x40 //中断后睡眠。断言时,如果产生中断,设备将在ALS循环结束时断电
#define ENABLE_NPIEN 0x80 //无持续中断启用
//控制寄存器
#define CONTROL_REGISTER 0x01
#define SRESET 0x80 //产生同步复位信号
//AGAIN
#define LOW_AGAIN 0X00//Low gain (1x) 低增益模式
#define MEDIUM_AGAIN 0X10//Medium gain (25x) 中等增益模式
#define HIGH_AGAIN 0X20//High gain (428x) 高增益模式
#define MAX_AGAIN 0x30//Max gain (9876x) 最大增益模式
//ATIME
//ALS时间设置两个光电二极管通道的内部ADC集成时间。
#define ATIME_100MS 0x00//100 millis 最大计数 36863
#define ATIME_200MS 0x01//200 millis 最大计数 65535
#define ATIME_300MS 0x02//300 millis 最大计数 65535
#define ATIME_400MS 0x03//400 millis 最大计数 65535
#define ATIME_500MS 0x04//500 millis 最大计数 65535
#define ATIME_600MS 0x05//600 millis 最大计数 65535
//ALS中断阈值寄存器(0x04-0x0B)
#define AILTL_REGISTER 0x04//ALS低阈值低字节
#define AILTH_REGISTER 0x05//ALS低阈值上限字节
#define AIHTL_REGISTER 0x06//ALS高阈值低字节
#define AIHTH_REGISTER 0x07//ALS高阈值上限字节
#define NPAILTL_REGISTER 0x08//无持续ALS低阈值低字节
#define NPAILTH_REGISTER 0x09//无持续ALS低阈值上限字节
#define NPAIHTL_REGISTER 0x0A//无持续ALS高阈值低字节
#define NPAIHTH_REGISTER 0x0B//无持续ALS高阈值上限字节
//持久化寄存器
#define PERSIST_REGISTER 0x0C
// Bits 3:0
// 0000 Every ALS cycle generates an interrupt 每个ALS周期产生一个中断
// 0001 Any value outside of threshold range 阈值范围之外的任何值
// 0010 2 consecutive values out of range 2个连续值超出范围
// 0011 3 consecutive values out of range 3个连续值超出范围
// 0100 5 consecutive values out of range 5个连续值超出范围
// 0101 10 consecutive values out of range 10个连续值超出范围
// 0110 15 consecutive values out of range 15个连续值超出范围
// 0111 20 consecutive values out of range 20个连续值超出范围
// 1000 25 consecutive values out of range 25个连续值超出范围
// 1001 30 consecutive values out of range 30个连续值超出范围
// 1010 35 consecutive values out of range 35个连续值超出范围
// 1011 40 consecutive values out of range 40个连续值超出范围
// 1100 45 consecutive values out of range 45个连续值超出范围
// 1101 50 consecutive values out of range 50个连续值超出范围
// 1110 55 consecutive values out of range 55个连续值超出范围
// 1111 60 consecutive values out of range 60个连续值超出范围
//ID寄存器 ID寄存器提供设备标识。该寄存器是一个只读寄存器,其值永远不会改变
#define ID_REGISTER 0x12
//状态寄存器 状态寄存器提供设备的内部状态。这个寄存器是只读的
#define STATUS_REGISTER 0x13//#read only
//ALS数据寄存器 建议按顺序读取所有四个ADC字节
#define CHAN0_LOW 0x14 //ALSCH0数据低字节
#define CHAN0_HIGH 0x15 //ALSCH0数据高位字节
#define CHAN1_LOW 0x16 //ALSCH1数据低字节
#define CHAN1_HIGH 0x14 //ALSCH1数据高位字节
//LUX_DF GA * 53 GA is the Glass Attenuation factor
#define LUX_DF 762.0
// LUX_DF 408.0
#define MAX_COUNT_100MS 36863 // 0x8FFF
#define MAX_COUNT 65535 // 0xFFFF
void TSL2591_Enable(void);
void TSL2591_Disable(void);
uint8_t TSL2591_Get_Gain(void);
void TSL2591_Set_Gain(uint8_t Gain);
uint8_t TSL2591_Get_IntegralTime(void);
void TSL2591_Set_IntegralTime(uint8_t Time);
uint8_t TSL2591_Init(void);
uint16_t TSL2591_Read_Lux(void);
void TSL2591_SET_InterruptThreshold(uint16_t SET_LOW, uint16_t SET_HIGH);
void TSL2591_SET_LuxInterrupt(uint16_t SET_LOW, uint16_t SET_HIGH);
uint32_t TSL2591_Read_FullSpectrum(void);
uint16_t TSL2591_Read_Infrared(void);
uint32_t TSL2591_Read_Visible(void);
#endif
编写测试程序程序
/*-------------------------------------------------*/
/*函数名:TSL2591_Read_Lux */
/*参 数:无 */
/*返回值:返回一个十六位的lux值 */
/*功 能:读取TSL2591数据以转换为lux 值 */
/*-------------------------------------------------*/
uint16_t TSL2591_Read_Lux(void)
{
uint16_t atime, max_counts,channel_0,channel_1;
TSL2591_Enable();
//延时
for(uint8_t i=0; i<TSL2591_Time+2; i++){
Delay_Ms(100);
}
TSL2591_WaitForWriteEnd();
//检测SDA
if(GPIO_ReadInputDataBit(I2Cx_SDA_PORT,I2Cx_SDA_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_Byte_Write(0xE7, 0x13);//没有寄存器定义,不知道有什么用,暂且留着
TSL2591_Disable();
atime = 100 * TSL2591_Time + 100;
if(TSL2591_Time == ATIME_100MS){
max_counts = MAX_COUNT_100MS;
}else{
max_counts = MAX_COUNT;
}
uint8_t 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();
}
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;
uint16_t 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
//lux2=((0.6*channel_0)-(channel_1))/Cpl;
//这是一个两段勒克斯方程,其中
//第一部分(Lux1)是荧光灯和白炽灯
//第二部分(Lux2)是暗淡的白炽灯
if(lux1>lux2){
return lux1;
}else{
return lux2;
}
}
实验效果
整个程序的代码比较多,不能完整展示,关键代码在于I2C代码的写时序和读时序需要完整代码可以在顶端连接下载。