Skip to content

Instantly share code, notes, and snippets.

@flxkid
Created September 5, 2020 19:47
Show Gist options
  • Save flxkid/2c8af86d51dc3532b6e0a085b8727e48 to your computer and use it in GitHub Desktop.
Save flxkid/2c8af86d51dc3532b6e0a085b8727e48 to your computer and use it in GitHub Desktop.
Modified for Python 3 from this wiki: http://www.cqrobot.wiki/index.php/TCS34725_Color_Sensor
#!/usr/bin/python
import time
import math
import smbus
#import pygame
import RPi.GPIO as GPIO
LED = 18
INT_PORT= 17
TCS34725_R_Coef = 0.136
TCS34725_G_Coef = 1.000
TCS34725_B_Coef = -0.444
TCS34725_GA = 1.0
TCS34725_DF = 310.0
TCS34725_CT_Coef = 3810.0
TCS34725_CT_Offset =1391.0
class TCS34725:
Gain_t = 0
IntegrationTime_t = 0
TCS34725_CMD_BIT = 0x80
TCS34725_CMD_Read_Byte = 0x00
TCS34725_CMD_Read_Word = 0x20
TCS34725_CMD_Clear_INT = 0x66
TCS34725_ENABLE = 0x00
TCS34725_ENABLE_AIEN = 0x10 # RGBC Interrupt Enable
TCS34725_ENABLE_WEN = 0x08 # Wait enable - Writing 1 activates the wait timer
TCS34725_ENABLE_AEN = 0x02 # RGBC Enable - Writing 1 actives the ADC, 0 disables it
TCS34725_ENABLE_PON = 0x01 # Power on - Writing 1 activates the internal oscillator, 0 disables it
TCS34725_ATIME = 0x01 # Integration time
TCS34725_WTIME = 0x03 # Wait time (if TCS34725_ENABLE_WEN is asserted)
TCS34725_WTIME_2_4MS = 0xFF # WLONG0 = 2.4ms WLONG1 = 0.029s
TCS34725_WTIME_204MS = 0xAB # WLONG0 = 204ms WLONG1 = 2.45s
TCS34725_WTIME_614MS = 0x00 # WLONG0 = 614ms WLONG1 = 7.4s
TCS34725_AILTL = 0x04 # Clear channel lower interrupt threshold
TCS34725_AILTH = 0x05
TCS34725_AIHTL = 0x06 # Clear channel upper interrupt threshold
TCS34725_AIHTH = 0x07
TCS34725_PERS = 0x0C # Persistence register - basic SW filtering mechanism for interrupts
TCS34725_PERS_NONE = 0b0000 # Every RGBC cycle generates an interrupt
TCS34725_PERS_1_CYCLE = 0b0001 # 1 clean channel value outside threshold range generates an interrupt
TCS34725_PERS_2_CYCLE = 0b0010 # 2 clean channel values outside threshold range generates an interrupt
TCS34725_PERS_3_CYCLE = 0b0011 # 3 clean channel values outside threshold range generates an interrupt
TCS34725_PERS_5_CYCLE = 0b0100 # 5 clean channel values outside threshold range generates an interrupt
TCS34725_PERS_10_CYCLE = 0b0101 # 10 clean channel values outside threshold range generates an interrupt
TCS34725_PERS_15_CYCLE = 0b0110 # 15 clean channel values outside threshold range generates an interrupt
TCS34725_PERS_20_CYCLE = 0b0111 # 20 clean channel values outside threshold range generates an interrupt
TCS34725_PERS_25_CYCLE = 0b1000 # 25 clean channel values outside threshold range generates an interrupt
TCS34725_PERS_30_CYCLE = 0b1001 # 30 clean channel values outside threshold range generates an interrupt
TCS34725_PERS_35_CYCLE = 0b1010 # 35 clean channel values outside threshold range generates an interrupt
TCS34725_PERS_40_CYCLE = 0b1011 # 40 clean channel values outside threshold range generates an interrupt
TCS34725_PERS_45_CYCLE = 0b1100 # 45 clean channel values outside threshold range generates an interrupt
TCS34725_PERS_50_CYCLE = 0b1101 # 50 clean channel values outside threshold range generates an interrupt
TCS34725_PERS_55_CYCLE = 0b1110 # 55 clean channel values outside threshold range generates an interrupt
TCS34725_PERS_60_CYCLE = 0b1111 # 60 clean channel values outside threshold range generates an interrupt
TCS34725_CONFIG = 0x0D
TCS34725_CONFIG_WLONG = 0x02 # Choose between short and long (12x) wait times via TCS34725_WTIME
TCS34725_CONTROL = 0x0F # Set the gain level for the sensor
TCS34725_ID = 0x12 # 0x44 = TCS34721/TCS34725, 0x4D = TCS34723/TCS34727
TCS34725_STATUS = 0x13
TCS34725_STATUS_AINT = 0x10 # RGBC Clean channel interrupt
TCS34725_STATUS_AVALID = 0x01 # Indicates that the RGBC channels have completed an integration cycle
TCS34725_CDATAL = 0x14 # Clear channel data
TCS34725_CDATAH = 0x15
TCS34725_RDATAL = 0x16 # Red channel data
TCS34725_RDATAH = 0x17
TCS34725_GDATAL = 0x18 # Green channel data
TCS34725_GDATAH = 0x19
TCS34725_BDATAL = 0x1A # Blue channel data
TCS34725_BDATAH = 0x1B
#Integration Time
TCS34725_INTEGRATIONTIME_2_4MS = 0xFF #< 2.4ms - 1 cycle - Max Count: 1024
TCS34725_INTEGRATIONTIME_24MS = 0xF6 #< 24ms - 10 cycles - Max Count: 10240
TCS34725_INTEGRATIONTIME_50MS = 0xEB #< 50ms - 20 cycles - Max Count: 20480
TCS34725_INTEGRATIONTIME_101MS = 0xD5 #< 101ms - 42 cycles - Max Count: 43008
TCS34725_INTEGRATIONTIME_154MS = 0xC0 #< 154ms - 64 cycles - Max Count: 65535
TCS34725_INTEGRATIONTIME_700MS = 0x00 #< 700ms - 256 cycles - Max Count: 65535
#Gain
TCS34725_GAIN_1X = 0x00 #< No gain */
TCS34725_GAIN_4X = 0x01 #< 4x gain */
TCS34725_GAIN_16X = 0x02 #< 16x gain */
TCS34725_GAIN_60X = 0x03 #< 60x gain */
R = 0
G = 0
B = 0
C = 0
RGB888_R = 0
RGB888_G = 0
RGB888_B = 0
RGB888 = 0
RGB565 = 0
def __init__(self, address=0x29, debug=False):
self.i2c = smbus.SMBus(1)
self.address = address
self.debug = debug
#Set GPIO mode
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(LED, GPIO.OUT)
self.pwm = GPIO.PWM(18, 1000)
self.pwm.start(100)
GPIO.setup(INT_PORT, GPIO.IN, pull_up_down=GPIO.PUD_UP)
if (self.debug):
print("Reseting TSL2581")
def Write_Byte(self, reg, value):
"Writes an 8-bit value to the specified register/address"
reg = reg | self.TCS34725_CMD_BIT;#Register addressing highest bit is set to 1
self.i2c.write_byte_data(self.address, reg, value)
if (self.debug):
print(("I2C: Write 0x%02X to register 0x%02X" % (value, reg)))
def Write_Word(self, reg, value):
"Writes an 8-bit value to the specified register/address"
reg = reg | self.TCS34725_CMD_BIT;
self.i2c.write_word_data(self.address, reg, value)
if (self.debug):
print(("I2C: Write 0x%02X to register 0x%02X" % (value, reg)))
def Read_Byte(self, reg):
"Read an unsigned byte from the I2C device"
reg = reg | self.TCS34725_CMD_BIT;
result = self.i2c.read_byte_data(self.address, reg)
if (self.debug):
print(("I2C: Device 0x%02X returned 0x%02X from reg 0x%02X" % (self.address, result & 0xFF, reg)))
return result
def Read_Word(self, reg):
"Read an unsigned byte from the I2C device"
reg = reg | self.TCS34725_CMD_BIT;
result = self.i2c.read_word_data(self.address, reg)
if (self.debug):
print(("I2C: Device 0x%02X returned 0x%02X from reg 0x%02X" % (self.address, result & 0xFF, reg)))
return result
def Set_Gain(self, gain):
self.Write_Byte(self.TCS34725_CONTROL, gain);
self.Gain_t = gain;
def Set_Integration_Time(self, time):
# Update the timing register
self.Write_Byte(self.TCS34725_ATIME, time)
self.IntegrationTime_t = time;
def Enable(self):
self.Write_Byte(self.TCS34725_ENABLE, self.TCS34725_ENABLE_PON)
time.sleep(0.01)
self.Write_Byte(self.TCS34725_ENABLE, self.TCS34725_ENABLE_PON | self.TCS34725_ENABLE_AEN)
time.sleep(0.01)
def Disable(self):
#Turn the device off to save power
reg = Read_Byte(self.TCS34725_ENABLE);
self.Write_Byte(self.TCS34725_ENABLE, reg & ~(TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN));
def Interrupt_Enable(self):
reg = self.Read_Byte(self.TCS34725_ENABLE)
self.Write_Byte(self.TCS34725_ENABLE, reg | self.TCS34725_ENABLE_AIEN)
def Interrupt_Disable(self):
reg = self.Read_Byte(self.TCS34725_ENABLE)
self.Write_Byte(self.TCS34725_ENABLE, reg & (~self.TCS34725_ENABLE_AIEN))
def Set_Interrupt_Persistence_Reg(self, PER):
if(PER < 0x10):
self.Write_Byte(self.TCS34725_PERS, PER)
else :
self.Write_Byte(self.TCS34725_PERS, self.TCS34725_PERS_60_CYCLE)
def Set_Interrupt_Threshold(self, Threshold_H, Threshold_L):
self.Write_Byte(self.TCS34725_AILTL, Threshold_L & 0xff)
self.Write_Byte(self.TCS34725_AILTH, Threshold_L >> 8)
self.Write_Byte(self.TCS34725_AIHTL, Threshold_H & 0xff)
self.Write_Byte(self.TCS34725_AIHTH, Threshold_H >> 8)
def Clear_Interrupt_Flag(self):
self.Write_Byte(self.TCS34725_CMD_Clear_INT, 0x00);
def TCS34725_init(self):
ID = self.Read_Byte(self.TCS34725_ID)
if(ID != 0x44 and ID != 0x4D):
return 1
self.Set_Integration_Time(self.TCS34725_INTEGRATIONTIME_154MS)
self.Set_Gain(self.TCS34725_GAIN_60X)
self.IntegrationTime_t = self.TCS34725_INTEGRATIONTIME_154MS
self.Gain_t = self.TCS34725_GAIN_60X
self.Enable()
self.Interrupt_Enable()
self.SetLight(40)
return 0
def GetLux_Interrupt(self, Threshold_H, Threshold_L):
self.Set_Interrupt_Threshold(Threshold_H, Threshold_L);
if(GPIO.input(INT_PORT) == GPIO.LOW):
self.Clear_Interrupt_Flag();
self.Set_Interrupt_Persistence_Reg(self.TCS34725_PERS_2_CYCLE);
return 1;
return 0;
def Read_ID(self):
return self.Read_Byte(self.TCS34725_ID)
def Get_RGBData(self):
self.C = self.Read_Word(self.TCS34725_CDATAL | self.TCS34725_CMD_Read_Word)
self.R = self.Read_Word(self.TCS34725_RDATAL | self.TCS34725_CMD_Read_Word)
self.G = self.Read_Word(self.TCS34725_GDATAL | self.TCS34725_CMD_Read_Word)
self.B = self.Read_Word(self.TCS34725_BDATAL | self.TCS34725_CMD_Read_Word)
if(self.IntegrationTime_t == self.TCS34725_INTEGRATIONTIME_2_4MS):
time.sleep(0.01)
elif(self.IntegrationTime_t == self.TCS34725_INTEGRATIONTIME_24MS):
time.sleep(0.04)
elif(self.IntegrationTime_t == self.TCS34725_INTEGRATIONTIME_50MS):
time.sleep(0.05)
elif(self.IntegrationTime_t == self.TCS34725_INTEGRATIONTIME_101MS):
time.sleep(0.1)
elif(self.IntegrationTime_t == self.TCS34725_INTEGRATIONTIME_154MS):
time.sleep(0.2)
elif(self.IntegrationTime_t == self.TCS34725_INTEGRATIONTIME_700MS):
time.sleep(0.7)
#Convert read data to RGB888 format
def GetRGB888(self):
i = 1
if(self.R >= self.G and self.R >= self.B):
i = self.R // 255 + 1
elif( self.G >= self.R and self.G >= self.B):
i = self.G // 255 + 1
elif( self.B >= self.G and self.B >= self.R):
i = self.B // 255 + 1
if(i!=0):
self.RGB888_R = self.R // i
self.RGB888_G = self.G // i
self.RGB888_B = self.B // i
if(self.RGB888_R > 30):
self.RGB888_R = self.RGB888_R - 30
if(self.RGB888_G > 30):
self.RGB888_G = self.RGB888_G - 30
if(self.RGB888_B > 30):
self.RGB888_B = self.RGB888_B - 30
self.RGB888_R = self.RGB888_R * 255 // 225
self.RGB888_G = self.RGB888_G * 255 // 225
self.RGB888_B = self.RGB888_B * 255 // 225
self.RGB888 = (self.RGB888_R<<16) | (self.RGB888_G<<8) |(self.RGB888_B)
def GetRGB565(self):
i = 1
RGB565_R = 0
RGB565_G = 0
RGB565_B = 0
if(self.R >= self.G and self.R >= self.B):
i = self.R // 255 + 1
elif( self.G >= self.R and self.G >= self.B):
i = self.G // 255 + 1
elif( self.B >= self.G and self.B >= self.R):
i = self.B // 255 + 1
if(i!=0):
RGB565_R = self.R // i
RGB565_G = self.G // i
RGB565_B = self.B // i
if(RGB565_R > 30):
RGB565_R = RGB565_R - 30
if(RGB565_G > 30):
RGB565_G = RGB565_G - 30
if(RGB565_B > 30):
RGB565_B = RGB565_B - 30
RGB565_R = RGB565_R * 255 // 225
RGB565_G = RGB565_G * 255 // 225
RGB565_B = RGB565_B * 255 // 225
self.RG565 = (((RGB565_R>>3) << 11) | ((RGB565_G>>2) << 5) | (RGB565_B>>3 ))&0xffff
def Get_Lux(self):
atime_ms = ((256 - self.IntegrationTime_t) * 2.4);
if(self.R + self.G + self.B > self.C):
ir = (self.R + self.G + self.B - self.C) // 2
else:
ir = 0
r_comp = self.R - ir;
g_comp = self.G - ir;
b_comp = self.B - ir;
Gain_temp = 1
if(self.Gain_t == self.TCS34725_GAIN_1X):
Gain_temp = 1
elif(self.Gain_t == self.TCS34725_GAIN_4X):
Gain_temp = 4
elif(self.Gain_t == self.TCS34725_GAIN_16X):
Gain_temp = 16
elif(self.Gain_t == self.TCS34725_GAIN_60X):
Gain_temp = 60
cpl = (atime_ms * Gain_temp) / (TCS34725_GA * TCS34725_DF);
lux = (TCS34725_R_Coef * (float)(r_comp) + TCS34725_G_Coef * \
(float)(g_comp) + TCS34725_B_Coef * (float)(b_comp)) / cpl;
return lux;
def Get_ColorTemp(self):
ir=1.0
if(self.R + self.G + self.B > self.C):
ir = (self.R + self.G + self.B - self.C - 1) // 2
else:
ir = 0
r_comp = self.R - ir;
b_comp = self.B - ir;
cct=TCS34725_CT_Coef * (float)(b_comp) / (float)(r_comp) + TCS34725_CT_Offset;
return cct;
def SetLight(self, value):
self.pwm.start(value)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment