【STM32项目开源】STM32单片机智能语音风扇控制系统

目录

一、设计背景和意义

1.1设计背景:

1.2设计意义:

二、实物展示

三、硬件功能介绍

2.1 硬件清单:

2.2 功能介绍:

四、软件设计流程图

五、硬件PCB展示

六、软件主函序展示

七、单片机实物资料

资料获取 查看主页介绍:兆龙电子单片机设计


一、设计背景和意义

1.1设计背景:

在物联网与智慧家居快速发展的当下,传统风扇控制系统存在诸多局限。多数风扇设备仍依赖手动调节,缺乏环境适应性与智能化控制能力,既无法根据室内环境和用户需求自动调节,也难以满足精细化吹风需求。随着人们对使用体验、能耗控制要求提升,单一控制模式已不适用。

现有智能风扇方案常存在功能割裂问题,远程调控、传感器联动、使用场景适配等功能未能有效整合,且成本较高难以普及。基于此,本设计以 STM32F103C8T6 为核心,融合多传感器与语音控制技术,构建低成本、高集成度的智能语音风扇控制系统,以解决传统风扇控制的智能化不足问题。

1.2设计意义:

本设计通过整合多种监测与语音调控技术,具有多重实用价值。从使用体验看,提供远程、按键、APP、语音指令等多元控制方式,满足不同场景下的吹风需求,尤其使用场景适配与自动调节功能提升了使用便捷性。

从节能角度,借助环境监测与用户使用习惯实现按需调速,避免无效能耗,符合绿色家居理念。从技术层面,探索了 STM32 微控制器与语音识别模块协同工作的实现方式,为低成本智能风扇系统开发提供了可参考的集成方案,推动智能风扇技术的普及应用,具有较好的实践与推广价值。

二、实物展示

下方为实物演示视频

【开源】基于STM32单片机智能语音风扇系统

下方为实物展示图片

三、硬件功能介绍

2.1 硬件清单:

  • STM32F103C8T6最小系统
  • OLED显示
  • DS18B20温度传感器
  • HC-SR501人体红外传感器
  • TB6612电机驱动模块
  • JDY-31-SPP蓝牙模块
  • 语音模块
  • 声光报警

2.2 功能介绍:

(1)STM32F103C8T6单片机作为主控单元
(2)温度采集:DS18B20传感器采集环境温度
(3)人体检测:人体红外传感器判断是否有人
(4)屏幕显示:OLED显示温度、有无人、档位、模式等信息
(5)风扇摇头:步进电机模拟风扇摇头
(6)手动模式:按键调节风扇风速
(7)自动模式:判断是否有人以及根据温度控制风扇开关和风速
(8)语音模式:通过语音控制风速、模式以及摇头
(9)定时功能:定时关闭
(10)APP控制:通过蓝牙远程查看数据以及下发控制

四、软件设计流程图

五、硬件PCB展示

六、软件主函序展示

