前言
不得不说,这颜色模块还挺有趣的,早上起床我就有想法想要把它实现了,之前一直把这模块压箱里了,本以为电赛要用到,结果材料清单无,所以就战略性放弃,现在才想起来有这个模块哈哈,就顺手拿来玩玩,其实对于TCS3200这个模块,还是比较不错的一款识别颜色,但是如果对颜色识别要求较高就不建议入手,这款识别模块抗干扰能力还是强的,是TCS230的升级版吧,具体下面再一一介绍。
另外就是发现关于这款模块的博文少,而且基于库函数的适用STM32f1的几乎没有,有的也是收费资源,因此就有了以下文章的问世哈哈
当然也有一篇基于HAL库的文章,同样在上面受益匪浅,推荐给大家:
基于STM32F103的TCS3200颜色传感器的使用_weixin_50950634的博客-CSDN博客
一、TCS3200如何用?
这里老规矩,还是讲一下TCS3200颜色识别模块怎么使用,首先,了解一下它有几个接口
上面两张图片已经很好地说明了,该模块含有8个引脚,即VCC、GND、S0、S1、S2、S3、LED(OE)、OUT,实际上在原理图上写了EO,但在实物图上并没有看到EO接口,只有LED接口,所以我就“自作主张”修改了一下,方便大家学习哈哈,这里是原理图,实物图会额外多出两个引脚(VCC、GND),那么这些引脚作用是什么呢?自问自答来了
S0、S1是一对情侣,S2、S3也是一对情侣,LED和OUT就两电灯泡
那么首先我们要如何定义这些端口呢,毋庸置疑,S0~S3全部推挽输出,LED推挽输出,OUT就下拉输入即可,怎么接比较好呢,除了OUT要设置在定时器的外部触发输入口(ETR),这里选用的是PA0(TIM2-ETR),其他接口无特别要求。测试时与被测物体保持在1cm时最佳。
先说明一下接线问题,因为我的博文主要还是以实际操作为主,理论部分较少,直接让你上手,理论后面再补哈哈
S0~S3分别接PA4~PA7,LED接PC5,OUT接PA0
那么认识认识它长怎么样吧?
是不是很酷炫哈哈
二、实现原理
那么这到底是如何实现的,接下来一探到底。
以上奉行的是拿来主义哈哈,其实是淘宝商家给的。这里比较详细地介绍了它的主要工作原理,大家在学习过程中可以多次返回来学习,肯定会有用的。
下面是S0~S3分别在高低电平下代表的意义(L表示低电平,H表示高电平)
这里我们可以看到四种模式,在测试时,按红绿蓝清除的顺序进行
这里可以看到四种情况,双L下不启动,其他按比例因子情况启动
后面我选择的是2%,参照另一位博主的,大家也可以自行更改。
当然在进行测试之前,一定要进行白平衡校准,即每次运行前拿一个白色物体放在模块前进行第一次识别,之后就可以识别其他颜色了,白平衡等到的R值G值B值均为255。之后就可以开始测试了。
三、测试实现程序
TCS3200函数:
#include "tcs3200.h"#include "delay.h"#include "usart.h"#include "lcd.h"float RGB_Scale[3]; int count=0; int cnt[3]; int flag=0; //S0-----PA4,S1-----PA5,S2-----PA6,S3-----PA7,LED-----PC5,OUT-----PA0void TCS_GPIO_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_4|GPIO_Pin_7); //PA.4567 Êä³ö¸ß GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_SetBits(GPIOC,GPIO_Pin_5); }void filter(int s2,int s3) { if(s2==0&&s3==0){S2_L;S3_L;} if(s2==0&&s3==1){ S2_L;S3_H;} if(s2==1&&s3==0){S2_H;S3_L;} if(s2==1&&s3==1){ S2_H;S3_H;}}void TSC_WB(int s2, int s3){ count = 0; flag ++; filter(s2, s3); }
定时器函数:
#include "timer.h"#include "led.h"#include "usart.h"#include "tcs3200.h"#include "lcd.h"extern float RGB_Scale[3]; extern int cnt[3]; extern int flag;extern int count;void TIM3_Int_Init(u16 arr,u16 psc){ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); TIM_TimeBaseStructure.TIM_Period = arr; TIM_TimeBaseStructure.TIM_Prescaler =psc; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); TIM_ITConfig( TIM3, //TIM2TIM_IT_Update | TIM_IT_Trigger, ENABLE );NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure); TIM_Cmd(TIM3, ENABLE); //ʹÄÜTIMxÍâÉè }void TIM2_Cap_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_ResetBits(GPIOA,GPIO_Pin_0); TIM_TimeBaseStructure.TIM_Period = 0xFFFF; TIM_TimeBaseStructure.TIM_Prescaler =0; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_ITRxExternalClockConfig(TIM2,TIM_TS_ETRF); TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0); TIM_SetCounter(TIM2, 0); TIM_Cmd(TIM2,ENABLE ); }void TIM3_IRQHandler(void) {if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); count=TIM_GetCounter(TIM2); switch(flag){ case 0: TSC_WB(0, 0); break; case 1: cnt[0] = count; TSC_WB(1, 1); break; case 2: cnt[1] = count; TSC_WB(0, 1); break; case 3: cnt[2] = count; TSC_WB(1, 0); break; default: count = 0; break; } TIM_SetCounter(TIM2,0);}}
最后主函数:
#include "led.h"#include "delay.h"#include "key.h"#include "sys.h"#include "usart.h"#include "lcd.h"#include "tcs3200.h"#include "timer.h"extern float RGB_Scale[3]; //外部声明 extern int cnt[3]; extern int flag;extern int count; int main(void) {delay_init(); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);uart_init(115200); LED_Init(); LCD_Init(); TCS_GPIO_Init();TIM3_Int_Init(9999,719);//100msTIM2_Cap_Init(); POINT_COLOR=RED; S0_L;//这里直接2%设置,LED永远亮着即可 S1_H; LED_ON;delay_ms(8000); RGB_Scale[0] = 255.0/ cnt[0]; RGB_Scale[1] = 255.0/ cnt[1] ; RGB_Scale[2] = 255.0/ cnt[2] ; LCD_ShowString(10,10,210,16,16,"Init"); LCD_ShowString(20,70,210,16,16,"R:");LCD_ShowString(20,90,210,16,16,"G:"); LCD_ShowString(20,110,210,16,16,"B:"); LCD_ShowNum(50, 10,(int)(cnt[0]*RGB_Scale[0]),3,16);LCD_ShowNum(50, 30,(int)(cnt[1]*RGB_Scale[1]),3,16);LCD_ShowNum(50, 50,(int)(cnt[2]*RGB_Scale[2]),3,16); //白平衡结束POINT_COLOR=BLUE;while(1){flag=0; count=0; delay_ms(10000); LCD_ShowNum(50, 70,(int)(cnt[0]*RGB_Scale[0]),3,16);LCD_ShowNum(50, 90,(int)(cnt[1]*RGB_Scale[1]),3,16);LCD_ShowNum(50, 110,(int)(cnt[2]*RGB_Scale[2]),3,16); } }
四、结果展示
白平衡结束后,我选用了一个青绿色纸盒进行测试,得到RGB值
RGB值如下:76、96、80
在自带的画图软件上查询是否准确
基本上误差不大,但是要说多么精准也没有哈哈,不过简单的识别还是可以做到的,不错,我又试了一个红色和粉色的,那个识别就比较准确。
五、总结
本来我想着直接拿来主义直接理解一波就行了,没想到网上资料少得可怜,拿来主义行不通,商家给的也只有51程序,所以没办法,只得自己手动敲代码了,刚开始那是毫无头绪,但是在看了其他优秀博文后,渐渐就有了思路,就开始上手了,其实不难,但是贵在坚持,肯定会有很多bug等着你,但是成功是给坚持到底的人的,遇到不懂及时查找资料解决,就算做不出来,也肯定会有收获。加油!
那么老规矩,觉得文章写的还可以的记得给点一下赞,收藏一下,说不定以后用得上呢哈哈
题外话:
挺喜欢彭于晏说的一句话:“我就是没有才华,所以才用命去拼!”
学习32之路固然辛苦,但要是坚持下来了,那不是很酷?哈哈哈