002基于 STM32 的智能灯光窗帘控制系统

难度定位 :★★★☆☆(中等)|适合:有一定基础、愿意动手调试、想体现硬件控制能力的同学|预估周期:3~4 周

一、这个毕设是干什么的?

一句话:做一套能根据环境光线自动调节灯光、定时开关,并能用手机远程控制窗帘和灯光的智能家居控制系统。

再展开说:以 STM32F103 为主控,用光敏传感器 感知环境亮度、自动调光,用舵机 拉动窗帘实现自动开合,用继电器 控制灯光通断,通过蓝牙 / WiFi 与手机连接,实现在手机上控制灯光和窗帘、切换多种场景模式(回家、离家、睡眠、观影),并支持定时开关。

二、它解决什么问题?

  • 天气变化、早晚光照不同,灯光要么太亮要么太暗 → 根据环境光线自动调节亮度;

  • 每天手动拉窗帘、开关灯很麻烦,人不在家 灯一直亮 → 定时开关、手机远程控制;

  • 观影、睡眠需要特定氛围,逐个开关很繁琐 → 一键切换「回家 / 离家 / 睡眠 / 观影」场景模式。

本质是:把「手动、单一」的灯光窗帘变成「自动感知 + 定时 + 远程 + 场景化」的智能控制系统,是智能家居里最贴近日常、演示效果最好的方向之一。

三、核心功能?

功能 说明
自动调光 光敏传感器感知环境亮度,自动调节灯光亮度
窗帘控制 舵机驱动窗帘开合,支持全开/全关/任意角度
灯光开关 继电器控制灯光通断,PWM 实现亮度调节
手机控制 蓝牙 / WiFi 连接手机 APP,远程控制灯和窗帘
定时开关 RTC 定时,到点自动开灯 / 关灯
场景模式 回家、离家、睡眠、观影一键切换

四、用到哪些技术?

类别 具体 作用
主控 STM32F103(Cortex-M3) 处理数据、控制所有外设
传感器 光敏电阻 / 光敏传感器 采集环境光照
执行 舵机(窗帘)、继电器(灯光) 控制窗帘开合、灯光通断
调光 TIM PWM 输出 调节灯光亮度
通信 蓝牙模块(HC-05)或 WiFi 与手机通信
显示/交互 手机 APP(蓝牙串口助手等) 远程控制、场景切换
开发 STM32CubeMX + Keil MDK + C 语言 编写烧录程序

五、系统是怎么工作的?

复制代码
感知(采光照)  →  处理(STM32 判定)  →  执行(灯光/窗帘)  →  交互(手机控制)
  光敏传感器        自动调光/定时        舵机+继电器         蓝牙/场景切换

一句话串起来:光敏传感器采集环境亮度 → STM32 判断是否昏暗并自动调光 → 舵机控制窗帘、继电器控制灯光 → 手机蓝牙下发指令切换场景、定时开关。

这条「感知 → 控制 → 执行 → 人机交互」链路是智能家居控制类毕设的通用骨架,学会它,后续做智能晾衣架、智能门锁、智能鱼缸都是同一套思路。

六、大概怎么做?

  1. 买齐硬件(STM32F103C8T6 最小系统板 + 光敏模块 + SG90 舵机 + 继电器 + HC-05 蓝牙 + 灯板);

  2. 用 STM32CubeMX 配置引脚、PWM、ADC、串口,生成工程;

  3. 在 Keil 里写逻辑代码:光敏采集 → 自动调光 → 舵机窗帘 → 继电器灯光 → 蓝牙指令解析 → 场景切换;

  4. 手机装蓝牙串口助手,连接 HC-05,发送指令控制灯光窗帘;

  5. 用手遮挡光敏验证自动调光、手机发指令验证场景切换,整条链路跑通即完成。

相比上一篇 ESP32 那套,这篇多了 PWM 调光、舵机控制和多模块协同,工作量适中、实物演示效果突出,适合中等基础的同学。

七、硬件清单与接线

1、硬件清单

器件 型号/规格 数量
主控板 STM32F103C8T6 最小系统板 1
光敏传感器 光敏电阻 + 分压电路 / 光敏模块 1
舵机 SG90(180°) 1
继电器模块 5V 单路继电器 1
蓝牙模块 HC-05(串口透传) 1
灯光 LED 灯板 / 灯带 + 驱动 1
供电 5V 电源(舵机+继电器需独立供电) 1
杜邦线 + 面包板 --- 若干

舵机和继电器工作电流较大,必须单独用 5V 供电,不能只靠 STM32 的 3.3V 引脚带动。

2、接线表

