基于STM32蓝牙智能温控风扇系统设计与实现(代码+原理图+PCB+蓝牙APP)

STM32蓝牙智能温控风扇系统设计与实现

基于STM32蓝牙智能温控风扇系统设计与实现(代码+原理图+PCB+蓝牙APP)_第1张图片

资料齐全:源代码,原理图,PCB和机智云相关教程,参考lun文等!

摘要:本文设计并实现了一种基于STM32F103C8T6单片机的蓝牙智能温控风扇系统。该系统具备OLED显示、自动/手动模式切换、温湿度检测、风扇档位调节、人体红外检测、倒计时以及蓝牙APP远程控制等功能。通过集成多种传感器和执行器,系统能够根据当前温湿度变化自动控制风扇转动,同时支持手机APP远程操作,提高了使用的便捷性和智能化程度。

关键词:STM32F103C8T6;蓝牙;智能温控风扇;自动/手动模式;手机APP远程控制

一、引言

随着科技的进步和人们生活水平的提高,智能家居设备逐渐走进千家万户。智能温控风扇作为智能家居的重要组成部分,能够根据环境温度和人体需求自动调节风速,为用户提供更加舒适的使用体验。传统的风扇控制方式存在功能单一、操作不便等问题,难以满足现代家庭对智能化、便捷化的需求。因此,设计一种基于STM32单片机的蓝牙智能温控风扇系统具有重要意义。

本系统以STM32F103C8T6单片机为核心控制器,结合温湿度传感器、人体红外传感器、蓝牙模块等,实现了风扇的智能化控制。用户可以通过按键或手机APP设置自动/手动模式,调节风扇档位和定时时间,系统还能根据温湿度变化自动调节风扇转速,为用户提供更加舒适、便捷的使用体验。

二、系统总体设计

(一)系统架构

本系统主要由STM32F103C8T6单片机、温湿度传感器、人体红外传感器、OLED显示屏、按键模块、风扇驱动模块、蓝牙模块以及手机APP等部分组成。系统架构图如图1所示。

(二)功能需求

  1. 显示功能:OLED显示屏实时显示当前温度、湿度、风扇档数、速度以及自动/手动模式。
  2. 模式切换:按键可以设置自动/手动模式切换,自动档模式下可以设置温度阈值。
  3. 手动模式:用户可以自由开启风扇,调整档位等级,每调速一次风扇档位加一,最大上限为5档。
  4. 自动模式:人体红外检测到人并且当前温度大于温度上限值时,风扇开启,并根据温度自动调节风速档位。
  5. 倒计时功能:用户可以设置定时时间,时间到风扇自动关闭。
  6. 蓝牙APP远程控制:手机APP具有手动、自动模式切换、档位调节和倒计时设置等功能。

三、硬件设计

(一)核心控制器——STM32F103C8T6单片机

STM32F103C8T6单片机是基于ARMCortex-M3内核的32位微控制器,具有高性能、低功耗、丰富的外设和灵活的功耗管理等特点。在本系统中,STM32F103C8T6单片机作为核心控制器,负责接收传感器数据、处理控制逻辑以及输出控制信号。

(二)传感器模块

  1. 温湿度传感器:本系统选用DHT11数字温湿度传感器。DHT11具有测量精度高、响应速度快、抗干扰能力强等优点,能够实时测量环境温度和湿度。它通过单总线协议与STM32单片机进行通信,将测量到的温湿度数据传输给单片机。
  2. 人体红外传感器:选用HC-SR501人体红外传感器。该传感器能够检测人体发出的红外线,当检测到有人时输出高电平信号,否则输出低电平信号。STM32单片机通过检测该传感器的输出信号来判断是否有人存在。

(三)显示模块

OLED显示屏选用0.96寸I2C接口的OLED显示屏。OLED显示屏具有自发光、对比度高、视角广、响应速度快等优点,能够清晰地显示各种信息。通过I2C接口与STM32单片机进行通信,实现温湿度、风扇档数、速度以及模式等信息的显示。

