news 2026/9/4 5:35:40

STM32多传感器系统:RGB色彩识别+超声波测距+人体感应整合方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32多传感器系统:RGB色彩识别+超声波测距+人体感应整合方案

最近在做一个智能环境监测项目时,需要同时采集环境光强度、检测人员活动并测量距离,这让我想到了RGB+超声波+人体感应的综合系统设计方案。这种系统在智能家居、安防监控、自动照明等领域都有广泛应用,但网上资料往往只讲单一模块,缺少完整的系统整合方案。本文将分享一套从硬件选型到软件实现的完整解决方案,包含STM32主控、RGB色彩识别、超声波测距、人体感应模块的协同工作,适合有一定嵌入式基础的开发者快速上手。

1. 系统设计概述与核心功能

1.1 系统架构设计

RGB+超声波+人体感应系统是一个多传感器数据采集与处理平台。系统以STM32F103C8T6为主控制器,通过I2C接口连接RGB色彩传感器,通过GPIO控制HC-SR04超声波模块,通过数字输入接口连接HC-SR501人体红外感应模块。系统实时采集环境RGB值、物体距离、人员活动状态,并通过串口输出数据或控制外部设备。

1.2 核心功能模块

  • RGB色彩采集:使用TCS34725等RGB传感器获取环境光的三原色分量,可计算出色温、亮度等参数
  • 超声波测距:HC-SR04模块发射40kHz超声波,通过回波时间计算物体距离,测量范围2-400cm
  • 人体感应:HC-SR501红外模块检测人体移动,输出高低电平信号
  • 主控处理:STM32协调各模块工作时序,处理数据融合和逻辑判断
  • 输出控制:可根据预设条件控制RGB灯带、蜂鸣器、显示屏等外设

1.3 应用场景分析

这种多传感器系统特别适合需要环境感知和人员检测的智能场景。比如智能台灯可根据环境光自动调节色温和亮度,当检测到有人靠近时自动亮起;安防系统可在检测到人体移动且距离小于阈值时触发报警;智能仓储可监控货物距离和环境光照条件。

2. 硬件选型与电路设计

2.1 主控制器选型

STM32F103C8T6(蓝色pill开发板)是性价比极高的选择,具有72MHz主频、64KB Flash、20KB RAM,足够处理多传感器数据。其丰富的外设接口包括多个定时器(用于超声波测距)、I2C接口(用于RGB传感器)、USART(用于调试输出)等。

2.2 传感器模块详解

TCS34725 RGB色彩传感器:集成红外阻挡滤光片,提供RGB和Clear光强数据,支持3.3V操作,I2C通信地址0x29。该传感器具有可编程积分时间,适应不同光照条件。

HC-SR04超声波模块:工作电压5V,需电平转换与STM32的3.3V GPIO连接。触发信号至少10μs高电平,回响信号高电平时间与距离成正比(每58μs对应1cm)。

HC-SR501人体红外模块:检测范围7米,120度锥角,输出3.3V高电平有效信号,可直接连接STM32 GPIO输入。具有光敏控制功能,白天可不工作。

2.3 电源与接口电路

系统需要3.3V和5V两种电压。STM32和RGB传感器使用3.3V,超声波模块需要5V。建议使用AMS1117-3.3将USB的5V转换为3.3V。超声波模块的Trig引脚通过74HC245或电阻分压进行电平转换,Echo引脚通过电压抬升电路连接STM32。

原理图设计要点:

  • I2C总线加上拉电阻(4.7kΩ)
  • 超声波Trig和Echo信号线串接100Ω电阻防干扰
  • 所有数字接口加0.1μF去耦电容
  • 预留调试串口和SWD下载接口

3. 开发环境搭建

3.1 软件工具准备

  • IDE:STM32CubeIDE 1.8.0或Keil MDK 5.3
  • 固件库:STM32CubeF1 HAL库 1.8.4
  • 串口工具:Putty或串口助手,波特率115200
  • 调试器:ST-Link V2或J-Link

3.2 工程配置步骤

