用STM32F103C8T6和光敏传感器打造智能环境光检测系统(HAL库实战)

最近在工作室调试设备时,发现手动调节台灯亮度实在麻烦——白天光线充足时需要调暗,阴天时又得反复调整。于是萌生了一个想法:为何不自己动手做个能自动感知环境光照的小装置?这个需求让我想起了抽屉里吃灰已久的STM32F103C8T6开发板,配合常见的光敏电阻,完全可以实现一个低成本的环境光检测系统。

1. 硬件选型与电路设计

1.1 核心器件选择

STM32F103C8T6 作为经典的Cortex-M3内核微控制器,具备丰富的外设资源:

  • 12位精度ADC(多达16个外部通道)
  • 7通道DMA控制器
  • 72MHz主频处理能力
  • 64KB Flash/20KB RAM

光敏传感器选用 GL5528 光敏电阻,其特性参数如下:

参数 数值 说明
亮电阻 5-10KΩ 光照强度10Lux时
暗电阻 0.5-2MΩ 完全黑暗环境下
响应时间 20-30ms 从暗到亮的恢复时间
光谱峰值 540nm 对绿光最敏感

1.2 分压电路设计

光敏电阻需要配合固定电阻组成分压电路,将电阻变化转换为电压信号。典型电路连接方式:

// 电路连接示意图
VCC(3.3V) --- [光敏电阻] --- ADC_IN6 --- [10KΩ电阻] --- GND

提示:固定电阻值选择应与光敏电阻的工作范围匹配,建议通过公式 R_fixed = √(R_light*R_dark) 计算

2. CubeMX工程配置

2.1 时钟树配置

  1. 启用HSE(8MHz外部晶振)
  2. PLL倍频至72MHz系统时钟
  3. ADC时钟分频为12MHz(不超过14MHz限制)
# 时钟配置关键参数
SYSCLK   -> 72MHz
HCLK     -> 72MHz
PCLK1    -> 36MHz
PCLK2    -> 72MHz
ADC_CLK  -> 12MHz (PCLK2/6)

2.2 ADC与DMA配置

ADC1参数设置

  • 通道6(PA6引脚)
  • 右对齐数据格式
  • 扫描模式禁用
  • 连续转换使能
  • 采样时间239.5周期(提高精度)

DMA关键配置

Mode:            Circular
Data Width:      Half Word
Memory Increment: Enable

注意:DMA循环模式可实现后台持续数据采集,不占用CPU资源

3. 代码实现与数据处理

3.1 初始化流程

在main.c中添加以下初始化代码:

// 全局变量定义
#define SAMPLE_SIZE 50
uint32_t adc_buffer[SAMPLE_SIZE];
float light_level = 0;

// 在main()函数中初始化
HAL_ADCEx_Calibration_Start(&hadc1);
HAL_ADC_Start_DMA(&hadc1, adc_buffer, SAMPLE_SIZE);

3.2 数据滤波算法

原始ADC数据需要经过处理才能得到稳定的光照值:

// 移动平均滤波实现
float get_filtered_light() {
    static float filtered = 0;
    uint32_t sum = 0;
    
    for(int i=0; i<SAMPLE_SIZE; i++) {
        sum += adc_buffer[i];
    }
    
    float raw = (float)sum / SAMPLE_SIZE;
    filtered = 0.2 * raw + 0.8 * filtered; // 一阶低通滤波
    return filtered;
}

3.3 光照强度标定

建立ADC值与实际照度(Lux)的对应关系:

ADC值范围 电压(V) 近似照度(Lux) LED状态
0-500 0-0.4 <10 (黑暗) 常亮
500-1500 0.4-1.2 10-100 慢闪(1Hz)
1500-3000 1.2-2.4 100-1000 快闪(5Hz)
>3000 >2.4 >1000 关闭

4. 系统调试与优化

4.1 硬件调试技巧

  1. 电压测量 :先用万用表确认分压点电压随光照变化
  2. 信号观察 :用逻辑分析仪捕获ADC采样时序
  3. 抗干扰措施
    • 在ADC输入引脚添加0.1μF去耦电容
    • 避免长导线连接传感器

4.2 软件调试方法

添加调试输出查看实时数据:

printf("ADC: %4d  Voltage: %.2fV  Light: %.0fLux\r\n", 
       raw_adc, raw_adc*3.3f/4095, lux_value);

常见问题排查表:

现象 可能原因 解决方案
ADC值不变化 引脚配置错误 检查CubeMX引脚分配
数据跳动严重 采样时间不足 增加ADC采样周期
DMA传输中断 缓冲区溢出 检查DMA缓冲区大小设置

5. 功能扩展与进阶应用

5.1 添加阈值报警功能

通过比较器实现光照强度超标报警:

if(lux_value > WARNING_THRESHOLD) {
    HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_SET);
} else {
    HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_RESET);
}

5.2 无线数据传输方案

结合ESP-01S WiFi模块上报数据:

// AT指令发送示例
void send_to_server(float lux) {
    char cmd[64];
    sprintf(cmd, "AT+CIPSEND=%d\r\n", strlen(data));
    HAL_UART_Transmit(&huart1, (uint8_t*)cmd, strlen(cmd), 100);
    
    sprintf(cmd, "{\"light\":%.1f}\r\n", lux);
    HAL_UART_Transmit(&huart1, (uint8_t*)cmd, strlen(cmd), 100);
}

5.3 低功耗优化策略

  1. 启用ADC间断模式
  2. 配置STM32进入Stop模式
  3. 通过RTC定时唤醒采样
// 进入低功耗模式
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);

6. 实际应用案例

在我的书桌照明系统中,这个检测器实现了自动调光功能。当环境光低于150Lux时自动开启台灯,并根据实时光照动态调整亮度。经过两周的持续运行,系统表现稳定,ADC采样值标准差保持在±3LSB以内。

一个有趣的发现是,不同时段自然光的光谱特性会影响传感器读数——晨光通常比午后阳光产生更高的ADC值。这提示我们在更精确的应用中可能需要考虑光谱补偿。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