stm32单片机通过串口通信实现将GY_33颜色传感器的接收到的颜色和RGB值上传给上位机

目录

 硬件连接

实现串口1和串口3相互通信

GY_33的概述

对GY_33的数据分析

GY_33数据处理

GY_33的配套软件使用

代码


主要思路:注:这里我使用串口1和串口3,可以更改串口

                   1.上位机通过串口1发送数据给stm32单片机

                   2.stm32通过串口3发送数据给GY_33

                   3.GY_33通过串口3发送数据给stm32单片机

                   4.stm32处理数据完后通过串口1发送数据给上位

所需:stm32单片机(这里使用的是正点原子stm32mini板),GY_33传感器,GY_33配套软件,串口助手,USB转TTL

以下为GY_33的配套资料以及软件的链接

GY-33_免费高速下载|百度网盘-分享无限制


 硬件连接

这里使用的是串口1,串口3.

根据mini板的芯片图

                                          串口1的引脚为PA10(RX),PA9(TX)

                      

                                         串口3的引脚为PB10(TX),PB11(RX)

GY_33硬件图,DR(RX) ,CT(TX)                              

 所以根据输出端->接收端,接收端->输出端:

GY_33的连线:

1.VCC->3V3

2.GND->GND

3.DR->PB10

4.CT->PB11

stm32单片机连接(本来有接线帽接好了就不用操作这步):

1.PA10->TXD

2.PA9->RXD

上位机:插好usb

实现串口1和串口3相互通信

思路:串口1接收到数据后,进入串口1中断,将串口1接收到的数据保存,通过串口3发送给

GY_33。(串口3同理)

代码如下

void USART1_IRQHandler ()//串口1中断
{
	
	if(USART_GetITStatus(USART1,USART_IT_RXNE))//如果接收到数据
	{   u8 data;
		data=USART_ReceiveData(USART1);//赋值	
		USART_SendData(USART3,data);//发给传感器
	}
}

GY_33的概述

GY-33是一款低成本颜色识别传感器模块。 工作电压3-5v,功耗小,体积小,安装方便。 其工作原理是,照明LED发光,照射到被测 物体后,返回光经过滤镜检测RGB的比例值 ,根据RGB的比例值识别出颜色。 此模块,有两种方式读取数据,即 串口UART(TTL电平)或者IIC(2线)。 串口的波特率有9600bps与115200bps,可配置, 有连续,询问输出两种方式,可掉电保存设置。 有简单的7种颜色识别,不需要计算RGB值。 可适应不同的工作环境,与单片机及电脑连接。 模块另外可以设置单独传感器芯片工作模式, 作为简单传感器模块,MCU不参与数据处理工作。 

简单来说,他可以识别不同颜色反馈不同的数据回来,让我们通过反馈数据来识别颜色,可应用于智能车等识别颜色的模块。

对GY_33的数据分析

1.GY_33的输出格式:

 分析:1.Byte0和Byte1中的0x5A 0X5A代表一段新数据发送开始的标志

             2.Byte2中的数值代表发送数据的类型(下面会细说)

             3.Byte3中代表要发送几个数据(不包括校验和),图中Byte3=6,所以下面Byte4-Byte9为它所要发送的有效数据,Byte10为校验和(就是将前面所有数据加起来(包括帧头),仅仅保留第八位的和),来检验它发送的数据有无错误(可以减少错误,但不能避免,不精确)

2.GY_33数据分析

由于我们采用的是串口模式,它只会发送0x15,0x25,0x45这三种数据

 对三种数据举例分析

1.Byte2=0x15(RGBC)

例如发送下面这串代码(16进制)

<5A-5A-15-08-01-78-01-92-00-4C-05-05-33 > 

5A 5A 为缀头     0x15为数据类型,表示发送的是原始RGBC值    08为发送八个数据

 我们可以通过这串数据算出,R,G,B,C的值

2.Byte2=0x25(亮度,色温,颜色)

例如发送下面这串代码(16进制)

< 5A-5A-25-06-02-CC-0C-5D-00-02-18 > 

5A 5A 为缀头     0x25为数据类型,表示发送的是亮度,色温,颜色   06为发6个数据

 亮度和色温的计算很简单,进行一个位运算,而颜色的值,将其转化为2进制,哪一位为1

则亮,例如color等于4,转化为2进制为100,那么bit2为1,所以为粉色。

3.Byte=0x45(处理好的RGB值)

 这一段数据就是将Byte=0x15这串数据,经过MCU计算好的R,G,B值

 很容易可以看到,5A 5A为帧头,0x45代表数据类型,03代表有三个有效数据

第一位为R:FF   第二位G:FF    第三位B:4C     第四位为校验和

GY_33数据处理

由于传感器会发出三种类型的数据,并且每一类型的数据所含数字个数不同,需要我们选择一种数据,进行处理,返回RGB值,并且判断颜色。