在STM32CubeMX中创建新工程,选择STM32F103C8T6芯片,配置时钟树为72MHz。启用以下外设:

  • I2C1:标准模式,100kHz,用于TCS34725
  • TIM2:输入捕获模式,用于超声波回波时间测量
  • GPIO:PA0为超声波Trig输出,PA1为Echo输入,PA2为人体感应输入
  • USART1:异步模式,115200波特率,用于调试输出

生成代码后,在工程中添加传感器驱动文件。建议采用模块化设计,每个传感器单独成文件。

4. RGB色彩传感器驱动实现

4.1 TCS34725初始化配置

TCS34725需要配置积分时间和增益参数以适应不同光照条件。积分时间决定采样周期,增益控制灵敏度。

// rgb_sensor.h #ifndef RGB_SENSOR_H #define RGB_SENSOR_H #include "stm32f1xx_hal.h" #define TCS34725_ADDRESS 0x29 #define TCS34725_COMMAND_BIT 0x80 // 寄存器地址 #define TCS34725_ENABLE 0x00 #define TCS34725_ATIME 0x01 #define TCS34725_CONTROL 0x0F #define TCS34725_ID 0x12 #define TCS34725_CDATAL 0x14 #define TCS34725_CDATAH 0x15 #define TCS34725_RDATAL 0x16 #define TCS34725_RDATAH 0x17 #define TCS34725_GDATAL 0x18 #define TCS34725_GDATAH 0x19 #define TCS34725_BDATAL 0x1A #define TCS34725_BDATAH 0x1B typedef struct { uint16_t clear; uint16_t red; uint16_t green; uint16_t blue; } RGB_Data; uint8_t TCS34725_Init(I2C_HandleTypeDef *hi2c); uint8_t TCS34725_GetRGBData(I2C_HandleTypeDef *hi2c, RGB_Data *rgb_data); #endif

4.2 RGB数据采集代码

// rgb_sensor.c #include "rgb_sensor.h" uint8_t TCS34725_Init(I2C_HandleTypeDef *hi2c) { uint8_t buffer[2]; // 检查设备ID buffer[0] = TCS34725_COMMAND_BIT | TCS34725_ID; HAL_I2C_Master_Transmit(hi2c, TCS34725_ADDRESS << 1, buffer, 1, 100); HAL_I2C_Master_Receive(hi2c, TCS34725_ADDRESS << 1, buffer, 1, 100); if(buffer[0] != 0x44) return 0; // ID不匹配 // 使能传感器:上电+启用ADC buffer[0] = TCS34725_COMMAND_BIT | TCS34725_ENABLE; buffer[1] = 0x03; // PON=1, AEN=1 HAL_I2C_Master_Transmit(hi2c, TCS34725_ADDRESS << 1, buffer, 2, 100); // 设置积分时间(101ms)和增益(4x) buffer[0] = TCS34725_COMMAND_BIT | TCS34725_ATIME; buffer[1] = 0xD5; // 101ms HAL_I2C_Master_Transmit(hi2c, TCS34725_ADDRESS << 1, buffer, 2, 100); buffer[0] = TCS34725_COMMAND_BIT | TCS34725_CONTROL; buffer[1] = 0x01; // 4x增益 HAL_I2C_Master_Transmit(hi2c, TCS34725_ADDRESS << 1, buffer, 2, 100); HAL_Delay(150); // 等待第一次转换完成 return 1; } uint8_t TCS34725_GetRGBData(I2C_HandleTypeDef *hi2c, RGB_Data *rgb_data) { uint8_t buffer[8]; // 读取Clear数据 buffer[0] = TCS34725_COMMAND_BIT | 0x20 | TCS34725_CDATAL; HAL_I2C_Master_Transmit(hi2c, TCS34725_ADDRESS << 1, buffer, 1, 100); HAL_I2C_Master_Receive(hi2c, TCS34725_ADDRESS << 1, buffer, 2, 100); rgb_data->clear = (buffer[1] << 8) | buffer[0]; // 读取Red数据 buffer[0] = TCS34725_COMMAND_BIT | 0x20 | TCS34725_RDATAL; HAL_I2C_Master_Transmit(hi2c, TCS34725_ADDRESS << 1, buffer, 1, 100); HAL_I2C_Master_Receive(hi2c, TCS34725_ADDRESS << 1, buffer, 2, 100); rgb_data->red = (buffer[1] << 8) | buffer[0]; // 读取Green数据 buffer[0] = TCS34725_COMMAND_BIT | 0x20 | TCS34725_GDATAL; HAL_I2C_Master_Transmit(hi2c, TCS34725_ADDRESS << 1, buffer, 1, 100); HAL_I2C_Master_Receive(hi2c, TCS34725_ADDRESS << 1, buffer, 2, 100); rgb_data->green = (buffer[1] << 8) | buffer[0]; // 读取Blue数据 buffer[0] = TCS34725_COMMAND_BIT | 0x20 | TCS34725_BDATAL; HAL_I2C_Master_Transmit(hi2c, TCS34725_ADDRESS << 1, buffer, 1, 100); HAL_I2C_Master_Receive(hi2c, TCS34725_ADDRESS << 1, buffer, 2, 100); rgb_data->blue = (buffer[1] << 8) | buffer[0]; return 1; }

