当前位置: 首页 > news >正文

STM32项目分享:智能窗帘(机智云)

 一、前言

项目成品图片:

哔哩哔哩视频链接:

https://www.bilibili.com/video/BV1fusnzPEwT/?spm_id_from=333.337.search-card.all.click&vd_source=a90461cae133c0c360a3780433efae62

(资料分享见文末) 

 二、项目简介

1.功能详解

基于STM32的智能窗帘(机智云)

功能如下:

  1. 温湿度采集:使用DHT11温湿度传感器采集环境温湿度
  2. 光照强度采集:通过光敏传感器采集环境光照强度
  3. 一氧化碳浓度采集:通过MQ-7传感器检测一氧化碳浓度
  4. LED照明灯控制:可自动模式下根据环境光强触发或手动模式下按键或APP开关
  5. OLED显示:将检测到的环境数据显示在OLED屏幕上。
  6. 蜂鸣器报警:自动模式下一氧化碳浓度超标或温度超标或湿度超标时控制蜂鸣器报警
  7. JR6001语音模块:提示窗帘当前模式
  8. 阈值调节:可通过按键设置环境温湿度、光照强度阈值、系统时间、定时开启时间以及关闭时间
  9. 模式切换:可通过按键或APP切换模式
  10. 机智云APP:通过手机APP可以显示环境信息,可切换模式和控制指令下发

2.主要器件

  • STM32F103C8T6最小系统板
  •  DHT11温湿度传感器
  •  OLED显示屏(4针IIC协议)
  • ESP8266-01S(WIFI模块)
  • 光敏电阻传感器
  •  MQ-7一氧化碳传感器
  • JR6001语音模块
  •  扬声器
  •  28BYJ51步进电机
  • 蜂鸣器
  • 大功率LED灯

三、原理图设计

四、PCB硬件设计

PCB图 

五、程序设计 

