本模块是基于AMS的TCS3472XFN彩色光数字转换器为核心的颜色传感器,传感器提供红色,绿色,蓝色(RGB)和清晰光感应值的数字输出。集成红外阻挡滤光片可最大限度地减少入射光的红外光谱成分,并可精确地进行颜色测量。具有高灵敏度,宽动态范围和红外阻隔滤波器。最小化IR和UV光谱分量效应,以产生准确的颜色测量。并且带有环境光强检测和可屏蔽中断。通过12C接口通信。本设计基于同一个设计原理,提供2个不同造型设计(方形版本/双孔版本),提供用户更多安装尺寸和环境的选择,其中双孔版本布局了2个LED灯对于物体进行补光。
一模块来源
模块实物展示:
资料下载链接:https://pan.baidu.com/s/1z_5qOfe-YMbj0TYSbDD-sQ?pwd=6668
资料提取码:6668
二 规格参数
工作电压:3.3-5V
工作电流:2.5~330uA
输出方式: IIC
管脚数量:7 Pin
以上信息见厂家资料文件
三移植过程
我们的目标是将例程移植至CW32F030C8T6开发板上【能够识别颜色数据】。首先要获取资料,查看数据手册应如何实现读取数据,再移植至我们的工程。
3.1查看资料
I2C地址:
I2C 设备地址为 0X29
注意:0X29 这个设备地址是 7 位的,8 位设备地址需要向高位移一位变成0X52。
I2C写时序:
首先主机会发送一个开始信号,然后将其 I2C 的 7 位地 址与写操作位组合成8位的数据发送给从机, 从机接收到后会响应一个应答信号,主机此时将命令寄存器地址发送给从机,从机接收到发送响应信号,此时主机发送命令寄存的值,从机回应一个响应信号,直到主机发送一个停止信号,此次 IIC 写数据操作结束。
I2C读时序:
首先主机会发送一个开始信号,然后将其 I2C 的 7 位地址与写操作位组合成 8位的数 据发送给从机,从机接收到后会响应一个应答信号,主机此时将命令寄存器地址发送给从机, 从机接收到发送响应信号,此时主机重新发送一个开始信号,并且将其 7 位地址和读操作位 组合成 8 位的数据发送给从机,从机接收到信号后发送响应信号,再将其寄存器中的值发送 给主机,主机端给予响应信号,直到主机端发送停止信号,此次通信结束。
3.2引脚选择
模块接线图
3.3移植至工程
移植步骤中的导入.c和.h文件与【CW32模块使用】DHT11温湿度传感器相同,只是将.c和.h文件更改为bsp_tcs34725.c与bsp_tcs34725.h。这里不再过多讲述,移植完成后面修改相关代码。
在文件bsp_tcs34725.c中,编写如下代码。
/** Change Logs:* Date Author Notes* 2024-06-20 LCKFB-LP first version*/#include "bsp_tcs34725.h"#include "stdio.h"#include "board.h"COLOR_RGBC rgb;COLOR_HSL hsl;/******************************************************************* 函 数 名 称:TC34725_GPIO_Init* 函 数 说 明:tc34725的引脚初始化* 函 数 形 参:无* 函 数 返 回:无* 作 者:LC* 备 注:无******************************************************************/void TC34725_GPIO_Init(void){GPIO_InitTypeDef GPIO_InitStruct; // GPIO初始化结构体RCC_TCS34725_ENABLE(); // 使能GPIO时钟GPIO_InitStruct.Pins = GPIO_SDA|GPIO_SCL; // GPIO引脚GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; // 开漏输出GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; // 输出速度高GPIO_Init(PORT_TCS34725, &GPIO_InitStruct); // 初始化}/******************************************************************* 函 数 名 称:IIC_Start* 函 数 说 明:IIC起始时序* 函 数 形 参:无* 函 数 返 回:无* 作 者:LC* 备 注:无******************************************************************/void IIC_Start(void){SDA_OUT();SDA(1);delay_us(5);SCL(1);delay_us(5);SDA(0);delay_us(5);SCL(0);delay_us(5);}/******************************************************************* 函 数 名 称:IIC_Stop* 函 数 说 明:IIC停止信号* 函 数 形 参:无* 函 数 返 回:无* 作 者:LC* 备 注:无******************************************************************/void IIC_Stop(void){SDA_OUT();SCL(0);SDA(0);SCL(1);delay_us(5);SDA(1);delay_us(5);}/******************************************************************* 函 数 名 称:IIC_Send_Ack* 函 数 说 明:主机发送应答或者非应答信号* 函 数 形 参:0发送应答 1发送非应答* 函 数 返 回:无* 作 者:LC* 备 注:无******************************************************************/void IIC_Send_Ack(unsigned char ack){SDA_OUT();SCL(0);SDA(0);delay_us(5);if(!ack) SDA(0);else SDA(1);SCL(1);delay_us(5);SCL(0);SDA(1);}/******************************************************************* 函 数 名 称:I2C_WaitAck* 函 数 说 明:等待从机应答* 函 数 形 参:无* 函 数 返 回:0有应答 1超时无应答* 作 者:LC* 备 注:无******************************************************************/unsigned char I2C_WaitAck(void){char ack = 0;unsigned char ack_flag = 10;SCL(0);SDA(1);SDA_IN();delay_us(5);SCL(1);delay_us(5);while( (SDA_GET()==1) && ( ack_flag ) ){ack_flag--;delay_us(5);}if( ack_flag <= 0 ){IIC_Stop();return 1;}else{SCL(0);SDA_OUT();}return ack;}/******************************************************************* 函 数 名 称:Send_Byte* 函 数 说 明:写入一个字节* 函 数 形 参:dat要写人的数据* 函 数 返 回:无* 作 者:LC* 备 注:无******************************************************************/void Send_Byte(uint8_t dat){int i = 0;SDA_OUT();SCL(0);//拉低时钟开始数据传输for( i = 0; i < 8; i++ ){SDA( (dat & 0x80) >> 7 );delay_us(1);SCL(1);delay_us(5);SCL(0);delay_us(5);dat<<=1;}}/******************************************************************* 函 数 名 称:Read_Byte* 函 数 说 明:IIC读时序* 函 数 形 参:无* 函 数 返 回:读到的数据* 作 者:LC* 备 注:无******************************************************************/unsigned char Read_Byte(void){unsigned char i,receive=0;SDA_IN();//SDA设置为输入for(i=0;i<8;i++ ){SCL(0);delay_us(5);SCL(1);delay_us(5);receive<<=1;if( SDA_GET() ){receive|=1;}delay_us(5);}SCL(0);return receive;}/******************************************************************************** @brief Writes data to a slave device.** @param slaveAddress - Adress of the slave device.* @param dataBuffer - Pointer to a buffer storing the transmission data.* @param bytesNumber - Number of bytes to write.* @param stopBit - Stop condition control.* Example: 0 - A stop condition will not be sent;* 1 - A stop condition will be sent.*******************************************************************************/void TCS34725_I2C_Write(uint8_t slaveAddress, uint8_t* dataBuffer,uint8_t bytesNumber, uint8_t stopBit){uint8_t i = 0;IIC_Start();Send_Byte((slaveAddress << 1) | 0x00); //发送从机地址写命令I2C_WaitAck();for(i = 0; i < bytesNumber; i++){Send_Byte(*(dataBuffer + i));I2C_WaitAck();}if(stopBit == 1) IIC_Stop();}/******************************************************************************** @brief Reads data from a slave device.** @param slaveAddress - Adress of the slave device.* @param dataBuffer - Pointer to a buffer that will store the received data.* @param bytesNumber - Number of bytes to read.* @param stopBit - Stop condition control.* Example: 0 - A stop condition will not be sent;* 1 - A stop condition will be sent.*******************************************************************************/void TCS34725_I2C_Read(uint8_t slaveAddress, uint8_t* dataBuffer, uint8_t bytesNumber, uint8_t stopBit){uint8_t i = 0;IIC_Start();Send_Byte((slaveAddress << 1) | 0x01); //发送从机地址读命令I2C_WaitAck();for(i = 0; i < bytesNumber; i++){if(i == bytesNumber - 1){*(dataBuffer + i) = Read_Byte();//读取的最后一个字节发送NACKIIC_Send_Ack(1);}else{*(dataBuffer + i) = Read_Byte();IIC_Send_Ack(0);}}if(stopBit == 1) IIC_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(uint8_t subAddr, uint8_t* dataBuffer, uint8_t bytesNumber){uint8_t sendBuffer[10] = {0, };uint8_t 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(uint8_t subAddr, uint8_t* dataBuffer, uint8_t bytesNumber){subAddr |= TCS34725_COMMAND_BIT;TCS34725_I2C_Write(TCS34725_ADDRESS, (uint8_t*)&subAddr, 1, 0);TCS34725_I2C_Read(TCS34725_ADDRESS, dataBuffer, bytesNumber, 1);}/******************************************************************************** @brief TCS34725设置积分时间** @return None*******************************************************************************/void TCS34725_SetIntegrationTime(uint8_t time){TCS34725_Write(TCS34725_ATIME, &time, 1);}/******************************************************************************** @brief TCS34725设置增益** @return None*******************************************************************************/void TCS34725_SetGain(uint8_t gain){TCS34725_Write(TCS34725_CONTROL, &gain, 1);}/******************************************************************************** @brief TCS34725使能** @return None*******************************************************************************/void TCS34725_Enable(void){uint8_t 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){uint8_t 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寄存器中的值*******************************************************************************/uint8_t TCS34725_Init(void){uint8_t id=0;TC34725_GPIO_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_1X);TCS34725_Enable();return 1;}return 0;}/******************************************************************************** @brief TCS34725获取单个通道数据** @return data - 该通道的转换值*******************************************************************************/uint16_t TCS34725_GetChannelData(uint8_t reg){uint8_t tmp[2] = {0,0};uint16_t data;TCS34725_Read(reg, tmp, 2);data = (tmp[1] << 8) | tmp[0];return data;}/******************************************************************************** @brief TCS34725获取各个通道数据** @return 1 - 转换完成,数据可用* 0 - 转换未完成,数据不可用*******************************************************************************/uint8_t TCS34725_GetRawData(COLOR_RGBC *rgbc){uint8_t status = TCS34725_STATUS_AVALID;TCS34725_Read(TCS34725_STATUS, &status, 1);if(status & TCS34725_STATUS_AVALID){rgbc->c = TCS34725_GetChannelData(TCS34725_CDATAL);rgbc->r = TCS34725_GetChannelData(TCS34725_RDATAL);rgbc->g = TCS34725_GetChannelData(TCS34725_GDATAL);rgbc->b = TCS34725_GetChannelData(TCS34725_BDATAL);return 1;}return 0;}/******************************************************************************///RGB转HSLvoid RGBtoHSL(COLOR_RGBC *Rgb, COLOR_HSL *Hsl){uint8_t maxVal,minVal,difVal;uint8_t r = Rgb->r*100/Rgb->c; //[0-100]uint8_t g = Rgb->g*100/Rgb->c;uint8_t 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;elseHsl->h = 60*(g-b)/difVal+360;}else{if(maxVal==g)Hsl->h = 60*(b-r)/difVal+120;elseif(maxVal==b)Hsl->h = 60*(r-g)/difVal+240;}//计算饱和度if(Hsl->l<=50)Hsl->s=difVal*100/(maxVal+minVal); //[0-100]elseHsl->s=difVal*100/(200-(maxVal+minVal));}}/******************************************************************************/
在文件bsp_tcs34725.h中,编写如下代码。
/** Change Logs:* Date Author Notes* 2024-06-20 LCKFB-LP first version*/#ifndef _BSP_TCS34725_H_#define _BSP_TCS34725_H_#include "board.h"//端口移植#define RCC_TCS34725_ENABLE() __RCC_GPIOB_CLK_ENABLE()#define PORT_TCS34725 CW_GPIOB#define GPIO_SDA GPIO_PIN_8#define GPIO_SCL GPIO_PIN_9//设置SDA输出模式#define SDA_OUT() {GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.Pins = GPIO_SDA;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;GPIO_Init(PORT_TCS34725, &GPIO_InitStruct);}//设置SDA输入模式#define SDA_IN() {GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.Pins = GPIO_SDA;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;GPIO_Init(PORT_TCS34725, &GPIO_InitStruct);}//获取SDA引脚的电平变化#define SDA_GET() GPIO_ReadPin(PORT_TCS34725, GPIO_SDA)//SDA与SCL输出#define SDA(x) GPIO_WritePin(PORT_TCS34725, GPIO_SDA, (x?GPIO_Pin_SET:GPIO_Pin_RESET) )#define SCL(x) GPIO_WritePin(PORT_TCS34725, GPIO_SCL, (x?GPIO_Pin_SET:GPIO_Pin_RESET) )/******************************************************************************/#define TCS34725_ADDRESS (0x29)#define TCS34725_COMMAND_BIT (0x80)#define TCS34725_ENABLE (0x00)#define TCS34725_ENABLE_AIEN (0x10) /* RGBC Interrupt Enable */#define TCS34725_ENABLE_WEN (0x08) /* Wait enable - Writing 1 activates the wait timer */#define TCS34725_ENABLE_AEN (0x02) /* RGBC Enable - Writing 1 actives the ADC, 0 disables it */#define TCS34725_ENABLE_PON (0x01) /* Power on - Writing 1 activates the internal oscillator, 0 disables it */#define TCS34725_ATIME (0x01) /* Integration time */#define TCS34725_WTIME (0x03) /* Wait time (if TCS34725_ENABLE_WEN is asserted) */#define TCS34725_WTIME_2_4MS (0xFF) /* WLONG0 = 2.4ms WLONG1 = 0.029s */#define TCS34725_WTIME_204MS (0xAB) /* WLONG0 = 204ms WLONG1 = 2.45s */#define TCS34725_WTIME_614MS (0x00) /* WLONG0 = 614ms WLONG1 = 7.4s */#define TCS34725_AILTL (0x04) /* Clear channel lower interrupt threshold */#define TCS34725_AILTH (0x05)#define TCS34725_AIHTL (0x06) /* Clear channel upper interrupt threshold */#define TCS34725_AIHTH (0x07)#define TCS34725_PERS (0x0C) /* Persistence register - basic SW filtering mechanism for interrupts */#define TCS34725_PERS_NONE (0b0000) /* Every RGBC cycle generates an interrupt */#define TCS34725_PERS_1_CYCLE (0b0001) /* 1 clean channel value outside threshold range generates an interrupt */#define TCS34725_PERS_2_CYCLE (0b0010) /* 2 clean channel values outside threshold range generates an interrupt */#define TCS34725_PERS_3_CYCLE (0b0011) /* 3 clean channel values outside threshold range generates an interrupt */#define TCS34725_PERS_5_CYCLE (0b0100) /* 5 clean channel values outside threshold range generates an interrupt */#define TCS34725_PERS_10_CYCLE (0b0101) /* 10 clean channel values outside threshold range generates an interrupt */#define TCS34725_PERS_15_CYCLE (0b0110) /* 15 clean channel values outside threshold range generates an interrupt */#define TCS34725_PERS_20_CYCLE (0b0111) /* 20 clean channel values outside threshold range generates an interrupt */#define TCS34725_PERS_25_CYCLE (0b1000) /* 25 clean channel values outside threshold range generates an interrupt */#define TCS34725_PERS_30_CYCLE (0b1001) /* 30 clean channel values outside threshold range generates an interrupt */#define TCS34725_PERS_35_CYCLE (0b1010) /* 35 clean channel values outside threshold range generates an interrupt */#define TCS34725_PERS_40_CYCLE (0b1011) /* 40 clean channel values outside threshold range generates an interrupt */#define TCS34725_PERS_45_CYCLE (0b1100) /* 45 clean channel values outside threshold range generates an interrupt */#define TCS34725_PERS_50_CYCLE (0b1101) /* 50 clean channel values outside threshold range generates an interrupt */#define TCS34725_PERS_55_CYCLE (0b1110) /* 55 clean channel values outside threshold range generates an interrupt */#define TCS34725_PERS_60_CYCLE (0b1111) /* 60 clean channel values outside threshold range generates an interrupt */#define TCS34725_CONFIG (0x0D)#define TCS34725_CONFIG_WLONG (0x02) /* Choose between short and long (12x) wait times via TCS34725_WTIME */#define TCS34725_CONTROL (0x0F) /* Set the gain level for the sensor */#define TCS34725_ID (0x12) /* 0x44 = TCS34721/TCS34725, 0x4D = TCS34723/TCS34727 */#define TCS34725_STATUS (0x13)#define TCS34725_STATUS_AINT (0x10) /* RGBC Clean channel interrupt */#define TCS34725_STATUS_AVALID (0x01) /* Indicates that the RGBC channels have completed an integration cycle */#define TCS34725_CDATAL (0x14) /* Clear channel data */#define TCS34725_CDATAH (0x15)#define TCS34725_RDATAL (0x16) /* Red channel data */#define TCS34725_RDATAH (0x17)#define TCS34725_GDATAL (0x18) /* Green channel data */#define TCS34725_GDATAH (0x19)#define TCS34725_BDATAL (0x1A) /* Blue channel data */#define TCS34725_BDATAH (0x1B)#define TCS34725_INTEGRATIONTIME_2_4MS 0xFF /**< 2.4ms - 1 cycle - Max Count: 1024 */#define TCS34725_INTEGRATIONTIME_24MS 0xF6 /**< 24ms - 10 cycles - Max Count: 10240 */#define TCS34725_INTEGRATIONTIME_50MS 0xEB /**< 50ms - 20 cycles - Max Count: 20480 */#define TCS34725_INTEGRATIONTIME_101MS 0xD5 /**< 101ms - 42 cycles - Max Count: 43008 */#define TCS34725_INTEGRATIONTIME_154MS 0xC0 /**< 154ms - 64 cycles - Max Count: 65535 */#define TCS34725_INTEGRATIONTIME_240MS 0x9C /**< 240ms - 100 cycles - Max Count: 65535 */#define TCS34725_INTEGRATIONTIME_700MS 0x00 /**< 700ms - 256 cycles - Max Count: 65535 */#define TCS34725_GAIN_1X 0x00 /**< No gain */#define TCS34725_GAIN_4X 0x01 /**< 4x gain */#define TCS34725_GAIN_16X 0x02 /**< 16x gain */#define TCS34725_GAIN_60X 0x03 /**< 60x gain *//******************************************************************************//******************************************************************************/#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)))typedef struct{unsigned short c; //[0-65536]unsigned short r;unsigned short g;unsigned short b;}COLOR_RGBC;//RGBCtypedef struct{unsigned short h; //[0,360]unsigned char s; //[0,100]unsigned char l; //[0,100]}COLOR_HSL;//HSL/******************************************************************************/extern COLOR_RGBC rgb;extern COLOR_HSL hsl;uint8_t TCS34725_Init(void);uint8_t TCS34725_GetRawData(COLOR_RGBC *rgbc);void RGBtoHSL(COLOR_RGBC *Rgb, COLOR_HSL *Hsl);#endif
四移植验证
在自己工程中的main主函数中,编写如下。
/** Change Logs:* Date Author Notes* 2024-06-20 LCKFB-LP first version*/#include "board.h"#include "stdio.h"#include "bsp_uart.h"#include "bsp_tcs34725.h"int32_t main(void){board_init(); // 开发板初始化uart1_init(115200); // 串口1波特率115200TCS34725_Init();printf("startrn");delay_ms(1000);while(1){TCS34725_GetRawData(&rgb); //读两次,实际测试时发现读到的颜色总是上一次的颜色RGBtoHSL(&rgb,&hsl);printf("R=%d G=%d B=%d C=%drn",rgb.r,rgb.g,rgb.b,rgb.c);printf("H=%d S=%d L=%drn",hsl.h,hsl.s,hsl.l);printf("n");delay_ms(1000);}}
移植现象:输出当前RGB值。
模块移植成功案例代码:
链接:https://pan.baidu.com/s/15K2g_r6xcYeBfNMh4m1eMQ?pwd=LCKF
提取码:LCKF
2915