基于STM32的楼道声光控系统设计

基于STM32的楼道声光控系统设计

一、系统概述与核心功能

1. 系统定位

基于STM32的楼道声光控系统以“环境感知-智能判断-节能控制”为核心,通过光线传感器与声音传感器融合检测,实现楼道照明的“人来灯亮、人走灯灭、光控优先”功能,替代传统声控/光控开关,解决白天误亮、夜间长明灯等问题,适用于居民楼、办公楼、地下车库等场景,显著降低能耗。

2. 核心功能模块

模块 功能描述
环境感知 光敏电阻(或BH1750)检测环境亮度(区分白天/黑夜),声音传感器(如LM393)检测脚步声/说话声
智能判断 光控优先:白天(光线充足)不响应声音;夜间(光线不足)检测到声音后触发亮灯
延时控制 亮灯后延时30秒(可调)自动熄灭,期间再次检测到声音则重置延时(避免频繁开关)
执行控制 继电器(或可控硅)驱动220V交流灯,支持过零检测(可选,减少继电器损耗)
低功耗设计 待机时STM32进入STOP模式,传感器中断唤醒,续航≥1年(市电供电,无电池依赖)
状态指示 LED指示灯(红:待机,绿:亮灯),蜂鸣器提示(可选,操作反馈)

二、硬件设计方案

1. 核心硬件选型

模块 型号 关键参数 接口方式
主控MCU STM32F103C8T6 72MHz Cortex-M3,64KB Flash,20KB RAM,12位ADC,2个定时器,支持低功耗模式 核心控制器
光线传感器 光敏电阻GL5528 亮电阻5-10kΩ(光照),暗电阻1-2MΩ(黑暗),模拟输出,响应时间<1s ADC1_IN0(PA0,分压电路)
声音传感器 LM393声音检测模块 数字输出(高电平触发),检测范围30-80dB,可调电位器调节灵敏度,带指示灯 GPIO(PA1,外部中断)
执行模块 5V继电器模块(带光耦) 触点容量10A/250V AC,光耦隔离,低电平触发(STM32 GPIO控制) GPIO(PA2,三极管驱动)
显示模块 双色LED(红/绿) 共阳/共阴,指示待机/亮灯状态 GPIO(PB0=红,PB1=绿)
电源模块 220V转5V开关电源模块 输入220V AC,输出5V/2A,给STM32、传感器、继电器供电(继电器需独立5V) 市电输入,5V输出
辅助模块 有源蜂鸣器(可选) 5V驱动,85dB,操作提示音 GPIO(PB2)

2. 硬件电路设计要点

2.1 核心电路连接

2.2 抗干扰与安全设计

三、软件设计与核心代码

1. 系统架构(前后台系统+中断)

采用前后台系统,以主循环轮询为主,中断处理声音触发事件,核心流程:

  1. 初始化:配置时钟、ADC(光线检测)、GPIO(声音/继电器/LED)、定时器(延时关灯)。

  2. 主循环

    • 读取光敏电阻ADC值,判断环境亮度(光控判断)。
    • 若光线不足(黑夜),使能声音传感器中断;若光线充足(白天),关闭声音检测。
    • 处理延时关灯逻辑(定时器倒计时,超时后关灯)。
  3. 中断服务:声音传感器触发外部中断,记录触发时间,启动/重置延时定时器。

2. 核心代码实现(基于标准库)

2.1 光线检测与光控判断

#include "stm32f10x.h"
#include "adc.h"

#define LIGHT_THRESHOLD 2000  // 光控阈值(ADC值,>2000=白天,<2000=黑夜)

// 初始化ADC1(PA0,光敏电阻)
void ADC1_Init(void) {
  ADC_InitTypeDef ADC_InitStruct;
  GPIO_InitTypeDef GPIO_InitStruct;
  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
  
  // 配置PA0为模拟输入
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(GPIOA, &GPIO_InitStruct);
  
  // ADC配置(12位,单次转换,软件触发)
  ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
  ADC_InitStruct.ADC_ScanConvMode = DISABLE;
  ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
  ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStruct.ADC_NbrOfChannel = 1;
  ADC_Init(ADC1, &ADC_InitStruct);
  
  ADC_Cmd(ADC1, ENABLE);
  ADC_ResetCalibration(ADC1);
  while (ADC_GetResetCalibrationStatus(ADC1));
  ADC_StartCalibration(ADC1);
  while (ADC_GetCalibrationStatus(ADC1));
}

// 读取光敏电阻ADC值(0-4095)
uint16_t Read_Light_ADC(void) {
  ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);
  while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
  return ADC_GetConversionValue(ADC1);
}

// 光控判断(返回1=黑夜,0=白天)
uint8_t Is_Dark(void) {
  uint16_t adc_val = Read_Light_ADC();
  return (adc_val < LIGHT_THRESHOLD) ? 1 : 0;  // ADC值小=光线暗
}

