目录
一、前言
项目成品图片:
哔哩哔哩视频链接:
STM32智能语音风扇
(资料分享见文末)
二、项目简介
1.功能详解
基于STM32的智能语音风扇
功能如下:
- STM32F103C8T6单片机作为主控单元
- 温度采集:DS18B20传感器采集环境温度
- 人体检测:人体红外传感器判断是否有人
- 屏幕显示:OLED显示温度、有无人、档位、模式等信息
- 风扇摇头:步进电机模拟风扇摇头
- 手动模式:按键调节风扇风速
- 自动模式:判断是否有人以及根据温度控制风扇开关和风速
- 语音模式:通过语音控制风速、模式以及摇头
- 定时功能:定时关闭
- APP控制:通过蓝牙远程查看数据以及下发控制
2.主要器件
- STM32F103C8T6单片机
- OLED 屏幕
- DS18B20温度传感器
- HC-SR501人体红外传感器
- TB6612电机驱动模块
- ESP8266-01S(WIFI模块)
- SNR8016语音模块
- 有源蜂鸣器
- 风扇模块
- ULN2003步进电机驱动芯片
- 步进电机
- LED灯
三、原理图设计
四、PCB硬件设计
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"
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置中断分组为2号
Delay_Init(); //延时初始化
Gpio_Init(); //IO初始化
Key_Init(); //按键初始化
while(DS18B20_Init()); //DS18B20初始化
Oled_Init(); //OLED初始化
Oled_Clear_All(); //清屏
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_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:风速切换
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:倒计时分+1
countdown_minute++;
if(countdown_minute >= 60)
countdown_minute = 0;
break;
case 5: //界面5:倒计时秒+1
countdown_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;
else
flag_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:倒计时分-1
countdown_minute--;
if(countdown_minute < 0)
countdown_minute = 59;
break;
case 5: //界面5:倒计时秒-1
countdown_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;
}
}
if(flag_display == 0) //测量界面
{
if(time_num % 10 == 0) //约2s检测一次
{
temp_value = DS18B20_Get_Temp(); //获取温度值
if(time_num % 30 == 0) //发送数据
{
UsartPrintf(USART1,"\r\n温度:%d.%dC",temp_value/10,temp_value%10);
if(HUMAN == 1)
UsartPrintf(USART1," 人体:有人");
else
UsartPrintf(USART1," 人体:没有");
if(motor_pwm == 0)
UsartPrintf(USART1,"\r\n关闭");
else if(motor_pwm == 300)
UsartPrintf(USART1,"\r\n一档");
else if(motor_pwm == 600)
UsartPrintf(USART1,"\r\n二档");
else if(motor_pwm == 900)
UsartPrintf(USART1,"\r\n三档");
if(flag_direction == 1)
UsartPrintf(USART1," 摇头开");
else
UsartPrintf(USART1," 摇头关");
if(flag_mode == 0)
UsartPrintf(USART1,"\r\n自动");
else
UsartPrintf(USART1,"\r\n手动");
}
}
if(USART1_WaitRecive() == 0) //接收蓝牙数据
{
if(usart1_buf[0] == 'A') //A:切换模式
{
if(flag_mode == 0)
{
flag_mode = 1;
}
else
{
flag_mode = 0;
}
}
else if(usart1_buf[0] == 'B') //B:加风速
{
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);
}
}
else if(usart1_buf[0] == 'C') //C:减风速
{
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(usart1_buf[0] == 'D') //D:开关摇头
{
flag_dir++;
if(flag_dir%2==1)
flag_direction = 1;
else
flag_direction = 0;
}
USART1_Clear();
}
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();
}
}
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;
}
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) //通风倒计时不为0
flag_countdown_begin = 1; //开始倒计时,进入定时器中断
if(flag_1s == 1) //1s到达
{
flag_1s = 0;
if(countdown_second > 0) //倒计时秒>0
countdown_second--; //倒计时秒-1
else //倒计时秒=0
{
if(countdown_minute > 0) //如果倒计时分>0
{
countdown_minute--; //倒计时分-1
countdown_second = 59; //倒计时秒=59
}
else //如果倒计时分=0
{
if(countdown_hour > 0) //如果倒计时时>0
{
countdown_hour--; //倒计时时-1
countdown_minute = 59; //倒计时分=59
countdown_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);
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);
}
time_num++; //计时变量+1
Delay_ms(10);
if(time_num %5 == 0) //最小系统LED闪烁
LED_SYS = ~LED_SYS;
if(time_num >= 5000)
{
time_num = 0;
}
}
}
六、实验效果
七、资料内容