#include "sys.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "math.h"
#include "delay.h"
#include "gpio.h"
#include "key.h"
#include "oled.h"
#include "usart.h"
#include "ds18b20.h"
#include "motor_bujin.h"
#include "timer.h"
#include "motor_dianji.h"/**********************************
变量定义
**********************************/
uint8_t key_num = 0;									//按键扫描标志位	
uint8_t flag_display = 0;							//显示界面标志位
uint32_t time_num = 0;								//10ms计时
char display_buf[32];									//显示数组_Bool flag_mode = 0;									//模式标志位(自动|手动)
_Bool flag_direction = 0;							//摇头标志位
int flag_dir	= 0;short temp_value = 0;                 //温度值
u16 temp_max = 30;                    //温度最大值
u16 temp_min = 20;										//温度最低值s16 motor_pwm = 0;										//电机速度int countdown_hour = 0;								//倒计时时
int countdown_minute = 0;							//倒计时分
int countdown_second = 0;							//倒计时秒
_Bool flag_countdown_begin = 0;				//倒计时开始标志位
_Bool flag_countdown_end = 0;					//倒计时结束标志位
extern _Bool flag_1s;									//1秒到达标志位extern _Bool flag_bujin_foreward;			//步进电机打开标志位
extern _Bool flag_bujin_reversal;			//步进电机关闭标志位
extern _Bool flag_bujin_state;				//步进电机状态标志位extern uint8_t usart1_buf[256];				//串口1接收数组
extern uint8_t usart2_buf[256];				//串口2接收数组
unsigned char   SendString[50];
uint8_t danwei = 0,send_renflag=0,send_modeflag=0,send_YTflag=0;
/**********************************
函数声明
**********************************/
void Key_function(void);							//按键函数
void Monitor_function(void);					//监测函数
void Display_function(void);					//显示函数
void Manage_function(void);						//处理函数/****
*******	主函数 
*****/
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	//配置中断分组为2号
Delay_Init();	    	 								//延时初始化	  
Gpio_Init();		  									//IO初始化
Key_Init();		  										//按键初始化
Oled_Init();		  									//OLED初始化
Oled_Clear_All();										//清屏
while(DS18B20_Init());              //DS18B20初始化
Usart1_Init(9600);  								//串口1初始化
Usart2_Init(9600);  								//串口2初始化
Step_Motor_Init();									//步进电机初始化
TIM2_Init(1000-1,7200-1);						//初始化0.1s的定时器
Motor_Dianji_Init();								//直流电机初始化
TIM_SetCompare1(MOTOR_DIANJI_TIM,motor_pwm);Delay_ms(1000);
Delay_ms(1000);while(1){
Key_function();										//按键函数
Monitor_function();								//监测函数
Display_function();								//显示函数
Manage_function();								//处理函数time_num++;												//计时变量+1
Delay_ms(10);
if(time_num %5 == 0)							//最小系统LED闪烁LED_SYS = ~LED_SYS;
if(time_num >= 5000){time_num = 0;}}
}/****
*******按键函数
*****/
void Key_function(void)
{key_num = Chiclet_Keyboard_Scan(0);					//按键扫描
if(key_num != 0)														//有按键按下{
switch(key_num){
case 1:																	//按键1:切换界面flag_display++;
if(flag_display >= 6)flag_display = 0;Oled_Clear_All();
break;case 2:																	//按键2:加键
switch(flag_display){
case 0:															//界面0:风速切换
if(flag_mode==1){
//flag_mode = 1;motor_pwm+=300;
if(motor_pwm <= 900){
TIM_SetCompare1(MOTOR_DIANJI_TIM,855+motor_pwm/20);  }
else{motor_pwm = 0;
TIM_SetCompare1(MOTOR_DIANJI_TIM,motor_pwm);}}
break;case 1:															//界面1:温度最大值+1
if(temp_max < 99)temp_max++;
break;case 2:															//界面2:温度最小值+1
if(temp_min < temp_max-1)temp_min++;
break;case 3:															//界面3:倒计时时+1
if(countdown_hour < 100)countdown_hour++;
break;case 4:															//界面4:倒计时分+1countdown_minute++;
if(countdown_minute >= 60)countdown_minute = 0;
break;case 5:															//界面5:倒计时秒+1countdown_second++;
if(countdown_second >= 60)countdown_second = 0;
break;default:
break;}
break;case 3:																	//按键3:减键
switch(flag_display){
case 0:															//界面0:摇头模式切换
if(flag_direction == 0)flag_direction = 1;
elseflag_direction = 0;
break;case 1:															//界面1:温度最大值-1
if(temp_max > temp_min+1)temp_max--;
break;case 2:															//界面2:温度最小值-1
if(temp_min > 0)temp_min--;
break;case 3:															//界面3:倒计时时-1
if(countdown_hour > 0)countdown_hour--;
break;case 4:															//界面4:倒计时分-1countdown_minute--;
if(countdown_minute < 0)countdown_minute = 59;
break;case 5:															//界面5:倒计时秒-1countdown_second--;
if(countdown_second < 0)countdown_second = 59;
break;default:
break;}
break;case 4:																//按键4:切换模式
if(flag_display == 0){
if(flag_mode == 0){flag_mode = 1;}
else{flag_mode = 0;}}
break;default:
break;}}
}/****
*******监测函数
*****/
void Monitor_function(void)
{
if(flag_display == 0)																			//测量界面{
if(time_num % 10 == 0)																	//约2s检测一次{temp_value = DS18B20_Get_Temp();                      //获取温度值}if(USART2_WaitRecive() == 0)					//接收语音指令{
if(usart2_buf[0] == 0x01)						//0x01:切换手动模式{flag_mode = 1;}
else if(usart2_buf[0] == 0x02)			//0x02:切换自动模式{flag_mode = 0;}
else if(usart2_buf[0] == 0x03)			//0x03:关摇头{flag_direction = 0;}
else if(usart2_buf[0] == 0x04)			//0x04:开摇头{flag_direction = 1;}
else if(usart2_buf[0] == 0x05)			//0x05:减风速{flag_mode = 1;motor_pwm-=300;
if(motor_pwm > 0){
TIM_SetCompare1(MOTOR_DIANJI_TIM,855+motor_pwm/20);}
else{motor_pwm = 0;
TIM_SetCompare1(MOTOR_DIANJI_TIM,motor_pwm);}}
else if(usart2_buf[0] == 0x06)			//0x06:加风速{flag_mode = 1;motor_pwm+=300;
if(motor_pwm <= 900){
TIM_SetCompare1(MOTOR_DIANJI_TIM,855+motor_pwm/20);}
else{motor_pwm = 900;
TIM_SetCompare1(MOTOR_DIANJI_TIM,motor_pwm);}}
USART2_Clear();}}
}/****
*******显示函数
*****/
void Display_function(void)
{
switch(flag_display)																		//根据不同的显示模式标志位,显示不同的界面{
case 0:																								//界面0:测量界面,显示温度、人体、档位、摇头、倒计时时间
Oled_ShowCHinese(1, 0, "温度:");
sprintf(display_buf,"%d.%dC ",temp_value/10,temp_value%10);
Oled_ShowString(1, 6, display_buf);Oled_ShowCHinese(2, 0, "人体:");
if(HUMAN == 1)
Oled_ShowCHinese(2, 3, "有人");
else
Oled_ShowCHinese(2, 3, "没有");if(motor_pwm == 0)
Oled_ShowCHinese(3, 0, "关闭");
else if(motor_pwm == 300)
Oled_ShowCHinese(3, 0, "一档");
else if(motor_pwm == 600)
Oled_ShowCHinese(3, 0, "二档");
else if(motor_pwm == 900)
Oled_ShowCHinese(3, 0, "三档");if(flag_direction == 1)
Oled_ShowCHinese(3, 5, "摇头开");
else
Oled_ShowCHinese(3, 5, "摇头关");sprintf(display_buf,"%02d:%02d:%02d",countdown_hour,countdown_minute,countdown_second);
Oled_ShowString(4,0,display_buf);if(flag_mode == 0)
Oled_ShowCHinese(4, 5, "自动");
else
Oled_ShowCHinese(4, 5, "手动");
break;case 1:																								//界面1:显示设置温度最大值
Oled_ShowCHinese(1,0,"设置温度最大值");
if(time_num % 5 == 0){
sprintf(display_buf,"%d ",temp_max);
Oled_ShowString(2, 6, display_buf);}
if(time_num % 10 == 0){
Oled_ShowString(2, 6, "    ");}
break;case 2:																								//界面2:显示设置温度最小值
Oled_ShowCHinese(1,0,"设置温度最小值");
if(time_num % 5 == 0){
sprintf(display_buf,"%d ",temp_min);
Oled_ShowString(2, 6, display_buf);}
if(time_num % 10 == 0){
Oled_ShowString(2, 6, "    ");}
break;case 3:																								//界面3:显示设置倒计时时
Oled_ShowCHinese(1,1,"设置倒计时时");
if(time_num % 5 == 0){
sprintf(display_buf,"%02d:%02d:%02d",countdown_hour,countdown_minute,countdown_second);
Oled_ShowString(2,4,display_buf);}
if(time_num % 10 == 0){
Oled_ShowString(2,4,"  ");}
break;case 4:																								//界面4:显示设置倒计时分
Oled_ShowCHinese(1,1,"设置倒计时分");
if(time_num % 5 == 0){
sprintf(display_buf,"%02d:%02d:%02d",countdown_hour,countdown_minute,countdown_second);
Oled_ShowString(2,4,display_buf);}
if(time_num % 10 == 0){
Oled_ShowString(2,7,"  ");}
break;case 5:																								//界面5:显示设置倒计时秒
Oled_ShowCHinese(1,1,"设置倒计时秒");
if(time_num % 5 == 0){
sprintf(display_buf,"%02d:%02d:%02d",countdown_hour,countdown_minute,countdown_second);
Oled_ShowString(2,4,display_buf);}
if(time_num % 10 == 0){
Oled_ShowString(2,10,"  ");}
break;default:
break;}
}/****
*******处理函数
*****/
void Manage_function(void)
{
if(flag_display == 0)																			//测量界面{
if(flag_mode == 0)											//自动模式下,(有人时,温度大于最大值三档、大于中值二档、大于最小值一档,否则关闭){
if((temp_value > temp_max*10) && HUMAN == 1){motor_pwm = 900;
TIM_SetCompare1(MOTOR_DIANJI_TIM,855+motor_pwm/20);}
else if((temp_value > ((temp_max+temp_min)/2)*10) && HUMAN == 1){motor_pwm = 600;
TIM_SetCompare1(MOTOR_DIANJI_TIM,855+motor_pwm/20);}
else if((temp_value > temp_min*10) && HUMAN == 1){motor_pwm = 300;
TIM_SetCompare1(MOTOR_DIANJI_TIM,855+motor_pwm/20);}
else{motor_pwm = 0;
TIM_SetCompare1(MOTOR_DIANJI_TIM,motor_pwm);}}if(countdown_hour != 0 || countdown_minute != 0 || countdown_second != 0)			//通风倒计时不为0flag_countdown_begin = 1;																										//开始倒计时,进入定时器中断if(flag_1s == 1)																															//1s到达{flag_1s = 0;if(countdown_second > 0)																										//倒计时秒>0countdown_second--;																												//倒计时秒-1else//倒计时秒=0{if(countdown_minute > 0)																									//如果倒计时分>0{countdown_minute--;																											//倒计时分-1countdown_second = 59;																									//倒计时秒=59}else//如果倒计时分=0{if(countdown_hour > 0)																									//如果倒计时时>0{countdown_hour--;																											//倒计时时-1countdown_minute = 59;																								//倒计时分=59countdown_second = 59;																								//倒计时秒=59}else//如果倒计时时=0,倒计时结束{flag_countdown_begin = 0;flag_countdown_end = 1;}}}}if(flag_countdown_end == 1)																										//倒计时结束,关闭风扇进入手动模式{flag_countdown_end = 0;motor_pwm = 0;TIM_SetCompare1(MOTOR_DIANJI_TIM,motor_pwm);Beep=1;
Delay_ms(1000);Beep=0;flag_mode = 1;}
if(motor_pwm == 0)flag_direction = 0;
if(flag_direction == 1)																	//如果在摇头模式,步进电机摇头{
if(flag_bujin_state == 0){flag_bujin_foreward = 1;flag_bujin_reversal = 0;}
else{flag_bujin_foreward = 0;flag_bujin_reversal = 1;}}
else{flag_bujin_foreward = 0;flag_bujin_reversal = 0;}}
else//设置界面,关闭风扇{flag_countdown_begin = 0;flag_direction = 0;flag_bujin_foreward = 0;flag_bujin_reversal = 0;motor_pwm = 0;
TIM_SetCompare1(MOTOR_DIANJI_TIM,motor_pwm);}
}