这里选择Byte=0x45的数据,也就是处理好的RGB值,其他类型数据方法接收类似。

<5A-5A-15-08-01-78-01-92-00-4C-05-05-33 > (Byte2=0x15)

< 5A-5A-25-06-02-CC-0C-5D-00-02-18 > (Byte2=0x25)

<5A-5A-45-03-FF-FF-4C-46> (Byte2=0x45)

注:虽然三种数据长度各不相同,但同一类型数据,长度相同

容易看到3中数据类型不同,长度也不同,但是传感器会将他们一起发送出来,例如

5A 5A 15 08 01 78 01 92 00 4C 05 05 33  5A 5A 25 06 02 CC  0C 5D 00 02 18 5A 5A 45 03 FF F 4C 46 5A 5A 15 08 01 78 01 92 00 4C 05 05 33  5A 5A 25 06 02 CC  0C 5D 00 02 18 5A 5A 45 03 FF F 4C 46(加深颜色为了看到清楚)

在如此大的数据中,我们需要提取 5A 5A 45 03 FF F 4C 46这数据只要找到这串数据的不同之处即可,不难发现这串数据开头格式为5A 5A 45,也就是说我们接受到5A 5A 45 这几个连起来的数据就开始接受我们要的数据(也可以用5A 5A 45 03(更加精确))

代码实现如下

if(USART_GetITStatus(USART3,USART_IT_RXNE))//如果接收到数据,进入串口3中断
	{
		int data;//
		u8 result;
		static int i=0,temp1,temp2,staus=0,j=0,staus2=0,temp3=1,temp4=2,temp5=3;
		data=USART_ReceiveData(USART3);//赋值	
		if(data==0x5A){staus2=1;}//如果接收到帧头开始准备接受数据
		if(staus2)//测试是否是我们所需的数据
		{
			j++;
			if(j==1){temp3=data;}//将第一个帧头保存下来
			if(j==2){temp4=data;}//第二个帧头保存下来
			if(j==3)
				{
					temp5=data;//保存数据类型
                    j=0;//归0
					if(temp5==0x45&&temp4==0x5A&&temp3==0X5A)//符合我们所需类型
					{
						staus2=0;//关闭测试
						staus=1;//数据类型正确,开启接受数据
					}
		        }
		 }
		if (staus)//接收数据
		{	
			  i++;
			  if(i==3){ temp1 = data;}//存放R
			  if(i==4){ temp2 = data;}//存放G
			  if(i==5)
				   {   delay_us(20);/*延时避免数据传输过快导致错误,单个中断时可用,多中断不行,该中断完成时间太久,未完成任务就被其他中断打断*/
					   //判断颜色(通过实际测试得)
					  if(temp1>=255&&temp2>=255&&data>=255)
					  {
						  printf("R:%d   G:%d   B:%d   白色\r\n",temp1,temp2,data);
					  }
                     if(temp1<=40&&temp2<=40&&data<=40)
					  {
						  printf("R:%d   G:%d   B:%d   黑色\r\n",temp1,temp2,data);
					  }
					  else
					  {	  
	                     if(temp2>temp1&&temp2>data)
						  {
							  printf("R:%d   G:%d   B:%d   绿色\r\n",temp1,temp2,data);
						  }
	                     if(temp1>temp2&&temp1>data)
						  {
							  printf("R:%d   G:%d   B:%d   红色\r\n",temp1,temp2,data);
						  }
					       if(data>temp1&&data>temp2)
						  {
							  printf("R:%d   G:%d   B:%d   蓝色\r\n",temp1,temp2,data);
						  }					  
					  }    					  					
					  i = 0;//发送完毕,接受新数据
					  staus = 0;//关闭数据接受状态
				  }
		}					
		
	}

GY_33的配套软件使用

以下指令为本次所需

 

 该指令的实现可通过USB转TTL直接连传感器,通过上图配套软件直接配置GY_33.

注意,要调白平衡,调试方法,将传感器对准白色物体,再发送白平衡指令,不然传感器数据不准,因为没有参照物。

指令的发送可通过以下软件实现。

1.串口助手(注:要选择16进制发送)

 2.COLOR

代码

 根据协议来初始化串口参数,以下为完全代码