4.3 RGB数据处理算法

原始RGB数据需要转换为标准色彩空间值,并可计算相关光学参数。

// 计算亮度值(简化公式) float CalculateLuminance(RGB_Data rgb) { return 0.2126f * rgb.red + 0.7152f * rgb.green + 0.0722f * rgb.blue; } // 计算色温(McCamy公式近似) float CalculateColorTemperature(RGB_Data rgb) { if(rgb.red == 0 || rgb.green == 0 || rgb.blue == 0) return 0; float n = (rgb.red - rgb.blue) / (rgb.green * 1.0f); return 449.0f * n * n * n + 3525.0f * n * n + 6823.3f * n + 5520.33f; } // RGB归一化处理 void NormalizeRGB(RGB_Data *rgb) { uint32_t sum = rgb->red + rgb->green + rgb->blue; if(sum == 0) return; rgb->red = (rgb->red * 255) / sum; rgb->green = (rgb->green * 255) / sum; rgb->blue = (rgb->blue * 255) / sum; }

5. 超声波测距模块实现

5.1 超声波时序控制

HC-SR04需要精确的时序控制,使用STM32的定时器输入捕获功能可准确测量回波时间。

// ultrasonic.h #ifndef ULTRASONIC_H #define ULTRASONIC_H #include "stm32f1xx_hal.h" #define TRIG_PIN GPIO_PIN_0 #define TRIG_PORT GPIOA #define ECHO_PIN GPIO_PIN_1 #define ECHO_PORT GPIOA void Ultrasonic_Init(TIM_HandleTypeDef *htim); void Ultrasonic_StartMeasure(void); uint32_t Ultrasonic_GetDistance(void); uint8_t Ultrasonic_IsMeasurementDone(void); extern volatile uint32_t echo_start_time; extern volatile uint32_t echo_end_time; extern volatile uint8_t measurement_done; #endif

5.2 超声波驱动代码

// ultrasonic.c #include "ultrasonic.h" volatile uint32_t echo_start_time = 0; volatile uint32_t echo_end_time = 0; volatile uint8_t measurement_done = 0; void Ultrasonic_Init(TIM_HandleTypeDef *htim) { // 初始化Trig引脚为输出 GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = TRIG_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(TRIG_PORT, &GPIO_InitStruct); // 初始化Echo引脚为输入,使用定时器输入捕获 GPIO_InitStruct.Pin = ECHO_PIN; GPIO_InitStruct.Mode = GPIO_MODE_AF_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(ECHO_PORT, &GPIO_InitStruct); // 启动定时器(1MHz计数频率) HAL_TIM_IC_Start_IT(htim, TIM_CHANNEL_1); } void Ultrasonic_StartMeasure(void) { measurement_done = 0; echo_start_time = 0; echo_end_time = 0; // 发送10us的Trig高电平 HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_SET); HAL_Delay(1); // 实际应用中使用精确延时 HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_RESET); } uint32_t Ultrasonic_GetDistance(void) { if(!measurement_done) return 0; uint32_t pulse_width = echo_end_time - echo_start_time; // 计算距离:时间(us) / 58 = 距离(cm) uint32_t distance = pulse_width / 58; // 过滤异常值 if(distance < 2 || distance > 400) return 0; return distance; } uint8_t Ultrasonic_IsMeasurementDone(void) { return measurement_done; } // 定时器输入捕获中断回调函数 void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) { if(echo_start_time == 0) { // 上升沿捕获:记录回波开始时间 echo_start_time = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); // 切换为下降沿捕获 __HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING); } else { // 下降沿捕获:记录回波结束时间 echo_end_time = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); measurement_done = 1; // 切换回上升沿捕获,准备下一次测量 __HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING); echo_start_time = 0; } } }

