所需:stm32单片机(这里使用的是正点原子stm32mini板),GY_33传感器,GY_33配套软件,串口助手,USB转TTL
1.GY-33介绍及其接线
GY-33是一款低成本颜色识别传感器模块。工作电压3-5v,功耗小,体积小,安装方便。其工作原理是,照明LED发光,照射到被测物体后,返回光经过滤镜检测RGB的比例值,根据RGB的比例值识别出颜色。此模块,有两种方式读取数据,即串口UART(TTL电平)或者IIC(2线)。串口的波特率有9600bps与115200bps,可配置,有连续,询问输出两种方式,其响应频率为10hz
先来看看GY-33的实物及其接线
我们只需要焊接排针在这四位上,然后用杜邦线把这四位同stm32对应的引脚连接即可,由于我设置GY-33通过串口3同stm32通信 ,根据原理图
DR应该连接PB10,CT应该连接PB11
2.通信原理
首先我们得先了解GY-33是怎么通过stm32和上位机完成通信的(
这一步至关重要,如果连这个过程是怎样进行的都不知道,那就像无头苍蝇,永远完成不了这个功能)--------------
思路是1.
上位机通过串口1发送指令到stm32
2.stm32再通过串口3把指令发到GY-33颜色传感器
3.GY-33接受到指令后会自动输出其测量的颜色对应的数据(第四部分会讲数据类型及数据处理)回串口3
4.串口3接受到数据后中断,我们可以在串口3中断函数里对数据进行处理,从而提取出RGB值并打印出对应的颜色和RGB值
(文字看着腻歪,直接看下图通信思路及实现方法)
3.代码
先看看串口的通信协议
程序应该按通信协议设置
话不多说,直接
上代码(看串口3中断函数代码前可以先看第四部分)
#include "stm32f10x.h"#include "stdio.h"//printf函数void USART1_Init(void){ 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;//根据GY-33响应频率10hz 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;//根据GY-33响应频率10hz 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);//使能串口1 USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//使能接收缓存非空寄存器}void USART3_Init(void){ 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;//根据GY-33响应频率10hz 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);//串口3发送指令给传感器 }}void USART3_IRQHandler(){ if(USART_GetITStatus(USART3,USART_IT_RXNE))//如果接收到数据 { u8 data; static int result1,result2,result3;//静态保存 static int i=0,staus=0,j=0,staus2=0,temp1=0,temp2=0,temp3=0; data=USART_ReceiveData(USART3);//赋值 if(data==0x5A) staus2=1; if(staus2) { j++; if(j==1)temp1=data; if(j==2)temp2=data; if(j==3) { temp3=data;j=0; if(temp3==0x45&&temp2==0x5A&&temp1==0X5A) { staus2=0; staus=1; } } }//如果连续收到0x5a,0x5a,0x45,staus置1,进入下面数据处理 if (staus)//将0x45看成第一位数据,保存第三,四,五位数据,分别对应红,绿,蓝的RGB值 { i++; if(i==3) result1=USART_ReceiveData(USART3); if(i==4) result2=USART_ReceiveData(USART3); if(i==5) { result3=USART_ReceiveData(USART3); if(result1==255&&result2==255&&result3==255)//三者RGB值都为255即打印白色 printf("R=%d G=%d B=%d 白色rn",result1,result2,result3); if(result1<50&&result2<50&&result3<50)//三者RGB值都比较小即为黑色 printf("R=%d G=%d B=%d 黑色rn",result1,result2,result3); else { if(result1>result2&&result1>result3)//不符合三者RGB都大或都小的情况下,红色RGB值最大即打印红色 printf("R=%d G=%d B=%d 红色rn",result1,result2,result3); if(result2>result1&&result2>result3)//不符合三者RGB都大或都小的情况下,绿色RGB值最大即打印绿色 printf("R=%d G=%d B=%d 绿色rn",result1,result2,result3); if(result3>result2&&result1
SR&0X40)==0);//循环发送,直到发送完毕 USART1->DR = (u8) ch; return ch;}#endif
4.GY-33发送出来的数据及如何处理数据
一共有三种不同的数据类型(0x15,0x25,0x45),每种数据都是以俩个0x5a开头(帧头)
GY-33发给串口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 465A 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(不同数据类型用不同颜色)
并且每一种类型的数据所含数字的个数不同(
每串数据的第四位数表示这串数据的有效数据个数,同种数据类型数字个数相同),我们需要选择一种数据类型来处理,这里我们就选择最简单的第三种数据进行处理吧
处理方法:首先得判断是第三种数据(依次接收到的数据是0x5a,0x5a,0x45)//若再判断下一位为0x03会更好,然后再把第三种数据的第五,六,七位取出来并打印(具体处理方法查看上面的代码) 其他俩种数据类型根据上面表格也可处理,处理方法与第三种数据类型类似
5.软件使用
在使用GY-33颜色传感器前,得先对其进行
颜色白校准(使用COLOR,USA转ttl)
u***转ttl直接连传感器,通过COLOR软件直接配置GY-33
白校准后打开xcom(注:16进制发送勾选上,波特率停止位等配置按如下)
打开串口就可以接收到打印的数据了
完成此次任务,我发现对信息的筛选及整合能力很关键,最重要的应该是先搞明白原理。
|