假期学校是实践题目,实现的功能如标题。
使用的普中开发板,有详细的传感器资料,matlab部分主要是依靠网络上的资料。
一、引言
tcs3200传感器的原理网上有很多,主要讲一下思路:
- 单片机设置一个外部触发中断和内部定时器中断;
- 传感器发送方波至单片机,每来一次上升沿,中断回调函数触发一次,计数加一;
- 定时器回调函数每50ms读取一次count值并清零;
- 白平衡;
- matlab读取串口传输的数据,并通过GUI界面显示颜色。
二、cubeMX配置引脚:
PA0–TIM2_CH1
其余都是GPIO_Output
TIM2的通道1做外部触发,上升沿到来触发一次
TIM6做内部定时器,我单片机设置的是72MHz,50ms=(7200*500)/70M
通信串口用的usart1,波特率115200
各引脚的状态配置如上
打开定时器、外部中断、通信接口的中断
RCC设置为外部晶振
sys设置为serial wire,否则后续在keil中可能无法调试
三、keil配置
外加子文件的话记得添加路径
点setting后进入下面的界面,设置成SW,即前面配置时对应的sys中的serial wire
四、代码:
main.c
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* USER CODE BEGIN Includes */
#include "system.h"
#include "SysTick.h"
#include "key.h"
#include "exti.h"
#include "stm32f4xx_it.h"
/* USER CODE END Includes */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
float RGB_Scale[3]; //数组存储3个RGB比例因子
int count = 0; //统计脉冲数
int cnt[3]; //数组存储RGB三种颜色的脉冲值
int flag=0; //滤波器选择模式标志
int white_balance=0;
/* USER CODE END PD */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void filter(int s2,int s3) //滤波器模式选择函数,根据S2和S3的电位来选择红、绿、蓝、三种颜色的滤波器
{
if(s2==0&&s3==0)
{PCout(2)=0;PCout(3)=0;}
if(s2==0&&s3==1)
{PCout(2)=0;PCout(3)=1;}
if(s2==1&&s3==0)
{PCout(2)=1;PCout(3)=0;}
if(s2==1&&s3==1)
{PCout(2)=1;PCout(3)=1;}
}
void TSC_WB(int s2, int s3) //结束上一种颜色识别,开始下一种颜色的识别
{
count = 0; //统计脉冲值清零
flag ++; //输出信号计数标志+1,进行下一个颜色的脉冲统计
filter(s2, s3); //选择滤波器模式
}
/* USER CODE END 0 */
/**
1. @brief The application entry point.
2. @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
u8 key,i=0;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
SysTick_Init(168);
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM6_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim2);
HAL_TIM_Base_Start_IT(&htim6); //使能TIM6
PCout(0)=0;PCout(1)=1; //2%的输出比例因子
PAout(1)=1; //打开白光LED
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
key=KEY_Scan(1);
switch(key)
{
case KEY0_PRESS:white_balance=0;break; //停止检测
case KEY1_PRESS:white_balance=1;break; //白平衡
case KEY2_PRESS:white_balance=2;break; //检测
}
}
/* USER CODE END 3 */
}
/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//50ms一次
{
if(htim->Instance == htim6.Instance){
count = __HAL_TIM_GET_COUNTER(&htim2); //记脉冲数
if(white_balance==1){ //白平衡
switch(flag){
case 0:
TSC_WB(0,0); //让红色光线通过滤波器
break;
case 1:
cnt[0] = count; //存储50ms内的红光通过滤波器时脉冲个数
RGB_Scale[0] = 255.0/ cnt[0]; //红色光比例因子
TSC_WB(1,1); //选择让绿色光线通过滤波器的模式
break;
case 2:
cnt[1] = count; //存储50ms内的绿光通过滤波器时脉冲个数
RGB_Scale[1] = 255.0/ cnt[1] ; //绿色光比例因子
TSC_WB(0,1); //选择让蓝色光线通过滤波器的模式
break;
case 3:
cnt[2] = count; //存储50ms内的蓝光通过滤波器时脉冲个数
RGB_Scale[2] = 255.0/ cnt[2] ; //蓝色光比例因子
TSC_WB(1,0); //选择无滤波器的模式
white_balance=0;
flag=0;
break;}
LED1=!LED1;
TIM2->CNT=0;
if(white_balance==0){
printf("%d ",(int)(cnt[0]*RGB_Scale[0]));
printf("%d ",(int)(cnt[1]*RGB_Scale[1]));
printf("%d \n",(int)(cnt[2]*RGB_Scale[2]));}}
else if(white_balance==2) //检测模式
{
switch(flag){
case 0:
TSC_WB(0, 0); //选择让红色光线通过滤波器的模式
break;
case 1:
cnt[0] = count; //存储50ms内的红光通过滤波器时,TCS3200输出的脉冲个数
int R=cnt[0]*RGB_Scale[0];
if(R>255) R=255;
TSC_WB(1, 1); //选择让绿色光线通过滤波器的模式
break;
case 2:
cnt[1] = count; //存储50ms内的绿光通过滤波器时,TCS3200输出的脉冲个数
int G=cnt[1]*RGB_Scale[1];
if(G>255) G=255;
TSC_WB(0, 1); //选择让蓝色光线通过滤波器的模式
break;
case 3:
cnt[2] = count; //存储50ms内的蓝光通过滤波器时,TCS3200输出的脉冲个数
int B=cnt[2]*RGB_Scale[2];
if(B>255) B=255;
TSC_WB(1, 0); //选择无滤波器的模式
white_balance=0;
flag=0;
break;}
LED2=!LED2; //DS1灯
TIM2->CNT=0;
if(white_balance==0){
printf("%d ",(int)(cnt[0]*RGB_Scale[0]));
printf("%d ",(int)(cnt[1]*RGB_Scale[1]));
printf("%d \n",(int)(cnt[2]*RGB_Scale[2]));}
}
else {} //空载
}
}
/* USER CODE END 4 */
matlab代码
function pushbutton1_Callback(hObject, eventdata, handles)
global R G B
s=serial('com3');
set(s,'BaudRate', 115200,'DataBits',8,'Parity','none');
s.DataTerminalReady='off';
fclose(instrfind);
fopen(s);
a=fscanf(s,'%d');
fclose(s);
fprintf('%c',a);
R=a(1,1)
G=a(2,1)
B=a(3,1)
set(handles.edit2,'string',num2str(R));
set(handles.edit3,'string',num2str(G));
set(handles.edit4,'string',num2str(B));
上述代码实现的是打开串口,接受串口发送的数据保存成数组3*1的数组,读取数组
这之后是将RGB转换成HSV,这部分不是我做的不大了解了,但好像就是if else的判断确定色域,网上应该有不少这方面的参考代码
五、参考资料
1.外部中断:https://blog.youkuaiyun.com/qq_45607873/article/details/124633942
2.基于stm32f103的颜色识别,写的很好,有原理什么的,我主要参考的这个博客:https://blog.youkuaiyun.com/weixin_50950634/article/details/114645247?
3.MATLAB App Designer 特别篇:RGB颜色提取器(据说是比GUI先进的工具,参考学习):https://blog.youkuaiyun.com/slandarer/article/details/115035583
4.matlab GUI编写串口助手:https://bbs.elecfans.com/jishu_1872177_1_1.html
5.matlabGUI串口助手的文件,文件不好使了,但是是很好的参考资料,可以用来学习:https://download.youkuaiyun.com/download/zhufenghao/7359223?