七、单片机实物资料

资料获取 查看主页介绍:兆龙电子单片机设计

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/923625.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/923625.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

git clone vllm

这个错误不是 vLLM 本身的问题&#xff0c;而是 pip 在 clone GitHub 仓库时失败了&#xff1a; error: RPC failed; curl 16 Error in the HTTP2 framing layer fatal: expected flush after ref listing根因通常是&#xff1a; 网络问题&#xff08;访问 GitHub 被中断 / 代理…

光谱相机的新兴领域应用

光谱相机在‌新兴领域‌的应用正快速拓展&#xff0c;结合‌AI、纳米技术、量子传感‌等前沿科技&#xff0c;突破传统检测极限。以下是六大最具潜力的新兴应用方向及技术突破点&#xff1a;‌1. 元宇宙与数字孪生‌‌应用场景‌&#xff1a;‌虚拟材质建模‌&#xff1a;通过高…

深入理解数据结构之复杂度

文章目录1.数据结构前言1.1 数据结构1.2 算法2.算法效率2.1 复杂度的概念2.2 复杂度的重要性3.1 大O的渐进表式法3.2 时间复杂度计算示例3.2.1 示例13.2.2 示例23.2.3 示例33.2.4 示例43.2.5 示例53.2.6 示例63.2.7 示例74.空间复杂度4.1 空间复杂度计算示例4.1.1 示例14.1.2 示…

