STM32 HAL库的TCS3200使用教程

一、 TCS3200

 TCS3200是TAOS公司推出的可编程彩色光到频率的转换器,它把可配置的硅光电二极管与电流频率转换器集成在一个单一的CMOS电路上,同时集成了三种颜色(RGB)的滤光器,是业界第一个具有数字兼容接口的RGB彩色传感器。

引脚:

二、cubemx配置

1. 配置PA0-PA3为S0-S3输出

2. 增加一个串口作为python接口 buad 115200

3. tim2时钟源为外部,并且ARR最大防止溢出

4. tim1最为1s的中断 时钟源进行计数

三、keil编写代码

main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
float RGB_Scale[3];          //????3?RGB????
float fei[3] = {0};
int count=0;               //?????
int cnt[3];              //????RGB????????
int flag = 0;
send_t send;
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* 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_DMA_Init();
  MX_TIM2_Init();
  MX_TIM1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	HAL_TIM_Base_Start_IT(&htim1); 
	
	HAL_TIM_Base_Start(&htim2);    
	S0_L;
	S1_H;
	HAL_Delay(5000);
	RGB_Scale[0] = 255.0/ cnt[0];     //红色光比例因孿
  RGB_Scale[1] = 255.0/ cnt[1] ;    //绿色光比例因孿
  RGB_Scale[2] = 255.0/ cnt[2] ;    //蓝色光比例因孿
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		HAL_Delay(100);
			for(int i=0; i<3; i++){
			    fei[i] = cnt[i] * RGB_Scale[i]; 
			}
		send.head = 0x5a;
		send.tail = 0xa5;
		send.R = fei[0];
		send.G = fei[1];
		send.B = fei[2];
		HAL_UART_Transmit_DMA(&huart1,(uint8_t *)&send,sizeof(send_t)); 

  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV2;
  RCC_OscInitStruct.PLL.PLLN = 85;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
	if(htim->Instance==htim1.Instance){
		uint16_t count=__HAL_TIM_GET_COUNTER(&htim2);
		switch(flag){
			case 0:
				S2_H;
				S3_L;
//NOTHINT to do clear the counter
			  __HAL_TIM_SetCounter(&htim2,0);
				S2_L;
				S3_L;//红色
				flag = 1 ;
			  break ;
			case 1:
				S2_H;
				S3_H;//绿色
				cnt[0] = count;//获取红色的数倿
			  __HAL_TIM_SetCounter(&htim2,0);
				flag = 2 ;
			  break ;
			case 2:
				S2_L;
				S3_H;//蓝色
				cnt[1] = count;//获取绿色的数倿
			  __HAL_TIM_SetCounter(&htim2,0);
				flag = 3 ;
			  break ;
			case 3:
				S2_L;
				S3_L;
				cnt[2] = count;//获取蓝色的数倿
			  __HAL_TIM_SetCounter(&htim2,0);
				flag = 0 ;
			  break ;
			
				
		}
	}
}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

main.h

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.h
  * @brief          : Header for main.c file.
  *                   This file contains the common defines of the application.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "stm32g4xx_hal.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */

/* USER CODE END ET */

/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */

/* USER CODE END EC */

/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */

/* USER CODE END EM */

/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);

/* USER CODE BEGIN EFP */

/* USER CODE END EFP */

/* Private defines -----------------------------------------------------------*/
#define S0_Pin GPIO_PIN_0
#define S0_GPIO_Port GPIOA
#define S1_Pin GPIO_PIN_1
#define S1_GPIO_Port GPIOA
#define S2_Pin GPIO_PIN_2
#define S2_GPIO_Port GPIOA
#define S3_Pin GPIO_PIN_3
#define S3_GPIO_Port GPIOA

/* USER CODE BEGIN Private defines */
#define S0_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);  

#define S0_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);

#define S1_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);  

#define S1_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);

#define S2_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);  

#define S2_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);

#define S3_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);  

#define S3_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
 
typedef struct{
    uint8_t head;
    float R;
    float G;
    float B;
    uint8_t tail;
} __attribute__((packed)) send_t;

/* USER CODE END Private defines */

#ifdef __cplusplus
}
#endif

#endif /* __MAIN_H */

这里有个小坑,

typedef struct{
    uint8_t head;
    float R;
    float G;
    float B;
    uint8_t tail;
} __attribute__((packed)) send_t;

无__attribute__((packed))的话代码会优化,多发了几个0

四、python

import serial
import struct
import tkinter as tk
from tkinter import ttk
from threading import Thread

