目录
一、项目概述
本项目基于STM32F103C8T6单片机,设计并实现了一款集语音控制、环境监测与蓝牙互联于一体的智能语音台灯。系统通过光敏电阻传感器实时采集环境光照强度,利用超声波传感器检测坐姿距离,并配合光电红外传感器判断人体存在情况。采集到的数据通过OLED屏幕实时显示,包括光照值、坐姿距离、计时时间及有人/无人状态。系统支持按键调节光照与距离阈值,并可在自动与手动模式间切换。自动模式下,当检测到有人且光照低于阈值时自动开灯,并根据环境明暗程度智能调节亮度;当坐姿距离小于设定阈值时,有源蜂鸣器触发报警提醒。手动模式下,用户可通过按键自由调节灯光亮度并控制计时开关。此外,系统搭载SNR8016语音识别模块,支持语音切换模式、调节亮度及控制计时;通过BT04A蓝牙模块与手机APP互联,用户可在APP端查看环境信息、切换模式并下发控制指令,实现远程交互与智能化管理。
二、实现功能
1、功能详解:
主控:STM32F103C8T6系统板。
环境采集:光敏测光照,超声波测坐姿距离,光电红外检测有无人。
显示:OLED显示光照、坐姿距离、计时时间及有无人信息。
阈值调节:按键调节光照阈值与超声波距离阈值。
模式切换:按键切换自动/手动模式。
自动模式:有人且光照低于阈值时开灯,越暗越亮,反之越暗。
手动模式:按键调节灯光亮度,可开关计时功能。
坐姿检测:自动模式下距离小于阈值时蜂鸣器报警。
语音功能:语音控制模式切换、灯光亮度及计时开关。
手机APP:蓝牙连接APP,显示环境信息,切换模式并下发控制。
2、项目清单:
STM32F103C8T6单片机
OLED 屏幕
光敏电阻传感器
光电红外传感器
超声波传感器
SNR8016语音识别模块
大功率LED模块
有源蜂鸣器
BT04A蓝牙模块
3、演示视频:
哔哩哔哩视频链接点击观看:https://www.bilibili.com/video/BV1DRNe6wEvM/?share_source=copy_web&vd_source=f4437c8e4429101e5bf1054c39d5474f
三、硬件介绍
PCB硬件设计:


