TCS3200颜色识别模块

TCS3200颜色识别模块

TCS3200简介

  • 供电电源(2.7V to 5.5V)
  • 可配置颜色滤波器和输出信号频率
  • 高分辨率光强转换到频率(工作原理)

TCS3200工作原理

TCS3200颜色识别模块_第1张图片
在这里插入图片描述

  • TCS3200是TAOS公司推出的可编程彩色光到频率的转换器,它把可配置的硅光电二极管与电流频率转换器集成在一个单一的CMOS电路上,同时集成了三种颜色(RGB)的滤光器;TCS3200能检测物体反射的光强,并生成不同频率的方波信号(50%占空比)

  • TCS3200有一个8*8的光电二极管矩阵,其中分别有三组16个光电二极管有RGB三种滤波器,一组16个光点二极管无滤波器,共64个光电二极管

  • 具有不同滤波器的光电二极管分别检测RGB的值

  • S2和S3用于配置光电二极管矩阵(选择上面四组光电二极管中的一组),S0和S1用于配置电流频率转换器(可以控制输出信号的频率范围)

TCS3200引脚定义

TCS3200颜色识别模块_第2张图片

  • 注意: 对于常见TCS3200颜色识别模块 O E ‾ \overline {OE} OE引脚一般不引出,但会有LED引脚控制模块的LED灯亮灭(一般四个),用于在无光源环境下识别物体

TCS3200功能表

TCS3200颜色识别模块_第3张图片

  • S2、S3用于选择滤波器 对应有 RGB 无滤波器

  • S0、S1用于选择输出波形的频率范围(可以理解为限制输出信号频率的最大值)

  • 下面对TCS3200的输出信号频率作一个简单讲解

TCS3200颜色识别模块_第4张图片

根据网上资料: 该传感器的典型输出频率范围从2Hz-500KHz (但官方资料好像典型值应该到600KHz, 不重要)

S0=H, S1=H对应输出状态为100% 输出典型值为600KHz

S0=H, S1=L对应输出状态为20% 输出典型值为600*0.2 = 120KHz

S0=L, S1=H对应输出状态为2% 输出典型值为 600*0.02=12KHz

注意:该值应为输出频率的最大值, 接着往下看
TCS3200颜色识别模块_第5张图片

这是TCS3200运行特征表的一部分,可以看到在100%输出的模式下, 不同颜色光照对应的输出信号频率范围

TCS3200工作流程

TCS3200颜色识别模块_第6张图片

白平衡校准

白平衡就是告诉TCS3200什么是白色的,以此为参照才能计算其他颜色的RGB。理论上,白色是由等量的RGB混合而成(255、255、255)但实际中,由于光照条件人的感知能力有限等原因,我们看到的白色很有可能不是由均匀的RGB组成,并且TCS3200对三种颜色的敏感性也不相同(参考TCS3200运行特征表),因此进行白平衡给TCS3200一个标准(这个标准有时候不一定准确,会导致识别的结果出现一定的误差)

白平衡的方法: 在装置启动前,先将一个白色物体(不是白色就校验不准)置于传感器处,等待传感器检测,MCU计算出比例因子

题外话: 校验不准容易导致后续的检测中出现异常值,RGB的值超出255,这样在现有的RGB体系下我们无法找到对应的颜色;校验的越准,越不容易出现异常值

颜色识别

参考TCS230,大致有两种思路

TCS3200颜色识别模块_第7张图片

这里采用第二种思路

程序设计

设计思路

设置一个定时器每隔1s进入一次中断服务,期间对TCS3200输出的信号进行采集和处理;设置另外一个定时器,捕获TCS3200的输出信号**(外部时钟源模式2,上升沿使计数器加一);第一次的检测用于白平衡,后续循环检测RGB**,每完成一组将RGB的值显示在OLED屏幕上

标准库下使用外部时钟源模式2

1. 通用定时器框图(部分)

TCS3200颜色识别模块_第8张图片

回顾一下这个图,要想用外部时钟源模式2,信号的流向是这样子的。

可简单分为三个部分:

  • 外部时钟源模式2参数配置 (极性选择,边沿检测,预分频器,滤波器)
  • 从模式控制器配置(复位、使能、向上/下、计数)
  • 时基单元配置(TimeBase)

接下来根据信号的流向,讲解整个流程的配置

2. 配置外部时钟模式2

TCS3200颜色识别模块_第9张图片

  • 首先从参考手册的描述中可知,设定该模式主要操作的是SMCR寄存器也就是所谓的从模式寄存器

  • 第二句话说明它的功能,即我们所需的功能

TCS3200颜色识别模块_第10张图片

  • 框图: 对应第一部分

  • 调用的库函数
    TCS3200颜色识别模块_第11张图片

TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0);
  • 不分频,极性不翻转(高电平有效), 不滤波
3. 配置从模式
  • 在参考手册中,只对从模式中的四个做出详细的介绍

TCS3200颜色识别模块_第12张图片

  • 但在手册对于定时器寄存器描述中,我们找到从模式控制寄存器(TIMx_SMCR)

TCS3200颜色识别模块_第13张图片

  • 可以看到其实有八种模式可以配置,然后可以发现外部时钟模式1,刚好对应了我们框图中的信号流向,因此我们需要将从模式配置为外部时钟模式1,从模式的外部时钟模式1和时钟选择的外部时钟源模式1不同

  • 下面介绍需要使用和了解的库函数

    • 函数TIM_ITRxExternalClockConfig

TCS3200颜色识别模块_第14张图片

    /**
      * @brief  Configures the TIMx Internal Trigger as External Clock
      * @param  TIMx: where x can be  1, 2, 3, 4, 5, 9, 12 or 15 to select the TIM peripheral.
      * @param  TIM_ITRSource: Trigger source.
      *   This parameter can be one of the following values:
      * @param  TIM_TS_ITR0: Internal Trigger 0
      * @param  TIM_TS_ITR1: Internal Trigger 1
      * @param  TIM_TS_ITR2: Internal Trigger 2
      * @param  TIM_TS_ITR3: Internal Trigger 3
      * @retval None
      */
    void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource)
    {
      /* Check the parameters */
      assert_param(IS_TIM_LIST6_PERIPH(TIMx));
      assert_param(IS_TIM_INTERNAL_TRIGGER_SELECTION(TIM_InputTriggerSource));
      /* Select the Internal Trigger */
      TIM_SelectInputTrigger(TIMx, TIM_InputTriggerSource);  // 选择输入触发的通道
      /* Select the External clock mode1 */
      TIMx->SMCR |= TIM_SlaveMode_External1;   // 内部使用了从模式的外部模式1
    }
  • 可以看到该函数无论是在库函数编程手册,还是在ST库的注释中,都只有4个参数可选择(但实际不是, 接着往下看)

  • 可以看到该函数内部调用了函数TIM_SelectInputTrigger

  • 函数TIM_SelectInputTrigger

TCS3200颜色识别模块_第15张图片

 /**
   * @brief  Selects the Input Trigger source
   * @param  TIMx: where x can be  1, 2, 3, 4, 5, 8, 9, 12 or 15 to select the TIM peripheral.
   * @param  TIM_InputTriggerSource: The Input Trigger source.
   *   This parameter can be one of the following values:
   *     @arg TIM_TS_ITR0: Internal Trigger 0
   *     @arg TIM_TS_ITR1: Internal Trigger 1
   *     @arg TIM_TS_ITR2: Internal Trigger 2
   *     @arg TIM_TS_ITR3: Internal Trigger 3
   *     @arg TIM_TS_TI1F_ED: TI1 Edge Detector
   *     @arg TIM_TS_TI1FP1: Filtered Timer Input 1
   *     @arg TIM_TS_TI2FP2: Filtered Timer Input 2
   *     @arg TIM_TS_ETRF: External Trigger input  // 我们要选的参数
   * @retval None
   */
 void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource)
 {
   uint16_t tmpsmcr = 0;
   /* Check the parameters */
   assert_param(IS_TIM_LIST6_PERIPH(TIMx));
   assert_param(IS_TIM_TRIGGER_SELECTION(TIM_InputTriggerSource));
   /* Get the TIMx SMCR register value */
   tmpsmcr = TIMx->SMCR;
   /* Reset the TS Bits */
   tmpsmcr &= (uint16_t)(~((uint16_t)TIM_SMCR_TS));
   /* Set the Input Trigger source */
   tmpsmcr |= TIM_InputTriggerSource;
   /* Write to TIMx SMCR */
   TIMx->SMCR = tmpsmcr;
 }
  • 实际可调用参数有8个

  • 配置代码

TIM_ITRxExternalClockConfig(TIM2, TIM_TS_ETRF);
4. 配置时基单元(略)

至此,框图信号流动路线全部配置完毕,外部时钟源模式2即可使用

主要代码

TCS.h
#ifndef __TCS_H
#define __TCS_H
#include "stm32f10x.h"

/**
 * @breif TCS3200端口定义
 * 		  S0: PA4
 * 		  S1: PA5
 * 		  S2: PA6
 * 		  S3: PA7
 * 		  LED: PB0
 */
#define  S0_L 		GPIO_ResetBits(GPIOA, GPIO_Pin_4);
#define  S0_H       GPIO_SetBits(GPIOA, GPIO_Pin_4);