(四)按键模块

按键模块包括模式切换按键、档位调节按键和定时设置按键。按键通过GPIO引脚与STM32单片机相连,当按键按下时,单片机检测到电平变化,执行相应的操作。

(五)风扇驱动模块

风扇驱动模块采用PWM(脉冲宽度调制)方式控制风扇转速。STM32单片机通过输出不同占空比的PWM信号,调节风扇驱动电路的电压,从而控制风扇的转速。

(六)蓝牙模块

蓝牙模块选用HC-05蓝牙串口通信模块。HC-05模块能够与手机APP进行蓝牙通信,实现数据的传输和控制指令的接收。通过串口与STM32单片机相连,将单片机处理后的数据发送给手机APP,同时接收手机APP发送的控制指令。

四、软件设计

(一)开发环境

本系统采用Keil uVision作为开发环境。Keil uVision是一款功能强大的单片机开发软件,它支持多种编程语言(如C语言),提供了丰富的库函数和开发工具,方便开发者进行程序编写和调试。

(二)软件架构

本系统的软件架构主要包括初始化模块、数据采集模块、数据处理模块、控制逻辑模块、显示模块、按键处理模块、蓝牙通信模块以及定时模块等部分。

  1. 初始化模块:负责初始化STM32单片机的各个外设(如GPIO、I2C、USART、PWM等)以及传感器和显示模块。
  2. 数据采集模块:负责采集温湿度传感器和人体红外传感器的数据,并将采集到的数据转换为数字信号后存储到单片机的内存中。
  3. 数据处理模块:负责对采集到的数据进行处理和分析,如计算平均值、判断数据是否超出预设范围等。
  4. 控制逻辑模块:根据数据处理模块的结果,执行相应的控制逻辑,如控制风扇的开启和关闭、调节风扇档位等。
  5. 显示模块:负责将温湿度、风扇档数、速度以及模式等信息显示到OLED显示屏上。
  6. 按键处理模块:负责检测按键的状态,当按键按下时执行相应的操作,如模式切换、档位调节和定时设置等。
  7. 蓝牙通信模块:负责蓝牙模块与手机APP之间的通信,包括数据上传和指令接收等。
  8. 定时模块:负责实现倒计时功能,当定时时间到时,关闭风扇。

(三)关键程序实现

  1. 温湿度数据采集

     

    c复制代码

    void DHT11_ReadData(uint8_t *temp, uint8_t *humi) {
    uint8_t buffer[5] = {0};
    DHT11_Start(); // 启动DHT11传感器
    if (DHT11_CheckResponse()) { // 检查传感器响应
    buffer[0] = DHT11_ReadByte();
    buffer[1] = DHT11_ReadByte();
    buffer[2] = DHT11_ReadByte();
    buffer[3] = DHT11_ReadByte();
    buffer[4] = DHT11_ReadByte();
    if (buffer[4] == (buffer[0] + buffer[1] + buffer[2] + buffer[3])) { // 校验数据
    *humi = buffer[0];
    *temp = buffer[2];
    }
    }
    }
  2. 风扇控制

     

    c复制代码

    void Fan_Control(uint8_t mode, uint8_t temp, uint8_t temp_threshold, uint8_t *fan_speed) {
    if (mode == AUTO_MODE) {
    if (Human_Detected() && temp > temp_threshold) { // 人体检测到且温度超过阈值
    if (temp >= 30) {
    *fan_speed = 5; // 最高档
    } else if (temp >= 28) {
    *fan_speed = 4;
    } else if (temp >= 26) {
    *fan_speed = 3;
    } else if (temp >= 24) {
    *fan_speed = 2;
    } else {
    *fan_speed = 1;
    }
    Fan_On(*fan_speed); // 开启风扇并设置档位
    } else {
    Fan_Off(); // 关闭风扇
    }
    } else if (mode == MANUAL_MODE) {
    Fan_On(*fan_speed); // 手动模式下根据设置档位开启风扇
    }
    }
  3. 蓝牙通信

     

    c复制代码

    void Bluetooth_Init(void) {
    USART_InitTypeDef USART_InitStruct;
    // 初始化USART(用于与蓝牙模块通信)
    USART_InitStruct.USART_BaudRate = 9600;
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;
    USART_InitStruct.USART_StopBits = USART_StopBits_1;
    USART_InitStruct.USART_Parity = USART_Parity_No;
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART1, &USART_InitStruct);
    USART_Cmd(USART1, ENABLE);
    }
    void Bluetooth_Receive(void) {
    if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET) {
    uint8_t data = USART_ReceiveData(USART1);
    // 处理接收到的数据,如模式切换、档位调节等指令
    }
    }
  4. 定时功能

     

    c复制代码

    void Timer_Init(void) {
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
    // 初始化定时器
    TIM_TimeBaseStruct.TIM_Period = 9999;
    TIM_TimeBaseStruct.TIM_Prescaler = 7199;
    TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStruct);
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    TIM_Cmd(TIM2, ENABLE);
    }
    void TIM2_IRQHandler(void) {
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    if (timer_count > 0) {
    timer_count--;
    if (timer_count == 0) {
    Fan_Off(); // 定时时间到,关闭风扇
    }
    }
    }
    }

