#include "TCS34725.h" tcs34725IntegrationTime_t _tcs34725IntegrationTime; tcs34725Gain_t _tcs34725Gain; uint8_t TCS34725_I2C_Read(uint8_t addr, uint8_t reg) { uint8_t TCS34725_I2C[3]={0,}; uint16_t value = 0; uint8_t data = 0; data=HAL_I2C_Mem_Read(&hi2c1, addr, reg, 1, TCS34725_I2C, 1, 10); // i2c_status(data); value = TCS34725_I2C[0]; return value; } void TCS34725_I2C_Write(uint8_t addr, uint8_t reg, uint8_t data) { uint8_t tmp_afe; tmp_afe = data; HAL_I2C_Mem_Write(&hi2c1, addr, reg, 1, &tmp_afe, 1, 10); } /**************************************************************************/ /*! Adjusts the gain on the TCS34725 (adjusts the sensitivity to light) */ /**************************************************************************/ uint8_t RGB_Data[100] = {0,}; typedef struct{ uint8_t Clear_H; uint8_t Clear_L; uint8_t Red_H; uint8_t Red_L; uint8_t Green_H; uint8_t Green_L; uint8_t Blue_H; uint8_t Blue_L; }RGB_Bit_st; void RGB_data_arrage(uint8_t* rgbval){ static uint8_t Cnt = 0; static uint16_t Clear_Calc_data ; static uint16_t Red_Calc_data ; static uint16_t Green_Calc_data ; static uint16_t Blue_Calc_data ; RGB_Bit_st data; memcpy(&data.Clear_L,&rgbval[0],8); uint16_t Clear = (data.Clear_H << 8) | data.Clear_L; uint16_t Red = (data.Red_H << 8) | data.Red_L; uint16_t Green = (data.Green_H << 8) | data.Green_L; uint16_t Blue = (data.Blue_H << 8) | data.Blue_L; #if 1 // PYJ.2019.03.15_BEGIN -- switch(Cnt){ case 0: Clear_Calc_data = Clear; Red_Calc_data = Red; Green_Calc_data = Green; Blue_Calc_data = Blue; Cnt = 1; #if 0 // PYJ.2019.03.16_BEGIN -- printf("=============CNT : 0================\r\n"); printf("Clear_Calc_data : %04x \r\n",Clear_Calc_data); printf("Red_Calc_data : %04x \r\n",Red_Calc_data); printf("Green_Calc_data : %04x \r\n",Green_Calc_data); printf("Blue_Calc_data : %04x \r\n",Blue_Calc_data); #endif // PYJ.2019.03.16_END -- break; case 1: Clear_Calc_data += Clear; Red_Calc_data += Red; Green_Calc_data += Green; Blue_Calc_data += Blue; Cnt = 2; #if 0 // PYJ.2019.03.16_BEGIN -- printf("=============CNT : 1================\r\n"); printf("Clear_Calc_data : %04x \r\n",Clear_Calc_data); printf("Red_Calc_data : %04x \r\n",Red_Calc_data); printf("Green_Calc_data : %04x \r\n",Green_Calc_data); printf("Blue_Calc_data : %04x \r\n",Blue_Calc_data); #endif // PYJ.2019.03.16_END -- break; case 2: Clear_Calc_data += Clear; Red_Calc_data += Red; Green_Calc_data += Green; Blue_Calc_data += Blue; Cnt = 3; #if 0 // PYJ.2019.03.16_BEGIN -- printf("=============CNT : 2================\r\n"); printf("Clear_Calc_data : %04x \r\n",Clear_Calc_data); printf("Red_Calc_data : %04x \r\n",Red_Calc_data); printf("Green_Calc_data : %04x \r\n",Green_Calc_data); printf("Blue_Calc_data : %04x \r\n",Blue_Calc_data); #endif // PYJ.2019.03.16_END -- break; case 3: Clear_Calc_data = (Clear_Calc_data + Clear)/4; Red_Calc_data = (Red_Calc_data + Red)/4; Green_Calc_data = (Green_Calc_data + Green)/4; Blue_Calc_data = (Blue_Calc_data + Blue)/4; #if 0 // PYJ.2019.03.16_BEGIN -- printf("=============CNT : 3================\r\n"); printf("Clear_Calc_data : %04x \r\n",Clear_Calc_data); printf("Red_Calc_data : %04x \r\n",Red_Calc_data); printf("Green_Calc_data : %04x \r\n",Green_Calc_data); printf("Blue_Calc_data : %04x \r\n",Blue_Calc_data); #endif // PYJ.2019.03.16_END -- RGB_Data[Bluecell_STX] = 0xbe; RGB_Data[Bluecell_Type] = RGB_Status_Data_Response;//Type RGB_Data[Bluecell_Length] = 12;//Length RGB_Data[Bluecell_DATA] = My_RGB_ID;//Src ID RGB_Data[4] = ((Clear_Calc_data & 0xFF00) >> 8); RGB_Data[5] = (Clear_Calc_data & 0x00FF); RGB_Data[6] = ((Red_Calc_data & 0xFF00) >> 8); RGB_Data[7] = (Red_Calc_data & 0x00FF); RGB_Data[8] = ((Green_Calc_data & 0xFF00) >> 8); RGB_Data[9] = (Green_Calc_data & 0x00FF); RGB_Data[10] = ((Blue_Calc_data & 0xFF00) >> 8); RGB_Data[11] = (Blue_Calc_data & 0x00FF); RGB_Data[12] = 0;//dst id(Blue_Calc_data & 0x00FF); RGB_Data[13] = STH30_CreateCrc(&RGB_Data[Bluecell_Type],RGB_Data[Bluecell_Length]);//crc RGB_Data[14] = 0xeb; #if 0 // PYJ.2019.03.16_BEGIN -- for(uint8_t i = Bluecell_STX; i < 15; i++) printf("RGB_Data[%d] : %02x\n",i,RGB_Data[i]); #endif // PYJ.2019.03.16_END -- // Uart2_Data_Send(&RGB_Data[0],15); Cnt = 0; // memset(&RGB_Data[0],0x00,100); break; } #else #if 1 // PYJ.2019.03.16_BEGIN -- #if 0 // PYJ.2019.03.16_BEGIN -- RGB_Data[0] = ((Clear_Calc_data & 0xFF00) >> 8); RGB_Data[1] = (Clear_Calc_data & 0x00FF); RGB_Data[2] = ((Red_Calc_data & 0xFF00) >> 8); RGB_Data[3] = (Red_Calc_data & 0x00FF); RGB_Data[4] = ((Green_Calc_data & 0xFF00) >> 8); RGB_Data[5] = (Green_Calc_data & 0x00FF); RGB_Data[6] = ((Blue_Calc_data & 0xFF00) >> 8); RGB_Data[7] = (Blue_Calc_data & 0x00FF); #endif // PYJ.2019.03.16_END -- #if 0 // PYJ.2019.03.16_BEGIN -- temp_data.Clear_L temp_data.Clear_H temp_data.Red_L temp_data.Red_H temp_data.Green_L temp_data.Green_H temp_data.Blue_L temp_data.Blue_H #endif // PYJ.2019.03.16_END -- #endif // PYJ.2019.03.16_END -- // memset(&temp[0],0xFF,8); Uart2_Data_Send(&temp[0],8); #endif // PYJ.2019.03.15_END -- } void TCS34725_getrawdata(void) { RGB_Bit_st data; uint8_t DEV_DATA = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_ID); data.Clear_L = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_CDATAL); data.Clear_H = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_CDATAH); data.Red_L = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_RDATAL); data.Red_H = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_RDATAH); data.Green_L = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_GDATAL); data.Green_H = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_GDATAH); data.Blue_L = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_BDATAL); data.Blue_H = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_BDATAH); #if 0 // PYJ.2019.03.15_BEGIN -- printf("C_DATA_L : %02x C_DATA_H %02x \r\n",data.Clear_L, data.Clear_H); printf("R_DATA_L : %02x R_DATA_H %02x \r\n",data.Red_L,data.Red_H); printf("G_DATA_L : %02x G_DATA_H %02x \r\n",data.Green_L,data.Green_H); printf("B_DATA_L : %02x B_DATA_H %02x \r\n",data.Blue_L,data.Blue_L); #endif // PYJ.2019.03.15_END -- #if 0 double CLEAR = 0; double RED = 0; double GREEN = 0; double BLUE = 0; printf("************************************\r\n"); printf("1. DEV ID\t:\t%x\r\n", DEV_DATA); CLEAR = (C_DATA_H << 8) | C_DATA_L; data_ret_C = (CLEAR / 65535)*255; printf("CLEAR : %d\r\n",data_ret_C); RED = (R_DATA_H << 8) | R_DATA_L; data_ret_R = (RED / 65535)*255; printf("RED : %d\r\n",data_ret_R); GREEN = (G_DATA_H << 8) | G_DATA_L; data_ret_G = (GREEN / 65535)*255; printf("GREEN : %d\r\n",data_ret_G); BLUE = (B_DATA_H << 8) | B_DATA_L; data_ret_B = (BLUE / 65535)*255; printf("BLUE : %d\r\n",data_ret_B); #else #if 0 // PYJ.2019.03.16_BEGIN -- uint16_t CLEAR = 0; uint16_t RED = 0; uint16_t GREEN = 0; uint16_t BLUE = 0; #endif // PYJ.2019.03.16_END -- #if 0 // PYJ.2019.03.15_BEGIN -- CLEAR = (C_DATA_H << 8) | C_DATA_L; // data_ret_C = (CLEAR / 65535)*255; RED = (R_DATA_H << 8) | R_DATA_L; // data_ret_R = (RED / 65535)*255; GREEN = (G_DATA_H << 8) | G_DATA_L; // data_ret_G = (GREEN / 65535)*255; BLUE = (B_DATA_H << 8) | B_DATA_L; // data_ret_B = (BLUE / 65535)*255; #else #if 0 // PYJ.2019.03.16_BEGIN -- CLEAR = (C_DATA_H << 8) | C_DATA_L; RED = (R_DATA_H << 8) | R_DATA_L; GREEN = (G_DATA_H << 8) | G_DATA_L; BLUE = (B_DATA_H << 8) | B_DATA_L; #endif // PYJ.2019.03.16_END -- RGB_data_arrage(&data.Clear_L); #endif // PYJ.2019.03.15_END -- #if 0 printf("02%04x%05d%04x%05d%04x%05d%04x%05d03\r\n",data_ret_C,data_ret_C,data_ret_R,data_ret_R,data_ret_G,data_ret_G,data_ret_B,data_ret_B); #else // printf("%04x,%05d,%04x,%05d,%04x,%05d,%04x,%05d,\r\n",data_ret_C,data_ret_C,data_ret_R,data_ret_R,data_ret_G,data_ret_G,data_ret_B,data_ret_B); // printf("%x %d %d %d %d %d %d %d %d\r\n",DEV_DATA,(uint16_t)CLEAR,data_ret_C,(uint16_t)RED,data_ret_R,(uint16_t)GREEN,data_ret_G,(uint16_t)BLUE,data_ret_B); // printf("Dev ID : (%x) %d %d %d %d \r\n",DEV_DATA,(uint16_t)CLEAR,(uint16_t)RED,(uint16_t)GREEN,(uint16_t)BLUE); #endif #endif #if 0 uint16_t CLEAR = 0; uint16_t RED = 0; uint16_t GREEN = 0; uint16_t BLUE = 0; CLEAR = (C_DATA_H << 8) | C_DATA_L; RED = (R_DATA_H << 8) | R_DATA_L; GREEN = (G_DATA_H << 8) | G_DATA_L; BLUE = (B_DATA_H << 8) | B_DATA_L; printf("1. DEV ID\t:\t%x\r\n", DEV_DATA); printf("3. C\t:\tHEX : [%04x]\tDEC : [%05d]\r\n", CLEAR,CLEAR); printf("4. R\t:\tHEX : [%04x]\tDEC : [%05d]\r\n", RED,RED); printf("5. G\t:\tHEX : [%04x]\tDEC : [%05d]\r\n", GREEN,GREEN); printf("6. B\t:\tHEX : [%04x]\tDEC : [%05d]\r\n", BLUE,BLUE); #else #endif } void TCS34725_disable(void){ /* Turn the device off to save power */ uint8_t reg = 0; reg = TCS34725_I2C_Read(TCS34725_ADDRESS,TCS34725_ENABLE); TCS34725_I2C_Write(TCS34725_ADDRESS,TCS34725_ENABLE, reg & ~(TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN)); } void TCS34725_enable(void) { TCS34725_I2C_Write(TCS34725_ADDRESS, TCS34725_ENABLE, TCS34725_ENABLE_PON); HAL_Delay(3); TCS34725_I2C_Write(TCS34725_ADDRESS, TCS34725_ENABLE, TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN); switch (_tcs34725IntegrationTime) { case TCS34725_INTEGRATIONTIME_2_4MS: HAL_Delay(3); break; case TCS34725_INTEGRATIONTIME_24MS: HAL_Delay(24); break; case TCS34725_INTEGRATIONTIME_50MS: HAL_Delay(50); break; case TCS34725_INTEGRATIONTIME_101MS: HAL_Delay(101); break; case TCS34725_INTEGRATIONTIME_154MS: HAL_Delay(154); break; case TCS34725_INTEGRATIONTIME_700MS: HAL_Delay(700); break; } } void tcs34725SetIntegrationTime(tcs34725IntegrationTime_t it) { TCS34725_I2C_Write(TCS34725_ADDRESS,TCS34725_ATIME, it); _tcs34725IntegrationTime = it; } void getRawDataOneShot (void) { // TCS34725_enable(); TCS34725_getrawdata(); // TCS34725_disable(); } /**************************************************************************/ /*! @brief Converts the raw R/G/B values to color temperature in degrees Kelvin */ /**************************************************************************/ uint16_t calculateColorTemperature(uint16_t r, uint16_t g, uint16_t b) { float X, Y, Z; /* RGB to XYZ correlation */ float xc, yc; /* Chromaticity co-ordinates */ float n; /* McCamy's formula */ float cct; /* 1. Map RGB values to their XYZ counterparts. */ /* Based on 6500K fluorescent, 3000K fluorescent */ /* and 60W incandescent values for a wide range. */ /* Note: Y = Illuminance or lux */ X = (-0.14282F * r) + (1.54924F * g) + (-0.95641F * b); Y = (-0.32466F * r) + (1.57837F * g) + (-0.73191F * b); Z = (-0.68202F * r) + (0.77073F * g) + ( 0.56332F * b); /* 2. Calculate the chromaticity co-ordinates */ xc = (X) / (X + Y + Z); yc = (Y) / (X + Y + Z); /* 3. Use McCamy's formula to determine the CCT */ n = (xc - 0.3320F) / (0.1858F - yc); /* Calculate the final CCT */ cct = (449.0F * powf(n, 3)) + (3525.0F * powf(n, 2)) + (6823.3F * n) + 5520.33F; /* Return the results in degrees Kelvin */ return (uint16_t)cct; } /**************************************************************************/ /*! @brief Converts the raw R/G/B values to lux */ /**************************************************************************/ uint16_t calculateLux(uint16_t r, uint16_t g, uint16_t b) { float illuminance; /* This only uses RGB ... how can we integrate clear or calculate lux */ /* based exclusively on clear since this might be more reliable? */ illuminance = (-0.32466F * r) + (1.57837F * g) + (-0.73191F * b); return (uint16_t)illuminance; } /**************************************************************************/ /*! @brief Sets gain to the specified value */ /**************************************************************************/ void tcs34725SetGain(tcs34725Gain_t gain) { TCS34725_I2C_Write(TCS34725_ADDRESS,TCS34725_CONTROL, gain); _tcs34725Gain = gain; } /**************************************************************************/ /*! @brief Converts the raw R/G/B values to color temperature in degrees Kelvin using the algorithm described in DN40 from Taos (now AMS). */ /**************************************************************************/ uint16_t calculateColorTemperature_dn40(uint16_t r, uint16_t g, uint16_t b, uint16_t c) { int rc; /* Error return code */ uint16_t r2, g2, b2; /* RGB values minus IR component */ int gl; /* Results of the initial lux conversion */ uint8_t gain_int; /* Gain multiplier as a normal integer */ uint16_t sat; /* Digital saturation level */ uint16_t ir; /* Inferred IR content */ /* Analog/Digital saturation: * * (a) As light becomes brighter, the clear channel will tend to * saturate first since R+G+B is approximately equal to C. * (b) The TCS34725 accumulates 1024 counts per 2.4ms of integration * time, up to a maximum values of 65535. This means analog * saturation can occur up to an integration time of 153.6ms * (64*2.4ms=153.6ms). * (c) If the integration time is > 153.6ms, digital saturation will * occur before analog saturation. Digital saturation occurs when * the count reaches 65535. */ if ((256 - _tcs34725IntegrationTime) > 63) { /* Track digital saturation */ sat = 65535; } else { /* Track analog saturation */ sat = 1024 * (256 - _tcs34725IntegrationTime); } /* Ripple rejection: * * (a) An integration time of 50ms or multiples of 50ms are required to * reject both 50Hz and 60Hz ripple. * (b) If an integration time faster than 50ms is required, you may need * to average a number of samples over a 50ms period to reject ripple * from fluorescent and incandescent light sources. * * Ripple saturation notes: * * (a) If there is ripple in the received signal, the value read from C * will be less than the max, but still have some effects of being * saturated. This means that you can be below the 'sat' value, but * still be saturating. At integration times >150ms this can be * ignored, but <= 150ms you should calculate the 75% saturation * level to avoid this problem. */ if ((256 - _tcs34725IntegrationTime) <= 63) { /* Adjust sat to 75% to avoid analog saturation if atime < 153.6ms */ sat -= sat/4; } /* Check for saturation and mark the sample as invalid if true */ if (c >= sat) { return 0; } /* AMS RGB sensors have no IR channel, so the IR content must be */ /* calculated indirectly. */ ir = (r + g + b > c) ? (r + g + b - c) / 2 : 0; /* Remove the IR component from the raw RGB values */ r2 = r - ir; g2 = g - ir; b2 = b - ir; /* Convert gain to a usable integer value */ switch(_tcs34725Gain) { case TCS34725_GAIN_4X: /* GAIN 4X */ gain_int = 4; break; case TCS34725_GAIN_16X: /* GAIN 16X */ gain_int = 16; break; case TCS34725_GAIN_60X: /* GAIN 60X */ gain_int = 60; break; case TCS34725_GAIN_1X: /* GAIN 1X */ default: gain_int = 1; break; } /* Calculate the counts per lux (CPL), taking into account the optional * arguments for Glass Attenuation (GA) and Device Factor (DF). * * GA = 1/T where T is glass transmissivity, meaning if glass is 50% * transmissive, the GA is 2 (1/0.5=2), and if the glass attenuates light * 95% the GA is 20 (1/0.05). A GA of 1.0 assumes perfect transmission. * * NOTE: It is recommended to have a CPL > 5 to have a lux accuracy * < +/- 0.5 lux, where the digitization error can be calculated via: * 'DER = (+/-2) / CPL'. */ float cpl = (((256-_tcs34725IntegrationTime)*2.4f) * gain_int) / (1.0f * 310.0f); /* Determine lux accuracy (+/- lux) */ float der = 2.0f / cpl; /* Determine the maximum lux value */ float max_lux = 65535.0 / (cpl * 3); /* Lux is a function of the IR-compensated RGB channels and the associated * color coefficients, with G having a particularly heavy influence to * match the nature of the human eye. * * NOTE: The green value should be > 10 to ensure the accuracy of the lux * conversions. If it is below 10, the gain should be increased, but * the clear<100 check earlier should cover this edge case. */ gl = 0.136f * (float)r2 + /** Red coefficient. */ 1.000f * (float)g2 + /** Green coefficient. */ -0.444f * (float)b2; /** Blue coefficient. */ float lux = gl / cpl; /* A simple method of measuring color temp is to use the ratio of blue */ /* to red light, taking IR cancellation into account. */ uint16_t cct = (3810 * (uint32_t)b2) / /** Color temp coefficient. */ (uint32_t)r2 + 1391; /** Color temp offset. */ return cct; } void i2c_status(HAL_StatusTypeDef data){ switch(data){ case HAL_OK :printf("HAL_OK \r\n");break; case HAL_ERROR :printf("HAL_ERROR \r\n");break; case HAL_BUSY :printf("HAL_BUSY \r\n");break; case HAL_TIMEOUT :printf("HAL_TIMEOUT\r\n");break; } } void TCS34725_init(void){ uint8_t DEV_DATA = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_ID); // tcs34725SetIntegrationTime(TCS34725_INTEGRATIONTIME_700MS); // tcs34725SetGain(TCS34725_GAIN_60X); TCS34725_enable(); if(DEV_DATA == 0x44 || DEV_DATA == 0x4D){ printf("TCS34725_Success\r\n"); }else{ printf("TCS34725_Failed : %02x\r\n",DEV_DATA); } }