STM32 引脚 连接器件 说明
PA0 光敏模块 AO ADC 采集光照(0~4095)
PA6 (TIM3_CH1) 灯板 PWM 输入 PWM 调光
PB0 继电器 IN 控制灯光电源通断
PB6 (TIM4_CH1) 舵机信号线 PWM 控制舵机角度
PA9/PA10 (USART1) 蓝牙模块 TX/RX 串口通信(交叉接)
3.3V 光敏模块 VCC 传感器供电
5V 舵机、继电器 VCC 执行机构独立供电
GND 所有器件共地 必须共地

关键提醒 :蓝牙 RX 接 STM32 TX、蓝牙 TX 接 STM32 RX(交叉);所有模块与 STM32 共地;舵机和继电器单独 5V 供电,否则会拉低电压导致复位。

八、外设原理简述

1、光敏传感器

  • 光敏电阻阻值随光照变化,配合分压电路输出模拟电压,接 STM32 ADC 读取;

  • 光照越强,输出的 ADC 值越小(或相反,取决于接法),需实测标定阈值;

  • 用途:判定环境是否昏暗,驱动自动调光。

2、舵机(SG90)

  • 通过 PWM 脉冲宽度控制角度:周期 20ms(50Hz),脉宽 0.5ms 对应 0°,2.5ms 对应 180°,线性对应;

  • 用 STM32 定时器 TIM 输出 PWM,改变占空比即可让窗帘转到任意角度;

  • 用途:拉动窗帘开合。

3、继电器

  • 用弱电(STM32 GPIO)控制强电/大电流通断的开关;

  • GPIO 输出高/低电平即可控制继电器吸合/断开,进而通断灯光电源;

  • 用途:灯光电源的开关控制。

4、蓝牙模块(HC-05)

  • 串口透传:STM32 通过 UART 收发字符串,手机端用蓝牙串口助手即可通信;

  • 手机 APP 发送 home/away/sleep/movie 等指令,STM32 串口中断接收并执行;

  • 用途:手机远程控制、场景切换。

九、开发环境搭建

  1. 安装 STM32CubeMX 和 Keil MDK;

  2. CubeMX 新建工程,选芯片 STM32F103C8T6;

  3. 配置外设:ADC1(PA0)、TIM3 PWM(PA6)、TIM4 PWM(PB6)、GPIO 输出(PB0)、USART1(蓝牙)、并启用一个定时器/RTC 做定时;

  4. 生成 Keil 工程(HAL 库),在 main.c 里添加业务逻辑代码;

  5. 编译下载(ST-Link / 串口 ISP),即可运行。

十、软件设计(.h / .c 多文件工程)

与上一篇一致,代码按功能拆分:头文件(.h)放声明与配置,源文件(.c)放实现,模块独立、职责清晰,符合工程规范。

1、工程文件结构

复制代码
smart_light_curtain/
├── config.h     // 全局配置:引脚、PWM通道、阈值、定时参数
├── sensor.h     // 光敏传感器模块声明
├── sensor.c     // 光敏 ADC 采集实现
├── light.h      // 灯光模块声明
├── light.c      // PWM 调光 + 继电器通断实现
├── curtain.h    // 窗帘模块声明
├── curtain.c    // 舵机 PWM 角度控制实现
├── comm.h       // 通信模块声明
├── comm.c       // 蓝牙串口指令接收实现
├── scene.h      // 场景模块声明
├── scene.c      // 场景模式状态机实现
└── main.c       // 主程序 + 自动调光 + 定时

2、config.h ------ 全局配置(必改)

复制代码
#ifndef CONFIG_H
#define CONFIG_H
#include <stdint.h>
​
/* 灯光 PWM:TIM3_CH1 (PA6),ARR=999,占空比=比较值/999 */
#define TIM_LIGHT        &htim3
#define CH_LIGHT         TIM_CHANNEL_1
​
/* 舵机 PWM:TIM4_CH1 (PB6),周期20ms,50Hz */
#define TIM_CURTAIN      &htim4
#define CH_CURTAIN       TIM_CHANNEL_1
​
/* 光敏 ADC */
#define ADC_LIGHT        &hadc1
​
/* 继电器(灯光电源) */
#define RELAY_PORT       GPIOB
#define RELAY_PIN        GPIO_PIN_0
​
/* 蓝牙串口 */
#define BT_UART          &huart1
​
/* 光照阈值(光敏ADC,实测标定:低于此值为昏暗) */
#define LUX_DARK         2500
#define LUX_BRIGHT       1000
​
/* 窗帘角度 */
#define CURTAIN_OPEN     180
#define CURTAIN_CLOSE    0
​
/* 定时开关时间(24h制) */
#define TIMER_ON_HOUR    18
#define TIMER_ON_MIN     0
#define TIMER_OFF_HOUR   23
#define TIMER_OFF_MIN    30
​
#endif

