基于STM32F407ZGT6和TCS3200的颜色采集,使用MATLAB制作上位机,利用串口进行通信(标准库)

目录

一、引言

1、设计要求

2、软硬件的使用

二、Keil代码部分

1、定时器

2、TCS3200设置

3、串口设置

三、上位机部分

四、参考资料


一、引言

暑期实践的课题,题目和标题是一样的。

使用的是普中·天马F407板子,上位机使用MATLAB制作,都是在网上找的资料。

工程文件在主页里面有,不需要积分,可以直接下载。

工程文件在主页里面有,不需要积分,可以直接下载。

工程文件在主页里面有,不需要积分,可以直接下载。

1、设计要求

设计一套固体颜色自动检测以及显示的系统;

颜色算法可靠、识别速度不低于1s;

将颜色检测结果在上位机分类显示。

2、软硬件的使用

使用F407作为单片机,MATLAB作为上位机制作软件。

软件:

keil5 MDK和MATLAB 2023a.

硬件:

TCS3200颜色传感器,STM32407ZGT6,TFT3.5-ILI9488彩屏

二、Keil代码部分

1、定时器

使用的是定时器5,定时器用来记录每个滤波器发送过来的脉冲数,采用向上计数的方式。

//**********************************************//定时器(用来计数每个滤波器开启时发过来的脉冲数)
void TIM5_Init()                                 
{
	GPIO_InitTypeDef GPIO_InitStructure;//设置GPIO为TIM的时钟输入引脚
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//设置定时器参数
	NVIC_InitTypeDef NVIC_InitStructure;//设置中断优先级
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//打开PB端口时钟    
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;               
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;//gpio模式设置为复用模式
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;   
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//设置为推挽
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//不上下拉
	GPIO_Init(GPIOA,&GPIO_InitStructure);                  
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM5);//设置GPIO复用为中断定时器输入
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);//使能TIM时钟
    TIM_TimeBaseStructure.TIM_Period = 30000;//自动重装载值
    TIM_TimeBaseStructure.TIM_Prescaler =0; //定时器分频
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
    TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
    TIM_ClearITPendingBit(TIM5,TIM_IT_Update);//清除溢出中断标志位
    TIM_ITConfig(TIM5,TIM_IT_Update,ENABLE );//使能定时器更新中断
	 
TIM_TIxExternalClockConfig(TIM5,TIM_TIxExternalCLK1Source_TI1,TIM_ICPolarity_Falling,15);
  TIM_SetCounter(TIM5,0);//计数器清零
  TIM_Cmd(TIM5, ENABLE);//使能TIMx外设
  NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;  
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);   				
}

2、TCS3200设置

通过对引脚输出不同的高低电平来达到开启不同的滤波器,滤波器开启的时间用延时来确定。

先开启不同的滤波器,通过控制Pin_2、Pin_3引脚的高低电平来控制,然后使用定时器来记录发送过来的方波数,检测200ms,后将定时器内数据存储到数组中,重置定时器。

//*************************************//TCS3200滤波过程(检测)开启不同的滤波器的过程
void TIM5_CAP(void)                             
{
	GPIO_ResetBits(GPIOA,s2_PIN);
	GPIO_ResetBits(GPIOA,s3_PIN);      //红色滤波
	TIM_SetCounter(TIM5,0);
	delay_ms(200);		
	count=TIM_GetCounter(TIM5); 
  cnt[0] = count;  		
  TIM_SetCounter(TIM5,0);
	
	GPIO_SetBits(GPIOA,s2_PIN);
	GPIO_SetBits(GPIOA,s3_PIN);       //绿色滤波
	TIM_SetCounter(TIM5,0);
	delay_ms(200);
	count=TIM_GetCounter(TIM5); 
	cnt[1] = count; 
  TIM_SetCounter(TIM5,0);	
	
	GPIO_ResetBits(GPIOA,s2_PIN);
	GPIO_SetBits(GPIOA,s3_PIN);        //蓝色滤波
	TIM_SetCounter(TIM5,0);
  delay_ms(200);	 
  count=TIM_GetCounter(TIM5);					
	cnt[2] = count; 		
  TIM_SetCounter(TIM5,0);			
											
}

3、串口设置

通过串口输出检测到的数据,屏幕上显示RGB的值,同时串口接收上位机传输来的数据,串口先输入数字2,开启白平衡,输入数字1,为开启颜色检测。

白平衡和检测过后,会通过串口输出有三个变量的数组。R,G,B.

//***************************//串口1中断服务程序;利用串口收发数据,在串口处输入2,为白平衡,输入1,为开始检测