#define  S1_L       GPIO_ResetBits(GPIOA, GPIO_Pin_5);
#define  S1_H    	GPIO_SetBits(GPIOA, GPIO_Pin_5);

#define  S2_L       GPIO_ResetBits(GPIOA, GPIO_Pin_6);
#define  S2_H       GPIO_SetBits(GPIOA, GPIO_Pin_6);

#define  S3_L       GPIO_ResetBits(GPIOA, GPIO_Pin_7);
#define  S3_H       GPIO_SetBits(GPIOA, GPIO_Pin_7);

#define  LED_OFF    GPIO_ResetBits(GPIOB, GPIO_Pin_0);
#define  LED_ON     GPIO_SetBits(GPIOB, GPIO_Pin_0);

extern float RGB_Scale[3];  // R、G、B 比例因子
extern uint16_t count;  // 脉冲计数
extern uint16_t cnt[3]; // RGB 三种颜色的脉冲数

// 频率选择
typedef enum
{
	TCS_2Percentage = 0x01,
	TCS_20Percentage = 0x02,
	TCS_100Percentage = 0x03,
	TCS_Frequent_OFF = 0x04
}TCS_FrequentTypeDef;

// 滤波器
typedef enum
{
	TCS_Filter_Red = 0x01,
	TCS_Filter_Blue = 0x02,
	TCS_Filter_Green = 0x03,
	TCS_Filter_None = 0x04
} TCS_FilterTypeDef;

void TCS_Init(void);
void TCS_FrequentKeyer(TCS_FrequentTypeDef TCS_Frequent);

#endif

TCS.c
#include "stm32f10x.h"
#include "MyNVIC.h"
#include "TCS.h"

float RGB_Scale[3];  // R、G、B 比例因子
uint16_t count;  // 脉冲计数
uint16_t cnt[3]; // RGB 三种颜色的脉冲数
static TCS_FilterTypeDef flag = TCS_Filter_None;  // 滤波器选择模式标志

/**
 *  @brief 颜色识别端口初始化  PA 4 5 6 7;  PB 0 
 */
void TCS_PortInit(void)
{
	// RCC
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);	
	// GPIO  S0-S3(PA4-7) 用来控制TCS3200工作模式 配置为通用推挽输出
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	// LED(PB0) 用来控制TCS3200的LED的亮灭 配置为通用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}	

/**
 * @brief TIM1 初始化 用于计时 定时时间为1s
 */
void TCS_TIM1_Init(void)
{
	// RCC
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
	
	// TimeBase
	TIM_TimeBaseInitTypeDef TimeBase_InitStructure;
	TimeBase_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TimeBase_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TimeBase_InitStructure.TIM_Period = 10000-1; // ARR
	TimeBase_InitStructure.TIM_Prescaler = 7200-1; // PSC
	TimeBase_InitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM1, &TimeBase_InitStructure);
	
	// NVIC
	MyNVIC_TIM1_Config();
	
	// 开启中断
	TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
	
	TIM_Cmd(TIM1, ENABLE);
}

/**
 *  @brief TIM2 初始化 外部时钟模式 用于捕获TCS3200 OUT口的信号 PA0信号输入口 TIM_ETR
 */
void TCS_TIM2_Init(void)
{
	// RCC
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// GPIO
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_ResetBits(GPIOA, GPIO_Pin_0);  // 拉倒低电平
	
	// TimeBase
	TIM_TimeBaseInitTypeDef TimeBase_InitStructure;
	TimeBase_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TimeBase_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TimeBase_InitStructure.TIM_Period = 0xFFFF; // ARR  65535
	TimeBase_InitStructure.TIM_Prescaler = 0;  // PSC
	TimeBase_InitStructure.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM2, &TimeBase_InitStructure);
	
	// Select the clock source  选择时钟源
	TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0);
	TIM_ITRxExternalClockConfig(TIM2, TIM_TS_ETRF);
	TIM_SetCounter(TIM2, 0);  // 将CNT置零
	
	TIM_Cmd(TIM2, ENABLE);  // 开启定时器
}

/**
 *  @brief 频率调制	
 *
 *  @param TCS_FrequentTypeDef:  TCS_2Percentage TCS_20Percentage TCS_100Percentage TCS_Frequent_OFF
 */
void TCS_FrequentKeyer(TCS_FrequentTypeDef TCS_Frequent)
{
	switch(TCS_Frequent)
	{	
		case TCS_2Percentage:
			S0_L;
			S1_H;
			break;
		case TCS_20Percentage:
			S0_L;
			S1_H;
			break;
		case TCS_100Percentage:
			S0_H;
			S1_H;
			break;
		case TCS_Frequent_OFF:
			S0_L;
			S1_L;
			break;
		default:
			break;
	}
}