【Vue3】10-编写vue项目时,ref的应用(2)

合集篇&#xff1a; 1.【Vue3】创建并运行一个简易的Vue3项目 2.【Vue3】编写vue实现一个简单效果&#xff0c;并使用setup糖简化代码 目录refref 定义对象类型的响应式数据1. 概念理解a. 概念b. 分析2. 代码实操代码场景步骤一&#xff1a;导入ref步骤二&#xff1a;修改数据形…

clickhouse 中SUM(CASE WHEN ...) 返回什么类型?

文章目录clickhouse 中SUM(CASE WHEN ...) 返回什么类型&#xff1f;CASE WHENSUM(CASE WHEN ...) 返回什么类型&#xff1f;clickhouse 中SUM(CASE WHEN …) 返回什么类型&#xff1f; CASE WHEN ClickHouse中的CASE WHEN用法与SQL标准中的用法基本相同&#xff0c;用于实现…

【算法】C语言多组输入输出模板

在 C语言 里&#xff0c;“多组输入输出”是很多在线评测系统&#xff08;OJ&#xff09;常见的模式&#xff0c;通常有两种情况&#xff1a;1. 输入到文件结束&#xff08;EOF&#xff09;比如题目没有告诉有多少组数据&#xff0c;就需要一直读直到输入结束。#include <st…

