本模塊是基于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;i8;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();//讀取的最后一個字節發送NACK IIC_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轉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; //[0-100] if(maxVal == minVal)//若r=g=b,灰度 { Hsl->h = 0; Hsl->s = 0; } else { //計算色調 if(maxVal==r) { if(g>=b) Hsl->h = 60*(g-b)/difVal; else Hsl->h = 60*(g-b)/difVal+360; } else { if(maxVal==g)Hsl->h = 60*(b-r)/difVal+120; else if(maxVal==b)Hsl->h = 60*(r-g)/difVal+240; } //計算飽和度 if(Hsl->l<=50)Hsl-?>s=difVal*100/(maxVal+minVal); //[0-100] else Hsl->s=difVal*100/(200-(maxVal+minVal)); } } /******************************************************************************/
在文件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;//RGBC typedef 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波特率115200 TCS34725_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
審核編輯 黃宇
-
傳感器
+關注
關注
2551文章
51147瀏覽量
753992 -
CW32
+關注
關注
1文章
210瀏覽量
662
發布評論請先 登錄
相關推薦
評論