/**
 *  @brief 选择滤波器
 *  @param TCS_Filter: TCS_Filter_Red TCS_Filter_Blue TCS_Filter_Green TCS_Filter_None 
 */
void TCS_SelectFilter(TCS_FilterTypeDef TCS_Filter)
{
	flag = TCS_Filter;  // 更新标志位
	switch(TCS_Filter)
	{
		case TCS_Filter_Red:
			S2_L;
			S3_L;
			break;
		case TCS_Filter_Blue:
			S2_L;
			S3_H;
			break;
		case TCS_Filter_Green:
			S2_H;
			S3_H;
			break;
		case TCS_Filter_None:
			S2_H;
			S3_L;
			break;
		default:
			break;
	}
}

/**
 * @brief TCS3200初始化 初始化端口 和两个用到的定时器 
 */
void TCS_Init(void)
{
	TCS_PortInit();   // 控制端口
	TCS_TIM1_Init();  // 定时计时器
	TCS_TIM2_Init();  // 捕获脉冲数 包括输入端口初始化 
	TCS_FrequentKeyer(TCS_Frequent_OFF);  // 频率调制器断电
	TCS_SelectFilter(TCS_Filter_None);  // 关闭TCS滤波器
	LED_OFF;  // 关闭LED
}

/**
 * @brief TIM1更新中断
 */
void TIM1_UP_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM1, TIM_IT_Update))
	{
		count = TIM_GetCounter(TIM2);  // 读取脉冲数
		// 依次读取 RGB三种颜色的值
		switch(flag)
		{
			case TCS_Filter_None:
				count = 0;
				TCS_SelectFilter(TCS_Filter_Red);  // 选择红色滤波器
				break;
			case TCS_Filter_Red:
				cnt[0] = count;  
				TCS_SelectFilter(TCS_Filter_Green);  // 选择绿色滤波器
				break;
			case TCS_Filter_Green:
				cnt[1] = count;
				TCS_SelectFilter(TCS_Filter_Blue);  // 选择蓝色滤波器
				break;
			case TCS_Filter_Blue:
				cnt[2] = count;
				TCS_SelectFilter(TCS_Filter_None);  // 关闭滤波器
				break;
			default:
				break;
		}
		// 将TIM2的计数器清零
		TIM_SetCounter(TIM2, 0);
		
		// 清除标志位
		TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
	}
}

MyNVIC.h
#ifndef __MyNVIC_H
#define __MyNVIC_H

void MyNVIC_TIM1_Config(void);

#endif

MyNVIC.c
#include "stm32f10x.h"

/**
 * @brief TIM1 中断向量嵌套配置 
 */
void MyNVIC_TIM1_Config(void)
{
	NVIC_SetPriorityGrouping(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
	
	NVIC_Init(&NVIC_InitStructure);

}

main.c
#include "stm32f10x.h" 
#include "delay.h"  // 江科大对应的驱动
#include "OLED.h"  // 江科大对应的驱动
#include "TCS.h"
int main(void)
{
	OLED_Init();
	TCS_Init();  // 初始化TCS3200
	
	TCS_FrequentKeyer(TCS_2Percentage);  // 选择输出频率
	// 这里选2% 因为计数器最多到65535 
	// 若选20%最高输出120kHz 120000 当检测时长为1s时会超出计数器的范围
	// 但输出频率越高,结果越精确
	// 感兴趣的可以尝试两个定时器级联 扩大计数范围
	LED_ON;  // LED 开
	
	// 第一次获得的参数 进行白平衡 
	Delay_ms(8000);  // 延时8s,两轮检测确保白平衡的进行
	RGB_Scale[0] = 255.0/cnt[0];  // Get Red Scale
	RGB_Scale[1] = 255.0/cnt[1];  // Get Green Scale
	RGB_Scale[2] = 255.0/cnt[2];  // Get Blue Scale
	
	while(1)
	{
		Delay_ms(4000);
		OLED_ShowString(1, 1, "R:");
		OLED_ShowNum(1, 3, cnt[0]*RGB_Scale[0], 3);
		OLED_ShowString(2, 1, "G:");
		OLED_ShowNum(2, 3, cnt[1]*RGB_Scale[1], 3);
		OLED_ShowString(3, 1, "B:");
		OLED_ShowNum(3, 3, cnt[2]*RGB_Scale[2], 3);
	}
}

效果展示

【TCS3200颜色识别模块】

参考资料

基于STM32F103的TCS3200颜色传感器的使用

肝了一下午,学会TCS3200颜色识别——基于STM32,分享一波

高分辨颜色传感器TCS230的原理与应用

TCS3200.pdf (DataSheet)

STM32F10xxx参考手册(中文).pdf

你可能感兴趣的:(单片机学习笔记,自动化,学习,stm32,c语言)