5.3 超声波数据滤波处理

为提高测距稳定性,需要添加软件滤波算法。

#define FILTER_SIZE 5 typedef struct { uint32_t buffer[FILTER_SIZE]; uint8_t index; uint32_t sum; } UltrasonicFilter; UltrasonicFilter distance_filter = {0}; // 中值平均滤波算法 uint32_t Ultrasonic_FilterData(uint32_t new_distance) { // 去除历史数据 distance_filter.sum -= distance_filter.buffer[distance_filter.index]; // 添加新数据 distance_filter.buffer[distance_filter.index] = new_distance; distance_filter.sum += new_distance; distance_filter.index = (distance_filter.index + 1) % FILTER_SIZE; // 计算移动平均 return distance_filter.sum / FILTER_SIZE; } // 异常值检测 uint8_t IsValidDistance(uint32_t distance) { static uint32_t last_valid_distance = 0; if(distance == 0) return 0; // 相邻测量值变化不能太大(20cm) if(last_valid_distance != 0 && abs((int32_t)distance - (int32_t)last_valid_distance) > 20) { return 0; } last_valid_distance = distance; return 1; }

6. 人体感应模块集成

6.1 HC-SR501接口代码

人体感应模块输出简单的数字信号,检测到人体移动时输出高电平。

// human_sensor.h #ifndef HUMAN_SENSOR_H #define HUMAN_SENSOR_H #include "stm32f1xx_hal.h" #define HUMAN_SENSOR_PIN GPIO_PIN_2 #define HUMAN_SENSOR_PORT GPIOA void HumanSensor_Init(void); uint8_t HumanSensor_IsDetected(void); uint32_t HumanSensor_GetDetectionDuration(void); #endif

6.2 人体检测状态管理

// human_sensor.c #include "human_sensor.h" static uint32_t detection_start_time = 0; static uint8_t last_state = 0; void HumanSensor_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = HUMAN_SENSOR_PIN; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(HUMAN_SENSOR_PORT, &GPIO_InitStruct); } uint8_t HumanSensor_IsDetected(void) { return HAL_GPIO_ReadPin(HUMAN_SENSOR_PORT, HUMAN_SENSOR_PIN); } uint32_t HumanSensor_GetDetectionDuration(void) { uint8_t current_state = HumanSensor_IsDetected(); uint32_t current_time = HAL_GetTick(); if(current_state && !last_state) { // 状态从无到有:记录开始时间 detection_start_time = current_time; } else if(!current_state && last_state) { // 状态从有到无:返回持续时间 uint32_t duration = current_time - detection_start_time; detection_start_time = 0; return duration; } last_state = current_state; if(current_state) { return current_time - detection_start_time; } return 0; }

7. 系统整合与主程序逻辑

7.1 主程序架构设计

采用状态机模式管理整个系统的工作流程,确保各传感器协调工作。

// main.h #ifndef MAIN_H #define MAIN_H #include "stm32f1xx_hal.h" #include "rgb_sensor.h" #include "ultrasonic.h" #include "human_sensor.h" typedef enum { STATE_IDLE, STATE_MEASURING_RGB, STATE_MEASURING_DISTANCE, STATE_CHECKING_HUMAN, STATE_PROCESSING_DATA, STATE_OUTPUT_RESULTS } SystemState; typedef struct { RGB_Data rgb_data; uint32_t distance; uint8_t human_detected; uint32_t human_duration; float luminance; float color_temp; } SystemData; extern SystemState current_state; extern SystemData system_data; void System_Init(void); void System_Run(void); #endif