class RGBDisplayApp:
    def __init__(self, root):
        self.root = root
        self.root.title("RGB 颜色接收显示器")
        
        # 串口接收器实例
        self.serial_receiver = SerialRGBReceiver()
        
        # 创建UI组件
        self.setup_ui()
        
        # 连接串口
        if not self.serial_receiver.connect():
            self.status_label.config(text="串口连接失败", foreground="red")
        
    def setup_ui(self):
        # 主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 串口控制区域
        serial_frame = ttk.LabelFrame(main_frame, text="串口设置", padding="10")
        serial_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(serial_frame, text="端口:").grid(row=0, column=0, padx=5, pady=5)
        self.port_entry = ttk.Entry(serial_frame)
        self.port_entry.insert(0, self.serial_receiver.port)
        self.port_entry.grid(row=0, column=1, padx=5, pady=5)
        
        ttk.Label(serial_frame, text="波特率:").grid(row=0, column=2, padx=5, pady=5)
        self.baudrate_entry = ttk.Entry(serial_frame)
        self.baudrate_entry.insert(0, self.serial_receiver.baudrate)
        self.baudrate_entry.grid(row=0, column=3, padx=5, pady=5)
        
        self.connect_btn = ttk.Button(serial_frame, text="连接", command=self.toggle_connection)
        self.connect_btn.grid(row=0, column=4, padx=5, pady=5)
        
        # 颜色显示区域
        color_frame = ttk.LabelFrame(main_frame, text="颜色显示", padding="10")
        color_frame.pack(fill=tk.BOTH, expand=True, pady=5)
        
        # 颜色预览画布
        self.color_canvas = tk.Canvas(color_frame, width=200, height=200, bg='white')
        self.color_canvas.pack(pady=10)
        
        # RGB值显示
        value_frame = ttk.Frame(color_frame)
        value_frame.pack(pady=5)
        
        ttk.Label(value_frame, text="R:").grid(row=0, column=0, padx=5)
        self.r_label = ttk.Label(value_frame, text="0.00", width=10)
        self.r_label.grid(row=0, column=1, padx=5)
        
        ttk.Label(value_frame, text="G:").grid(row=0, column=2, padx=5)
        self.g_label = ttk.Label(value_frame, text="0.00", width=10)
        self.g_label.grid(row=0, column=3, padx=5)
        
        ttk.Label(value_frame, text="B:").grid(row=0, column=4, padx=5)
        self.b_label = ttk.Label(value_frame, text="0.00", width=10)
        self.b_label.grid(row=0, column=5, padx=5)
        
        # 状态栏
        self.status_label = ttk.Label(main_frame, text="准备就绪", relief=tk.SUNKEN)
        self.status_label.pack(fill=tk.X, pady=5)
        
    def toggle_connection(self):
        if self.serial_receiver.ser and self.serial_receiver.ser.is_open:
            self.serial_receiver.stop_receiving()
            self.connect_btn.config(text="连接")
            self.status_label.config(text="已断开连接", foreground="black")
        else:
            self.serial_receiver.port = self.port_entry.get()
            self.serial_receiver.baudrate = int(self.baudrate_entry.get())
            if self.serial_receiver.connect():
                self.serial_receiver.start_receiving()
                self.connect_btn.config(text="断开")
                self.status_label.config(text="已连接", foreground="green")
            else:
                self.status_label.config(text="连接失败", foreground="red")
    
    def update_rgb(self, r, g, b):
        # 确保在UI线程中更新
        self.root.after(0, lambda: self._update_rgb(r, g, b))
    
    def _update_rgb(self, r, g, b):
        # 更新RGB值显示
        self.r_label.config(text=f"{r:.2f}")
        self.g_label.config(text=f"{g:.2f}")
        self.b_label.config(text=f"{b:.2f}")
        
        # 确定RGB值的范围并归一化到0-1
        max_val = max(r, g, b)
        if max_val > 1:
            # 0-255范围,转换为0-1
            r_norm = r / 255.0
            g_norm = g / 255.0
            b_norm = b / 255.0
        else:
            # 已经是0-1范围
            r_norm = r
            g_norm = g
            b_norm = b
        
        # 确保归一化后的值在0-1范围内
        r_norm = max(0, min(1, r_norm))
        g_norm = max(0, min(1, g_norm))
        b_norm = max(0, min(1, b_norm))
        
        # 转换为16进制颜色代码
        hex_color = "#{:02X}{:02X}{:02X}".format(
            int(r_norm * 255),
            int(g_norm * 255),
            int(b_norm * 255)
        )
        
        # 更新颜色预览
        self.color_canvas.config(bg=hex_color)
        
        # 更新状态
        self.status_label.config(text=f"接收中 - 当前颜色: {hex_color}", foreground="blue")

class SerialRGBReceiver:
    def __init__(self, port='COM11', baudrate=115200):
        self.port = port
        self.baudrate = baudrate
        self.ser = None
        self.running = False
        self.root = None
        
    def set_root(self, root):
        self.root = root
        
    def connect(self):
        try:
            self.ser = serial.Serial(self.port, self.baudrate, timeout=1)
            print(f"Connected to {self.port} at {self.baudrate} baud")
            return True
        except Exception as e:
            print(f"Error connecting to serial port: {e}")
            return False
    
    def disconnect(self):
        if self.ser and self.ser.is_open:
            self.ser.close()
            print("Disconnected from serial port")
    
    def start_receiving(self):
        if self.ser and self.ser.is_open:
            self.running = True
            self.receive_thread = Thread(target=self.read_data, daemon=True)
            self.receive_thread.start()

    def stop_receiving(self):
        self.running = False
        if self.ser and self.ser.is_open:
            self.ser.close()

    def read_data(self):
        try:
            while self.running:
                data = self.ser.read(14)
                if len(data) == 14:
                    head, r, g, b, tail = struct.unpack('<BfffB', data)
                    if head == 0x5A and tail == 0xA5:
                        print(f"Received RGB: Head={head}, R={r}, G={g}, B={b}, Tail={tail}")
                        if self.root:
                            self.root.update_rgb(r, g, b)
                    else:
                        print("Invalid frame head or tail")
                else:
                    print("Received incomplete frame")
        except struct.error as e:
            print(f"Error unpacking data: {e}")
        except Exception as e:
            print(f"Error reading data: {e}")

if __name__ == "__main__":
    root = tk.Tk()
    app = RGBDisplayApp(root)
    app.serial_receiver.set_root(app)
    
    def on_closing():
        app.serial_receiver.stop_receiving()
        root.destroy()
    
    root.protocol("WM_DELETE_WINDOW", on_closing)
    root.mainloop()

连结即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值