## 题目要求
技术要求
(1)雨滴传感器模块:用于检测雨滴;
(2)光线强度传感器模块:用于检测光线强度;
(3)红外接收模块和蓝牙模块,用于遥控控制;
(4)步进电机模块:用于窗户窗帘驱动。
技术指标
(1)可以通过红外遥控与语音设置是否打开自动模式;
(2)在自动模式下,当光照强度超过设定阈值时,自动展开窗帘;当光照强度低于设定阈值时,自动关闭窗帘;
(3)在自动模式下,当检测到大量雨滴值超过设定阈值时,自动展开窗帘,此优先级比光照检测高;
(4)可以通过板载的旋转编码器调节各参数阈值的大小,并在板载OLED屏幕上显示,若设定参数时为自动模式,则关闭自动模式
(5)主控芯片接收到数据后,驱动电机运转,现实智能窗帘窗户系统。
(6)可以通过板载的编码器调节自动或手动模式
## 原理图设计说明
### 主控电路
![主控电路.png](//image.lceda.cn/pullimage/dv2bOW3XepSthDOWv97bdi2T3Z4fjGXRSdnIhpKb.png)
### 光线传感器
![光线传感器.png](//image.lceda.cn/pullimage/UBZAdHvVT2OQNveyRHMmXgsbWiGCBB5LWAnvSKu7.png)
![光线传感器模块实物图.png](//image.lceda.cn/pullimage/AXOgypgnwCBCAIxxGNmByCgAUB4o6uGfPGLIPZCi.png)
![光敏电阻商城图片.png](//image.lceda.cn/pullimage/CjYZ2EGDOaTLFcfOEKBtQ7mRTTz0FFS57xIEiiG1.png)
### 雨滴传感器
![雨滴传感器.png](//image.lceda.cn/pullimage/zmaujCrf1xCgikOUaU1Q7d1mfuwHtMTzqtFemSUi.png)
![雨滴传感器实物图.png](//image.lceda.cn/pullimage/HTMaOB7KcJK5GQPUm4FIfqHLYQpWDVNcG2W0Khf4.png)
![雨滴传感器商家.png](//image.lceda.cn/pullimage/M46bPM8k10WRZsFR1ydRMn6I1jNIoNMnyM14pTc8.png)
### 红外检测模块
![红外模块.png](//image.lceda.cn/pullimage/vVY9gN326QfEviddEOmMFlkIpRufueGfQRFiIaPQ.png)
![红外模块实物图.png](//image.lceda.cn/pullimage/lJKJhDPBYVgXRBRNqauH873nS5tc7eomkJx8rWRp.png)
![红外接收头商城.png](//image.lceda.cn/pullimage/jdloYdqWLrIOS1BQmWFND5H8xQfK0rJmnR7KR8FK.png)
### 语音识别模块
![语音识别模块.png](//image.lceda.cn/pullimage/1zTUEdYBJ91d9pOZaXmLi0ubVd032bS93fV28eyB.png)
![语音识别模块实物.png](//image.lceda.cn/pullimage/myNYTHXXHYaNJGa02Vdm2VvcrtTcPBE3xRmheLeW.png)
![语音识别模块商城.png](//image.lceda.cn/pullimage/hCw6BqWRGvSSHZSOvB2VatQx8LHPm0TDr9kLFDNA.png)
### 板载调试模块
![编码器电路.png](//image.lceda.cn/pullimage/9jgqHa8QCJPz49KsTPHK45sFbxaupiPf0TdPt72F.png)
旋转编码器
![OLED屏幕.png](//image.lceda.cn/pullimage/Zv9pQstQPGpMXgr4UFWj1stqxS8m06rLxvH0Pbfu.png)
OLED显示屏
![板载调试模块实物.png](//image.lceda.cn/pullimage/g5FfvtnrW4E6QDs56jxISwSoCTI0aK6bfyS3gEkE.png)
### 板载指示灯模块
![指示灯电路.png](//image.lceda.cn/pullimage/U20LnED5ZJzB5UjmThI4Fs4Ack1D6ZjfplPRucFk.png)
![指示灯实物.png](//image.lceda.cn/pullimage/UyQumKtHeUtWoSsE0hbLT6pvROn32lHinFa6gYiJ.png)
## PCB设计
![PCB_LAYOUT.png](//image.lceda.cn/pullimage/rLrhBKDQzCbFFpjXtXgFcc0AaJXaNpQcHjkeFcff.png)
![彩色丝印.png](//image.lceda.cn/pullimage/KUUX5A1zQ8zi9aHWZHJuj1yr9VIYDIFjA9UyL89Q.png)
![PCB正面.jpg](//image.lceda.cn/pullimage/GXtxlZ5nFR7MMCM5UIkQlYqDI8r44Wf9KsF8Ya9Q.jpeg)
![PCB背面.jpg](//image.lceda.cn/pullimage/2IySxqFYbbRn73WyT3YXAeWX9rHAIWjnONGwsUZx.jpeg)
## 软件说明
#### 主程序
```
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "ec11.h"
#include "oled.h"
#include "light_adc.h"
#include <djcd.h>
#include "step_moter.h"
#include "mode_change.h"
#include "bsp_voice.h"
#include "bsp_ir_receiver.h"
int main(void)
{
int nemu_num = 0; //页面切换参数
systick_config(); //滴答定时器初始话
OLED_Init(); //OLED屏幕初始化
EC11_Config(); //旋转编码器配置
ld_adc_config(); //雨滴传感器、光线传感器配置
led_gpio_config(); //指示灯初配置
stepper_motor_config(); //步进电机配置
OLED_Clear(); //OLED清屏
curtain_reset(); //窗帘初始化
mode_change_config(); //模式转换初始化
infrared_goio_config(); //红外引脚配置
hlk_usart_init(9600); //语音识别串口配置
voice_timer_config(); //语音识别定时器设置
timer_IR_config(); //红外检测定时器设置
while(1) {
if (nemu_num == 0) nemu_num = nemu_main();
if (nemu_num == 1) nemu_num = nemu1();
if (nemu_num == 2) nemu_num = nemu2();
if (nemu_num == 3) nemu_num = nemu3();
if (nemu_num == 4) nemu_num = nemu4();
if (nemu_num == 5) nemu_num = nemu6();
}
}
```
#### 多级菜单
```
#include "djcd.h"
#include "bsp_voice.h"
#include "step_moter.h"
int nemu_main(void)
{
int nemu_num = 1;
OLED_Clear();
OLED_ShowString(35,0,"Welcome",16,1);//6*8 “ABC”
OLED_ShowString(15,16,"Set numerical",16,1);//12*24 “ABC”
OLED_ShowString(15,32,"Show numerical",16,1);//12*24 “ABC”
OLED_ShowString(15,48,"Mode Change",16,1);//12*24 “ABC”
OLED_Refresh();
while(1)
{
nemu_num = turn_state;
if (nemu_num < 0)
{
turn_state = 17;
} else if (nemu_num >= 1 && nemu_num < 9)
{
nemu_num = 1;
} else if (nemu_num >= 9 && nemu_num <17)
{
nemu_num = 2;
} else if (nemu_num >= 17 && nemu_num < 19)
{
nemu_num = 3;
} else if (nemu_num >= 19)
{
turn_state = 1;
}
switch(nemu_num)
{
case 1:
OLED_ShowString(0,16,"*",16,1);
OLED_ShowString(0,32," ",16,1);
OLED_ShowString(0,48," ",16,1);
OLED_Refresh();
break;
case 2:
OLED_ShowString(0,16," ",16,1);
OLED_ShowString(0,32,"*",16,1);
OLED_ShowString(0,48," ",16,1);
OLED_Refresh();
break;
case 3:
OLED_ShowString(0,16," ",16,1);
OLED_ShowString(0,32," ",16,1);
OLED_ShowString(0,48,"*",16,1);
OLED_Refresh();
break;
}
motor_stop();
if (KEY_state != 0)
{
KEY_state = 0;
return nemu_num;
}
}
}
int nemu1(void)
{
unsigned char auto_mode_report[5] = { 0XAA, 0X55, 0X01, 0X55, 0XAA };
//播报【当前为手动模式】语音
unsigned char manual_mode_report[5] = { 0XAA, 0X55, 0X02, 0X55, 0XAA };
int nemu_num = 1;
int temp = 1;
OLED_Clear();
OLED_ShowString(15,0,"Set numerical",16,1);
OLED_ShowString(0,16,"light num",16,1);
OLED_ShowString(0,32,"wet num",16,1);
OLED_ShowString(0,48,"Turn Back",16,1);
OLED_Refresh();
KEY_state = 0;
while(1)
{
OLED_ShowNum(80,16,light_taget,4,16,1);
OLED_ShowNum(80,32,wet_taget,4,16,1);
nemu_num = turn_state;
if (nemu_num < 0)
{
turn_state = 17;
} else if (nemu_num >= 1 && nemu_num < 9)
{
nemu_num = 1;
} else if (nemu_num >= 9 && nemu_num <17)
{
nemu_num = 2;
} else if (nemu_num >= 17 && nemu_num < 19)
{
nemu_num = 3;
} else if (nemu_num >= 19)
{
turn_state = 1;
}
switch(nemu_num)
{
case 1:
OLED_ShowString(0,32,"wet num",16,1);
OLED_ShowString(0,48,"Turn Back",16,1);
if (temp == 0)
{
temp = 1;
OLED_ShowString(0,16,"light num",16,1);
OLED_Refresh();
}else {
temp = 0;
OLED_ShowString(0,16,"light num",16,0);
OLED_Refresh();
}
delay_1ms(500);
if (KEY_state != 0)
{
OLED_ShowString(0,16,"light num",16,1);
if (AUTO_state == 1)
{
AUTO_state = 0;
hlk_usart_send_string(manual_mode_report, 5);
}
while(KEY_state == 1)
{
turn_state = 0;
OLED_ShowNum(80,16,light_taget,4,16,1);
OLED_Refresh();
delay_1ms(500);
OLED_ShowNum(80,16,light_taget,4,16,0);
OLED_Refresh();
delay_1ms(500);
light_taget = light_taget + turn_state;
if (KEY_state != 1)
{
KEY_state = 0;
turn_state = nemu_num;
break;
}
}
}
break;
case 2:
delay_1ms(50);
OLED_ShowString(0,32,"wet num",16,1);
OLED_ShowString(0,48,"Turn Back",16,1);
if (temp == 0)
{
temp = 1;
OLED_ShowString(0,32,"wet num",16,1);
OLED_Refresh();
}else {
temp = 0;
OLED_ShowString(0,32,"wet num",16,0);
OLED_Refresh();
}
delay_1ms(500);
if (KEY_state != 0)
{
OLED_ShowString(0,32,"wet num",16,1);
if (AUTO_state == 1)
{
AUTO_state = 0;
hlk_usart_send_string(manual_mode_report, 5);
}
while(KEY_state > 0)
{
turn_state = 0;
OLED_ShowNum(80 ,32,wet_taget,4,16,1);
OLED_Refresh();
delay_1ms(500);
OLED_ShowNum(80,32,wet_taget,4,16,0);
OLED_Refresh();
delay_1ms(500);
wet_taget = wet_taget + turn_state;
if (KEY_state != 1)
{
KEY_state = 0;
turn_state = nemu_num;
break;
}
}
}
break;
case 3:
OLED_ShowString(0,16,"light num",16,1);
OLED_ShowString(0,32,"wet num",16,1);
if (temp == 0)
{
temp = 1;
OLED_ShowString(0,48,"Turn Back",16,1);
OLED_Refresh();
}else {
temp = 0;
OLED_ShowString(0,48,"Turn Back",16,0);
OLED_Refresh();
}
delay_1ms(500);
if (KEY_state != 0)
{
KEY_state = 0;
return 0;
}
break;
}
motor_stop();
}
}
int nemu2(void)
{
OLED_Clear();
OLED_ShowString(10,0,"Show numerical",16,1);
OLED_ShowString(0,16,"light_num",16,1);
OLED_ShowString(0,32,"wet_num",16,1);
OLED_ShowString(0,48,"Turn Back",16,1);
OLED_Refresh();
while(1)
{
OLED_ShowNum(80,16,light_num,4,16,1);
OLED_ShowNum(80,32,wet_num,4,16,1);
OLED_Refresh();
delay_1ms(500);
if (KEY_state != 0)
{
KEY_state = 0;
return 0;
}
motor_stop();
}
}
int nemu3(void)
{
int nemu_num = 1;
OLED_Clear();
OLED_ShowString(20,0,"Mode change",16,1);
OLED_ShowString(0,16,"Now mode",16,1);
OLED_ShowString(0,32,"Change mode",16,1);
OLED_ShowString(0,48,"Turn Back",16,1);
OLED_Refresh();
turn_state = 1;
while(1)
{
nemu_num = turn_state;
if (nemu_num < 0)
{
turn_state = 17;
} else if (nemu_num >= 1 && nemu_num < 9)
{
nemu_num = 1;
} else if (nemu_num >= 9 && nemu_num <17)
{
nemu_num = 2;
} else if (nemu_num >= 17 && nemu_num < 19)
{
nemu_num = 3;
} else if (nemu_num >= 19)
{
turn_state = 1;
}
switch(nemu_num)
{
case 1:
OLED_ShowString(100,16,"<-",16,1);
OLED_ShowString(100,32," ",16,1);
OLED_ShowString(100,48," ",16,1);
OLED_Refresh();
if (KEY_state != 0)
{
KEY_state = 0;
return 4;
}
break;
case 2:
OLED_ShowString(100,16," ",16,1);
OLED_ShowString(100,32,"<-",16,1);
OLED_ShowString(100,48," ",16,1);
OLED_Refresh();
if (KEY_state != 0)
{
KEY_state = 0;
return 5;
}
break;
case 3:
OLED_ShowString(100,16," ",16,1);
OLED_ShowString(100,32," ",16,1);
OLED_ShowString(100,48,"<-",16,1);
OLED_Refresh();
if (KEY_state != 0)
{
KEY_state = 0;
return 0;
}
break;
}
motor_stop();
}
}
int nemu4(void)
{
OLED_Clear();
OLED_ShowString(35,0,"Now mode",16,1);
OLED_ShowString(55,48,"Turn back",16,0);
OLED_Refresh();
while(1)
{
if (AUTO_state == 1)
{
OLED_ShowString(10,16,"AUTO mode",24,1);
}else if(AUTO_state == 0)
{
OLED_ShowString(5,16,"ManualMode",24,1);
}
OLED_Refresh();
if (KEY_state != 0)
{
KEY_state = 0;
return 3;
}
motor_stop();
}
}
int nemu6(void)
{
unsigned char auto_mode_report[5] = { 0XAA, 0X55, 0X01, 0X55, 0XAA };
//播报【当前为手动模式】语音
unsigned char manual_mode_report[5] = { 0XAA, 0X55, 0X02, 0X55, 0XAA };
int nemu_num = 1;
int temp = 1;
OLED_Clear();
OLED_ShowString(35,0,"Warning",16,1);
OLED_ShowString(0,16,"Do you want chan",16,1);
OLED_ShowString(0,32,"ge the mode",16,1);
OLED_ShowString(0,48,"YES",16,1);
OLED_ShowString(110,48,"NO",16,1);
OLED_Refresh();
while(1)
{
nemu_num = turn_state;
if (nemu_num < 0)
{
turn_state = 17;
} else if (nemu_num >= 1 && nemu_num < 9)
{
nemu_num = 1;
} else if (nemu_num >= 9 && nemu_num <17)
{
nemu_num = 2;
} else if (nemu_num >= 17 && nemu_num < 19)
{
nemu_num = 3;
} else if (nemu_num >= 19)
{
turn_state = 1;
}
switch(nemu_num)
{
case 1:
OLED_ShowString(110,48,"NO",16,1);
if (temp == 1)
{
OLED_ShowString(0,48,"YES",16,1);
temp = 0;
delay_1ms(500);
}else
{
OLED_ShowString(0,48,"YES",16,0);
temp = 1;
delay_1ms(500);
}
OLED_Refresh();
if (KEY_state != 0)
{
KEY_state = 0;
if (AUTO_state == 1)
{
AUTO_state = 0;
}else if (AUTO_state == 0)
{
hlk_usart_send_string(auto_mode_report, 5);
AUTO_state = 1;
}
return 4;
}
break;
case 2:
OLED_ShowString(0,48,"YES",16,1);
if (temp == 1)
{
OLED_ShowString(110,48,"NO",16,1);
temp = 0;
delay_1ms(500);
}else
{
OLED_ShowString(110,48,"NO",16,0);
temp = 1;
delay_1ms(500);
}
OLED_Refresh();
if (KEY_state != 0)
{
hlk_usart_send_string(manual_mode_report, 5);
KEY_state = 0;
return 3;
}
break;
}
}
}
```
#### 语音识别代码
```
void timer_voice_IRQHandler (void)
{
if(timer_interrupt_flag_get(TIMER6,TIMER_INT_FLAG_UP) == SET)
{
timer_interrupt_flag_clear(TIMER6,TIMER_INT_FLAG_UP); // 清除中断标志位
if( rx_flag == 1 )//接收到语音命令
{
rx_flag = 0;
switch( rx_data )//根据语音命令确定对应的动作
{
case 0x01://开窗帘命令
open_curtain();
//motor_stop();
//设置非自动模式
AUTO_state = 0;
break;
case 0x02://关窗帘命令
close_curtain();
//motor_stop();
//设置非自动模式
AUTO_state = 0;
break;
case 0x03://自动模式命令
AUTO_state = 1;
break;
case 0x04://手动模式命令
AUTO_state = 0;
break;
}
//清除当前数据
clear_hlk_rx_buff();
}
//步进电机限位判断
limit_judgment(get_step_count());
}
}
```
#### 红外识别代码
```
void timer_IR_IRQHandler (void)
{
//播报【当前为自动模式】语音
unsigned char auto_mode_report[5] = {0XAA, 0X55, 0X01, 0X55, 0XAA};
//播报【当前为手动模式】语音
unsigned char manual_mode_report[5] = {0XAA, 0X55, 0X02, 0X55, 0XAA};
//播报【窗帘已打开】语音
unsigned char curtain_open_report[5] = {0XAA, 0X55, 0X03, 0X55, 0XAA};
//播报【窗帘已关闭】语音
unsigned char curtain_clear_report[5] = {0XAA, 0X55, 0X04, 0X55, 0XAA};
if(timer_interrupt_flag_get(TIMER4,TIMER_INT_FLAG_UP) == SET)
{
timer_interrupt_flag_clear(TIMER4,TIMER_INT_FLAG_UP);
if( get_infrared_command() == 0X68 )
{
clear_infrared_command();
AUTO_state = 1;
//播报【当前为自动模式】语音
hlk_usart_send_string(auto_mode_report, 5);
}
//如果按下【#】键,进入非自动模式
if( get_infrared_command() == 0Xb0 )
{
clear_infrared_command();
AUTO_state = 0;
//播报【当前为手动模式】语音
hlk_usart_send_string(manual_mode_report, 5);
}
//如果按下【<】键,关闭窗帘
if( get_infrared_command() == 0X10 )
{
clear_infrared_command();
close_curtain();
delay_1ms(1000);
AUTO_state = 0;
//播报【窗帘已关闭】语音语音
hlk_usart_send_string(curtain_clear_report, 5);
}
//如果按下【>】键,展开窗帘
if( get_infrared_command() == 0X5a )
{
temp = 10;
clear_infrared_command();
open_curtain();
AUTO_state = 0;
//播报【窗帘已打开】语音语音
hlk_usart_send_string(curtain_open_report, 5);
}
}
}
```
完整代码见附件
## 注意事项
红外控制不是很灵敏,需要多次按键才可以识别成功
红外遥控器的购买链接:
https://detail.tmall.com/item.htmid=548393997684&spm=a1z09.2.0.0.206a2e8dH3nUIB&_u=8201d9rg5ed88c
## 演示视频
演示视频:
https://www.bilibili.com/video/BV1a84y117qC/?vd_source=fda5f531b52244dbb434e4a99b5f9018