五、系统测试与优化

(一)系统测试

系统测试的主要目的是为了验证智能温控风扇控制系统的设计是否满足预期的功能需求和性能指标。测试内容包括硬件测试和软件测试两个方面。

  1. 硬件测试

    • STM32单片机测试:测试STM32单片机的运行稳定性,包括GPIO引脚的输入输出功能、I2C和USART通信等。
    • 传感器测试:测试温湿度传感器和人体红外传感器的测量精度和响应速度。
    • 显示模块测试:测试OLED显示屏的显示效果和通信稳定性。
    • 风扇驱动模块测试:测试风扇的转速调节和开关控制功能。
    • 蓝牙模块测试:测试蓝牙模块的通信稳定性和数据传输速度。
  2. 软件测试

    • 功能测试:测试系统的各项功能是否正常工作,如自动/手动模式切换、风扇档位调节、定时功能、蓝牙APP远程控制等。
    • 性能测试:测试系统的响应时间、稳定性、可靠性等性能指标。

(二)系统优化

在测试过程中,可能会发现系统的某些部分存在性能瓶颈或不足。针对这些问题,可以对系统进行优化和改进。例如:

  • 优化算法:对风扇转速调节算法进行优化,提高系统的控制精度和响应速度。
  • 改进用户界面:对手机APP的用户界面进行优化,提高用户体验。
  • 增加传感器:可以考虑增加更多的传感器,如空气质量传感器等,以实现对风扇环境的更全面监测。

六、结论与展望

(一)结论

本文详细阐述了一种基于STM32F103C8T6单片机的蓝牙智能温控风扇系统的设计与实现。该系统集成了温湿度检测、人体红外检测、OLED显示、按键处理、风扇控制、蓝牙通信以及定时等多种功能,能够根据当前温湿度变化自动控制风扇转动,同时支持手机APP远程操作。通过系统测试和优化,验证了系统的可行性和稳定性。

(二)展望

随着物联网技术的不断发展,智能温控风扇系统有望与家庭物联网系统进行更深入的集成,实现与其他家电的互联互通。未来可以考虑增加更多的智能化功能,如语音控制、智能学习等,进一步提高系统的智能化水平和用户体验。同时,还可以对系统的硬件和软件进行优化和升级,降低系统成本,提高系统的可靠性和稳定性,使其更加适用于家庭、办公室等场所。

