难度定位 :★★★☆☆(中等)|适合:有一定基础、愿意动手调试、想体现硬件控制能力的同学|预估周期:3~4 周
一、这个毕设是干什么的?
一句话:做一套能根据环境光线自动调节灯光、定时开关,并能用手机远程控制窗帘和灯光的智能家居控制系统。
再展开说:以 STM32F103 为主控,用光敏传感器 感知环境亮度、自动调光,用舵机 拉动窗帘实现自动开合,用继电器 控制灯光通断,通过蓝牙 / WiFi 与手机连接,实现在手机上控制灯光和窗帘、切换多种场景模式(回家、离家、睡眠、观影),并支持定时开关。
二、它解决什么问题?
天气变化、早晚光照不同,灯光要么太亮要么太暗 → 根据环境光线自动调节亮度;
每天手动拉窗帘、开关灯很麻烦,人不在家 灯一直亮 → 定时开关、手机远程控制;
观影、睡眠需要特定氛围,逐个开关很繁琐 → 一键切换「回家 / 离家 / 睡眠 / 观影」场景模式。
本质是:把「手动、单一」的灯光窗帘变成「自动感知 + 定时 + 远程 + 场景化」的智能控制系统,是智能家居里最贴近日常、演示效果最好的方向之一。
三、核心功能?
| 功能 | 说明 |
|---|---|
| 自动调光 | 光敏传感器感知环境亮度,自动调节灯光亮度 |
| 窗帘控制 | 舵机驱动窗帘开合,支持全开/全关/任意角度 |
| 灯光开关 | 继电器控制灯光通断,PWM 实现亮度调节 |
| 手机控制 | 蓝牙 / WiFi 连接手机 APP,远程控制灯和窗帘 |
| 定时开关 | RTC 定时,到点自动开灯 / 关灯 |
| 场景模式 | 回家、离家、睡眠、观影一键切换 |
四、用到哪些技术?
| 类别 | 具体 | 作用 |
|---|---|---|
| 主控 | STM32F103(Cortex-M3) | 处理数据、控制所有外设 |
| 传感器 | 光敏电阻 / 光敏传感器 | 采集环境光照 |
| 执行 | 舵机(窗帘)、继电器(灯光) | 控制窗帘开合、灯光通断 |
| 调光 | TIM PWM 输出 | 调节灯光亮度 |
| 通信 | 蓝牙模块(HC-05)或 WiFi | 与手机通信 |
| 显示/交互 | 手机 APP(蓝牙串口助手等) | 远程控制、场景切换 |
| 开发 | STM32CubeMX + Keil MDK + C 语言 | 编写烧录程序 |
五、系统是怎么工作的?
感知(采光照) → 处理(STM32 判定) → 执行(灯光/窗帘) → 交互(手机控制)
光敏传感器 自动调光/定时 舵机+继电器 蓝牙/场景切换
一句话串起来:光敏传感器采集环境亮度 → STM32 判断是否昏暗并自动调光 → 舵机控制窗帘、继电器控制灯光 → 手机蓝牙下发指令切换场景、定时开关。
这条「感知 → 控制 → 执行 → 人机交互」链路是智能家居控制类毕设的通用骨架,学会它,后续做智能晾衣架、智能门锁、智能鱼缸都是同一套思路。
六、大概怎么做?
买齐硬件(STM32F103C8T6 最小系统板 + 光敏模块 + SG90 舵机 + 继电器 + HC-05 蓝牙 + 灯板);
用 STM32CubeMX 配置引脚、PWM、ADC、串口,生成工程;
在 Keil 里写逻辑代码:光敏采集 → 自动调光 → 舵机窗帘 → 继电器灯光 → 蓝牙指令解析 → 场景切换;
手机装蓝牙串口助手,连接 HC-05,发送指令控制灯光窗帘;
用手遮挡光敏验证自动调光、手机发指令验证场景切换,整条链路跑通即完成。
相比上一篇 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 串口中断接收并执行;用途:手机远程控制、场景切换。
九、开发环境搭建
安装 STM32CubeMX 和 Keil MDK;
CubeMX 新建工程,选芯片 STM32F103C8T6;
配置外设:ADC1(PA0)、TIM3 PWM(PA6)、TIM4 PWM(PB6)、GPIO 输出(PB0)、USART1(蓝牙)、并启用一个定时器/RTC 做定时;
生成 Keil 工程(HAL 库),在
main.c里添加业务逻辑代码;编译下载(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 闹钟 | 设到点时间,观察自动开/关灯 |
分步验收清单:
编译下载后串口打印正常 → 工程 OK;
遮挡光敏,灯自动变亮、移开变暗 → 自动调光 OK;
手机蓝牙发
away,灯关、帘关 → 指令解析 + 场景 OK;发
movie,灯暗、帘关 → 场景联动 OK;设 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 上云、加语音/人体感应、扩展多路设备联动 |