本帖最后由 jinglixixi 于 2023-1-11 17:17 编辑
#申请原创#
要想识别色彩就离不开色彩传感器的使用,而色彩传感器的种类又有许多种,如早期的TCS230、TCS3200到现在的TCS34725等。 对于TCS230这类的传感器,它是以脉冲计数的方式来获得检测值,并通过色彩通道的选择来获得RGB的值。此外,为了达到一个可供使用的标准值,还需进行白平衡等处理,使用起来相对比较麻烦。 图1 TCS230
而现在推出的色彩传感器,如TCS34725则是数字化的,并采用I2C接口来传送数据,在使用时直接就可读取到色彩的RGB值,并可获得两种色彩模式的检测结果,即RGB模式和HSL模式。因此在使用上,它要比以前的色彩传感器要方便许多,功能也丰富一些。 图2 TCS34725
1. 整体结构 为此,在制作色彩识别与样本色彩显示器时是直接选取TCS34725来做检测器件,该设计的整体结构见图3所示。 图3 整体结构
在整体结构中,是以复旦微的FM33LGxx开发板作为处理核心,由TCS34725检测色彩值,由彩色的LCD屏来承担显示任务,其实物构成如图4所示。 图4 实物构成
2.色彩传感器及其使用
TCS34725是采用I2C方式工作,其遵循的通讯协议如下:
TCS34725与开发板的引脚连接关系为: PE9 ---SCL PD10---SDA 由于TCS34725使用I2C的方式工作,为此是以GPIO口来模拟I2C的方式来实现。 其中,对所用引脚的功能配置函数为: - void TCS34725_I2C_Init()
- {
- FL_GPIO_InitTypeDef GPIO_InitStruct = {0};
- FL_GPIO_ResetOutputPin(GPIOD, FL_GPIO_PIN_10);
- GPIO_InitStruct.pin = FL_GPIO_PIN_10;
- GPIO_InitStruct.mode = FL_GPIO_MODE_OUTPUT;
- GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
- GPIO_InitStruct.pull = FL_DISABLE;
- FL_GPIO_Init(GPIOD, &GPIO_InitStruct);
-
- FL_GPIO_ResetOutputPin(GPIOE, FL_GPIO_PIN_9);
- GPIO_InitStruct.pin = FL_GPIO_PIN_9;
- GPIO_InitStruct.mode = FL_GPIO_MODE_OUTPUT;
- GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
- GPIO_InitStruct.pull = FL_DISABLE;
- FL_GPIO_Init(GPIOE, &GPIO_InitStruct);
- }
由于在TCS34725工作时,既有数据输入处理,又有数据输出处理,故为其配置的输入、输出模式设置函数为: - void TCS_SDA_OUT()
- {
- FL_GPIO_InitTypeDef GPIO_InitStruct = {0};
- FL_GPIO_ResetOutputPin(GPIOD, FL_GPIO_PIN_10);
- GPIO_InitStruct.pin = FL_GPIO_PIN_10;
- GPIO_InitStruct.mode = FL_GPIO_MODE_OUTPUT;
- GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
- GPIO_InitStruct.pull = FL_DISABLE;
- FL_GPIO_Init(GPIOD, &GPIO_InitStruct);
- }
- void TCS_SDA_IN()
- {
- FL_GPIO_InitTypeDef GPIO_InitStruct = {0};
- FL_GPIO_ResetOutputPin(GPIOD, FL_GPIO_PIN_10);
- GPIO_InitStruct.pin = FL_GPIO_PIN_10;
- GPIO_InitStruct.mode = FL_GPIO_MODE_INPUT;
- GPIO_InitStruct.pull = FL_ENABLE;
- FL_GPIO_Init(GPIOD, &GPIO_InitStruct);
- }
TCS34725发送和接收字节数据的函数分别为: - void TCS34725_I2C_Send_Byte(u8 byte)
- {
- u8 i;
- TCS_SDA_OUT();
- TCS_SCL_L;
- for(i = 0; i < 8; i++)
- {
- if(((byte&0x80)>>7)==1) TCS_SDA_H;
- else
- TCS_SDA_L;
- byte <<= 1;
- FL_DelayUs(2);
- TCS_SCL_H;
- FL_DelayUs(2);
- TCS_SCL_L;
- FL_DelayUs(2);
- }
- }
- u8 TCS34725_I2C_Read_Byte(u8 ack)
- {
- u8 i,receive = 0;
- TCS_SDA_IN();
- for(i = 0; i < 8; i++)
- {
- TCS_SCL_L;
- FL_DelayUs(2);
- TCS_SCL_H;
- receive <<= 1;
- if(TCS_SDA_READ) receive++;
- FL_DelayUs(1);
- }
- if (!ack) TCS34725_I2C_NACK();
- else TCS34725_I2C_ACK();
- return receive;
- }
TCS34725的初始化函数为: - u8 TCS34725_Init(void)
- {
- u8 id=0;
- TCS34725_I2C_Init();
- TCS34725_Read(TCS34725_ID, &id, 1);
- if(id==0x4D | id==0x44)
- {
- TCS34725_SetIntegrationTime(TCS34725_INTEGRATIONTIME_50MS);
- TCS34725_SetGain(TCS34725_GAIN_1X);
- TCS34725_Enable();
- return 1;
- }
- return 0;
- }
获取输出值的函数为: - u8 TCS34725_GetRawData(COLOR_RGBC *rgbc)
- {
- u8 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;
- }
3.LCD屏显示驱动
在显示方面,所使用的显示器件为0.96寸的彩色LCD屏,其显示分辨率为160*80像素点。该显示屏采用SPI接口方式工作,为此它与开发板的引脚连接关系为: SCL ---PD3 SDA ---PD5 RES ---PD4 DC ---PC5 CS ---PD2
LCD屏对引脚的功能配置函数为: - void lcd_app(void)
- {
- FL_GPIO_InitTypeDef GPIO_InitStruct = {0};
- FL_GPIO_ResetOutputPin(GPIOD, FL_GPIO_PIN_2|FL_GPIO_PIN_3|FL_GPIO_PIN_4|FL_GPIO_PIN_5);
- GPIO_InitStruct.pin = FL_GPIO_PIN_2|FL_GPIO_PIN_3|FL_GPIO_PIN_4|FL_GPIO_PIN_5;
- GPIO_InitStruct.mode = FL_GPIO_MODE_OUTPUT;
- GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
- GPIO_InitStruct.pull = FL_DISABLE;
- FL_GPIO_Init(GPIOD, &GPIO_InitStruct);
-
- FL_GPIO_ResetOutputPin(GPIOC, FL_GPIO_PIN_5);
- GPIO_InitStruct.pin = FL_GPIO_PIN_5;
- GPIO_InitStruct.mode = FL_GPIO_MODE_OUTPUT;
- GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
- GPIO_InitStruct.pull = FL_DISABLE;
- FL_GPIO_Init(GPIOC, &GPIO_InitStruct);
- }
以GPIO口模拟SPI方式发送字节数据的函数为: - void LCD_Writ_Bus(u8 dat)
- {
- u8 i;
- OLED_CS_Clr();
- for(i=0;i<8;i++)
- {
- OLED_SCLK_Clr();
- if(dat&0x80)
- OLED_SDIN_Set();
- else
- OLED_SDIN_Clr();
- OLED_SCLK_Set();
- dat<<=1;
- }
- OLED_CS_Set();
- }
LCD屏的初始化函数为:
voidLcd_Init(void) { OLED_RST_Clr(); FL_DelayMs(200); OLED_RST_Set(); FL_DelayMs(200); LCD_WR_REG(0x11); FL_DelayMs(100); LCD_WR_REG(0x21); LCD_WR_REG(0xB1); LCD_WR_DATA8(0x05); LCD_WR_DATA8(0x3A); LCD_WR_DATA8(0x3A); LCD_WR_REG(0xB2); LCD_WR_DATA8(0x05); LCD_WR_DATA8(0x3A); LCD_WR_DATA8(0x3A); LCD_WR_REG(0xB3); LCD_WR_DATA8(0x05); LCD_WR_DATA8(0x3A); LCD_WR_DATA8(0x3A); LCD_WR_DATA8(0x05); LCD_WR_DATA8(0x3A); LCD_WR_DATA8(0x3A); LCD_WR_REG(0xB4); LCD_WR_DATA8(0x03); LCD_WR_REG(0xC0); LCD_WR_DATA8(0x62); LCD_WR_DATA8(0x02); LCD_WR_DATA8(0x04); LCD_WR_REG(0xC1); LCD_WR_DATA8(0xC0); LCD_WR_REG(0xC2); LCD_WR_DATA8(0x0D); LCD_WR_DATA8(0x00); LCD_WR_REG(0xC3); LCD_WR_DATA8(0x8D); LCD_WR_DATA8(0x6A); LCD_WR_REG(0xC4); LCD_WR_DATA8(0x8D); LCD_WR_DATA8(0xEE); LCD_WR_REG(0xC5); LCD_WR_DATA8(0x0E); LCD_WR_REG(0xE0); LCD_WR_DATA8(0x10); LCD_WR_DATA8(0x0E); LCD_WR_DATA8(0x02); LCD_WR_DATA8(0x03); LCD_WR_DATA8(0x0E); LCD_WR_DATA8(0x07); LCD_WR_DATA8(0x02); LCD_WR_DATA8(0x07); LCD_WR_DATA8(0x0A); LCD_WR_DATA8(0x12); LCD_WR_DATA8(0x27); LCD_WR_DATA8(0x37); LCD_WR_DATA8(0x00); LCD_WR_DATA8(0x0D); LCD_WR_DATA8(0x0E); LCD_WR_DATA8(0x10); LCD_WR_REG(0xE1); LCD_WR_DATA8(0x10); LCD_WR_DATA8(0x0E); LCD_WR_DATA8(0x03); LCD_WR_DATA8(0x03); LCD_WR_DATA8(0x0F); LCD_WR_DATA8(0x06); LCD_WR_DATA8(0x02); LCD_WR_DATA8(0x08); LCD_WR_DATA8(0x0A); LCD_WR_DATA8(0x13); LCD_WR_DATA8(0x26); LCD_WR_DATA8(0x36); LCD_WR_DATA8(0x00); LCD_WR_DATA8(0x0D); LCD_WR_DATA8(0x0E); LCD_WR_DATA8(0x10); LCD_WR_REG(0x3A); LCD_WR_DATA8(0x05); LCD_WR_REG(0x36); LCD_WR_DATA8(0x78); LCD_WR_REG(0x29); }
4. 功能实现 有了前面的准备工作,就可以开始其功能设计了。 其设计思想为: 1)进行色彩值的归一化处理 由于TCS34725传感器是按3基色的亮度来进行检测的,因此对其检测值需要进行归一化处理,其处理方法就是用RGB的色彩值*255/亮度值。 以红色为例,其进行归一化的语句为: rv=rgb.r*255/rgb.c; 对于G、B这两种色彩的归一化处理与之相仿。
2)实现样本色彩的标识处理 在获得了色彩的归一化结果后,其输出值是24位色,为了便于以16位色彩的形式进行显示,需进行色彩位数的变换处理,对于565的色彩表示方式,所进行的变换处理为: fv=((rv>>3)<<8)+((gv>>2)<<5)+(bv>>3); 其中fv就是变换后的16位色彩值,而rv、gv和bv是8位色彩值。
此外,还要做的2件事为:一是绘制样本色彩框,以标识样本色彩的区域,另一个则是标识样本色彩,即填充一个样本色彩块。 实现样本色彩框的绘制函数为: - void LCD_box(u16 x1,u16 y1,u16 x2,u16 y2)
- {
- int i,l;
- LCD_Address_Set(x1,y1,x2,y1);
- l=x2-x1;
- for(i=0;i<l;i++)
- {
- LCD_WR_DATA8(0xff);
- LCD_WR_DATA8(0xff);
- }
- LCD_Address_Set(x1,y2,x2,y2);
- for(i=0;i<l;i++)
- {
- LCD_WR_DATA8(0xff);
- LCD_WR_DATA8(0xff);
- }
- l=y2-y1;
- for(i=0;i<l;i++)
- {
- LCD_DrawPoint(x1,y1+i,WHITE);
- }
- for(i=0;i<l;i++)
- {
- LCD_DrawPoint(x2,y1+i,WHITE);
- }
- }
实现样本色彩标识的函数为: - void LCD_color(u16 Color)
- {
- u16 i,j;
- LCD_Address_Set(110,30,129,49);
- for(i=0;i<20;i++)
- {
- for (j=0;j<20;j++)
- {
- LCD_WR_DATA(Color);
- }
- }
- }
功能处理的主程序: - int main(void)
- {
- u16 rv,gv,bv,fv;
- MF_Clock_Init();
- MF_SystemClock_Config();
- FL_Init();
- MF_Config_Init();
- UserInit();
- led_int();
- lcd_app();
- Lcd_Init();
- LCD_Clear(BLACK);
- BACK_COLOR=BLACK;
- FL_DelayMs(2000);
- LCD_ShowString(20,30,"R: G: B:",YELLOW);
- LCD_color(RED);
- LCD_box(109,29,130,50);
- TCS34725_Init();
- TCS34725_GetRawData(&rgb);
- while(1)
- {
- TCS34725_GetRawData(&rgb);
- rv=rgb.r*255/rgb.c;
- gv=rgb.g*255/rgb.c;
- bv=rgb.b*255/rgb.c;
- LCD_ShowNum(0,50,rv,4,YELLOW);
- LCD_ShowNum(32,50,gv,4,YELLOW);
- LCD_ShowNum(64,50,bv,4,YELLOW);
- fv=((rv>>3)<<8)+((gv>>2)<<5)+(bv>>3);
- LCD_color(fv);
- FL_DelayMs(1000);
- LED0_TOG();
- }
- }
5. 验证测试 经程序的编译与下载,其检测的效果如图5至图7所示,其中用于彩色检测的材料为彩色的泡沫塑料板。 从测试效果看,其结果还是可信的,能在一定应用场合使用。 此外,由于传感器上所配的LED灯有些偏黄,会对反射光的检测有一定的影响。
图5 检测粉色
图6 检测绿色
图7 检测蓝色
TCS34725相关代码及主程序:
|