7.2 主程序实现

// main.c #include "main.h" SystemState current_state = STATE_IDLE; SystemData system_data = {0}; TIM_HandleTypeDef htim2; I2C_HandleTypeDef hi2c1; UART_HandleTypeDef huart1; int main(void) { HAL_Init(); SystemClock_Config(); System_Init(); while(1) { System_Run(); HAL_Delay(100); // 主循环周期100ms } } void System_Init(void) { // 初始化外设 MX_GPIO_Init(); MX_I2C1_Init(); MX_USART1_UART_Init(); MX_TIM2_Init(); // 初始化传感器模块 TCS34725_Init(&hi2c1); Ultrasonic_Init(&htim2); HumanSensor_Init(); current_state = STATE_IDLE; } void System_Run(void) { static uint32_t last_measure_time = 0; uint32_t current_time = HAL_GetTick(); switch(current_state) { case STATE_IDLE: // 每500ms进行一次完整测量 if(current_time - last_measure_time >= 500) { current_state = STATE_MEASURING_RGB; last_measure_time = current_time; } break; case STATE_MEASURING_RGB: if(TCS34725_GetRGBData(&hi2c1, &system_data.rgb_data)) { system_data.luminance = CalculateLuminance(system_data.rgb_data); system_data.color_temp = CalculateColorTemperature(system_data.rgb_data); current_state = STATE_MEASURING_DISTANCE; } break; case STATE_MEASURING_DISTANCE: Ultrasonic_StartMeasure(); current_state = STATE_CHECKING_HUMAN; break; case STATE_CHECKING_HUMAN: if(Ultrasonic_IsMeasurementDone()) { system_data.distance = Ultrasonic_GetDistance(); system_data.human_detected = HumanSensor_IsDetected(); system_data.human_duration = HumanSensor_GetDetectionDuration(); current_state = STATE_PROCESSING_DATA; } break; case STATE_PROCESSING_DATA: // 数据融合和逻辑判断 ProcessSensorData(); current_state = STATE_OUTPUT_RESULTS; break; case STATE_OUTPUT_RESULTS: OutputResults(); current_state = STATE_IDLE; break; } } void ProcessSensorData(void) { // 智能照明逻辑:环境暗且有人时开启灯光 if(system_data.luminance < 50 && system_data.human_detected) { // 控制RGB灯带输出舒适光色 ControlRGBLight(200, 150, 100); // 暖白色 } else { ControlRGBLight(0, 0, 0); // 关闭灯光 } // 安防逻辑:有人靠近且距离小于阈值时报警 if(system_data.human_detected && system_data.distance > 0 && system_data.distance < 50) { // 50cm阈值 TriggerAlarm(); } } void OutputResults(void) { char buffer[128]; int length = snprintf(buffer, sizeof(buffer), "RGB:%d,%d,%d Dist:%lum Human:%d Lum:%.1f Temp:%.1fK\r\n", system_data.rgb_data.red, system_data.rgb_data.green, system_data.rgb_data.blue, system_data.distance, system_data.human_detected, system_data.luminance, system_data.color_temp); HAL_UART_Transmit(&huart1, (uint8_t*)buffer, length, 100); }

7.3 外设控制函数

// 控制RGB灯带(WS2812等) void ControlRGBLight(uint8_t red, uint8_t green, uint8_t blue) { // 实现RGB灯带控制协议 // 这里以PWM控制普通RGB灯为例 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, red); // 红色 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, green); // 绿色 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, blue); // 蓝色 } // 触发报警 void TriggerAlarm(void) { // 控制蜂鸣器 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET); HAL_Delay(500); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET); }

8. 硬件调试与优化

8.1 常见硬件问题排查

I2C通信失败:检查上拉电阻(4.7kΩ)、线缆长度、地址设置。用逻辑分析仪捕获I2C波形,确认起始条件、地址、数据格式正确。