四、程序设计
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "pwm.h"
#include "control.h"
#include "adc.h"
#include "key.h"
#include "timer.h"
#include "oled.h"
#include <stdio.h>
#include "hc-sr04.h"
#include "timer2.h"
#include "IoData.h"
unsigned char setn=0;
uint8_t keu_num = 0;
uint8_t page_num = 1;
uint8_t option = 0;
uint8_t send = 0;
/**** 数据变量 ****/
int close_flag = 0;
int time_delay = 10; //延时关灯时长
int mask_delay = 0;
int led_time = 0; //使用时长
int power = 0; //档位
int Timing_status = 0; //计时开关
int Beep_status=0;
int light_door = 3000; //光照阈值
int distance_door = 30;//距离阈值
int time_door = 300; //提醒时长
int auto_mode = 0; //auto_mode = 0;表示为手动模式
void get_all_sensor_data();
void Sensor_Data_Handle();
void Key_event_handle(void);
void OLED_Show_OnePage(void); //第一屏显示内容
void OLED_Show_TwoPage(void); //第二屏显示内容
void OLED_Show_ThreePage(void); //第三屏显示内容
void time_limit(void);
void Value_limit(void);
void SysDate_To_mask(void);
void mask_To_Updata(void);
void Blue_tooth_order_handle();
int main(void)
{
SystemInit();//配置系统时钟为72M
delay_init();
uart3_init(9600);
uart1_init(115200);
uart2_init(115200);
OLED_Init();
KEY_Init();
PWM_Init();
PWM_SetCompare2(0);
IoData_Init();
Control_Init();
Adc_Init();
HC_SR04_Init();
Timer2_Init(9,14398);
while(1)
{
Key_event_handle();
if(page_num == 1){
OLED_Show_OnePage();
}else if(page_num == 2){
OLED_Show_TwoPage();
}
get_all_sensor_data();
Sensor_Data_Handle();
if(Time_Period[0]>=500){ //一秒钟
if(Led_Level>0){
if(Timing_status==1){
led_time++;
}
}else led_time = 0;
if(Timing_status==1){
if(led_time>time_door){
Beep=1;delay_ms(100);Beep=0;
}
}
Time_Period[0] = 0;
}
}
}
void Key_event_handle(void)
{
keu_num = KEY_Scan(0);
switch(keu_num)
{
case 1:
if(page_num == 1){
option=0;page_num = 2;
OLED_Clear();OLED_Show_TwoPage();
}else if(page_num==2){
option=0;page_num = 1;
OLED_Clear();OLED_Show_OnePage();
}
break;
case 2:
if(page_num==1){
option++;
if(option>2){
option=0;
}
}else if(page_num==2){
option++;
if(option>3){
option=0;
}
}
break;
case 3:
if(page_num==1&&option==0){
auto_mode =1;
Led_Level=0;
PWM_SetCompare2(2*Led_Level);
}else if(page_num==1&&option==1){
if(Led_Level<100)Led_Level+=10;
PWM_SetCompare2(2*Led_Level);
}else if(page_num==1&&option==2){
Timing_status=1;
}else if(page_num==2&& option == 1){
light_door+=10;
}else if(page_num==2&& option == 2){
distance_door+=1;
}else if(page_num==2&& option == 3){
time_door+=60;
}
break;
case 4:
if(page_num==1&&option==0){
auto_mode =0;
Led_Level=0;
PWM_SetCompare2(2*Led_Level);
}
if(page_num==1&&option==1){
if(Led_Level>0)Led_Level-=10;
PWM_SetCompare2(2*Led_Level);
}else if(page_num==1&&option==2){
Timing_status=0;
}
else if(page_num==2&& option == 1){
light_door-=10;
}
else if(page_num==2&& option == 2){
distance_door-=1;
}
else if(page_num==2&& option == 3){
time_door-=60;
}
break;
}
}
void get_all_sensor_data()
{
Get_Light_Value(&Light_Value);//获取光照数据
HC_SR04_Deboanle(&distance);
Get_Body_Value(&body_status);
}
void Sensor_Data_Handle()
{
if(auto_mode == 1) //如果开启了自动模式则可以实现根据数据的自动控制
{
if(body_status==1){
if(Light_Value<light_door){
Led_Level=100-Light_Value*100/4095;
mask_delay = 0;
}else{
Led_Level=0;
}
if(distance<distance_door)Beep = 1;
else Beep = 0;
}else{
Beep = 0;
Led_Level=0;
}
PWM_SetCompare2(2*Led_Level);
}else if(auto_mode == 0){
if(body_status==1){
if(distance<distance_door && Led_Level>0)Beep = 1;
else Beep = 0;
}else{
Beep = 0;
}
}
}
/*
白(0) 黄(1) 灯(2) 定(3) 倒(4) 计(5) 时(6) 人(7) 体(8) 光(9) 照(10) 强(11) 度(12) 时(13) 间(14) 有(15)
无(16) 开(17) 关(18) 自(19) 手(20) 动(21) 模(22) 式(23) 阈(24) 值(25) 距(26) 离(27) ℃(28)
使(29) 用(30) 时(31) 长(32) 亮(33) 智(34) 能(35) 档(36) 提(37) 醒(38) 延(39) 时(40) 关(41) 灯(42) 后(43)
*/
void OLED_Show_OnePage(void)
{
uint8_t a,b,c,d;
if(option==1){a=0;b=1;c=1;d=1;}
else if(option==2){a=1;b=0;c=1;d=1;}
else if(option==3){a=1;b=1;c=0;d=1;}
else if(option==4){a=1;b=1;c=1;d=0;}
else{a=1;b=1;c=1;d=1;}
if(auto_mode == 1){
OLED_ShowChinese(16*6,16*0,19,16,1);//智能
OLED_ShowChinese(16*7,16*0,21,16,1);
}else if(auto_mode == 0){
OLED_ShowChinese(16*6,16*0,20,16,1);//手动
OLED_ShowChinese(16*7,16*0,21,16,1);
}
OLED_ShowChinese(16*0,0,9,16,1);//光照
OLED_ShowChinese(16*1,0,10,16,1);
OLED_ShowChar(16*2,0,':',16,1);
OLED_ShowNum(16*2+8,0,Light_Value,4,16,1);
OLED_ShowChinese(16*0,16,7,16,1);//人体
OLED_ShowChinese(16*1,16,8,16,1);
OLED_ShowChar(16*2,16,':',16,1);
if(body_status == 1){
OLED_ShowChinese(16*2+8,16,15,16,1); //有
}else if(body_status == 0){
OLED_ShowChinese(16*2+8,16,16,16,1); //无
}
OLED_ShowChinese(16*4,16,26,16,1); //距离
OLED_ShowChinese(16*5,16,27,16,1);
OLED_ShowChar(16*6,16,':',16,1);
OLED_ShowNum(16*6+8,16,distance,3,16,1);
OLED_ShowChinese(16*0,16*2,33,16,1); //亮
OLED_ShowChinese(16*1,16*2,12,16,1); //度
OLED_ShowChar(16*2,16*2,':',16,1);
OLED_ShowNum(16*2+8,16*2,Led_Level,3,16,a);
OLED_ShowChinese(16*4+8,16*2,5,16,1); //亮
OLED_ShowChinese(16*5+8,16*2,6,16,1); //度
OLED_ShowChar(16*6+8,16*2,':',16,1);
if(Timing_status==1){
OLED_ShowChinese(16*7,16*2,17,16,b);
}else {
OLED_ShowChinese(16*7,16*2,18,16,b);
}
OLED_ShowChinese(16*0,16*3,29,16,1); //使
OLED_ShowChinese(16*1,16*3,30,16,1); //用
OLED_ShowChinese(16*2,16*3,31,16,1); //时
OLED_ShowChinese(16*3,16*3,32,16,1); //长
OLED_ShowChar(16*4,16*3,':',16,1);
OLED_ShowNum(16*4+8,16*3,led_time/60,3,16,1);
OLED_ShowChar(16*6,16*3,':',16,1);
OLED_ShowNum(16*6+8,16*3,led_time%60,2,16,1);
OLED_Refresh();
}
void OLED_Show_TwoPage(void)
{
uint8_t a,b,c,d;
if(option==1){a=0;b=1;c=1;d=1;}
else if(option==2){a=1;b=0;c=1;d=1;}
else if(option==3){a=1;b=1;c=0;d=1;}
else if(option==4){a=1;b=1;c=1;d=0;}
else{a=1;b=1;c=1;d=1;}
OLED_ShowChinese(16*0,0,9,16,1); //光
OLED_ShowChinese(16*1,0,10,16,1); //照
OLED_ShowChinese(16*2,0,24,16,1); //阈
OLED_ShowChinese(16*3,0,25,16,1); //值
OLED_ShowChar(16*4,0,':',16,1);
OLED_ShowNum(16*4+8,0,light_door,4,16,a);
OLED_ShowChinese(16*0,16,26,16,1); //距
OLED_ShowChinese(16*1,16,27,16,1); //离
OLED_ShowChinese(16*2,16,24,16,1); //阈
OLED_ShowChinese(16*3,16,25,16,1); //值
OLED_ShowChar(16*4,16,':',16,1);
OLED_ShowNum(16*4+8,16,distance_door,3,16,b);
OLED_ShowChinese(16*0,32,37,16,1); //提
OLED_ShowChinese(16*1,32,38,16,1); //醒
OLED_ShowChinese(16*2,32,31,16,1); //时
OLED_ShowChinese(16*3,32,32,16,1); //长
OLED_ShowChar(16*4,32,':',16,1);
OLED_ShowNum(16*4+8,32,time_door/60,3,16,c);
OLED_Refresh();
}
void light_door_limit(void)
{
if(Led_Level > 100)Led_Level = 100;
else if(Led_Level<0)Led_Level = 0;
}
void Value_limit(void)
{
if(Led_Level >= 100)Led_Level = 100;
else if(Led_Level<=0)Led_Level = 0;
}
五、项目成品效果图

六、项目总结
本项目成功整合了STM32主控、多传感器融合、语音识别与蓝牙通信技术,构建了一套功能完善、交互方式多样的智能台灯系统。硬件方面,各模块(OLED、光敏电阻、光电红外、超声波、SNR8016、LED、蜂鸣器、BT04A)协同工作稳定,实现了环境感知、坐姿监测、语音控制与APP远程交互的完整闭环。软件方面,自动与手动双模式设计兼顾了智能化与个性化需求,阈值可调与蜂鸣器报警提升了实用性与护眼效果。项目验证了STM32在智能家居终端设备中的可行性,也为后续功能扩展(如WiFi联网、数据云端存储)提供了良好基础。整体而言,该系统达到了预期设计目标,具有较高的实用价值和推广意义。
七、包含资料
本资料免费分享,获取全套资料请看主页,并将告诉助手需要资料的项目编号,助手收到消息后,会发送资料给你。
资料获取:查看主页介绍"充哥单片机设计"
文章若对你有所帮助,期待点赞收藏,后续会持续分享各类单片机实战案例。
内容仅作为学习参考,有任何不妥之处,欢迎大家一起探讨!