2.2 声音检测与中断处理

// 全局变量
uint8_t sound_triggered = 0;  // 声音触发标志
uint32_t last_sound_time = 0;  // 上次声音触发时间(ms)

// 外部中断配置(PA1,声音传感器OUT)
void EXTI1_Init(void) {
  GPIO_InitTypeDef GPIO_InitStruct;
  EXTI_InitTypeDef EXTI_InitStruct;
  NVIC_InitTypeDef NVIC_InitStruct;
  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
  
  // PA1配置为输入(上拉)
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIOA, &GPIO_InitStruct);
  
  // 外部中断线1配置(PA1)
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);
  EXTI_InitStruct.EXTI_Line = EXTI_Line1;
  EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;  // 下降沿触发(声音触发时OUT从高变低)
  EXTI_InitStruct.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStruct);
  
  // NVIC配置(优先级分组1,抢占优先级0,子优先级0)
  NVIC_InitStruct.NVIC_IRQChannel = EXTI1_IRQn;
  NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStruct);
}

// 外部中断1服务函数(声音触发)
void EXTI1_IRQHandler(void) {
  if (EXTI_GetITStatus(EXTI_Line1) != RESET) {
    if (Is_Dark()) {  // 仅在黑夜响应声音
      sound_triggered = 1;
      last_sound_time = HAL_GetTick();  // 记录触发时间(需实现HAL_GetTick,或用SysTick)
    }
    EXTI_ClearITPendingBit(EXTI_Line1);  // 清除中断标志
  }
}

2.3 延时关灯与继电器控制

// 全局变量
#define LIGHT_ON_TIME 30000  // 亮灯时间(30秒=30000ms)
uint8_t light_state = 0;    // 灯状态(0=关,1=开)

// 继电器控制(PA2,高电平触发)
void Relay_Control(uint8_t state) {
  GPIO_WriteBit(GPIOA, GPIO_Pin_2, state ? Bit_SET : Bit_RESET);
  light_state = state;
  // LED指示:绿灯亮=开,红灯亮=关
  GPIO_WriteBit(GPIOB, GPIO_Pin_0, state ? Bit_RESET : Bit_SET);  // 红灯
  GPIO_WriteBit(GPIOB, GPIO_Pin_1, state ? Bit_SET : Bit_RESET);  // 绿灯
}

// 主循环中的延时处理逻辑
void Main_Loop_Process(void) {
  static uint32_t timer_count = 0;
  
  if (sound_triggered) {
    sound_triggered = 0;
    if (!light_state) {  // 灯未亮时,启动亮灯
      Relay_Control(1);  // 开灯
      timer_count = HAL_GetTick();  // 启动定时器
    } else {  // 灯已亮时,重置延时
      timer_count = HAL_GetTick();
    }
  }
  
  // 灯亮状态下,检查延时是否超时
  if (light_state) {
    if (HAL_GetTick() - timer_count > LIGHT_ON_TIME) {
      Relay_Control(0);  // 关灯
    }
  }
  
  // 白天自动关灯(双重保障)
  if (!Is_Dark() && light_state) {
    Relay_Control(0);
  }
}

2.4 主程序框架

#include "stm32f10x.h"
#include "adc.h"
#include "exti.h"
#include "relay.h"

int main(void) {
  HAL_Init();  // 初始化HAL库(若用标准库,可替换为SystemInit)
  SystemClock_Config();  // 配置系统时钟72MHz
  
  ADC1_Init();       // 初始化ADC(光线检测)
  EXTI1_Init();      // 初始化外部中断(声音检测)
  Relay_Init();      // 初始化继电器/LED(GPIO配置)
  
  while (1) {
    Main_Loop_Process();  // 主循环处理(延时关灯、光控判断)
    HAL_Delay(100);       // 100ms轮询一次(降低CPU占用)
  }
}

参考代码 基于STM32的楼道声光控设计 www.youwenfan.com/contentcst/133690.html

四、关键技术与优化

1. 抗干扰与误触发抑制

2. 低功耗设计

3. 延时精度优化

五、系统调试与扩展

1. 调试步骤

阶段 操作 工具
硬件调试 测量光敏电阻分压(光照/黑暗时ADC值)、继电器线圈电压(吸合时5V) 万用表、示波器
传感器测试 遮挡光敏电阻(模拟黑夜),拍手触发声音传感器,观察继电器是否吸合 肉眼观察LED状态
延时测试 亮灯后计时30秒,检查是否自动熄灭;再次发声,检查是否重置延时 秒表、逻辑分析仪(GPIO波形)
功耗测试 白天待机时测量STM32电流(应<10mA),STOP模式下<1mA 万用表(电流档)

2. 扩展功能

专注于matlab/simulink,电子电路,编程