3、sensor.h / sensor.c ------ 光敏传感器模块

sensor.h:

复制代码
#ifndef SENSOR_H
#define SENSOR_H
#include <stdbool.h>
#include <stdint.h>
​
void sensor_init(void);               /* 初始化ADC */
uint16_t sensor_light_read(void);     /* 读取光照ADC值 */
bool sensor_is_dark(void);            /* 判断是否昏暗 */
#endif
sensor.c:

#include "sensor.h"
#include "config.h"
​
void sensor_init(void) {
    HAL_ADC_Start(ADC_LIGHT);        /* 启动ADC连续转换 */
}
​
uint16_t sensor_light_read(void) {
    HAL_ADC_PollForConversion(ADC_LIGHT, 10);   /* 等待转换完成 */
    return HAL_ADC_GetValue(ADC_LIGHT);         /* 返回0~4095 */
}
​
bool sensor_is_dark(void) {
    return sensor_light_read() > LUX_DARK;      /* 超过阈值判昏暗 */
}

4、light.h / light.c ------ 灯光模块(PWM 调光 + 继电器)

light.h:

复制代码
#ifndef LIGHT_H
#define LIGHT_H
#include <stdbool.h>
#include <stdint.h>
​
void light_init(void);
void light_set_brightness(uint8_t percent);  /* 0~100 亮度 */
void light_power(bool on);                   /* 继电器通断 */
#endif
light.c:

#include "light.h"
#include "config.h"
​
void light_init(void) {
    HAL_TIM_PWM_Start(TIM_LIGHT, CH_LIGHT);  /* 启动PWM */
}
​
void light_set_brightness(uint8_t percent) {
    if (percent > 100) percent = 100;
    /* ARR=999,占空比=percent*10 */
    __HAL_TIM_SET_COMPARE(TIM_LIGHT, CH_LIGHT, percent * 10);
}
​
void light_power(bool on) {
    HAL_GPIO_WritePin(RELAY_PORT, RELAY_PIN,
                      on ? GPIO_PIN_SET : GPIO_PIN_RESET);
}

5、curtain.h / curtain.c ------ 窗帘模块(舵机角度)

curtain.h:

复制代码
#ifndef CURTAIN_H
#define CURTAIN_H
#include <stdint.h>
​
void curtain_init(void);
void curtain_set_angle(uint8_t angle);  /* 0~180 角度 */
void curtain_open(void);
void curtain_close(void);
#endif

curtain.c:

复制代码
#include "curtain.h"
#include "config.h"

void curtain_init(void) {
    HAL_TIM_PWM_Start(TIM_CURTAIN, CH_CURTAIN);
    curtain_close();                    /* 默认关帘 */
}

void curtain_set_angle(uint8_t angle) {
    if (angle > 180) angle = 180;
    /* 20ms周期(ARR=1999):0.5ms->0° 对应count=50,
       2.5ms->180° 对应count=250,线性换算 */
    uint32_t cmp = 50 + (uint32_t)angle * 10 / 9;
    __HAL_TIM_SET_COMPARE(TIM_CURTAIN, CH_CURTAIN, cmp);
}

void curtain_open(void)  { curtain_set_angle(CURTAIN_OPEN); }
void curtain_close(void) { curtain_set_angle(CURTAIN_CLOSE); }

6、comm.h / comm.c ------ 蓝牙串口模块

comm.h:

复制代码
#ifndef COMM_H
#define COMM_H

void comm_init(void);   /* 启动串口中断接收 */
#endif

comm.c:

复制代码
#include "comm.h"
#include "config.h"
#include "scene.h"

static uint8_t rxByte;
static char    rxBuf[16];
static uint8_t rxLen = 0;

void comm_init(void) {
    HAL_UART_Receive_IT(BT_UART, &rxByte, 1);  /* 单字节中断接收 */
}

/* 串口接收中断回调:逐字节收,遇到换行执行指令 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
    if (huart == BT_UART) {
        rxBuf[rxLen++] = (char)rxByte;
        if (rxByte == '\n' || rxLen >= sizeof(rxBuf) - 1) {
            rxBuf[rxLen] = '\0';
            scene_execute(rxBuf);               /* 执行场景指令 */
            rxLen = 0;
        }
        HAL_UART_Receive_IT(BT_UART, &rxByte, 1); /* 继续接收 */
    }
}

