STM32项目分享:智能语音风扇

目录

一、前言

二、项目简介

1.功能详解

2.主要器件

三、原理图设计

四、PCB硬件设计

PCB图 

五、程序设计 

六、实验效果 

七、资料内容

项目分享


一、前言

项目成品图片:

哔哩哔哩视频链接:

STM32智能语音风扇

(资料分享见文末) 

二、项目简介

1.功能详解

基于STM32的智能语音风扇

功能如下:

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

六、实验效果 

七、资料内容

项目分享

猜你喜欢

转载自blog.csdn.net/qq_44016222/article/details/146128998
今日推荐