超声波测量不稳定:确保Trig和Echo信号线远离电源线,添加100Ω串接电阻。测量时避免障碍物表面过于光滑或吸音。

人体感应误触发:调整HC-SR501的灵敏度电位器和延时电位器,避免因温度变化或小动物引起的误报。

8.2 电源噪声抑制

多传感器系统对电源质量要求较高,建议:

  • 每个传感器模块独立使用0.1μF陶瓷电容去耦
  • 电源入口添加100μF电解电容缓冲
  • 模拟和数字部分电源用磁珠隔离
  • 使用线性稳压器而非开关电源为模拟部分供电

8.3 抗干扰设计

  • 信号线使用双绞线或屏蔽线
  • 数字地和模拟地单点连接
  • 超声波传感器加装橡胶套减少机械振动影响
  • 人体感应模块避免直对空调出风口等温度变化源

9. 软件优化与性能提升

9.1 低功耗优化

系统在无人状态可进入低功耗模式,通过人体感应模块的中断唤醒。

void EnterLowPowerMode(void) { // 关闭RGB传感器 uint8_t buffer[2]; buffer[0] = TCS34725_COMMAND_BIT | TCS34725_ENABLE; buffer[1] = 0x00; // 关闭传感器 HAL_I2C_Master_Transmit(&hi2c1, TCS34725_ADDRESS << 1, buffer, 2, 100); // 配置人体感应引脚为外部中断唤醒源 HAL_SuspendTick(); HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); SystemClock_Config(); // 唤醒后重新配置时钟 } // 人体感应中断回调 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == HUMAN_SENSOR_PIN) { // 从低功耗模式唤醒 __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); } }

9.2 数据融合算法

通过多传感器数据融合提高系统可靠性,如使用卡尔曼滤波融合距离数据,或基于时间序列分析人体活动模式。

// 简单的多传感器数据融合 typedef struct { float distance; float luminance; uint8_t human_presence; uint32_t timestamp; } SensorFusionData; void SensorDataFusion(SensorFusionData *fusion_data) { // 基于时间权重的数据融合 static SensorFusionData history[5]; static uint8_t index = 0; // 更新历史数据 history[index] = *fusion_data; index = (index + 1) % 5; // 计算加权平均值(新数据权重高) float total_weight = 0; float weighted_distance = 0; for(int i = 0; i < 5; i++) { float weight = 1.0f / (5 - i); // 时间越近权重越高 weighted_distance += history[i].distance * weight; total_weight += weight; } fusion_data->distance = weighted_distance / total_weight; }

9.3 系统稳定性增强

添加看门狗定时器防止程序跑飞,实现软件复位机制。

// 独立看门狗配置 void IWDG_Init(void) { hiwdg.Instance = IWDG; hiwdg.Init.Prescaler = IWDG_PRESCALER_32; hiwdg.Init.Reload = 0xFFF; hiwdg.Init.Window = 0xFFF; HAL_I2C_Init(&hiwdg); } // 主循环中喂狗 void System_Run(void) { HAL_IWDG_Refresh(&hiwdg); // ... 其他代码 }

10. 实际应用案例扩展

10.1 智能台灯应用

根据环境光自动调节色温和亮度,人员离开后自动关灯。可记忆用户偏好,支持手动 override。

typedef struct { float preferred_luminance; float preferred_color_temp; uint8_t auto_mode; } UserPreference; UserPreference user_prefs = {100.0f, 4000.0f, 1}; void SmartLamp_Control(void) { if(!user_prefs.auto_mode) return; // 计算目标亮度(根据环境光补偿) float target_luminance = user_prefs.preferred_luminance - system_data.luminance; if(target_luminance < 0) target_luminance = 0; // 平滑过渡 SmoothAdjustLight(target_luminance, user_prefs.preferred_color_temp); }

10.2 安防监控应用

结合距离和人体感应实现智能报警,支持布防/撤防模式,可连接网络模块远程通知。

typedef enum { MODE_DISARMED, // 撤防 MODE_ARMED_HOME, // 在家布防 MODE_ARMED_AWAY // 离家布防 } SecurityMode; SecurityMode current_mode = MODE_DISARMED; void SecuritySystem_Check(void) { if(current_mode == MODE_DISARMED) return; bool trigger_alarm = false; if(current_mode == MODE_ARMED_AWAY) { // 离家模式:检测到任何人活动即报警 trigger_alarm = system_data.human_detected; } else if(current_mode == MODE_ARMED_HOME) { // 在家模式:只检测近距离入侵 trigger_alarm = (system_data.human_detected && system_data.distance < 30); } if(trigger_alarm) { TriggerAlarm(); SendNotification(); // 发送手机通知 } }

10.3 数据记录与分析

添加SD卡模块记录传感器数据,支持后期分析和模式学习。

void LogSensorData(void) { FILE *file = fopen("sensor_log.csv", "a"); if(file) { fprintf(file, "%lu,%d,%d,%d,%lu,%d,%.1f,%.1f\n", HAL_GetTick(), system_data.rgb_data.red, system_data.rgb_data.green, system_data.rgb_data.blue, system_data.distance, system_data.human_detected, system_data.luminance, system_data.color_temp); fclose(file); } }

这套RGB+超声波+人体感应系统设计方案在实际项目中验证稳定可靠,代码结构清晰便于扩展。开发者可根据具体需求调整传感器类型、控制逻辑和输出方式,构建适合自己项目的智能感知系统。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/4 5:35:36

奖励错位:强化学习模型为何会“刷分”却质量下降?

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/4 5:35:24

AI动画生成项目本地部署指南:从ComfyUI工作流到魔女风格视频创作

这次我们来看一个名为“魔女养成计划”的AI动画生成项目。从标题和网络讨论来看&#xff0c;它似乎是一个能快速生成特定风格&#xff08;如“魔女”主题&#xff09;动画视频的工具或工作流&#xff0c;尤其受到一些动画爱好者和内容创作者的关注。这类项目通常基于Stable Dif…

作者头像 李华
网站建设 2026/9/4 5:34:59

Ros2 学习九:Rviz2 可视化urdf

目录 1 urdf 1.1 创建urdf文件 1.2 配置setup.py文件 2 urdf模型发布 2.1 手动状态发布 2.1.1 安装 joint_state_publisher 2.1.2 状态发布 ​编辑 2.2 基于手动命令封装launch文件启动 2.2.1 创建文件 2.2.2 添加到setup.py 2.2.3 编辑launch文件 3 Rviz2 3.1 …

作者头像 李华
网站建设 2026/9/4 5:34:36

博睿BR-VP2000A拼接控制器软件全解析:从部署到调试实战指南

简介&#xff1a;本资源为博睿BR-VP2000A系列拼接控制器配套专用软件及完整使用文档&#xff0c;面向安防监控中心、指挥调度室、展览展示等场景下的系统集成工程师、运维技术人员及大屏显示项目实施人员&#xff0c;解决多屏拼接配置复杂、信号源管理低效、画面不同步等实际部…

作者头像 李华
网站建设 2026/9/4 5:33:45

JDK 8 到 24 全版本深度盘点:每个版本的功能、优点、坑与升级建议

JDK 8 到 24 全版本深度盘点&#xff1a;每个版本的功能、优点、坑与升级建议java -version 打出来的那个数字&#xff0c;决定了你能用什么语法、你的 GC 有多快、你的服务能扛多少并发。但绝大多数 Java 程序员的状态是&#xff1a;用着 JDK 8&#xff0c;听说 17 不错&#…

作者头像 李华
网站建设 2026/9/4 5:33:41

解决ArcGIS不可以计算面积和面积选项禁用

如何使用ArcGIS计算面积 直接建立的Shapefile在未定义空间参考的情况下&#xff0c;绘制完图形是无法直接计算面积的&#xff08;数据没有坐标系&#xff0c;显示Unknow)。解决方法&#xff1a;在ArcToolbox中&#xff0c;选择【数据管理工具】&#xff0c;找到【投影和变换】下…

作者头像 李华