#include "stm32f10x.h"
#include "led.h"
#include "beep.h"
#include "usart.h"
#include "delay.h"
#include "dht11.h"
#include "oled.h"
#include "key.h"
#include "Modules.h"
#include "TIM2.h"
#include "adcx.h"
#include "flash.h"
#include "stepmotor.h"
#include "MyRTC.h"
#include "usart2.h"
#include "usart3.h"
#include "gizwits_product.h"
#include "gizwits_protocol.h"
#include "TIM3.h"/****************异方辰电子工作室******************STM32*文件       :	STM32智能窗帘(机智云版)
*版本	    :	V2.0
*日期	    :	2025.10.17
*MCU	    :	STM32F103C8T6
*接口	    :	见代码
*BILIBILI	:	异方辰电子
*小红书	    :	异方辰电子
*CSDN	    :	异方辰电子
*授权IP	    :	辰哥单片机设计、异方辰、YFC电子、北海单片机设计**********************BEGIN***********************/
/*接线:
光敏--PA0
一氧化碳--PA1
DHT11--PA11
按键1-4:PB12--PB15
步进电机IN1--PB8、IN2--PB9、IN3--PC14、IN4--PC15
LED--PB0
蜂鸣器--PC13
OLED:SCL--PB6、SDA--PB7
蓝牙:RX--PA2、TX--PA3
调试接口RX--PA10、TX--PA9
JR6001:TX--PB11、RX--PB10
*/
#define KEY_Long1	11#define KEY_1	1
#define KEY_2	2
#define KEY_3	3
#define KEY_4	4#define FLASH_START_ADDR	0x0801f000	//写入的起始地址SensorModules sensorData;								//声明传感器数据结构体变量
SensorThresholdValue Sensorthreshold;		//声明传感器阈值结构体变量
DriveModules driveData;									//声明驱动器状态结构体变量uint8_t mode = 0;	//系统模式  1自动  2手动  3设置
u8 dakai;//串口3使用的传递变量
u8 Flag_dakai;//串口3接收标志位
uint8_t is_secondary_menu = 0;  // 0一级菜单,1二级菜单
uint8_t secondary_pos = 1;      // 二级菜单光标位置(1-3对应时/分/秒)
uint8_t secondary_type = 0;   // 二级菜单类型:0=RTC时间,1=定时开启,2=定时关闭uint8_t send_data[] = "A7:00002";//语音播放曲目1
uint8_t send_data1[] = "A7:00003";//语音播放曲目2//系统静态变量
static uint8_t count_a = 1;  //自动模式按键数
uint8_t count_m = 1;  //手动模式按键数
static uint8_t count_s = 1;	 //设置模式按键数int main(void)
{ SystemInit();//配置系统时钟为72M	delay_init(72);ADCx_Init();LDR_Init();DHT11_Init();MQ7_Init();USART1_Config();//串口1初始化PCUSART3_Config();//串口2初始化//语音模块USART2_Config(); //串口3初始化蓝牙LED_Init();BEEP_Init();BEEP_OFF;Key_Init();MOTOR_Init();OLED_Init();userInit();gizwitsInit();TIM3_Int_Init(72-1,1000-1);gizwitsSetMode(WIFI_AIRLINK_MODE); //默认一键配网delay_ms(200);ScanGizwitsMode();//机智云配网模式delay_ms(500);OLED_Clear();//flash读取FLASH_ReadThreshold();if (Sensorthreshold.tempValue > 40 || Sensorthreshold.humiValue >80 || Sensorthreshold.luxValue > 300 || OPEN_HOUR > 23 || OPEN_MINUTE > 59 || CLOSE_HOUR > 23||CLOSE_MINUTE>59||MyRTC_Time[3]>23||MyRTC_Time[4]>59||MyRTC_Time[5]>59){FLASH_W(FLASH_START_ADDR, 35, 80, 100, 20,21,20,22,20,20,00);FLASH_ReadThreshold();}TIM2_Init(72-1,1000-1);MyRTC_Init();	printf("Start \n");USART3_SendString("AF:30");   //音量调到最大delay_ms(300);USART3_SendString("A7:00001");  //欢迎使用delay_ms(1000);while (1){	SensorScan();	//获取传感器数据	userHandle();//上报switch(mode){case AUTO_MODE:if(SetAuto() ==1 ){OLED_autoPage1();	//显示主页面1固定信息SensorDataDisplay1();	//显示传感器1数据}else{OLED_autoPage2();	//显示主页面2固定信息SensorDataDisplay2();	//显示传感器2数据}AutoControl();/*按键1按下时切换模式*/if (KeyNum == KEY_1)   //系统模式mode  1自动  2手动  3设置{KeyNum = 0;mode = MANUAL_MODE;count_m = 1;OLED_Clear();}if (KeyNum == KEY_Long1){KeyNum = 0;mode = SETTINGS_MODE;count_s = 1;OLED_Clear();}Control_Manager();userHandle();//上报gizwitsHandle((dataPoint_t *)&currentDataPoint);//下发break;case MANUAL_MODE:OLED_manualOption(SetManual());ManualControl(SetManual());if (SetManual() <= 4)		{	OLED_manualPage1();ManualSettingsDisplay1();}if (KeyNum == KEY_1)   //系统模式mode  0手动  1自动(默认){KeyNum = 0;mode = AUTO_MODE;count_a = 1;OLED_Clear();}Control_Manager();userHandle();//上报gizwitsHandle((dataPoint_t *)&currentDataPoint);//下发break;case SETTINGS_MODE:
{// 1. 静态变量:标记页面固定文字是否已初始化(避免重复绘制)static uint8_t is_threshold_page_inited = 0;  // 阈值页面(case2-4)文字初始化标记static uint8_t is_timing_page_inited = 0;     // 定时页面(case5-6)文字初始化标记static uint8_t first_enter_case5 = 1;         // 定时开启页面首次进入清屏标记static uint8_t first_enter_case6 = 1;         // 定时关闭页面首次进入清屏标记uint8_t old_count_s = count_s;                // 切换前页面编号(用于判断跨页面)uint8_t curr_count_s = SetSelection();        // 当前页面编号(含KEY2切换逻辑)uint8_t refresh_needed = 1;                   // 动态元素刷新标志uint8_t sys_time_back_refresh = 0;            // 系统时间二级菜单返回刷新标志// -------------------------- 二级菜单逻辑(时/分/秒调整) --------------------------if (is_secondary_menu == 1){//-------------------------------------2// 按键2:切换光标位置(时→分→秒 / 时→分)if (KeyNum == KEY_2){KeyNum = 0;secondary_pos++;							//移动光标// 清除旧光标(仅操作光标区域,不碰文字)--移动光标switch(secondary_type)																//secondary_type--KEY3改变{case 0: // RTC时间:清除时/分/秒光标OLED_ShowChar(30, 16, ' ', 16, 1);OLED_ShowChar(62, 16, ' ', 16, 1);OLED_ShowChar(94, 16, ' ', 16, 1);secondary_pos = (secondary_pos > 3) ? 1 : secondary_pos;break;case 1: // 定时开启:清除时/分光标case 2: // 定时关闭:清除时/分光标OLED_ShowChar(80, (secondary_type==1?0:32), ' ', 16, 1);OLED_ShowChar(112, (secondary_type==1?0:32), ' ', 16, 1);secondary_pos = (secondary_pos > 2) ? 1 : secondary_pos;break;}}//-------------------------------------1// 按键3:数值+1else if (KeyNum == KEY_3){KeyNum = 0;switch(secondary_type){case 0: // RTC时间调整switch(secondary_pos){case 1: MyRTC_Time[3] = (MyRTC_Time[3]+1)%24; break; // 时+1case 2: MyRTC_Time[4] = (MyRTC_Time[4]+1)%60; break; // 分+1case 3: MyRTC_Time[5] = (MyRTC_Time[5]+1)%60; break; // 秒+1}MyRTC_SetTime(); // 写入硬件时钟break;case 1: // 定时开启调整if (secondary_pos == 1) OPEN_HOUR = (OPEN_HOUR+1)%24;else OPEN_MINUTE = (OPEN_MINUTE+1)%60;break;case 2: // 定时关闭调整if (secondary_pos == 1) CLOSE_HOUR = (CLOSE_HOUR+1)%24;else CLOSE_MINUTE = (CLOSE_MINUTE+1)%60;break;}}// 按键4:数值-1else if (KeyNum == KEY_4){KeyNum = 0;switch(secondary_type){case 0: // RTC时间调整switch(secondary_pos){case 1: MyRTC_Time[3] = (MyRTC_Time[3]+23)%24; break; // 时-1case 2: MyRTC_Time[4] = (MyRTC_Time[4]+59)%60; break; // 分-1case 3: MyRTC_Time[5] = (MyRTC_Time[5]+59)%60; break; // 秒-1}MyRTC_SetTime(); // 写入硬件时钟break;case 1: // 定时开启调整if (secondary_pos == 1) OPEN_HOUR = (OPEN_HOUR+23)%24;else OPEN_MINUTE = (OPEN_MINUTE+59)%60;break;case 2: // 定时关闭调整if (secondary_pos == 1) CLOSE_HOUR = (CLOSE_HOUR+23)%24;else CLOSE_MINUTE = (CLOSE_MINUTE+59)%60;break;}}// 按键1:返回一级菜单(仅刷新动态元素,不重绘固定文字)else if (KeyNum == KEY_1){KeyNum = 0;// 系统时间二级菜单返回:清除二级菜单残留if (secondary_type == 0){sys_time_back_refresh = 1;OLED_Clear();}// 定时二级菜单返回:清除光标else{OLED_ShowChar(80, (secondary_type==1?0:32), ' ', 16, 1);OLED_ShowChar(112, (secondary_type==1?0:32), ' ', 16, 1);}// 重绘一级菜单动态元素(不重绘固定文字)if (curr_count_s >= 1 && curr_count_s <= 4){OLED_settingsPage1(); SettingsThresholdDisplay1(); // 刷新阈值数据OLED_settingsOption(curr_count_s); // 刷新光标}else if (curr_count_s >=5 && curr_count_s <=6){SettingsThresholdDisplay2(); // 刷新定时数据OLED_settingsOption(curr_count_s); // 刷新光标}else if (curr_count_s == 1){// 完整重绘case1对应的一级菜单内容(固定文字+数据+光标)OLED_settingsPage1();          // 绘制“温度阈值”等固定文字(覆盖二级残留)SettingsThresholdDisplay1();   // 刷新阈值数据OLED_settingsOption(curr_count_s); // 刷新case1的光标(“系统时间”行左侧“>”)}is_secondary_menu = 0; // 退出二级菜单secondary_pos = 1;refresh_needed = 1;}// 显示二级菜单动态内容(光标+数据)if (is_secondary_menu == 1){switch(secondary_type){case 0: // RTC时间设置界面OLED_settingsPage3(); // 仅绘制时间设置框架(固定文字,仅1次)SettingsThresholdDisplay3(); // 刷新时间数据// 绘制当前光标switch(secondary_pos){case 1: OLED_ShowChar(30, 16, 'v', 16, 1); break;case 2: OLED_ShowChar(62, 16, 'v', 16, 1); break;case 3: OLED_ShowChar(94, 16, 'v', 16, 1); break;}break;case 1: // 定时开启设置界面SettingsThresholdDisplay2(); // 刷新定时数据OLED_ShowChar(80, 0, (secondary_pos==1?'v':' '), 16, 1); // 时光标OLED_ShowChar(112, 0, (secondary_pos==2?'v':' '), 16, 1); // 分光标break;case 2: // 定时关闭设置界面SettingsThresholdDisplay2(); // 刷新定时数据OLED_ShowChar(80, 32, (secondary_pos==1?'v':' '), 16, 1); // 时光标OLED_ShowChar(112, 32, (secondary_pos==2?'v':' '), 16, 1); // 分光标break;}}// 执行刷新(仅动态元素)if (sys_time_back_refresh || refresh_needed){OLED_Refresh();sys_time_back_refresh = 0;refresh_needed = 0;}}// -------------------------- 一级菜单逻辑(阈值/定时页面切换) --------------------------else{// 1. 固定文字初始化:仅在首次进入或跨页面切换时绘制(不重复刷新)// 阈值页面(case2-4):绘制“温度阈值”“湿度阈值”等固定文字if (curr_count_s >= 1 && curr_count_s <= 4){if (is_threshold_page_inited == 0 || old_count_s >= 5){OLED_settingsPage1(); // 仅绘制1次固定文字is_threshold_page_inited = 1; // 标记已初始化is_timing_page_inited = 0;    // 重置定时页面标记}}// 定时页面(case5-6):绘制“定时开启”“定时关闭”等固定文字else if (curr_count_s >= 5 && curr_count_s <= 6){if (is_timing_page_inited == 0 || old_count_s <= 4){if (first_enter_case5 && curr_count_s ==5) // 首次进入定时开启页面{OLED_Clear();first_enter_case5 = 0;}if (first_enter_case6 && curr_count_s ==6) // 首次进入定时关闭页面{OLED_Clear();first_enter_case6 = 0;}OLED_settingsPage2(); // 仅绘制1次固定文字is_timing_page_inited = 1;  // 标记已初始化is_threshold_page_inited = 0;// 重置阈值页面标记}}// 2. 仅刷新动态元素:光标 + 数据(不碰固定文字)OLED_settingsOption(curr_count_s); // 刷新光标位置(仅左侧1列,不覆盖文字)// 阈值页面(case2-4):处理数值修改并刷新数据if (curr_count_s >= 1 && curr_count_s <= 4){ThresholdSettings(curr_count_s); // KEY3/KEY4修改阈值SettingsThresholdDisplay1();     // 仅刷新阈值数值(不绘制文字)OLED_Refresh();                  // 仅更新光标和数值到屏幕}// 定时页面(case5-6):刷新定时数据else if (curr_count_s >=5 && curr_count_s <=6){SettingsThresholdDisplay2();     // 仅刷新定时时间(不绘制文字)OLED_Refresh();                  // 仅更新光标和数值到屏幕}// 3. 进入二级菜单:仅切换状态,不重绘固定文字// 系统时间二级菜单(case1)if (curr_count_s == 1 && KeyNum == KEY_3){KeyNum = 0;OLED_Clear(); OLED_Refresh(); is_secondary_menu = 1;secondary_type = 0; // 标记为RTC时间菜单secondary_pos = 1;}// 定时开启二级菜单(case5)else if (curr_count_s == 5 && KeyNum == KEY_3){KeyNum = 0;is_secondary_menu = 1;secondary_type = 1; // 标记为定时开启菜单secondary_pos = 1;}// 定时关闭二级菜单(case6)else if (curr_count_s == 6 && KeyNum == KEY_3){KeyNum = 0;is_secondary_menu = 1;secondary_type = 2; // 标记为定时关闭菜单secondary_pos = 1;}// 4. 按键1:返回自动模式并保存所有设置if (KeyNum == KEY_1){KeyNum = 0;mode = AUTO_MODE;count_a = 1;OLED_Clear();OLED_Refresh();// 保存阈值、定时时间、RTC时间到FLASHFLASH_W(FLASH_START_ADDR, Sensorthreshold.tempValue, Sensorthreshold.humiValue,Sensorthreshold.luxValue, OPEN_HOUR, OPEN_MINUTE, CLOSE_HOUR, CLOSE_MINUTE,MyRTC_Time[3], MyRTC_Time[4], MyRTC_Time[5]);// 重置所有页面初始化标记(下次进入重新初始化)is_threshold_page_inited = 0;is_timing_page_inited = 0;first_enter_case5 = 1;first_enter_case6 = 1;}}
}userHandle();//上报gizwitsHandle((dataPoint_t *)&currentDataPoint);//下发
break;
default: break;}userHandle();//上报gizwitsHandle((dataPoint_t *)&currentDataPoint);//下发}
}

