文章目录
-
- 一、前言
-
- [1.1 技术背景](#1.1 技术背景)
- [1.2 应用场景](#1.2 应用场景)
- [1.3 读者收获](#1.3 读者收获)
- [1.4 技术栈](#1.4 技术栈)
- 二、环境准备
-
- [2.1 硬件要求](#2.1 硬件要求)
- [2.2 模块连接](#2.2 模块连接)
- 三、核心实现
-
- [3.1 PWM调光驱动](#3.1 PWM调光驱动)
- [3.2 人体感应与自动调光](#3.2 人体感应与自动调光)
- [3.3 触摸按键](#3.3 触摸按键)
- [3.4 主控程序](#3.4 主控程序)
- 四、系统架构
- 五、测试验证
-
- [5.1 功能测试](#5.1 功能测试)
- [5.2 性能测试](#5.2 性能测试)
- 六、故障排查
-
- [6.1 LED闪烁](#6.1 LED闪烁)
- [6.2 人体感应误触发](#6.2 人体感应误触发)
- 七、总结
-
- [7.1 核心知识点](#7.1 核心知识点)
- [7.2 扩展方向](#7.2 扩展方向)
一、前言
1.1 技术背景
智能台灯是现代智能家居的重要组成部分,不仅提供基本的照明功能,还集成了亮度调节、色温控制、定时开关、人体感应等智能化功能。通过环境光感应和人体存在检测,智能台灯可以实现自动开关和亮度调节,提供更加舒适和节能的照明体验。
STM32F103系列微控制器凭借其丰富的外设接口、较高的性价比和完善的生态系统,成为智能台灯控制系统的理想选择。
1.2 应用场景
- 学习办公:自动亮度调节,护眼模式
- 卧室床头:人体感应,夜间模式
- 儿童房间:定时关闭,防近视提醒
- 智能家具:语音控制,APP远程控制
1.3 读者收获
完成本教程后,你将掌握:
- PWM调光技术
- 人体红外感应(PIR)
- 环境光检测(光敏电阻/BH1750)
- 触摸按键设计
- 定时器应用
- 低功耗设计
1.4 技术栈
硬件平台:
- 主控芯片:STM32F103C8T6
- 人体感应:HC-SR501 PIR模块
- 环境光检测:BH1750 / 光敏电阻
- 调光方式:PWM + MOS管
- 显示模块:OLED12864
- 通信模块:ESP8266 WiFi
软件工具:
- IDE:Keil MDK-ARM / STM32CubeIDE
- 固件库:STM32Cube HAL库
二、环境准备
2.1 硬件要求
系统框图:
通信模块
LED驱动
传感器组
STM32F103主控
电源系统
PWM1
PWM2
AC 220V
DC 5V
DC 3.3V
TIM2
PWM输出
ADC
I2C1
GPIO
USART1
HC-SR501
人体感应
BH1750
光照强度
触摸按键
冷白光
LED
暖白光
LED
MOS管1
MOS管2
OLED显示
ESP8266
WiFi
硬件清单:
- STM32F103C8T6最小系统板 × 1
- HC-SR501人体感应模块 × 1
- BH1750光照传感器 × 1
- 触摸按键模块 × 3
- 冷白LED灯带 × 1
- 暖白LED灯带 × 1
- IRF540N MOS管 × 2
- OLED12864显示屏 × 1
- ESP8266 WiFi模块 × 1
- 5V电源适配器 × 1
- 杜邦线若干
2.2 模块连接
PWM输出:
- PA0(TIM2_CH1)→ 冷白LED驱动
- PA1(TIM2_CH2)→ 暖白LED驱动
传感器连接:
- PIR输出 → PA2
- BH1750 SCL → PB6
- BH1750 SDA → PB7
三、核心实现
3.1 PWM调光驱动
📄 创建文件:
Inc/led_pwm.h
c
/* led_pwm.h - LED PWM调光驱动 */
#ifndef __LED_PWM_H
#define __LED_PWM_H
#include "main.h"
#define PWM_MAX 1000 /* PWM最大值 */
/* 函数声明 */
void LED_PWM_Init(void);
void LED_SetCold(uint16_t brightness);
void LED_SetWarm(uint16_t brightness);
void LED_SetColorTemp(uint16_t cold, uint16_t warm);
void LED_SetBrightness(uint16_t brightness);
void LED_SetColorTempPercent(uint8_t percent);
void LED_Off(void);
#endif /* __LED_PWM_H */
📄 创建文件:
Src/led_pwm.c
c
/* led_pwm.c - LED PWM调光驱动实现 */
#include "led_pwm.h"
extern TIM_HandleTypeDef htim2;
/**
* @brief PWM初始化
*/
void LED_PWM_Init(void)
{
TIM_OC_InitTypeDef sConfigOC = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 71; /* 72MHz / 72 = 1MHz */
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = PWM_MAX - 1; /* 1kHz PWM频率 */
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_PWM_Init(&htim2);
/* 配置通道1 - 冷白LED */
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1);
/* 配置通道2 - 暖白LED */
HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2);
/* 启动PWM */
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
}
/**
* @brief 设置冷白LED亮度
*/
void LED_SetCold(uint16_t brightness)
{
if (brightness > PWM_MAX) brightness = PWM_MAX;
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, brightness);
}
/**
* @brief 设置暖白LED亮度
*/
void LED_SetWarm(uint16_t brightness)
{
if (brightness > PWM_MAX) brightness = PWM_MAX;
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, brightness);
}
/**
* @brief 设置混合色温
*/
void LED_SetColorTemp(uint16_t cold, uint16_t warm)
{
LED_SetCold(cold);
LED_SetWarm(warm);
}
/**
* @brief 设置总亮度(保持色温比例)
*/
void LED_SetBrightness(uint16_t brightness)
{
static uint16_t current_cold = 500;
static uint16_t current_warm = 500;
if (brightness > PWM_MAX) brightness = PWM_MAX;
/* 按比例调整 */
uint32_t total = current_cold + current_warm;
if (total == 0) total = 1;
uint16_t new_cold = (uint32_t)brightness * current_cold / total;
uint16_t new_warm = brightness - new_cold;
LED_SetCold(new_cold);
LED_SetWarm(new_warm);
}
/**
* @brief 设置色温比例(0-100,0=最冷,100=最暖)
*/
void LED_SetColorTempPercent(uint8_t percent)
{
if (percent > 100) percent = 100;
uint16_t warm = (uint32_t)percent * PWM_MAX / 100;
uint16_t cold = PWM_MAX - warm;
LED_SetColorTemp(cold, warm);
}
/**
* @brief 关闭LED
*/
void LED_Off(void)
{
LED_SetColorTemp(0, 0);
}
3.2 人体感应与自动调光
📄 创建文件:
Src/auto_control.c
c
/* auto_control.c - 自动控制 */
#include "main.h"
#include "led_pwm.h"
#include "bh1750.h"
#define PIR_PIN GPIO_PIN_2
#define PIR_PORT GPIOA
#define LIGHT_THRESHOLD_LOW 50 /* 低于此值开灯 */
#define LIGHT_THRESHOLD_HIGH 200 /* 高于此值关灯 */
#define DELAY_OFF_TIME 30000 /* 无人后30秒关灯 */
/* 状态 */
typedef enum {
MODE_MANUAL, /* 手动模式 */
MODE_AUTO /* 自动模式 */
} LampModeTypeDef;
static LampModeTypeDef lamp_mode = MODE_MANUAL;
static uint8_t lamp_on = 0;
static uint32_t last_pir_time = 0;
static uint16_t target_brightness = 500;
/**
* @brief 初始化PIR
*/
void PIR_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = PIR_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(PIR_PORT, &GPIO_InitStruct);
}
/**
* @brief 检查PIR状态
*/
uint8_t PIR_Check(void)
{
return HAL_GPIO_ReadPin(PIR_PORT, PIR_PIN) == GPIO_PIN_SET;
}
/**
* @brief 自动亮度调节
*/
void Auto_Brightness_Adjust(void)
{
uint16_t light;
uint16_t brightness;
/* 读取环境光 */
if (BH1750_ReadLight(&light) != 0) {
return;
}
/* 根据环境光计算目标亮度 */
/* 环境光越暗,台灯越亮 */
if (light < LIGHT_THRESHOLD_LOW) {
brightness = PWM_MAX; /* 最亮 */
} else if (light > LIGHT_THRESHOLD_HIGH) {
brightness = 0; /* 关闭 */
} else {
/* 线性插值 */
brightness = PWM_MAX * (LIGHT_THRESHOLD_HIGH - light) /
(LIGHT_THRESHOLD_HIGH - LIGHT_THRESHOLD_LOW);
}
target_brightness = brightness;
/* 平滑过渡 */
static uint16_t current_brightness = 0;
if (current_brightness < target_brightness) {
current_brightness += 10;
if (current_brightness > target_brightness) {
current_brightness = target_brightness;
}
} else if (current_brightness > target_brightness) {
current_brightness -= 10;
if (current_brightness < target_brightness) {
current_brightness = target_brightness;
}
}
LED_SetBrightness(current_brightness);
}
/**
* @brief 自动控制任务
*/
void Auto_Control_Task(void)
{
if (lamp_mode != MODE_AUTO) {
return;
}
/* 检测人体 */
if (PIR_Check()) {
last_pir_time = HAL_GetTick();
if (!lamp_on) {
lamp_on = 1;
DEBUG_PRINT("检测到人体,开灯\r\n");
}
}
/* 无人检测 */
if (lamp_on && (HAL_GetTick() - last_pir_time > DELAY_OFF_TIME)) {
lamp_on = 0;
LED_Off();
DEBUG_PRINT("长时间无人,关灯\r\n");
return;
}
/* 自动调光 */
if (lamp_on) {
Auto_Brightness_Adjust();
}
}
/**
* @brief 设置模式
*/
void Lamp_SetMode(LampModeTypeDef mode)
{
lamp_mode = mode;
if (mode == MODE_MANUAL) {
DEBUG_PRINT("切换到手动模式\r\n");
} else {
DEBUG_PRINT("切换到自动模式\r\n");
}
}
/**
* @brief 手动开关灯
*/
void Lamp_Toggle(void)
{
if (lamp_on) {
lamp_on = 0;
LED_Off();
DEBUG_PRINT("手动关灯\r\n");
} else {
lamp_on = 1;
LED_SetBrightness(500);
DEBUG_PRINT("手动开灯\r\n");
}
}
3.3 触摸按键
📄 创建文件:
Src/touch_key.c
c
/* touch_key.c - 触摸按键 */
#include "main.h"
#define KEY_POWER_PIN GPIO_PIN_3
#define KEY_UP_PIN GPIO_PIN_4
#define KEY_DOWN_PIN GPIO_PIN_5
#define KEY_PORT GPIOA
#define KEY_DEBOUNCE 20
#define KEY_LONG_TIME 1000
typedef enum {
KEY_NONE,
KEY_POWER,
KEY_UP,
KEY_DOWN
} KeyTypeDef;
typedef enum {
KEY_STATE_IDLE,
KEY_STATE_PRESS,
KEY_STATE_HOLD
} KeyStateTypeDef;
/* 函数声明 */
void TouchKey_Init(void);
KeyTypeDef TouchKey_Scan(void);
void TouchKey_Process(void);
static KeyStateTypeDef key_state = KEY_STATE_IDLE;
static uint32_t key_press_time = 0;
static KeyTypeDef last_key = KEY_NONE;
/**
* @brief 初始化触摸按键
*/
void TouchKey_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = KEY_POWER_PIN | KEY_UP_PIN | KEY_DOWN_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(KEY_PORT, &GPIO_InitStruct);
}
/**
* @brief 扫描按键
*/
KeyTypeDef TouchKey_Scan(void)
{
if (HAL_GPIO_ReadPin(KEY_PORT, KEY_POWER_PIN) == GPIO_PIN_SET) {
return KEY_POWER;
}
if (HAL_GPIO_ReadPin(KEY_PORT, KEY_UP_PIN) == GPIO_PIN_SET) {
return KEY_UP;
}
if (HAL_GPIO_ReadPin(KEY_PORT, KEY_DOWN_PIN) == GPIO_PIN_SET) {
return KEY_DOWN;
}
return KEY_NONE;
}
/**
* @brief 处理按键
*/
void TouchKey_Process(void)
{
KeyTypeDef key = TouchKey_Scan();
uint32_t current_time = HAL_GetTick();
switch (key_state) {
case KEY_STATE_IDLE:
if (key != KEY_NONE) {
key_state = KEY_STATE_PRESS;
key_press_time = current_time;
last_key = key;
}
break;
case KEY_STATE_PRESS:
if (key == KEY_NONE) {
/* 短按释放 */
key_state = KEY_STATE_IDLE;
/* 执行短按操作 */
switch (last_key) {
case KEY_POWER:
Lamp_Toggle();
break;
case KEY_UP:
/* 增加亮度 */
LED_SetBrightness(target_brightness + 100);
break;
case KEY_DOWN:
/* 降低亮度 */
LED_SetBrightness(target_brightness - 100);
break;
default:
break;
}
} else if ((current_time - key_press_time) > KEY_LONG_TIME) {
/* 长按 */
key_state = KEY_STATE_HOLD;
/* 执行长按操作 */
if (last_key == KEY_POWER) {
/* 长按电源键切换模式 */
Lamp_SetMode(lamp_mode == MODE_MANUAL ? MODE_AUTO : MODE_MANUAL);
}
}
break;
case KEY_STATE_HOLD:
if (key == KEY_NONE) {
key_state = KEY_STATE_IDLE;
} else if (last_key == KEY_UP) {
/* 长按增加亮度 */
LED_SetBrightness(target_brightness + 50);
HAL_Delay(50);
} else if (last_key == KEY_DOWN) {
/* 长按降低亮度 */
LED_SetBrightness(target_brightness - 50);
HAL_Delay(50);
}
break;
}
}
3.4 主控程序
📄 创建文件:
Src/main.c
c
/* main.c - 智能台灯主程序 */
#include "main.h"
#include "led_pwm.h"
#include "bh1750.h"
/* 函数声明 */
void System_Init(void);
/**
* @brief 系统初始化
*/
void System_Init(void)
{
HAL_Init();
SystemClock_Config();
/* 初始化外设 */
MX_GPIO_Init();
MX_TIM2_Init();
MX_I2C1_Init();
MX_USART1_UART_Init();
/* 初始化模块 */
LED_PWM_Init();
BH1750_Init();
PIR_Init();
TouchKey_Init();
DEBUG_PRINT("\r\n===========================\r\n");
DEBUG_PRINT("智能台灯控制系统启动\r\n");
DEBUG_PRINT("===========================\r\n");
}
/**
* @brief 主函数
*/
int main(void)
{
uint32_t last_auto_time = 0;
System_Init();
while (1) {
/* 处理触摸按键 */
TouchKey_Process();
/* 自动控灯任务(每100ms) */
if (HAL_GetTick() - last_auto_time >= 100) {
last_auto_time = HAL_GetTick();
Auto_Control_Task();
}
HAL_Delay(10);
}
}
四、系统架构
短按电源
长按电源
上下键
无按键
有人
无人
是
否
开始
系统初始化
主循环
扫描按键
按键处理
开关灯
切换模式
调节亮度
自动控灯任务
更新显示
检测人体
检测环境光
超时?
自动调光
关灯
五、测试验证
5.1 功能测试
- PWM调光:0-100%亮度调节
- 色温调节:冷白到暖白切换
- 人体感应:检测范围5米
- 自动调光:根据环境光自动调节
5.2 性能测试
- PWM频率:1kHz(无频闪)
- 响应时间:<100ms
- 功耗:<5W
六、故障排查
6.1 LED闪烁
排查:
- 提高PWM频率
- 检查电源滤波
- 增加MOS管驱动能力
6.2 人体感应误触发
优化:
- 调整PIR灵敏度
- 增加延时判断
- 优化安装位置
七、总结
7.1 核心知识点
- PWM调光:频率与占空比控制
- 人体感应:PIR原理与应用
- 自动调光:环境光反馈控制
- 触摸按键:电容触摸原理
7.2 扩展方向
- 添加WiFi远程控制
- 集成语音控制
- 添加定时功能
- 实现场景模式
💡 提示:PWM频率建议>1kHz,避免人眼可见频闪。