简介
TCS3472 是 ams OSRAM 的低成本、RGB+Clear 四通道颜色 / 环境光传感器,带红外滤光、16 位 ADC、I2C、3.3V 供电,主打精准颜色识别、色温、亮度(Lux),比 AS7341 便宜、通道少、更适合入门与量产。
引脚说明
| 引脚号 | 标识 | 管脚描述 |
|---|---|---|
| 1 | VCC | 3.3V/5V电源正 |
| 2 | GND | 电源地 |
| 3 | SDA | I2C数据线 |
| 4 | SCL | I2C时钟线 |
| 5 | INT | 中断输出引脚 |
| 6 | LED | 通用输入/输出 |
HAL库模拟IIC驱动参考
c
#define u32 uint32_t
#define u8 uint8_t
#define u16 uint16_t
/******************************************************************************/
// TCS34725 寄存器地址定义
#define TCS34725_ADDRESS (0x29)
#define TCS34725_COMMAND_BIT (0x80)
#define TCS34725_ENABLE (0x00)
#define TCS34725_ENABLE_AIEN (0x10) /* RGBC 中断使能 */
#define TCS34725_ENABLE_WEN (0x08) /* 等待定时器使能 */
#define TCS34725_ENABLE_AEN (0x02) /* ADC 使能 */
#define TCS34725_ENABLE_PON (0x01) /* 电源使能 */
#define TCS34725_ATIME (0x01) /* 积分时间寄存器 */
#define TCS34725_WTIME (0x03) /* 等待时间寄存器 */
#define TCS34725_AILTL (0x04) /* 清除通道中断下限(低8位) */
#define TCS34725_AILTH (0x05) /* 清除通道中断下限(高8位) */
#define TCS34725_AIHTL (0x06) /* 清除通道中断上限(低8位) */
#define TCS34725_AIHTH (0x07) /* 清除通道中断上限(高8位) */
#define TCS34725_PERS (0x0C) /* 中断持续寄存器 */
#define TCS34725_CONFIG (0x0D) /* 配置寄存器 */
#define TCS34725_CONTROL (0x0F) /* 增益控制寄存器 */
#define TCS34725_ID (0x12) /* 设备ID寄存器(0x44=34725/34721,0x4D=34727/34723) */
#define TCS34725_STATUS (0x13) /* 状态寄存器 */
#define TCS34725_STATUS_AINT (0x10) /* RGBC 中断标志 */
#define TCS34725_STATUS_AVALID (0x01) /* RGBC 数据有效标志 */
#define TCS34725_CDATAL (0x14) /* 清除通道数据(低8位) */
#define TCS34725_CDATAH (0x15) /* 清除通道数据(高8位) */
#define TCS34725_RDATAL (0x16) /* 红色通道数据(低8位) */
#define TCS34725_RDATAH (0x17) /* 红色通道数据(高8位) */
#define TCS34725_GDATAL (0x18) /* 绿色通道数据(低8位) */
#define TCS34725_GDATAH (0x19) /* 绿色通道数据(高8位) */
#define TCS34725_BDATAL (0x1A) /* 蓝色通道数据(低8位) */
#define TCS34725_BDATAH (0x1B) /* 蓝色通道数据(高8位) */
// 积分时间配置
#define TCS34725_INTEGRATIONTIME_2_4MS 0xFF /* 2.4ms - 1周期 - 最大计数1024 */
#define TCS34725_INTEGRATIONTIME_24MS 0xF6 /* 24ms - 10周期 - 最大计数10240 */
#define TCS34725_INTEGRATIONTIME_50MS 0xEB /* 50ms - 20周期 - 最大计数20480 */
#define TCS34725_INTEGRATIONTIME_101MS 0xD5 /* 101ms - 42周期 - 最大计数43008 */
#define TCS34725_INTEGRATIONTIME_154MS 0xC0 /* 154ms - 64周期 - 最大计数65535 */
#define TCS34725_INTEGRATIONTIME_240MS 0x9C /* 240ms - 100周期 - 最大计数65535 */
#define TCS34725_INTEGRATIONTIME_700MS 0x00 /* 700ms - 256周期 - 最大计数65535 */
// 增益配置
#define TCS34725_GAIN_1X 0x00 /* 无增益 */
#define TCS34725_GAIN_4X 0x01 /* 4倍增益 */
#define TCS34725_GAIN_16X 0x02 /* 16倍增益 */
#define TCS34725_GAIN_60X 0x03 /* 60倍增益 */
/******************************************************************************/
// 延时函数声明(需在其他文件实现,如基于SysTick的延时)
extern void delay_ms(u32 nms);
extern void delay_us(u32 nus);
#define TCS_I2C_SCL_PORT GPIOA
#define TCS_I2C_SCL_PIN GPIO_PIN_9
#define TCS_I2C_SDA_PORT GPIOA
#define TCS_I2C_SDA_PIN GPIO_PIN_8
#define TCS_SCL_H HAL_GPIO_WritePin(TCS_I2C_SCL_PORT, TCS_I2C_SCL_PIN, GPIO_PIN_SET) /* SCL置高 */
#define TCS_SCL_L HAL_GPIO_WritePin(TCS_I2C_SCL_PORT, TCS_I2C_SCL_PIN, GPIO_PIN_RESET) /* SCL置低 */
#define TCS_SDA_H HAL_GPIO_WritePin(TCS_I2C_SDA_PORT, TCS_I2C_SDA_PIN, GPIO_PIN_SET) /* SDA置高 */
#define TCS_SDA_L HAL_GPIO_WritePin(TCS_I2C_SDA_PORT, TCS_I2C_SDA_PIN, GPIO_PIN_RESET) /* SDA置低 */
/******************************************************************************/
// 颜色数据结构体
typedef struct{
u16 c; // 清除通道数据 [0-65535]
u16 r; // 红色通道数据
u16 g; // 绿色通道数据
u16 b; // 蓝色通道数据
}COLOR_RGBC;
typedef struct{
u16 h; // 色相 [0-360]
u8 s; // 饱和度 [0-100]
u8 l; // 亮度 [0-100]
}COLOR_HSL;
COLOR_RGBC rgb;
COLOR_HSL hsl;
/******************************************************************************/
// 辅助函数:三值最大/最小值计算(保持不变)
#define max3v(v1, v2, v3) ((v1)<(v2)? ((v2)<(v3)?(v3):(v2)):((v1)<(v3)?(v3):(v1)))
#define min3v(v1, v2, v3) ((v1)>(v2)? ((v2)>(v3)?(v3):(v2)):((v1)>(v3)?(v3):(v1)))
/******************************************************************************/
// 防止编译器优化延时函数
__STATIC_INLINE void delay_us(volatile uint32_t us)
{
// 72MHz时钟下,每个指令周期约为1/72μs(≈13.89ns)
// 以下循环体约执行3条指令,因此每个循环耗时约41.67ns
// 计算循环次数:us * (1μs / 41.67ns) ≈ us * 24
volatile uint32_t cycles = us * 240;
// 使用汇编指令确保循环不被优化,且精确控制执行时间
while(cycles--)
{
}
}
// I2C初始化(基于STM32 HAL库函数配置GPIO和时钟)
void TCS34725_I2C_Init()
{
// 1. 使能GPIO时钟(根据实际使用的端口修改,此处以GPIOA为例)
__HAL_RCC_GPIOA_CLK_ENABLE();
// 2. 定义GPIO初始化结构体
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 3. 配置SCL引脚(推挽输出,高速)
GPIO_InitStruct.Pin = TCS_I2C_SCL_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(TCS_I2C_SCL_PORT, &GPIO_InitStruct);
// 4. 配置SDA引脚(初始设为推挽输出,后续通过SD1_SetInput/OUT切换)
GPIO_InitStruct.Pin = TCS_I2C_SDA_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(TCS_I2C_SDA_PORT, &GPIO_InitStruct);
// 5. 初始电平:SCL、SDA均置高(I2C空闲状态)
TCS_SCL_H;
TCS_SDA_H;
HAL_Delay(1); // 稳定电平
}
/*********************************************/
// I2C起始信号(逻辑不变,基于库函数引脚操作)
void TCS34725_I2C_Start()
{
SD1_SetOutput(); // SDA设为输出
TCS_SDA_H;
TCS_SCL_H;
delay_us(4); // 延时≥4.7μs(I2C标准时序)
TCS_SDA_L;
delay_us(4); // 延时≥4μs
TCS_SCL_L; // 拉低SCL,准备发送数据
}
/*********************************************/
// I2C停止信号(逻辑不变)
void TCS34725_I2C_Stop()
{
SD1_SetOutput(); // SDA设为输出
TCS_SCL_L;
TCS_SDA_L;
delay_us(4);
TCS_SCL_H;
TCS_SDA_H;
delay_us(4); // 释放总线
}
/*********************************************/
// I2C等待ACK(逻辑不变)
u8 TCS34725_I2C_Wait_ACK()
{
u32 timeout = 0;
SD1_SetInput(); // SDA设为输入(等待从机ACK)
TCS_SDA_H;
delay_us(1);
TCS_SCL_H;
delay_us(1);
// 等待SDA拉低(ACK),超时则返回失败
while(I2C_SDA_READ())
{
timeout++;
if(timeout > 250) // 超时阈值可根据实际需求调整
{
TCS34725_I2C_Stop();
return 1; // ACK失败
}
}
TCS_SCL_L; // 拉低SCL,结束ACK检测
return 0; // ACK成功
}
/*********************************************/
// I2C发送ACK(逻辑不变)
void TCS34725_I2C_ACK()
{
TCS_SCL_L;
SD1_SetOutput();
TCS_SDA_L;
delay_us(2);
TCS_SCL_H;
delay_us(2);
TCS_SCL_L;
}
/*********************************************/
// I2C发送NACK(逻辑不变)
void TCS34725_I2C_NACK()
{
TCS_SCL_L;
SD1_SetOutput();
TCS_SDA_H;
delay_us(2);
TCS_SCL_H;
delay_us(2);
TCS_SCL_L;
}
/*********************************************/
// I2C发送1字节(逻辑不变)
void TCS34725_I2C_Send_Byte(u8 byte)
{
u8 i;
SD1_SetOutput(); // SDA设为输出
TCS_SCL_L; // 拉低时钟,开始数据传输
// 高位先行发送
for(i = 0; i < 8; i++)
{
if(((byte & 0x80) >> 7) == 1) TCS_SDA_H;
else TCS_SDA_L;
byte <<= 1;
delay_us(2);
TCS_SCL_H; // 高电平期间从机读取数据
delay_us(2);
TCS_SCL_L; // 拉低时钟,准备下一位
delay_us(2);
}
}
/*********************************************/
// I2C读取1字节(逻辑不变)
u8 TCS34725_I2C_Read_Byte(u8 ack)
{
u8 i, receive = 0;
SD1_SetInput(); // SDA设为输入
// 高位先行读取
for(i = 0; i < 8; i++)
{
TCS_SCL_L;
delay_us(2);
TCS_SCL_H; // 高电平期间主机读取数据
receive <<= 1;
if(I2C_SDA_READ()) receive++; // 读取当前bit
delay_us(1);
}
// 发送ACK/NACK
if (!ack) TCS34725_I2C_NACK(); // 最后1字节发送NACK
else TCS34725_I2C_ACK(); // 非最后1字节发送ACK
return receive;
}
/*********************************************/
// I2C写数据到从机(逻辑不变)
void TCS34725_I2C_Write(u8 slaveAddress, u8* dataBuffer, u8 bytesNumber, u8 stopBit)
{
u8 i = 0;
TCS34725_I2C_Start();
// 发送从机地址+写命令(最低位0)
TCS34725_I2C_Send_Byte((slaveAddress << 1) | 0x00);
if(TCS34725_I2C_Wait_ACK() != 0) return; // 等待ACK,失败则退出
// 发送数据
for(i = 0; i < bytesNumber; i++)
{
TCS34725_I2C_Send_Byte(*(dataBuffer + i));
if(TCS34725_I2C_Wait_ACK() != 0) return;
}
if(stopBit == 1) TCS34725_I2C_Stop(); // 按需发送停止信号
}
/*********************************************/
// I2C从从机读数据(逻辑不变)
void TCS34725_I2C_Read(u8 slaveAddress, u8* dataBuffer, u8 bytesNumber, u8 stopBit)
{
u8 i = 0;
TCS34725_I2C_Start();
// 发送从机地址+读命令(最低位1)
TCS34725_I2C_Send_Byte((slaveAddress << 1) | 0x01);
if(TCS34725_I2C_Wait_ACK() != 0) return; // 等待ACK,失败则退出
// 读取数据
for(i = 0; i < bytesNumber; i++)
{
if(i == bytesNumber - 1)
{
// 最后1字节:读后发NACK
*(dataBuffer + i) = TCS34725_I2C_Read_Byte(0);
}
else
{
// 非最后1字节:读后发ACK
*(dataBuffer + i) = TCS34725_I2C_Read_Byte(1);
}
}
if(stopBit == 1) TCS34725_I2C_Stop(); // 按需发送停止信号
}
/*********************************************/
/*******************************************************************************
* @brief Writes data into TCS34725 registers, starting from the selected
* register address pointer.
*
* @param subAddr - The selected register address pointer.
* @param dataBuffer - Pointer to a buffer storing the transmission data.
* @param bytesNumber - Number of bytes that will be sent.
*
* @return None.
*******************************************************************************/
void TCS34725_Write(u8 subAddr, u8* dataBuffer, u8 bytesNumber)
{
u8 sendBuffer[10] = {0, };
u8 byte = 0;
sendBuffer[0] = subAddr | TCS34725_COMMAND_BIT;
for(byte = 1; byte <= bytesNumber; byte++)
{
sendBuffer[byte] = dataBuffer[byte - 1];
}
TCS34725_I2C_Write(TCS34725_ADDRESS, sendBuffer, bytesNumber + 1, 1);
}
/*******************************************************************************
* @brief Reads data from TCS34725 registers, starting from the selected
* register address pointer.
*
* @param subAddr - The selected register address pointer.
* @param dataBuffer - Pointer to a buffer that will store the received data.
* @param bytesNumber - Number of bytes that will be read.
*
* @return None.
*******************************************************************************/
void TCS34725_Read(u8 subAddr, u8* dataBuffer, u8 bytesNumber)
{
subAddr |= TCS34725_COMMAND_BIT;
TCS34725_I2C_Write(TCS34725_ADDRESS, (u8*)&subAddr, 1, 0);
TCS34725_I2C_Read(TCS34725_ADDRESS, dataBuffer, bytesNumber, 1);
}
/*******************************************************************************
* @brief TCS34725设置积分时间
*
* @return None
*******************************************************************************/
void TCS34725_SetIntegrationTime(u8 time)
{
TCS34725_Write(TCS34725_ATIME, &time, 1);
}
/*******************************************************************************
* @brief TCS34725设置增益
*
* @return None
*******************************************************************************/
void TCS34725_SetGain(u8 gain)
{
TCS34725_Write(TCS34725_CONTROL, &gain, 1);
}
/*******************************************************************************
* @brief TCS34725使能
*
* @return None
*******************************************************************************/
void TCS34725_Enable(void)
{
u8 cmd = TCS34725_ENABLE_PON;
TCS34725_Write(TCS34725_ENABLE, &cmd, 1);
cmd = TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN;
TCS34725_Write(TCS34725_ENABLE, &cmd, 1);
//delay_s(600000);//delay_ms(3);//延时应该放在设置AEN之后
}
/*******************************************************************************
* @brief TCS34725失能
*
* @return None
*******************************************************************************/
void TCS34725_Disable(void)
{
u8 cmd = 0;
TCS34725_Read(TCS34725_ENABLE, &cmd, 1);
cmd = cmd & ~(TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN);
TCS34725_Write(TCS34725_ENABLE, &cmd, 1);
}
/*******************************************************************************
* @brief TCS34725初始化
*
* @return ID - ID寄存器中的值
*******************************************************************************/
u8 TCS34725_Init(void)
{
u8 id=0;
TCS34725_I2C_Init();
TCS34725_Read(TCS34725_ID, &id, 1); //TCS34725 的 ID 是 0x44 可以根据这个来判断是否成功连接,0x4D是TCS34727;
if(id==0x4D | id==0x44)
{
TCS34725_SetIntegrationTime(TCS34725_INTEGRATIONTIME_24MS);
TCS34725_SetGain(TCS34725_GAIN_4X);
TCS34725_Enable();
return 1;
}
return 0;
}
/*******************************************************************************
* @brief TCS34725获取单个通道数据
*
* @return data - 该通道的转换值
*******************************************************************************/
u16 TCS34725_GetChannelData(u8 reg)
{
u8 tmp[2] = {0,0};
u16 data;
TCS34725_Read(reg, tmp, 2);
data = (tmp[1] << 8) | tmp[0];
return data;
}
/*******************************************************************************
* @brief TCS34725获取各个通道数据
*
* @return 1 - 转换完成,数据可用
* 0 - 转换未完成,数据不可用
*******************************************************************************/
#define TCS34725_MAX_RAW_VALUE 65535
#define GAIN 0
u8 TCS34725_GetRawData(COLOR_RGBC *rgbc)
{
u8 status = TCS34725_STATUS_AVALID;
u32 total = 0;
TCS34725_Read(TCS34725_STATUS, &status, 1);
if(status & TCS34725_STATUS_AVALID)
{
rgbc->c = TCS34725_GetChannelData(TCS34725_CDATAL)>>GAIN;
rgbc->r = TCS34725_GetChannelData(TCS34725_RDATAL)>>GAIN;
rgbc->g = TCS34725_GetChannelData(TCS34725_GDATAL)>>GAIN;
rgbc->b = TCS34725_GetChannelData(TCS34725_BDATAL)>>GAIN;
total = rgbc->r + rgbc->g + rgbc->b;
if(rgbc->c > 765 || total >765 || rgbc->r > 255 || rgbc->g > 255 || rgbc->b > 255)
{
rgbc->r = rgbc->r * 255 / total;
rgbc->g = rgbc->g * 255 / total;
rgbc->b = rgbc->b * 255 / total;
rgbc->c = rgbc->c * 255 / total;
}
return 1;
}
return 0;
}
/******************************************************************************/
//RGB转HSL
void RGBtoHSL(COLOR_RGBC *Rgb, COLOR_HSL *Hsl)
{
u8 maxVal,minVal,difVal;
u8 r = Rgb->r*100/Rgb->c; //[0-100]
u8 g = Rgb->g*100/Rgb->c;
u8 b = Rgb->b*100/Rgb->c;
maxVal = max3v(r,g,b);
minVal = min3v(r,g,b);
difVal = maxVal-minVal;
//计算亮度
Hsl->l = (maxVal+minVal)/2; //[0-100]
if(maxVal == minVal)//若r=g=b,灰度
{
Hsl->h = 0;
Hsl->s = 0;
}
else
{
//计算色调
if(maxVal==r)
{
if(g>=b)
Hsl->h = 60*(g-b)/difVal;
else
Hsl->h = 60*(g-b)/difVal+360;
}
else
{
if(maxVal==g)Hsl->h = 60*(b-r)/difVal+120;
else
if(maxVal==b)Hsl->h = 60*(r-g)/difVal+240;
}
//计算饱和度
if(Hsl->l<=50)Hsl->s=difVal*100/(maxVal+minVal); //[0-100]
else
Hsl->s=difVal*100/(200-(maxVal+minVal));
}
}
/******************************************************************************/