7、scene.h / scene.c ------ 场景模式

scene.h:

复制代码
#ifndef SCENE_H
#define SCENE_H

void scene_execute(const char *cmd);  /* 解析指令执行场景 */
#endif

scene.c:

复制代码
#include "scene.h"
#include "light.h"
#include "curtain.h"
#include <string.h>

void scene_execute(const char *cmd) {
    /* 手机蓝牙发送的场景指令(可自行扩充) */
    if (strcmp(cmd, "home") == 0) {          /* 回家:高亮 + 开帘 */
        light_power(true);
        light_set_brightness(100);
        curtain_open();
    } else if (strcmp(cmd, "away") == 0) {   /* 离家:关灯 + 关帘 */
        light_power(false);
        light_set_brightness(0);
        curtain_close();
    } else if (strcmp(cmd, "sleep") == 0) {  /* 睡眠:微光 + 关帘 */
        light_power(true);
        light_set_brightness(10);
        curtain_close();
    } else if (strcmp(cmd, "movie") == 0) {  /* 观影:暗光 + 关帘 */
        light_power(true);
        light_set_brightness(30);
        curtain_close();
    }
}

8、main.c ------ 主程序(自动调光 + 定时)

复制代码
#include "main.h"        /* CubeMX 生成的句柄 */
#include "config.h"
#include "sensor.h"
#include "light.h"
#include "curtain.h"
#include "comm.h"

extern TIM_HandleTypeDef htim3;
extern TIM_HandleTypeDef htim4;
extern ADC_HandleTypeDef hadc1;
extern UART_HandleTypeDef huart1;

int main(void) {
    HAL_Init();
    SystemClock_Config();   /* CubeMX 生成:时钟 */
    MX_GPIO_Init();
    MX_TIM3_Init();         /* 灯光 PWM */
    MX_TIM4_Init();         /* 舵机 PWM */
    MX_ADC1_Init();
    MX_USART1_UART_Init();

    sensor_init();
    light_init();
    curtain_init();
    comm_init();

    while (1) {
        /* 自动调光:环境昏暗则开灯提亮,亮则关灯 */
        if (sensor_is_dark()) {
            light_power(true);
            light_set_brightness(100);
        } else {
            light_power(false);
            light_set_brightness(0);
        }
        HAL_Delay(200);     /* 每200ms判断一次 */
    }
}

定时开关用 RTC:在 RTC 闹钟中断回调里读取当前时间,到 TIMER_ON 开灯、到 TIMER_OFF 关灯,逻辑与上面的 on_timer 类似。以上为核心模块代码,其余底层由 CubeMX 生成。

十一、代码要点讲解

  • PWM 调光原理 :定时器 TIM 产生固定频率 PWM,通过改比较值(占空比)控制灯光亮度;ARR=999 时占空比 = 比较值 / 999 × 100%。

  • 舵机角度换算 :SG90 用 50Hz(20ms)PWM,0°~180° 对应脉宽 0.5ms~2.5ms,换算成计数 50 + angle×10/9,改变占空比即可控制窗帘任意角度开合。

  • 串口中断接收 :HAL_UART_Receive_IT 每次收 1 字节进回调,逐字节拼成字符串,遇换行 \n 交给 scene_execute 执行,不阻塞主循环,实时响应手机指令。

  • 场景状态机 :scene_execute 把灯光+窗帘联动封装成「回家/离家/睡眠/观影」4 种模式,手机一条指令完成多设备联动,是答辩的加分亮点。

  • 自动调光阈值 :光敏 ADC 值需实测标定,把 LUX_DARK 设为你实测「昏暗」时的值,避免过亮/过暗误判。

  • 模块化好处 :.h/.c 分离,改调光逻辑只动 light.c、改指令只动 scene.c,方便扩展新场景或新设备。

十二、功能测试与验收

功能 实现方式 测试方法
自动调光 sensor_is_dark() 判断 + light_set_brightness() 用手遮挡光敏,观察灯光自动变亮/变暗
窗帘控制 curtain_set_angle() 舵机 PWM 手机发指令,观察舵机带动窗帘开合
灯光开关 light_power() 继电器 观察继电器吸合、灯光通断
手机控制 蓝牙串口接收 scene_execute() 蓝牙串口助手发 home/away/sleep/movie 指令
场景切换 scene_execute() 联动灯+帘 发 sleep 指令,灯变暗、帘关闭
定时开关 RTC 闹钟 设到点时间,观察自动开/关灯