#include "oled.h"
#include "stdlib.h"
#include "oledfont.h"  	 
#include "delay.h"
//OLED的显存
//存放格式如下.
//[0]0 1 2 3 ... 127	
//[1]0 1 2 3 ... 127	
//[2]0 1 2 3 ... 127	
//[3]0 1 2 3 ... 127	
//[4]0 1 2 3 ... 127	
//[5]0 1 2 3 ... 127	
//[6]0 1 2 3 ... 127	
//[7]0 1 2 3 ... 127 			   
/**********************************************
//IIC Start
**********************************************/
/**********************************************
//IIC Start
**********************************************/
void OLED_IIC_Start()
{

	OLED_SCLK_Set() ;
	OLED_SDIN_Set();
	OLED_SDIN_Clr();
	OLED_SCLK_Clr();
}

/**********************************************
//IIC Stop
**********************************************/
void OLED_IIC_Stop()
{
OLED_SCLK_Set() ;
//	OLED_SCLK_Clr();
	OLED_SDIN_Clr();
	OLED_SDIN_Set();
	
}

void OLED_IIC_Wait_Ack()
{

	//GPIOB->CRH &= 0XFFF0FFFF;	//设置PB12为上拉输入模式
	//GPIOB->CRH |= 0x00080000;
//	OLED_SDA = 1;
//	delay_us(1);
	//OLED_SCL = 1;
	//delay_us(50000);
/*	while(1)
	{
		if(!OLED_SDA)				//判断是否接收到OLED 应答信号
		{
			//GPIOB->CRH &= 0XFFF0FFFF;	//设置PB12为通用推免输出模式
			//GPIOB->CRH |= 0x00030000;
			return;
		}
	}
*/
	OLED_SCLK_Set() ;
	OLED_SCLK_Clr();
}
/**********************************************
// IIC Write byte
**********************************************/

void Write_IIC_Byte(unsigned char IIC_Byte)
{
	unsigned char i;
	unsigned char m,da;
	da=IIC_Byte;
	OLED_SCLK_Clr();
	for(i=0;i<8;i++)		
	{
			m=da;
		//	OLED_SCLK_Clr();
		m=m&0x80;
		if(m==0x80)
		{OLED_SDIN_Set();}
		else OLED_SDIN_Clr();
			da=da<<1;
		OLED_SCLK_Set();
		OLED_SCLK_Clr();
		}


}
/**********************************************
// IIC Write Command
**********************************************/
void Write_IIC_Command(unsigned char IIC_Command)
{
   OLED_IIC_Start();
   Write_IIC_Byte(0x78);            //Slave address,SA0=0
	OLED_IIC_Wait_Ack();	
   Write_IIC_Byte(0x00);			//write command
	OLED_IIC_Wait_Ack();	
   Write_IIC_Byte(IIC_Command); 
	OLED_IIC_Wait_Ack();	
   OLED_IIC_Stop();
}
/**********************************************
// IIC Write Data
**********************************************/
void Write_IIC_Data(unsigned char IIC_Data)
{
   OLED_IIC_Start();
   Write_IIC_Byte(0x78);			//D/C#=0; R/W#=0
	OLED_IIC_Wait_Ack();	
   Write_IIC_Byte(0x40);			//write data
	OLED_IIC_Wait_Ack();	
   Write_IIC_Byte(IIC_Data);
	OLED_IIC_Wait_Ack();	
   OLED_IIC_Stop();
}
void OLED_WR_Byte(unsigned dat,unsigned cmd)
{
	if(cmd)
			{

   Write_IIC_Data(dat);
   
		}
	else {
   Write_IIC_Command(dat);
		
	}


}


/********************************************
// fill_Picture
********************************************/
void fill_picture(unsigned char fill_Data)
{
	unsigned char m,n;
	for(m=0;m<8;m++)
	{
		OLED_WR_Byte(0xb0+m,0);		//page0-page1
		OLED_WR_Byte(0x00,0);		//low column start address
		OLED_WR_Byte(0x10,0);		//high column start address
		for(n=0;n<128;n++)
			{
				OLED_WR_Byte(fill_Data,1);
			}
	}
}