六、实验效果 

 七、包含内容

  项目分享

http://www.dtcms.com/a/585047.html

相关文章:

  • web网页开发,在线%商城,电商,商品购买%系统demo,基于vscode,apache,html,css,jquery,php,mysql数据库
  • 国外免费服务器地址优速网站建设优化seo
  • jmeter 分布式压测
  • 黑马JAVAWeb-11 请求参数为数组-XML自动封装-XML手动封装-增删改查-全局异常处理-单独异常分别处理
  • 算法通关指南:数据结构和算法篇 --- 队列相关算法题》--- 1. 【模板】队列,2. 机器翻译
  • 招聘决策新变革:判断型 AI 的应用与价值
  • 缓存三大问题深度解析:穿透、击穿与雪崩
  • 如何开公司做网站百度官方营销推广平台加载中
  • Linux:make自动化和实战演练
  • Qt实战:自定义搜索跳转控件 | 附完整源码
  • nanochat大语言模型讲解一
  • Vue3:watch与watchEffect的异同
  • 做网站代理wordpress文章半透明
  • (论文速读)LyT-Net:基于YUV变压器的轻量级微光图像增强网络
  • 操作系统?进程!!!
  • Diffusion 到 Flow Matching ( 从 DDPM 到 Stable Diffusion ) 丝滑入门
  • 无监督学习与互信息
  • 数据集预处理:规范化和标准化
  • vue学习之组件与标签
  • 软件测试之bug分析定位技巧
  • Rust 练习册 :Pig Latin与语言游戏
  • Tomcat的基本使用作用
  • 完整网站建设教程网站建设需要会什么软件
  • 【ASP.Net MVC 】使用Moq让单元测试变得更简单
  • Linux:线程的概念与控制
  • 零基础学AI大模型之嵌入模型性能优化
  • 【二叉搜索树】:程序的“决策树”,排序数据的基石
  • Canvas/SVG 冷门用法:实现动态背景与简易数据可视化
  • 昆明做网站做的好的公司智能建站系统 网站建设的首选
  • kali安装npm/sourcemap