STM32F103+TCS3415颜色传感器程序实现

目录

一、传感器原理

二、 本实验实现功能

三、硬件引脚连接

四、传感器配置

1.IIC配置

2. 器件地址和寄存器地址 

3. 寄存器设置讲解

五、程序

1.TCS3415配置程序 .c

2.TCS3415配置程序 .h

3.其它程序

六、程序验证

1.示波器调试观察程序

2.注意事项

七、写在后面的话


一、传感器原理

              datasheet上说TCS3415是一种数字彩色光传感器,能够精确地导出环境光的色度和照度(强度),并提供具有16位分辨率的数字输出。个人感觉是属于环境光传感器(可百度搜一搜其定义),外界光通过红外阻隔滤片后,无用的IR、UV信号被削弱,获得可见光(380~770nm),然后通过R,G,B和Clear滤片进入各自的通道,光电二极管将光信号转换为电流或电压信号,积分型ADC对电压进行积分,输出为相应的数字信号。

             具体的积分型AD转换器原理这里就不赘述了,推荐观看B站一位老师讲解的双积分型AD转换器,一听就懂!链接如下:【数字电子技术基础 8.12 双积分型AD转换器】

 光谱响应该传感器对不同颜色的不同波长的响应度不同,即使是单色光,其它通道也会有响应。

二、 本实验实现功能

            基于STM32F103平台,通过TSC3415颜色传感器模块感应外界光,并导出RGBC通道采集到的值(这里不说是导出环境光的色度和光照强度,是因为采集到的RGBC值是随着光强的变化而变化,不能单纯地归为色度和照度),然后通过print()函数在电脑串口调试终端打印输出。

三、硬件引脚连接

           TCS3415只接GND、VCC、SCL、SDA四个引脚,STM32使用的模拟IIC,这里将PD6设置为SDA,PD7设置为SCL。所以TCS3415的SCL、SDA引脚分别与单片机的PD7、PD6引脚连接。

四、传感器配置

1.IIC配置

            从数据手册中可知道到 TCS3415 是 I²C 器件,支持SMBus 和 IIC协议通信;我们这里使用了 IIC Write/Read Protocol 通信。

I2C Write Protocols
 I2C Read  Protocols

 这里的每一个操作都需要使用到模拟IIC里面定义的函数。

2. 器件地址和寄存器地址 

             TCS3415的器件地址是 1001001(0x49,是个奇数),为的是单片机能够找到该传感器,才能进行后续的操作。该传感器有以下寄存器,想要执行相应的功能就需要对相应的寄存器进行配置。

  • 器件地址是个奇数,我们知道 I²C 的从机地址是 8 bit ,前 7 bit 是器件地址,最后 1 bit 代表是读操作(1)还是写操作(0),所以一般来说器件地址应该是偶数。因此需要给它左移 1 bit ,再加上读/写操作 
  • 其中,COMMAND (命令)寄存器指定后续读写操作的目标寄存器地址;例如,配置TIMING寄存器,其地址应该为0x80+01h=0x81,类似于基地址+偏移地址,才是真正的寄存器地址。

  • 我们这里只实现传感器基本的信号采集功能,因此就只配置了Control Register (00h)Timing Register (01h)Gain Register (07h),寄存器的值都是8Bit,可根据数据手册进行相应的赋值设置。

3. 寄存器设置讲解

              STM32通过IIC协议控制传感器来实现相应的功能,比如对传感器的ADC使能和上电;首先我们从资料手册中可以知道它们在Control Register (00h)中设置。

              从STM32中发送指令给传感器,使用IIC写操作,如以下的代码。产生IIC起始信号,发送从机地址(0x49<<1|0,为地址左移1位+写操作),等待传感器应答,然后再发送Control Register地址(0x80),等待传感器应答,最后发送ADC使能和上电命令(0000 0011b=0x03h)等待传感器应答,最后产生IIC停止信号。经过以上操作就完成了对对传感器的ADC使能和上电。

  • 这里的的操作一一与IIC的写协议对应,因为发送的是一个Byte,所以不需要统计data长度,配置其它的功能也是如此。