/***********************Delay****************************************/
void Delay_50ms(unsigned int Del_50ms)
{
	unsigned int m;
	for(;Del_50ms>0;Del_50ms--)
		for(m=6245;m>0;m--);
}

void Delay_1ms(unsigned int Del_1ms)
{
	unsigned char j;
	while(Del_1ms--)
	{	
		for(j=0;j<123;j++);
	}
}

//坐标设置

	void OLED_Set_Pos(unsigned char x, unsigned char y) 
{ 	OLED_WR_Byte(0xb0+y,OLED_CMD);
	OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
	OLED_WR_Byte((x&0x0f),OLED_CMD); 
}   	  
//开启OLED显示    
void OLED_Display_On(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ON
	OLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON
}
//关闭OLED显示     
void OLED_Display_Off(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFF
	OLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
}		   			 
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!	  
void OLED_Clear(void)  
{  
	u8 i,n;		    
	for(i=0;i<8;i++)  
	{  
		OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
		OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
		for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA); 
	} //更新显示
}
void OLED_On(void)  
{  
	u8 i,n;		    
	for(i=0;i<8;i++)  
	{  
		OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
		OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
		for(n=0;n<128;n++)OLED_WR_Byte(1,OLED_DATA); 
	} //更新显示
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示				 
//size:选择字体 16/12 
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size)
{      	
	unsigned char c=0,i=0;	
		c=chr-' ';//得到偏移后的值			
		if(x>Max_Column-1){x=0;y=y+2;}
		if(Char_Size ==16)
			{
			OLED_Set_Pos(x,y);	
			for(i=0;i<8;i++)
			OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
			OLED_Set_Pos(x,y+1);
			for(i=0;i<8;i++)
			OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
			}
			else {	
				OLED_Set_Pos(x,y);
				for(i=0;i<6;i++)
				OLED_WR_Byte(F6x8[c][i],OLED_DATA);
				
			}
}
//m^n函数
u32 oled_pow(u8 m,u8 n)
{
	u32 result=1;	 
	while(n--)result*=m;    
	return result;
}				  
//显示2个数字
//x,y :起点坐标	 
//len :数字的位数
//size:字体大小
//mode:模式	0,填充模式;1,叠加模式
//num:数值(0~4294967295);	 		  
void OLED_Display_Timer_Data(u8 x, u8 y, u32 Number)
{
    u8 Number_String[10][2] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; //注意停止位也要占一个字符
		OLED_ShowString(x, y, Number_String [Number / 100 % 10],16);
    OLED_ShowString(x +1*8, y , Number_String[ Number / 10 % 10],16);
    OLED_ShowString(x + 2*8, y, Number_String[Number % 10],16);
}
//显示一个字符号串
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size)
{
	unsigned char j=0;
	while (chr[j]!='\0')
	{		OLED_ShowChar(x,y,chr[j],Char_Size);
			x+=8;
		if(x>120){x=0;y+=2;}
			j++;
	}
}
//显示汉字
void OLED_ShowCHinese(u8 x,u8 y,u8 no)
{      			    
	u8 t,adder=0;
	OLED_Set_Pos(x,y);	
    for(t=0;t<16;t++)
		{
				OLED_WR_Byte(Hzk[2*no][t],OLED_DATA);
				adder+=1;
     }	
		OLED_Set_Pos(x,y+1);	
    for(t=0;t<16;t++)
			{	
				OLED_WR_Byte(Hzk[2*no+1][t],OLED_DATA);
				adder+=1;
      }					
}
/***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
{ 	
 unsigned int j=0;
 unsigned char x,y;
  
  if(y1%8==0) y=y1/8;      
  else y=y1/8+1;
	for(y=y0;y

你可能感兴趣的:(毕业设计1,stm32,智能家居,嵌入式硬件,单片机,物联网)