【Ubuntu】sudo apt update出现E :仓库***没有Release文件

【Ubuntu】sudo apt update出现E &#xff1a;仓库***没有Release文件 1 问题描述 在执行sudo apt update更新一下软件包时出现了如下报错 E: 仓库***没有Release 文件。 N: 无法安全地用该源进行更新&#xff0c;所以默认禁用该源。 N:参见apt-secure&#xff08;8&#xf…

全球后量子迁移进展:区域特色与产业落地差异

一、量子威胁具象化&#xff1a;从技术风险到产业冲击量子计算对传统密码体系的威胁已从理论走向现实&#xff0c;其破坏性不仅体现在算法破解效率的飞跃&#xff0c;更渗透到数据全生命周期的安全防护中。以金融领域为例&#xff0c;2024 年国际安全机构模拟实验显示&#xff…

贪心算法应用:决策树(ID3/C4.5)详解

Java中的贪心算法应用&#xff1a;决策树&#xff08;ID3/C4.5&#xff09;详解 决策树是一种常用的机器学习算法&#xff0c;它通过递归地将数据集分割成更小的子集来构建树形结构。ID3和C4.5是两种经典的决策树算法&#xff0c;它们都使用了贪心算法来选择最优的特征进行分割…

华为任旭东:开源协作,激发创新,共创智能世界 | GOSIM HANGZHOU 2025