分步验收清单:

  1. 编译下载后串口打印正常 → 工程 OK;

  2. 遮挡光敏,灯自动变亮、移开变暗 → 自动调光 OK;

  3. 手机蓝牙发 away,灯关、帘关 → 指令解析 + 场景 OK;

  4. 发 movie,灯暗、帘关 → 场景联动 OK;

  5. 设 RTC 到点,灯自动开关 → 定时 OK。

十三、能给你什么启发?

1. 选题优势:贴近日常生活、实物演示效果好、功能模块丰富(调光/舵机/继电器/蓝牙/场景),工作量适中,答辩讲解直观,是「中等难度、稳中有亮点」的选题。

2. 想冲更高分数,随便往这几个方向扩:

  • 升级 WiFi 远程:把蓝牙换 ESP8266/ESP32,接入云平台,实现手机异地远程控制(配合 MQTT);

  • 加语音控制:接语音识别模块,喊话即可控制灯光窗帘,交互更自然;

  • 多路灯光:扩展到多路继电器、多路 PWM,实现全屋多场景联动;

  • 传感器融合:加人体红外,人走自动关灯、人来自动开灯,更节能智能。

十四、开题报告 & 答辩要点

1、开题报告可直接改用的表述

1. 选题依据(背景):随着智能家居普及,用户对灯光和窗帘的自动化、远程化、场景化需求日益增长。传统灯光窗帘需手动操作,无法根据环境光线自动调节、无法远程控制,体验单一。本课题结合单片机控制、传感器感知和无线通信技术,设计一套智能灯光窗帘控制系统,具有现实应用价值。

2. 研究意义:本课题将 STM32 控制、PWM 调光、舵机控制、传感器采集、串口通信等嵌入式关键技术融入日常生活场景,既提升家居智能化与节能水平,也全面锻炼学生软硬件开发、模块化编程与系统调试能力,对巩固专业知识有重要意义。

3. 系统功能概述:系统基于 STM32F103,通过光敏传感器感知环境亮度实现自动调光,用舵机驱动窗帘开合、继电器控制灯光通断,通过蓝牙与手机通信实现远程控制和「回家/离家/睡眠/观影」多场景一键切换,并支持 RTC 定时开关。

4. 创新点(按实际情况选取):

  • 采用 .h/.c 模块化软件架构,代码清晰、易扩展、便于维护;

  • 灯光与窗帘多设备联动,支持场景化一键控制;

  • 自动调光 + 定时 + 远程多模式结合,功能闭环完整。

5. 技术难点:

  • PWM 调光与舵机角度精确控制;

  • 串口中断接收与指令解析的可靠性;

  • 多外设协同(ADC、TIM、UART、RTC)的时序与稳定性。

2、答辩常见问题(参考回答要点)

可能被问 回答要点
为什么选 STM32? Cortex-M3 主流,外设丰富、生态成熟,适合中控类毕设
灯光怎么调光? 定时器输出 PWM,改占空比即改亮度
舵机怎么控制角度? 20ms 周期 PWM,脉宽 0.5~2.5ms 对应 0°~180°,线性换算占空比
手机怎么控制? 蓝牙串口透传,STM32 串口中断接收指令,scene_execute 执行
有哪些改进空间? 换 WiFi 上云、加语音/人体感应、扩展多路设备联动
相关推荐
吴建旭 智宅焕1 小时前
智能家居B端投流获客系统的架构设计与实现:经济性约束、承接链路与交付确定性
智能家居
电子科技圈3 小时前
Arm电机控制开发工具哪家强?
arm开发·单片机·嵌入式硬件·设计模式·软件构建
JasmineX-14 小时前
下位机直接控制57步进电机匀速转动
stm32·单片机·嵌入式硬件
软件技术NINI4 小时前
基于SpringBoot和Vue的摇滚乐鉴赏网站
vue.js·spring boot·后端·spring·html·毕业设计·毕设
abc light4 小时前
ARM 裸机开发(6)——时钟树与定时器
arm开发·单片机·fpga开发
吠品14 小时前
智谱开源 ZCode 之后,真正的考试才开始
单片机·嵌入式硬件·1024程序员节
小李不想当小白18 小时前
SPI通信外设与W25Q64 (硬件SPI)(STM32标准库学习笔记)
笔记·stm32·单片机·嵌入式硬件·学习·嵌入式
LCG米18 小时前
STM32驱动W5500以太网模块实测:TCP吞吐瓶颈定位、TX指针回绕陷阱与断线重连保活落地
stm32·单片机·嵌入式硬件·tcp/ip
创界工坊工作室20 小时前
63-基于STC89C52霍尔传感器的智能化电能表设计
stm32·单片机·嵌入式硬件·51单片机·proteus