void USART1_IRQHandler(void)                	
{
	unsigned char Res = 0;
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
	{
		Res = USART_ReceiveData(USART1);	        //读取接收到的数据

//**********************************************燕颜色检测过程
		
   if (Res=='1')
    {
			while(1)
			{
				TIM5_CAP();//开启滤波
				LCD_Clear(WHITE);//刷新屏幕
				LCD_ShowFontHZ(80,10,"颜色检测");
				LCD_ShowString(10,40,tftlcd_data.width,tftlcd_data.height,24,"R:");
				LCD_ShowString(10,70,tftlcd_data.width,tftlcd_data.height,24,"G:");	
				LCD_ShowString(10,100,tftlcd_data.width,tftlcd_data.height,24,"B:");
				LCD_ShowNum(120, 40,(int)(cnt[0]*RGB[0]),3,24);
				LCD_ShowNum(120, 70,(int)(cnt[1]*RGB[1]),3,24);
				LCD_ShowNum(120, 100,(int)(cnt[2]*RGB[2]),3,24);
				
				R = (int)(cnt[0]*RGB[0]);
			  G = (int)(cnt[1]*RGB[1]);
			  B = (int)(cnt[2]*RGB[2]);
			      if(R>255)
							R=255;
						if(G>255)
							G=255;
						if(B>255)
							B=255;
			
				printf("%d,%d,%d\r\n",R,G,B);

			}
		}
	//*************************************************//白平衡
		if (Res=='2')
		{
			TIM5_CAP();//开启滤波
			//通过白平衡测试,计算得到白色物体RGB值255与1s内三色光脉冲数的RGB比例因子 
			RGB[0] = 255.0/ cnt[0] ;   //红色光比例因子    
			RGB[1] = 255.0/ cnt[1] ;   //绿色光比例因子
			RGB[2] = 255.0/ cnt[2] ;   //蓝色光比例因子
				
			LCD_Clear(WHITE);//屏幕刷新
			LCD_ShowFontHZ(80,10,"颜色检测");
			LCD_ShowString(10,40,tftlcd_data.width,tftlcd_data.height,24,"R:");
			LCD_ShowString(10,70,tftlcd_data.width,tftlcd_data.height,24,"G:");	
			LCD_ShowString(10,100,tftlcd_data.width,tftlcd_data.height,24,"B:");
			LCD_ShowNum(100, 40, RGB[0],3,24);  
			LCD_ShowNum(100, 70,RGB[1],3,24);
			LCD_ShowNum(100, 100,RGB[2],3,24); 
      LCD_ShowString(80,160,tftlcd_data.width,tftlcd_data.height,24,"White Blance");//白平衡结束

			R = (int)(cnt[0]*RGB[0]);
			G = (int)(cnt[1]*RGB[1]);
			B = (int)(cnt[2]*RGB[2]);
						if(R>255)
							R=255;
						if(G>255)
							G=255;
						if(B>255)
							B=255;
			printf("%.2f,%.2f,%.2f\r\n",RGB[0],RGB[1],RGB[2]);

		}	
			
	}		
}

三、上位机部分

上位机采用MATLAB App Design功能进行设计,主要实现接收单片机通过串口传输过来的数据,和向单片机通过串口发送指令。在运行上位机之前要将串口插上,不然会报错。

使用的是MATLAB 2023a

上位机面板:

上位机在编辑过程中主要使用各个部分的回调函数。

首先点击App,选择设计App,选择空白面板即可。

左侧选择按钮,放置在面板上

右侧更改按钮内容:

 右键单击选择回调

搜索串口的回调部分内容:

  % Code that executes after component creation
        function startupFcn(app)
            [app.COMS app.port] = get_com_ports();
            app.DropDown.Items=app.COMS;
            app.port_use=app.port(1);
            app.s=serial(app.port_use,'BaudRate',115200,'Terminator','LF');
        end

其中的get_com_ports()是用.m文件编写的串口搜索程序,建在同一个文件夹即可。我们在App中直接调用就可以获取到串口号。

.m内容:

function [COMS port] = get_com_ports()%获取串口号函数
command = 'wmic path win32_pnpentity get caption /format:list | find "COM"';
[status, cmdout] = system (command);
cmdout = strread(cmdout,'%s','delimiter','='); %按分隔符拆分字符串数组
if numel(cmdout)>0
    j=1;
    for i = 1:numel(cmdout)  %numel 返回元素个数
        if strcmp(cmdout{i}(1:7),'Caption')
            COMS{j} = cmdout{i+1};
            j=j+1;
        end
    end
    COMS_split=cell2mat(COMS);
    COMS_split=split(COMS_split,'(');%通过左括号将字符串分割
    j=1;
    for i = 1:numel(COMS_split)  %numel 返回元素个数
        if strcmp(COMS_split{i}(1:3),'COM')
            port_temp{j} = COMS_split{i};
            j=j+1;
        end
    end
    port_temp=split(port_temp,')');%通过右括号将字符串分割
    j=1;
    for i = 1:(numel(port_temp)-1)  %numel 返回元素个数
        if strcmp(port_temp{i}(1:3),'COM')
            port{j} = port_temp{i};
            j=j+1;
        end
    end