GOSIM HANGZHOU 2025峰会盛大开幕&#xff0c;华为首席开源联络官、CNCF基金会董事任旭东以《开源协作&#xff0c;激发创新&#xff0c;共创智能世界》为题发表Keynote演讲。颠覆性技术到工业应用的转换时间越来越短&#xff0c;AI技术正在推动传统软件产业的演进&#xff0c;…

本地部署 GPS 跟踪系统 Traccar 并实现外部访问

Traccar 是一款集成了强大的 java 后端服务的 GPS 跟踪系统 。它支持在多种设备使用&#xff0c;在物流运输、资产管理和个人安全等领域应用。本文将详细的介绍如何利用 Docker 在本地部署 Traccar 并结合路由侠实现外网访问本地部署的 Traccar 。 第一步&#xff0c;本地部署…

【开题答辩全过程】以 “川趣玩”旅行团预定微信小程序为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

Android Doze低电耗休眠模式 与 WorkManager

1. Doze模式下&#xff0c;WorkManager setInitialDelay设置小于15分钟&#xff0c;被系统强制到15分钟执行&#xff0c;怎么办 ? Android 拥有两项省电功能&#xff0c;通过管理设备未连接电源时应用的行为来延长用户电池续航时间&#xff1a;低电耗模式 (Doze) 和应用待机模…

iOS 能耗监控与电池优化实战:如何查看App耗电量、分析CPU、GPU内存使用、(uni-app iOS开发性能调试指南)

在 iOS 应用开发中&#xff0c;能耗与电池消耗是用户最直观的体验指标。 即便功能完善&#xff0c;如果 App 存在以下问题&#xff1a; 电池掉电快、设备发热严重&#xff1b;后台任务执行过多&#xff1b;页面渲染与文件操作引发 CPU/GPU 过载&#xff1b;日志或缓存导致频繁 …

Git 本地分支推送多个远程分支

方法一&#xff1a;一次性推送命令 命令格式&#xff1a; git push <远程仓库名> <本地分支引用>:<远程分支名1> <本地分支引用>:<远程分支名2> ...具体步骤&#xff1a; 确保你的代码修改已经提交到了本地分支 git add . git commit -m "你…

抖音私信评论互动消息通知监听自动获取,通过qq机器人转发到qq来通知

抖音私信评论互动消息通知监听自动获取&#xff0c;通过qq机器人转发到qq来通知 如果不是抖音平台&#xff0c;其他平台也类似的&#xff0c;也可以实现&#xff0c;只是目前懒得写了 本期视频点赞过10个就开源代码 有需要的人可以在视频底下留言 需求反馈多的我可以实现

UVM验证工具--gvim

目录 gvim语法高亮 gvim支持git Linux环境自带gvim工具&#xff0c;我们需要做如下设置&#xff1a; 支持UVM、SystemVerilog、verilog语法高亮支持git&#xff08;实时显示对文件的修改&#xff09; gvim语法高亮 gvim支持git

MyBatis 从入门到精通(第二篇)—— 核心架构、配置解析与 Mapper 代理开发

在第一篇博客中&#xff0c;我们掌握了 MyBatis 的基础概念与环境搭建&#xff0c;成功通过简单查询实现了数据持久化。但要真正用好 MyBatis&#xff0c;还需深入理解其 “内部工作原理” 与 “企业级开发规范”。本篇将聚焦三大核心&#xff1a;MyBatis 架构与核心类、全局配…

uniapp+<script setup lang=“ts“>单个时间格式转换(format)

有问题的时间&#xff08;只示例&#xff0c;不是真实数据&#xff09;修改后的时间展示&#xff08;只示例&#xff0c;不是真实数据&#xff09;原代码<view v-else-if"item?.payTime" class"order-info-item">支付时间&#xff1a;item?.payTim…

运维安全05,iptables规则保存与恢复

一&#xff1a;网络安全1.1、昨日功能优化配置后引发的问题&#xff1a;配置iptables后防火墙起到了防护作用&#xff0c;但使用127.0.0.1访问不了数据库了[rootlocalhost /]# mysql -u admin -p -h 127.0.0.1 Enter password:思考&#xff1a;如果使用localhost可以访问吗&…