不得不说,这颜色模块还挺有趣的,早上起床我就有想法想要把它实现了,之前一直把这模块压箱里了,本以为电赛要用到,结果材料清单无,所以就战略性放弃,现在才想起来有这个模块哈哈,就顺手拿来玩玩,其实对于TCS3200这个模块,还是比较不错的一款识别颜色,但是如果对颜色识别要求较高就不建议入手,这款识别模块抗干扰能力还是强的,是TCS230的升级版吧,具体下面再一一介绍。
另外就是发现关于这款模块的博文少,而且基于库函数的适用STM32f1的几乎没有,有的也是收费资源,因此就有了以下文章的问世哈哈
当然也有一篇基于HAL库的文章,同样在上面受益匪浅,推荐给大家:
基于STM32F103的TCS3200颜色传感器的使用_weixin_50950634的博客-CSDN博客
这里老规矩,还是讲一下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-----PA0
void 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, //TIM2
TIM_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);//100ms
TIM2_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之路固然辛苦,但要是坚持下来了,那不是很酷?哈哈哈