void Tcs3415_WriteByte(u8 reg, u8 data)
{
	IIC_Start();  
	IIC_Send_Byte(TCS3415_ADDRESS<<1 |0);  
	IIC_Wait_Ack();
	IIC_Send_Byte(reg);//CMD + addr,写入模式和寄存器地址
	IIC_Wait_Ack();
	IIC_Send_Byte(data);  //寄存器的值
  IIC_Wait_Ack();
	IIC_Stop();

}

五、程序

1.TCS3415配置程序 .c

代码里面有详细的注释,亲测可用! 是基于库函数的程序

#include "tcs3415.h"
#include "stdlib.h"
#include "stm32f10x.h"
#include "sys.h" 
#include "myiic.h"
#include "usart.h"
#include "usmart.h"	 
#include "delay.h"

/*******************************************************************************
 * @brief IIC连续写
 *
 * @param slaveAddress -器件地址
 * @param reg -寄存器地址 
 * @param len - 写入长度.
 * @param buf - 数据区

*******************************************************************************/
void TCS3415_I2C_Write(u8 slaveAddress, u8 reg,u8 len, u8 *buf)
{
	u8 i ;
	IIC_Start();  //数据手册 P12 Figure.20 I2C写 数据
	IIC_Send_Byte((slaveAddress << 1) | 0);	   //发送器件地址写命令
	IIC_Wait_Ack();
	IIC_Send_Byte(reg);//CMD +寄存器地址-->找到相应的寄存器
	IIC_Wait_Ack();	  //等待应答
	for(i = 0; i < len; i++)
	{
		IIC_Send_Byte(buf[i]);   //发送数据  好像也可以这样IC_Send_Byte(*(buf+i));
		IIC_Wait_Ack();
	 }
	 IIC_Stop();	
}

/*******************************************************************************
 * @brief IIC连续读
 *
 * @param slaveAddress -器件地址
 * @param reg -要读取的寄存器地址 
 * @param len - 要读取的长度.
 * @param buf - 读取到的数据存储区
 * @param 返回值 
 *                  
*******************************************************************************/
void TCS3415_I2C_Read(u8 slaveAddress, u8 reg,u8 len,u8 *buf)
{
	
	IIC_Start();   //数据手册 P12 Figure.21 I2C读 数据
	IIC_Send_Byte((slaveAddress << 1) | 0);	   //发送器件地址+写命令
	IIC_Wait_Ack();
	IIC_Send_Byte(reg);//CMD +寄存器地址-->找到相应的寄存器
	IIC_Wait_Ack();    //等待应答 
	IIC_Start();
	IIC_Send_Byte((TCS3415_ADDRESS << 1) | 1);	   //发送器件地址+读命令
	IIC_Wait_Ack();    //等待应答 
	while(len)
	{
		if(len ==1) *buf=IIC_Read_Byte(0); //读数据,发送nACK 
		
		else  *buf = IIC_Read_Byte(1); //读数据,发送ACK
		len--;
		buf++;
	 }			
	IIC_Stop();
 
}
	
/*******************************************************************************
 * @brief IIC写一个字节
 
 * @param reg -寄存器地址 
 * @param data - 数据
*******************************************************************************/
void Tcs3415_WriteByte(u8 reg, u8 data)
{
	IIC_Start();  
	IIC_Send_Byte(TCS3415_ADDRESS<<1 |0);
	IIC_Wait_Ack();
	IIC_Send_Byte(reg);//CMD + addr,写入模式和寄存器地址
	IIC_Wait_Ack();
	IIC_Send_Byte(data);
    IIC_Wait_Ack();
	IIC_Stop();
}
/*******************************************************************************
 * @brief IIC读一个字节
 * @param reg -寄存器地址 
 * @param 返回值 -读到的数据 
 *                 
*******************************************************************************/
u8 Tcs3415_ReadByte(u8 reg)
{
	u8 temp ;		
	IIC_Start();  
	IIC_Send_Byte(TCS3415_ADDRESS<<1 | 0);	 //发送器件地址+写命令		
	IIC_Wait_Ack();
	IIC_Send_Byte(reg);//CMD + addr,写入模式和寄存器地址
	IIC_Wait_Ack();
	IIC_Start();
	IIC_Send_Byte(TCS3415_ADDRESS<<1 | 1);  //发送器件地址+读命令
	IIC_Wait_Ack();
	temp = IIC_Read_Byte(1);
	IIC_Stop();
	return temp;
}