elseif numel(cmdout)==0
    COMS="没有搜索到串口";
    port="null";
    errordlg('没有搜索到任何可用端口');
end
end 

串口选择是左侧下拉框器件。选择回调,在回调中输入检测电脑串口号的程序,让其能选择使用那个串口。

        % Value changed function: DropDown
        function DropDownValueChanged(app, event)
            value = app.DropDown.Value;
            for i=1:length(app.DropDown.Items)    %遍历
                if strcmp(value,app.DropDown.Items{i})
                     app.port_use=app.port(1);%获得端口
                     app.s=serial(app.port_use,'BaudRate',115200,'Terminator','LF');
                end
            end
        end

 打开串口按键,和前面的搜索串口按键一样设置,只是回调中内容不同。我这里的打开串口,并没有真正的打开,只是按下之后有一次反馈。如果在这里写入打开串口的程序,会出现,打开串口之后,LCD屏幕复位。真正的打开串口程序在后面会写到。

    % Button pushed function: Button_2
        function Button_2Pushed(app, event)

            if app.lamp_flag==1%判断是否打开
                    app.Lamp.Color='g';
                    app.Button_2.Text="关闭串口";
                    app.lamp_flag=0;
                
            else       
                    app.Lamp.Color='r';
                    app.Button_2.Text="打开串口";
                    app.lamp_flag=1;
            end
        end

输出结果按键也是在左侧选择按钮即可,这里点击后才是打开串口,进行一次数据传输。

serial()这个函数就是打开串口的,后面是设置工作方式,波特率等。

打开一次后要直接关闭他,fclose()。否则下次使用串口,会提示串口被占用。

fgetl()是提取传输过来的数据,用split()分割。三个数据赋值,后进行颜色识别。

        % Button pushed function: Button_4
        function Button_4Pushed(app, event)

            if app.lamp_flag==0;
                app.s=serial('com5');
                set(app.s,'BaudRate', 115200,'DataBits',8,'Parity','none');
                app.s.DataTerminalReady='off';
                fclose(instrfind);
                fopen(app.s);
                a=fgetl(app.s);
                fclose(app.s);
                a=a(1:length(a)-1)
                a=split(a,',')
                R=a(1,1)
                G=a(2,1)
                B=a(3,1)
                app.Label_2.Text=R;
                app.Label_3.Text=G;
                app.Label_4.Text=B;

白平衡和开始检测也是左侧按钮,选择回调,点击后,先将以前开启的串口关闭,后再次开启串口使用fprintf()将数据发送到串口,单片机接收数据,执行操作

   % Button pushed function: Button_5
        function Button_5Pushed(app, event)
            if app.lamp_flag==0;
                app.s=serial('com5');
                set(app.s,'BaudRate', 115200,'DataBits',8,'Parity','none');
                app.s.DataTerminalReady='off';
                fclose(instrfind);
                fopen(app.s);
                num=['2']
                fprintf(app.s,num);%将数据发送至串口
                value=app.s;
                disp(value)
                fclose(app.s);
            end
        end

        % Button pushed function: Button_6
        function Button_6Pushed(app, event)
            if app.lamp_flag==0;
                app.s=serial('com5');
                set(app.s,'BaudRate', 115200,'DataBits',8,'Parity','none');
                app.s.DataTerminalReady='off';
                fclose(instrfind);
                fopen(app.s);
                num=['1']
                fprintf(app.s,num);%将数据发送至串口
                value=app.s;
                disp(value)
                fclose(app.s);
            end  
        end
    end

至于R,G,B值的显示,使用到的是左侧的文本,想要更改显示内容,只需要在按钮回调中写入

app.Label_2.Text=R;

app.Label_3.Text=G;

app.Label_4.Text=B;

就可以让RGB的数值显示,

中间区域的图像绘制,使用到的是左侧坐标区,

他的显示也是写在按钮回调中,

set(rectangle(app.UIAxes),'Edgecolor',[0,0,0],'LineWidth',0.8,'Facecolor',yanse);

四、参考资料

1.基于stm32f103的颜色识别,写的很好,有原理什么的,我主要参考的这个博客:https://blog.csdn.net/weixin_50950634/article/details/114645247?

2.上位机的制作主要是参考B站UP主的教程,教的比较好,全部都跟着做就能做好:

Matlab串口通信之获取设备端口号[毕设如此简单之上位机篇(四)]_哔哩哔哩_bilibili

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值