系列目录
模块介绍

TCS34725是一款低成本,高性价比的RGB全彩颜色识别传感器,传感器通过光学感应来识别物体的表面颜色。支持红、绿、蓝(RGB)三基色,支持明光感应,可以输出对应的具体数值,帮助您还原颜色本真。 为了提高精度,防止周边环境干扰,我们特意在传感器底部添加了一块红外遮光片,最大程度减小了入射光的红外频谱成份,让颜色管理更加准确。板载自带高亮LED,可以让传感器在低环境光的情况下依然能够正常使用,实现“补光”的功能。模块采用I2C通信。
接线
直接接到SD1,SA1接口上。
CubeMX配置
采用GPIO模拟I2C。PA0,PA1都配置成推挽输出,高速模式,默认无输出。


编写代码
该模块采用IIC协议通讯,需要大量的地址读写操作,这里不一一赘述,这里直接使用从众灵科技官方代码移植的驱动代码。
新建color.c和color.h,将一下驱动代码复制进对应文件,添加进工程。
#include "color.h"
COLOR_RGBC rgb;
COLOR_HSL hsl;
/******************************************************************************/
void delay_s(uint32_t i)
{
while(i--);
}
/******************************************************************************/
void TCS34725_I2C_Init()
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = TCS_SDA_Pin|TCS_SCL_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, TCS_SDA_Pin|TCS_SCL_Pin, GPIO_PIN_SET);
}
/*********************************************/
void TCS34725_I2C_Start()
{
TCS_SDA_OUT();
TCS_SDA_H;
TCS_SCL_H;
delay_s(40);//delay_us(4);
TCS_SDA_L;
delay_s(40);//delay_us(4);
TCS_SCL_L;
}
/*********************************************/
void TCS34725_I2C_Stop()
{
TCS_SDA_OUT();
TCS_SCL_L;
TCS_SDA_L;
delay_s(40);//delay_us(4);
TCS_SCL_H;
TCS_SDA_H;
delay_s(40);//delay_us(4);
}
/*********************************************/
//返回值:1,接收应答失败
// 0,接收应答成功
uint8_t TCS34725_I2C_Wait_ACK()
{
uint32_t t=0;
TCS_SDA_IN();//SDA设置为输入
TCS_SDA_H;
delay_s(10);//delay_us(1);
TCS_SCL_H;
delay_s(10);//delay_us(1);
while(TCS_SDA_READ)
{
t++;
if(t > 250)
{
TCS34725_I2C_Stop();
return 1;
}
}
TCS_SCL_L;
return 0;
}
/*********************************************/
//产生ACK应答
void TCS34725_I2C_ACK()
{
TCS_SCL_L;
TCS_SDA_OUT();//sda线输出
TCS_SDA_L;
delay_s(20);//delay_us(2);
TCS_SCL_H;
delay_s(20);//delay_us(2);
TCS_SCL_L;
}
/*********************************************/
//不产生ACK应答
void TCS34725_I2C_NACK()
{
TCS_SCL_L;
TCS_SDA_OUT();//sda线输出
TCS_SDA_H;
delay_s(20);//delay_us(2);
TCS_SCL_H;
delay_s(20);//delay_us(2);
TCS_SCL_L;
}
/*********************************************/
//I2C发送一个字节
void TCS34725_I2C_Send_Byte(uint8_t byte)
{
uint8_t i;
TCS_SDA_OUT();//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_s(20);//delay_us(2);
TCS_SCL_H;
delay_s(20);//delay_us(2);
TCS_SCL_L;
delay_s(20);//delay_us(2);
}
}
/*********************************************/
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
uint8_t TCS34725_I2C_Read_Byte(uint8_t ack)
{
uint8_t i,receive = 0;
TCS_SDA_IN();
for(i = 0; i < 8; i++)
{
TCS_SCL_L;
delay_s(20);//delay_us(2);
TCS_SCL_H;
receive <<= 1;
if(TCS_SDA_READ) receive++;
delay_s(10);//delay_us(1);
}
if (!ack) TCS34725_I2C_NACK();//发送nACK
else TCS34725_I2C_ACK(); //发送ACK
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;
TCS34725_I2C_Start();
TCS34725_I2C_Send_Byte((slaveAddress << 1) | 0x00); //发送从机地址写命令
TCS34725_I2C_Wait_ACK();
for(i = 0; i < bytesNumber; i++)
{
TCS34725_I2C_Send_Byte(*(dataBuffer + i));
TCS34725_I2C_Wait_ACK();
}
if(stopBit == 1) TCS34725_I2C_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;
TCS34725_I2C_Start();
TCS34725_I2C_Send_Byte((slaveAddress << 1) | 0x01); //发送从机地址读命令
TCS34725_I2C_Wait_ACK();
for(i = 0; i < bytesNumber; i++)
{
if(i == bytesNumber - 1)
{
*(dataBuffer + i) = TCS34725_I2C_Read_Byte(0);//读取的最后一个字节发送NACK
}
else
{
*(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(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);
}
void TCS34725_LedON(uint8_t enable) {
uint8_t cmd = 0;
TCS34725_Read(TCS34725_ENABLE, &cmd, 1);
if(enable) {
cmd |= TCS34725_ENABLE_AIEN;
} else {
cmd &= ~TCS34725_ENABLE_AIEN;
}
TCS34725_Write(TCS34725_ENABLE, &cmd, 1);
}
/*******************************************************************************
* @brief TCS34725初始化
*
* @return ID - ID寄存器中的值
*******************************************************************************/
uint8_t TCS34725_Init(uint8_t time,uint8_t gain)
{
uint8_t id=0;
uint8_t cmd_return[100];
TCS34725_I2C_Init();
TCS34725_Read(TCS34725_ID, &id, 1); //TCS34725 的 ID 是 0x44 可以根据这个来判断是否成功连接
sprintf((char *)cmd_return, "{id=%x\r\n}", id);
usart_send_str(&huart3,cmd_return);
if(id==0x44)
{
TCS34725_SetIntegrationTime(time);
TCS34725_SetGain(gain);
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;
}
uint16_t TCS34725_GetR(void) {
// COLOR_RGBC rgbc;
uint8_t status = TCS34725_STATUS_AVALID;
TCS34725_Read(TCS34725_STATUS, &status, 1);
if(status & TCS34725_STATUS_AVALID){
return TCS34725_GetChannelData(TCS34725_RDATAL);
}
return 0;
}
uint16_t TCS34725_GetG(void) {
// COLOR_RGBC rgbc;
uint8_t status = TCS34725_STATUS_AVALID;
TCS34725_Read(TCS34725_STATUS, &status, 1);
if(status & TCS34725_STATUS_AVALID){
return TCS34725_GetChannelData(TCS34725_GDATAL);
}
return 0;
}
uint16_t TCS34725_GetB(void) {
// COLOR_RGBC rgbc;
uint8_t status = TCS34725_STATUS_AVALID;
TCS34725_Read(TCS34725_STATUS, &status, 1);
if(status & TCS34725_STATUS_AVALID){
return TCS34725_GetChannelData(TCS34725_BDATAL);
}
return 0;
}
uint16_t TCS34725_GetC(void) {
// COLOR_RGBC rgbc;
uint8_t status = TCS34725_STATUS_AVALID;
TCS34725_Read(TCS34725_STATUS, &status, 1);
if(status & TCS34725_STATUS_AVALID){
return TCS34725_GetChannelData(TCS34725_CDATAL);
}
return 0;
}
/******************************************************************************/
//RGB转HSL
void 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;
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));
}
}
#include "color.h" COLOR_RGBC rgb; COLOR_HSL hsl; /******************************************************************************/ void delay_s(uint32_t i) { while(i--); } /******************************************************************************/ void TCS34725_I2C_Init() { GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = TCS_SDA_Pin|TCS_SCL_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); HAL_GPIO_WritePin(GPIOA, TCS_SDA_Pin|TCS_SCL_Pin, GPIO_PIN_SET); } /*********************************************/ void TCS34725_I2C_Start() { TCS_SDA_OUT(); TCS_SDA_H; TCS_SCL_H; delay_s(40);//delay_us(4); TCS_SDA_L; delay_s(40);//delay_us(4); TCS_SCL_L; } /*********************************************/ void TCS34725_I2C_Stop() { TCS_SDA_OUT(); TCS_SCL_L; TCS_SDA_L; delay_s(40);//delay_us(4); TCS_SCL_H; TCS_SDA_H; delay_s(40);//delay_us(4); } /*********************************************/ //返回值:1,接收应答失败 // 0,接收应答成功 uint8_t TCS34725_I2C_Wait_ACK() { uint32_t t=0; TCS_SDA_IN();//SDA设置为输入 TCS_SDA_H; delay_s(10);//delay_us(1); TCS_SCL_H; delay_s(10);//delay_us(1); while(TCS_SDA_READ) { t++; if(t > 250) { TCS34725_I2C_Stop(); return 1; } } TCS_SCL_L; return 0; } /*********************************************/ //产生ACK应答 void TCS34725_I2C_ACK() { TCS_SCL_L; TCS_SDA_OUT();//sda线输出 TCS_SDA_L; delay_s(20);//delay_us(2); TCS_SCL_H; delay_s(20);//delay_us(2); TCS_SCL_L; } /*********************************************/ //不产生ACK应答 void TCS34725_I2C_NACK() { TCS_SCL_L; TCS_SDA_OUT();//sda线输出 TCS_SDA_H; delay_s(20);//delay_us(2); TCS_SCL_H; delay_s(20);//delay_us(2); TCS_SCL_L; } /*********************************************/ //I2C发送一个字节 void TCS34725_I2C_Send_Byte(uint8_t byte) { uint8_t i; TCS_SDA_OUT();//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_s(20);//delay_us(2); TCS_SCL_H; delay_s(20);//delay_us(2); TCS_SCL_L; delay_s(20);//delay_us(2); } } /*********************************************/ //读1个字节,ack=1时,发送ACK,ack=0,发送nACK uint8_t TCS34725_I2C_Read_Byte(uint8_t ack) { uint8_t i,receive = 0; TCS_SDA_IN(); for(i = 0; i < 8; i++) { TCS_SCL_L; delay_s(20);//delay_us(2); TCS_SCL_H; receive <<= 1; if(TCS_SDA_READ) receive++; delay_s(10);//delay_us(1); } if (!ack) TCS34725_I2C_NACK();//发送nACK else TCS34725_I2C_ACK(); //发送ACK 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; TCS34725_I2C_Start(); TCS34725_I2C_Send_Byte((slaveAddress << 1) | 0x00); //发送从机地址写命令 TCS34725_I2C_Wait_ACK(); for(i = 0; i < bytesNumber; i++) { TCS34725_I2C_Send_Byte(*(dataBuffer + i)); TCS34725_I2C_Wait_ACK(); } if(stopBit == 1) TCS34725_I2C_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; TCS34725_I2C_Start(); TCS34725_I2C_Send_Byte((slaveAddress << 1) | 0x01); //发送从机地址读命令 TCS34725_I2C_Wait_ACK(); for(i = 0; i < bytesNumber; i++) { if(i == bytesNumber - 1) { *(dataBuffer + i) = TCS34725_I2C_Read_Byte(0);//读取的最后一个字节发送NACK } else { *(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(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); } void TCS34725_LedON(uint8_t enable) { uint8_t cmd = 0; TCS34725_Read(TCS34725_ENABLE, &cmd, 1); if(enable) { cmd |= TCS34725_ENABLE_AIEN; } else { cmd &= ~TCS34725_ENABLE_AIEN; } TCS34725_Write(TCS34725_ENABLE, &cmd, 1); } /******************************************************************************* * @brief TCS34725初始化 * * @return ID - ID寄存器中的值 *******************************************************************************/ uint8_t TCS34725_Init(uint8_t time,uint8_t gain) { uint8_t id=0; uint8_t cmd_return[100]; TCS34725_I2C_Init(); TCS34725_Read(TCS34725_ID, &id, 1); //TCS34725 的 ID 是 0x44 可以根据这个来判断是否成功连接 sprintf((char *)cmd_return, "{id=%x\r\n}", id); usart_send_str(&huart3,cmd_return); if(id==0x44) { TCS34725_SetIntegrationTime(time); TCS34725_SetGain(gain); 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; } uint16_t TCS34725_GetR(void) { // COLOR_RGBC rgbc; uint8_t status = TCS34725_STATUS_AVALID; TCS34725_Read(TCS34725_STATUS, &status, 1); if(status & TCS34725_STATUS_AVALID){ return TCS34725_GetChannelData(TCS34725_RDATAL); } return 0; } uint16_t TCS34725_GetG(void) { // COLOR_RGBC rgbc; uint8_t status = TCS34725_STATUS_AVALID; TCS34725_Read(TCS34725_STATUS, &status, 1); if(status & TCS34725_STATUS_AVALID){ return TCS34725_GetChannelData(TCS34725_GDATAL); } return 0; } uint16_t TCS34725_GetB(void) { // COLOR_RGBC rgbc; uint8_t status = TCS34725_STATUS_AVALID; TCS34725_Read(TCS34725_STATUS, &status, 1); if(status & TCS34725_STATUS_AVALID){ return TCS34725_GetChannelData(TCS34725_BDATAL); } return 0; } uint16_t TCS34725_GetC(void) { // COLOR_RGBC rgbc; uint8_t status = TCS34725_STATUS_AVALID; TCS34725_Read(TCS34725_STATUS, &status, 1); if(status & TCS34725_STATUS_AVALID){ return TCS34725_GetChannelData(TCS34725_CDATAL); } return 0; } /******************************************************************************/ //RGB转HSL void 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; 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)); } }
#include "color.h" COLOR_RGBC rgb; COLOR_HSL hsl; /******************************************************************************/ void delay_s(uint32_t i) { while(i--); } /******************************************************************************/ void TCS34725_I2C_Init() { GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = TCS_SDA_Pin|TCS_SCL_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); HAL_GPIO_WritePin(GPIOA, TCS_SDA_Pin|TCS_SCL_Pin, GPIO_PIN_SET); } /*********************************************/ void TCS34725_I2C_Start() { TCS_SDA_OUT(); TCS_SDA_H; TCS_SCL_H; delay_s(40);//delay_us(4); TCS_SDA_L; delay_s(40);//delay_us(4); TCS_SCL_L; } /*********************************************/ void TCS34725_I2C_Stop() { TCS_SDA_OUT(); TCS_SCL_L; TCS_SDA_L; delay_s(40);//delay_us(4); TCS_SCL_H; TCS_SDA_H; delay_s(40);//delay_us(4); } /*********************************************/ //返回值:1,接收应答失败 // 0,接收应答成功 uint8_t TCS34725_I2C_Wait_ACK() { uint32_t t=0; TCS_SDA_IN();//SDA设置为输入 TCS_SDA_H; delay_s(10);//delay_us(1); TCS_SCL_H; delay_s(10);//delay_us(1); while(TCS_SDA_READ) { t++; if(t > 250) { TCS34725_I2C_Stop(); return 1; } } TCS_SCL_L; return 0; } /*********************************************/ //产生ACK应答 void TCS34725_I2C_ACK() { TCS_SCL_L; TCS_SDA_OUT();//sda线输出 TCS_SDA_L; delay_s(20);//delay_us(2); TCS_SCL_H; delay_s(20);//delay_us(2); TCS_SCL_L; } /*********************************************/ //不产生ACK应答 void TCS34725_I2C_NACK() { TCS_SCL_L; TCS_SDA_OUT();//sda线输出 TCS_SDA_H; delay_s(20);//delay_us(2); TCS_SCL_H; delay_s(20);//delay_us(2); TCS_SCL_L; } /*********************************************/ //I2C发送一个字节 void TCS34725_I2C_Send_Byte(uint8_t byte) { uint8_t i; TCS_SDA_OUT();//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_s(20);//delay_us(2); TCS_SCL_H; delay_s(20);//delay_us(2); TCS_SCL_L; delay_s(20);//delay_us(2); } } /*********************************************/ //读1个字节,ack=1时,发送ACK,ack=0,发送nACK uint8_t TCS34725_I2C_Read_Byte(uint8_t ack) { uint8_t i,receive = 0; TCS_SDA_IN(); for(i = 0; i < 8; i++) { TCS_SCL_L; delay_s(20);//delay_us(2); TCS_SCL_H; receive <<= 1; if(TCS_SDA_READ) receive++; delay_s(10);//delay_us(1); } if (!ack) TCS34725_I2C_NACK();//发送nACK else TCS34725_I2C_ACK(); //发送ACK 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; TCS34725_I2C_Start(); TCS34725_I2C_Send_Byte((slaveAddress << 1) | 0x00); //发送从机地址写命令 TCS34725_I2C_Wait_ACK(); for(i = 0; i < bytesNumber; i++) { TCS34725_I2C_Send_Byte(*(dataBuffer + i)); TCS34725_I2C_Wait_ACK(); } if(stopBit == 1) TCS34725_I2C_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; TCS34725_I2C_Start(); TCS34725_I2C_Send_Byte((slaveAddress << 1) | 0x01); //发送从机地址读命令 TCS34725_I2C_Wait_ACK(); for(i = 0; i < bytesNumber; i++) { if(i == bytesNumber - 1) { *(dataBuffer + i) = TCS34725_I2C_Read_Byte(0);//读取的最后一个字节发送NACK } else { *(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(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); } void TCS34725_LedON(uint8_t enable) { uint8_t cmd = 0; TCS34725_Read(TCS34725_ENABLE, &cmd, 1); if(enable) { cmd |= TCS34725_ENABLE_AIEN; } else { cmd &= ~TCS34725_ENABLE_AIEN; } TCS34725_Write(TCS34725_ENABLE, &cmd, 1); } /******************************************************************************* * @brief TCS34725初始化 * * @return ID - ID寄存器中的值 *******************************************************************************/ uint8_t TCS34725_Init(uint8_t time,uint8_t gain) { uint8_t id=0; uint8_t cmd_return[100]; TCS34725_I2C_Init(); TCS34725_Read(TCS34725_ID, &id, 1); //TCS34725 的 ID 是 0x44 可以根据这个来判断是否成功连接 sprintf((char *)cmd_return, "{id=%x\r\n}", id); usart_send_str(&huart3,cmd_return); if(id==0x44) { TCS34725_SetIntegrationTime(time); TCS34725_SetGain(gain); 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; } uint16_t TCS34725_GetR(void) { // COLOR_RGBC rgbc; uint8_t status = TCS34725_STATUS_AVALID; TCS34725_Read(TCS34725_STATUS, &status, 1); if(status & TCS34725_STATUS_AVALID){ return TCS34725_GetChannelData(TCS34725_RDATAL); } return 0; } uint16_t TCS34725_GetG(void) { // COLOR_RGBC rgbc; uint8_t status = TCS34725_STATUS_AVALID; TCS34725_Read(TCS34725_STATUS, &status, 1); if(status & TCS34725_STATUS_AVALID){ return TCS34725_GetChannelData(TCS34725_GDATAL); } return 0; } uint16_t TCS34725_GetB(void) { // COLOR_RGBC rgbc; uint8_t status = TCS34725_STATUS_AVALID; TCS34725_Read(TCS34725_STATUS, &status, 1); if(status & TCS34725_STATUS_AVALID){ return TCS34725_GetChannelData(TCS34725_BDATAL); } return 0; } uint16_t TCS34725_GetC(void) { // COLOR_RGBC rgbc; uint8_t status = TCS34725_STATUS_AVALID; TCS34725_Read(TCS34725_STATUS, &status, 1); if(status & TCS34725_STATUS_AVALID){ return TCS34725_GetChannelData(TCS34725_CDATAL); } return 0; } /******************************************************************************/ //RGB转HSL void 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; 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)); } }
复制
复制
#ifndef __Z_COLOR_H__
#define __Z_COLOR_H__
#include "stdint.h"
#include "gpio.h"
#include "motor.h"
/******************************************************************************/
#define TCS_SCL_PIN GPIO_PIN_1
#define TCS_SDA_PIN GPIO_PIN_0
#define TCS_SDA_GPIO GPIOA
#define TCS_SCL_GPIO GPIOA
#define TCS_GPIO GPIOA
#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 TCS_SDA_IN() {TCS_SDA_GPIO->CRL&=0xFFFFFFF0;TCS_SDA_GPIO->CRL|=8;}
#define TCS_SDA_OUT() {TCS_SDA_GPIO->CRL&=0xFFFFFFF0;TCS_SDA_GPIO->CRL|=3;}
#define TCS_SDA_READ TCS_GPIO->IDR&(TCS_SDA_PIN)
#define TCS_SCL_H HAL_GPIO_WritePin(TCS_GPIO,TCS_SCL_PIN,(GPIO_PinState)1)
#define TCS_SCL_L HAL_GPIO_WritePin(TCS_GPIO,TCS_SCL_PIN,(GPIO_PinState)0)
#define TCS_SDA_H HAL_GPIO_WritePin(TCS_GPIO,TCS_SDA_PIN,(GPIO_PinState)1)
#define TCS_SDA_L HAL_GPIO_WritePin(TCS_GPIO,TCS_SDA_PIN,(GPIO_PinState)0)
/******************************************************************************/
#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;//RGBC
typedef struct{
unsigned short h; //[0,360]
unsigned char s; //[0,100]
unsigned char l; //[0,100]
}COLOR_HSL;//HSL
uint8_t TCS34725_Init(uint8_t time,uint8_t gain);
uint8_t TCS34725_GetRawData(COLOR_RGBC *rgbc);
void TCS34725_LedON(uint8_t enable);
void RGBtoHSL(COLOR_RGBC *Rgb, COLOR_HSL *Hsl);
uint16_t TCS34725_GetR(void);
uint16_t TCS34725_GetG(void);
uint16_t TCS34725_GetB(void);
uint16_t TCS34725_GetC(void);
#endif
#ifndef __Z_COLOR_H__ #define __Z_COLOR_H__ #include "stdint.h" #include "gpio.h" #include "motor.h" /******************************************************************************/ #define TCS_SCL_PIN GPIO_PIN_1 #define TCS_SDA_PIN GPIO_PIN_0 #define TCS_SDA_GPIO GPIOA #define TCS_SCL_GPIO GPIOA #define TCS_GPIO GPIOA #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 TCS_SDA_IN() {TCS_SDA_GPIO->CRL&=0xFFFFFFF0;TCS_SDA_GPIO->CRL|=8;} #define TCS_SDA_OUT() {TCS_SDA_GPIO->CRL&=0xFFFFFFF0;TCS_SDA_GPIO->CRL|=3;} #define TCS_SDA_READ TCS_GPIO->IDR&(TCS_SDA_PIN) #define TCS_SCL_H HAL_GPIO_WritePin(TCS_GPIO,TCS_SCL_PIN,(GPIO_PinState)1) #define TCS_SCL_L HAL_GPIO_WritePin(TCS_GPIO,TCS_SCL_PIN,(GPIO_PinState)0) #define TCS_SDA_H HAL_GPIO_WritePin(TCS_GPIO,TCS_SDA_PIN,(GPIO_PinState)1) #define TCS_SDA_L HAL_GPIO_WritePin(TCS_GPIO,TCS_SDA_PIN,(GPIO_PinState)0) /******************************************************************************/ #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;//RGBC typedef struct{ unsigned short h; //[0,360] unsigned char s; //[0,100] unsigned char l; //[0,100] }COLOR_HSL;//HSL uint8_t TCS34725_Init(uint8_t time,uint8_t gain); uint8_t TCS34725_GetRawData(COLOR_RGBC *rgbc); void TCS34725_LedON(uint8_t enable); void RGBtoHSL(COLOR_RGBC *Rgb, COLOR_HSL *Hsl); uint16_t TCS34725_GetR(void); uint16_t TCS34725_GetG(void); uint16_t TCS34725_GetB(void); uint16_t TCS34725_GetC(void); #endif
复制
复制
然后通过调用TCS34725_GetRawData(&color_rgbc);
TCS34725_GetRawData(&color_rgbc);
TCS34725_GetRawData(&color_rgbc);
,即可获取采集的rgb值。通过对比不同通道的大小,可以粗略的判断识别的RGB三原色。
打开sensor.c,定义get_color()
get_color()
get_color()
,编写相关代码。
/**
* @brief : 识别木块颜色,红绿蓝
* @param :无
* @retval 识别的颜色,R G B
**/
COLOR_RGBC color_rgbc;
uint8_t get_color() {
TCS34725_GetRawData(&color_rgbc);//获取RGB
if(color_rgbc.c>400){return 0;}
if (color_rgbc.r > color_rgbc.g && color_rgbc.r > color_rgbc.b ) {
//usart_send_str(&huart3,(uint8_t *)"May RED\r\n");
return 'R';
} else if (color_rgbc.g > color_rgbc.r && color_rgbc.g > color_rgbc.b) {
//usart_send_str(&huart3,(uint8_t *)"May GREEN\r\n");
return 'G';
} else if (color_rgbc.b > color_rgbc.g && color_rgbc.b > color_rgbc.r) {
//usart_send_str(&huart3,(uint8_t *)"May BULE\r\n");
return 'B';
}
return 0;
}
/** * @brief : 识别木块颜色,红绿蓝 * @param :无 * @retval 识别的颜色,R G B **/ COLOR_RGBC color_rgbc; uint8_t get_color() { TCS34725_GetRawData(&color_rgbc);//获取RGB if(color_rgbc.c>400){return 0;} if (color_rgbc.r > color_rgbc.g && color_rgbc.r > color_rgbc.b ) { //usart_send_str(&huart3,(uint8_t *)"May RED\r\n"); return 'R'; } else if (color_rgbc.g > color_rgbc.r && color_rgbc.g > color_rgbc.b) { //usart_send_str(&huart3,(uint8_t *)"May GREEN\r\n"); return 'G'; } else if (color_rgbc.b > color_rgbc.g && color_rgbc.b > color_rgbc.r) { //usart_send_str(&huart3,(uint8_t *)"May BULE\r\n"); return 'B'; } return 0; }
复制
/** * @brief : 识别木块颜色,红绿蓝 * @param :无 * @retval 识别的颜色,R G B **/ COLOR_RGBC color_rgbc; uint8_t get_color() { TCS34725_GetRawData(&color_rgbc);//获取RGB if(color_rgbc.c>400){return 0;} if (color_rgbc.r > color_rgbc.g && color_rgbc.r > color_rgbc.b ) { //usart_send_str(&huart3,(uint8_t *)"May RED\r\n"); return 'R'; } else if (color_rgbc.g > color_rgbc.r && color_rgbc.g > color_rgbc.b) { //usart_send_str(&huart3,(uint8_t *)"May GREEN\r\n"); return 'G'; } else if (color_rgbc.b > color_rgbc.g && color_rgbc.b > color_rgbc.r) { //usart_send_str(&huart3,(uint8_t *)"May BULE\r\n"); return 'B'; } return 0; }
复制
由于单次识别置信度较低,我们可以参考超声波一节,采集多个数值返回中间值以减少误差。定义get_adc_color_middle()
get_adc_color_middle()
get_adc_color_middle()
,编写对应函数。
/**
* @brief :处理颜色模块采集到的数据,取采集到的中间值
* @param :数组地址,元素个数
* @retval 处理后的颜色值
**/
char get_adc_color_middle() {
YSSB_LED(1);
uint8_t i;
static int ad_value[5] = {0}, myvalue;// ad_value_bak[5] = {0},
for(i=0;i<5;i++){ad_value[i] = get_color();HAL_Delay(200);};
selection_sort(ad_value, 5);
myvalue = ad_value[2];
YSSB_LED(0);
return myvalue;
}
/** * @brief :处理颜色模块采集到的数据,取采集到的中间值 * @param :数组地址,元素个数 * @retval 处理后的颜色值 **/ char get_adc_color_middle() { YSSB_LED(1); uint8_t i; static int ad_value[5] = {0}, myvalue;// ad_value_bak[5] = {0}, for(i=0;i<5;i++){ad_value[i] = get_color();HAL_Delay(200);}; selection_sort(ad_value, 5); myvalue = ad_value[2]; YSSB_LED(0); return myvalue; }
/** * @brief :处理颜色模块采集到的数据,取采集到的中间值 * @param :数组地址,元素个数 * @retval 处理后的颜色值 **/ char get_adc_color_middle() { YSSB_LED(1); uint8_t i; static int ad_value[5] = {0}, myvalue;// ad_value_bak[5] = {0}, for(i=0;i<5;i++){ad_value[i] = get_color();HAL_Delay(200);}; selection_sort(ad_value, 5); myvalue = ad_value[2]; YSSB_LED(0); return myvalue; }
复制
复制
这里的YSSB_LED是宏定义的TCS34725_LedON(x)
TCS34725_LedON(x)
TCS34725_LedON(x)
函数。用于开启颜色传感器的补光灯。打开color.h,加入该宏定义#define YSSB_LED(x) TCS34725_LedON(x)
#define YSSB_LED(x) TCS34725_LedON(x)
#define YSSB_LED(x) TCS34725_LedON(x)
现在我们获取到了颜色传感器传来的颜色,根据不同颜色,我们可以执行不同动作。
在sensor.c中定义color_task
color_task
color_task
函数。参考超声波的task,这里先只打印出来,更多的功能后续添加。
/**
* @brief :颜色传感器对应任务
* @param :无
* @retval 无
**/
void color_task(){
static uint32_t systick_ms_yanse = 0;
int millis=HAL_GetTick();//获取系统时间
uint8_t cmd_return[128];
char color_value;
if (millis - systick_ms_yanse > 20) {
systick_ms_yanse = HAL_GetTick();
color_value = get_adc_color_middle();//获取a0的ad值,计算出距离
if(color_value!=0)
{
sprintf((char *)cmd_return, "Color = [%c]\r\n", color_value);
usart_send_str(&huart3,cmd_return);
}else
{usart_send_str(&huart3,(uint8_t *)"no wood block \r\n");
}
}
}
/** * @brief :颜色传感器对应任务 * @param :无 * @retval 无 **/ void color_task(){ static uint32_t systick_ms_yanse = 0; int millis=HAL_GetTick();//获取系统时间 uint8_t cmd_return[128]; char color_value; if (millis - systick_ms_yanse > 20) { systick_ms_yanse = HAL_GetTick(); color_value = get_adc_color_middle();//获取a0的ad值,计算出距离 if(color_value!=0) { sprintf((char *)cmd_return, "Color = [%c]\r\n", color_value); usart_send_str(&huart3,cmd_return); }else {usart_send_str(&huart3,(uint8_t *)"no wood block \r\n"); } } }
复制
/** * @brief :颜色传感器对应任务 * @param :无 * @retval 无 **/ void color_task(){ static uint32_t systick_ms_yanse = 0; int millis=HAL_GetTick();//获取系统时间 uint8_t cmd_return[128]; char color_value; if (millis - systick_ms_yanse > 20) { systick_ms_yanse = HAL_GetTick(); color_value = get_adc_color_middle();//获取a0的ad值,计算出距离 if(color_value!=0) { sprintf((char *)cmd_return, "Color = [%c]\r\n", color_value); usart_send_str(&huart3,cmd_return); }else {usart_send_str(&huart3,(uint8_t *)"no wood block \r\n"); } } }
复制
在sensor.h中声明定义的函数
#include "stdint.h"
#include "color.h"
#define sound_vol HAL_GPIO_ReadPin(sound_GPIO_Port,sound_Pin)
#define Trig(x) HAL_GPIO_WritePin(Trig_GPIO_Port,Trig_Pin,(GPIO_PinState)x)
#define Echo() HAL_GPIO_ReadPin(Echo_GPIO_Port,Echo_Pin)
#define YSSB_LED(x) TCS34725_LedON(x); //颜色识别的LED灯
void sound_task(void);
void hcsr_task(void);
void color_task(void);
uint16_t get_csb_value(void);
uint8_t get_color(void);
#include "stdint.h" #include "color.h" #define sound_vol HAL_GPIO_ReadPin(sound_GPIO_Port,sound_Pin) #define Trig(x) HAL_GPIO_WritePin(Trig_GPIO_Port,Trig_Pin,(GPIO_PinState)x) #define Echo() HAL_GPIO_ReadPin(Echo_GPIO_Port,Echo_Pin) #define YSSB_LED(x) TCS34725_LedON(x); //颜色识别的LED灯 void sound_task(void); void hcsr_task(void); void color_task(void); uint16_t get_csb_value(void); uint8_t get_color(void);
#include "stdint.h" #include "color.h" #define sound_vol HAL_GPIO_ReadPin(sound_GPIO_Port,sound_Pin) #define Trig(x) HAL_GPIO_WritePin(Trig_GPIO_Port,Trig_Pin,(GPIO_PinState)x) #define Echo() HAL_GPIO_ReadPin(Echo_GPIO_Port,Echo_Pin) #define YSSB_LED(x) TCS34725_LedON(x); //颜色识别的LED灯 void sound_task(void); void hcsr_task(void); void color_task(void); uint16_t get_csb_value(void); uint8_t get_color(void);
复制
复制
然后在main里添加相关选项 `case 'I':color_task();break;` 需要注意的是,颜色传感器需要初始化。
/* USER CODE BEGIN 2 */
//motor_init();
//arm_init();
TCS34725_Init(TCS34725_INTEGRATIONTIME_700MS,TCS34725_GAIN_1X);
/* USER CODE BEGIN 2 */ //motor_init(); //arm_init(); TCS34725_Init(TCS34725_INTEGRATIONTIME_700MS,TCS34725_GAIN_1X);
/* USER CODE BEGIN 2 */ //motor_init(); //arm_init(); TCS34725_Init(TCS34725_INTEGRATIONTIME_700MS,TCS34725_GAIN_1X);
复制
复制
并且由于颜色识别传感器过远,因此上电后需要等待下在初始化颜色传感器,不然第一次会无法使用。
在主函数大概108行位置加入
/* USER CODE BEGIN SysInit */
HAL_Delay(1000);
/* USER CODE END SysInit */
/* USER CODE BEGIN SysInit */ HAL_Delay(1000); /* USER CODE END SysInit */
/* USER CODE BEGIN SysInit */ HAL_Delay(1000); /* USER CODE END SysInit */
复制
复制
工程源码
国内用户请使用gitee克隆或是使用代理访问Github
https://github.com/USTHzhanglu/stm32-hal/tree/main/color
评论(0)
您还未登录,请登录后发表或查看评论