/********************************************************************
*@brief:			Tcs3415_Set_TimingReg
*@description:	设置触发模式或积分时间
*@param: 		u8
*@return: void
********************************************************************/
void Tcs3415_Set_TimingReg(u8 time)
{
	Tcs3415_WriteByte(TCS3415_TIMING,time);// 设置运行模式 ffree模式400ms
}

/********************************************************************
*@brief:			Tcs3415_Set_Gain
*@description:	设置增益
*@param: void
*@return: void
********************************************************************/
void Tcs3415_Set_Gain(u8 gain)
{
	Tcs3415_WriteByte(TCS3415_GAIN,gain); //0x07 ADC增益控制寄存器的地址,//放大倍数为16和1分频
}
/********************************************************************
*@brief:			Tcs3415_Set_EnableADC
*@description:	启动ADC转换
*@param: void
*@return: void
********************************************************************/
void Tcs3415_Set_EnableADC(void)
{
	u8 cmd = TCS3415_CONTROL_ADCon;
	Tcs3415_WriteByte(TCS3415_CONTROL, cmd);//(0x80 ,0x03),对应着control register的ADC使能位和上电(0000 0011)
	//
}

/*******************************************************************************
 * @brief TCS3415失能
 *
 * @return None
*******************************************************************************/
void TCS34725_Disable(void)
{
	
	Tcs3415_WriteByte(TCS3415_CONTROL,0);
	
}

/********************************************************************
*@brief:			Tcs3415_Init
*@description:	初始化Tcs3415_Init设备
*@param: void
*@return: 		u8 初始化结果 0 成功 1 失败
********************************************************************/
void Tcs3415_Init(void) 
{
		Tcs3415_Set_TimingReg(INTEG_PARAM_TIME_400ms);// 设置运行模式 ffree模式积分时间为400ms  示波器输出1000 0001
		Tcs3415_Set_Gain(GAIN_16|PRESCALER_1); //放大倍数为16和1分频
		Tcs3415_Set_EnableADC(); //启动ADC转换
}

/*******************************************************************************
 * @brief TCS3415获取单个通道数据
 *
 * @return data - 该通道的转换值
*******************************************************************************/
uint16_t TCS3415_GetChannelData(u8 reg)
{
	u8 buf[2];
	u16 data;
	TCS3415_I2C_Read(TCS3415_ADDRESS,reg,2,buf);
	data = ((u16)buf[1] << 8) | buf[0];   
	return data;
}
/*******************************************************************************
 * @brief TCS34725获取各个通道数据
 *
 * @return 
*******************************************************************************/
void TCS3415_GetRawData(void)
{
	u16 r,g,b,c;
	
		r = TCS3415_GetChannelData(TCS3415_RDATAL);  
		g = TCS3415_GetChannelData(TCS3415_GDATAL);
		b = TCS3415_GetChannelData(TCS3415_BDATAL);
		c = TCS3415_GetChannelData(TCS3415_CDATAL);
		//printf("\r\n Rdata = %d\n",r);
   printf("R=%d G=%d B=%d C=%d\r\n",r,g,b,c);
		delay_ms(50);
}

2.TCS3415配置程序 .h

#include "stm32f10x.h"
#ifndef TCS3415_H_
#define TCS3415_H_

#define TCS3415_ADDRESS 0x49  //the I2C address for the color sensor 
#define TCS3415_COMMAND 0x80
#define TCS3415_COMMAND_word  0xA0  //数据手册 P14 Tab3. 因为开启的是SMB read/write word 块功能 1010 0000