#include "stm32f10x.h"
#include "stdio.h"
#include "delay.h"
void USART1_Init(void)//初始化串口1
{
	GPIO_InitTypeDef GPIO_InitStructure;//定义GPIO结构体
	USART_InitTypeDef USART_InitStructure;//定义串口结构体
	NVIC_InitTypeDef NVIC_InitStructure;//定义优先级结构体
	//使能时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能GPIOA
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 ,ENABLE);//使能串口1
	//发送TX
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//PA9
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
	GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化GPIOA
	//接收RX
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//PA10
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;//浮空输入
	GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化GPIOA
	//串口
	USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//不使用硬件
	USART_InitStructure.USART_BaudRate=9600;//波特率
	USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;//模式
	USART_InitStructure.USART_StopBits=USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity=USART_Parity_No;//奇偶校验关闭
	USART_InitStructure.USART_WordLength=USART_WordLength_8b;//字长
	USART_Init(USART1,&USART_InitStructure);//初始化串口1
	//优先级配置
	NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;//串口1中断
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能串口1中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;//响应优先级
	NVIC_Init(&NVIC_InitStructure);//初始化优先级
	//使能
	USART_Cmd(USART1,ENABLE);//使能串口
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//使能接收缓存非空寄存器
}
void USART3_Init(void)//初始化串口3
{
	GPIO_InitTypeDef GPIO_InitStructure;//定义GPIO结构体
	USART_InitTypeDef USART_InitStructure;//定义串口结构体
	NVIC_InitTypeDef NVIC_InitStructure;//定义优先级结构体
	//使能时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能GPIOB
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3 ,ENABLE);//使能串口3
	//发送TX
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//PB10
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
	GPIO_Init(GPIOB,&GPIO_InitStructure);//初始化GPIOB
	//接收RX
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11;//PB11
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;//浮空输入
	GPIO_Init(GPIOB,&GPIO_InitStructure);//初始化GPIOB
	//串口
	USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//不使用硬件
	USART_InitStructure.USART_BaudRate=9600;//波特率
	USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;//模式
	USART_InitStructure.USART_StopBits=USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity=USART_Parity_No;//奇偶校验关闭
	USART_InitStructure.USART_WordLength=USART_WordLength_8b;//字长
	USART_Init(USART3,&USART_InitStructure);//初始化串口3
	//优先级配置
	NVIC_InitStructure.NVIC_IRQChannel=USART3_IRQn;//串口3中断
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能串口3中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;//响应优先级
	NVIC_Init(&NVIC_InitStructure);//初始化优先级
	//使能
	USART_Cmd(USART3,ENABLE);//使能串口3
	USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);//使能接收缓存非空寄存器
}
void USART1_IRQHandler ()//串口1中断
{
	
	if(USART_GetITStatus(USART1,USART_IT_RXNE))//如果接收到数据
	{   u8 data;
		data=USART_ReceiveData(USART1);//赋值	
		USART_SendData(USART3,data);//发给传感器
	}
}
void USART3_IRQHandler()//串口3中断
{

	if(USART_GetITStatus(USART3,USART_IT_RXNE))//如果接收到数据
	{
		int data;
		u8 result;
		static int i=0,temp1,temp2,staus=0,j=0,staus2=0,temp3=1,temp4=2,temp5=3;
		data=USART_ReceiveData(USART3);//赋值	
		if(data==0x5A){staus2=1;}//如果接收到帧头开始准备接受数据
		if(staus2)//测试是否所需数据
		{
			j++;
			if(j==1){temp3=data;}保存第一个数
			if(j==2){temp4=data;}保存第二个数
			if(j==3)
				{
					temp5=data;j=0;
					if(temp5==0x45&&temp4==0x5A&&temp3==0X5A)//如果数据为0X5A 0X5A,0X45
					{
						staus2=0;//关闭测试
						staus=1;//前缀正确,开启接受数据
					}
		        }
		 }
		if (staus)//接收数据
		{	
			  i++;
			  if(i==3){ temp1 = data;}//存放R
			  if(i==4){ temp2 = data;}//存放G
			  if(i==5)
				   {   delay_us(20);//延时避免数据传输过快导致错误
					   //判断颜色
					  if(temp1>=255&&temp2>=255&&data>=255)
					  {
						  printf("R:%d   G:%d   B:%d   白色\r\n",temp1,temp2,data);
					  }
                     if(temp1<=40&&temp2<=40&&data<=40)
					  {
						  printf("R:%d   G:%d   B:%d   黑色\r\n",temp1,temp2,data);
					  }
					  else
					  {	  
	                     if(temp2>temp1&&temp2>data)
						  {
							  printf("R:%d   G:%d   B:%d   绿色\r\n",temp1,temp2,data);
						  }
	                     if(temp1>temp2&&temp1>data)
						  {
							  printf("R:%d   G:%d   B:%d   红色\r\n",temp1,temp2,data);
						  }
					       if(data>temp1&&data>temp2)
						  {
							  printf("R:%d   G:%d   B:%d   蓝色\r\n",temp1,temp2,data);
						  }					  
					  }    					  					
					  i = 0;//发送完毕,接受新数据
					  staus = 0;//关闭数据接受状态
				  }
		}					
		
	}
}
int main()
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	USART1_Init();
	USART3_Init();
	delay_init();
	while(1);        
}
//print所需函数
#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
int handle; 
};  
FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
_sys_exit(int x) 
{ 
x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{      
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
USART1->DR = (u8) ch;      
return ch;
}
#endif

猜你喜欢

转载自blog.csdn.net/A15768533126/article/details/121043023