//ADDRESS PART1  寄存器组的地址·基地址+偏移地址  =   0x80+偏移地址
#define TCS3415_CONTROL 0x80    				//基本功能控制
#define TCS3415_TIMING 0x81  						//积分时间
#define TCS3415_INTERRUPT 0x82					//中断控制·
#define TCS3415_INTSOURCE 0x83					//中断源
#define TCS3415_ID  0x84								//0x04=TCS3415 产品编号/版本号
#define TCS3415_GAIN 0x87								//ADC增益控制
#define TCS3415_BLOCK 0x8F						//SMBus的模块读操作(通过17H10H)
#define TCS3415_GDATAL 0x90							//ADC绿色通道低字节
#define TCS3415_GDATAH 0x91							//绿色 高
#define TCS3415_RDATAL 0x92							//红色 低
#define TCS3415_RDATAH 0x93							//红色 高
#define TCS3415_BDATAL 0x94							//蓝色 低
#define TCS3415_BDATAH 0x95							//蓝色 高
#define TCS3415_CDATAL 0x96							//清晰 低 0001 0110
#define TCS3415_CDATAH 0x97						  //清晰 高 0001 0111


#define TCS3415_CONTROL_ADCon 0x03// TCS3415_CONTROL的偏移值  ->  ADC使能 and power on 
#define TCS3415_CONTROL_POWER_ON 0x01// TCS3415_CONTROL的偏移值  ->  ADC不使能 但 power on 

#define ADC_VALID 0x10  //ADC有效。此只读字段表示ADC通道已完成一个积分周期。

//Timing Register
#define INTEG_MODE_FREE 0x00	//积分器自由运行,积分时间为12ms
#define INTEG_PARAM_TIME_100ms 0x01   //积分器自由运行,积分时间为100ms
#define INTEG_PARAM_TIME_400ms 0x02   //积分器自由运行,积分时间为400ms

#define INTEG_MODE_MANUAL 0x10	//通过EN手动控制积分 启动/停止
#define INTEG_MODE_SYN_SINGLE 0x20	//在由引脚同步启动2.4微秒后指定一个确切的内部定时同步整合周期
#define INTEG_MODE_SYN_MULTI 0x30	//在SYNC上集成指定数量的脉冲 最小同步宽度是50μs,SYNC in 必须至少3.6us /*SYNC in pulse count  1*/

//#define INTEG_PARAM_PULSE_COUNT1 0x30		
#define INTEG_PARAM_PULSE_COUNT2 0x31		/* 2*/
#define INTEG_PARAM_PULSE_COUNT4 0x32		/* 4 */
#define INTEG_PARAM_PULSE_COUNT8 0x33		/* 8 */
#define INTEG_PARAM_PULSE_COUNT16 0x34		/* 16*/
#define INTEG_PARAM_PULSE_COUNT32 0x35		/* 32 */
#define INTEG_PARAM_PULSE_COUNT64 0x36		/* 64 */
#define INTEG_PARAM_PULSE_COUNT128 0x37		/* 32 */
#define INTEG_PARAM_PULSE_COUNT256 0x38		/* 64 */


//Interrupt Control Register 
//#define INTR_STOP 40
#define INTR_DISABLE 0x00				  /* 禁用中断输出 */
#define INTR_LEVEL 0x10					  /* 电平中断 */
#define INTR_PERSIST_EVERY 0x00   /* 每个ADC周期产生中断 */  //中断的持久性,控制中断主处理器的速度
#define INTR_PERSIST_SINGLE 0x01	/*  阈值范围以外的值*/

//Interrupt Souce Register  只能选择4个ADC中断通道的一个来产生中断
#define INT_SOURCE_GREEN 0x00		/* Green channel */
#define INT_SOURCE_RED 0x01			/* Red channel  */
#define INT_SOURCE_BLUE 0x10		/* Blue channel  */
#define INT_SOURCE_CLEAR 0x03		/* Clear channel  */


//Gain Register   以下的两种可以  | 起来配合使用
//最灵敏的增益设置是:增益设置为11b(64x),预分频设置为000b(1分频)时
// 最不灵敏的部件设置为1x和64分频,如果此时仍是数字饱和度在最敏感的设置,可以降低积分时间。
#define GAIN_0 0x00    /**<  No gain  */
#define GAIN_4 0x10    /**<  4x gain  */
#define GAIN_16 0x20   /**<  16x gain */
#define GANI_64 0x30   /**<  64x gain */
#define PRESCALER_1 0x00     /**<  Divide by 1  */
#define PRESCALER_2 0x01     /**<  Divide by 2 */
#define PRESCALER_4 0x02		 /**<  Divide by 4  */
#define PRESCALER_8 0x03		 /**<  Divide by 8  */
#define PRESCALER_16 0x04		 /**<  Divide by 16  */
#define PRESCALER_32 0x05		 /**<  Divide by 32  */
#define PRESCALER_64 0x06		 /**<  Divide by 64  */


void TCS3415_I2C_Write(u8 slaveAddress, u8 reg,u8 len, u8 *buf);
void TCS3415_I2C_Read(u8 slaveAddress, u8 reg,u8 len,u8 *buf);
void Tcs3415_WriteByte(u8 reg, u8 data);
u8 Tcs3415_ReadByte(u8 reg);

void Tcs3415_Init(void); 
void Tcs3415_Set_TimingReg(u8 time);

void Tcs3415_Set_Gain(u8 gain);
void Tcs3415_Set_EnableADC(void);
void TCS34725_Disable(void);

uint16_t TCS3415_GetChannelData(u8 reg);
void TCS3415_GetRawData(void);

#endif

3.其它程序

            该程序是在STM32F103的IIC例程上修改的,加入了TCS3415的配置程序,其它的系统配置不需要改变。只需要在主函数中初始化传感器(Tcs3415_Init();)和调用TCS3415_GetRawData函数即可。

六、程序验证

1.示波器调试观察程序

           经过大佬的指点,小菜鸟才知道可以通过示波器来调试程序,观察程序的IIC通信是否存在问题!!!(🤩小菜鸟发现了新大陆,正点原子的手把手教你学STM32视频白看了/(ㄒoㄒ)/~~)不过后面发现Keil软件自带的Debug调试功能中的逻辑分析器更好用,直接在电脑上就可以调试程序。

比如下面,蓝色为SCL的逻辑电平,黄色为SDA的逻辑电平。图中为IIC_Send_Byte((0x49 << 1) | 0)程序中的发送器件地址+写命令。可以看到IIC可以正常通信,每个配置TCS3415的指令都可以观察到。如果对应IIC协议中的设置,可以排除是IIC通信问题。

2.注意事项

  • 较低光强的光可适当增加积分时间,较高的光强可适当增加积分时间。
  • 个人测试,如果直接使用电筒照射(光通量过大),输出值为65535(超量程),此时可以降低积分时间和增益倍数,如果还是超量程,那个就说明光太强了。资料手册中也说了可应用于高清电视,平板电脑、笔记本电脑、显示器等场景。

七、写在后面的话

  •  新手上路,记录以下自己的理解,通过这个应用,感觉自己是真正的向单片机迈入了一个脚!!!学习单片机真的是实操最重要┭┮﹏┭┮,以前学习的时候没有项目,就干看视频,看了就困,看完就忘/(ㄒoㄒ)/~~
  • 希望能够帮助到和我一样对单片机刚入门的人,如果有大佬看到了程序有错误,感谢指点🙏🙏🙏再接再厉,继续前行!!!
  • 其实程序中还是有一个不懂的地方,TCS3415_GetChannelData函数中获取颜色通道的值,输入的是低8位寄存器的地址,通过左移8位就可以读取到高8位的值。还是说,其实我这里并不是获取了高8位寄存器的值,而只是把低8位的值移到高8位的位置上,再加上后续来的低8位的值,只是两个低8位的拼接,而并不是读取的高8位寄存器的值。/(ㄒoㄒ)/~~。等我后续理解了再来补充吧😭😭😭,如果有大佬能够指点,感激不尽。
  • 5
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 30
    评论
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值