课程设计!基于STM32智能家居(程序+电路图+手机APP)!

前言

本文给大家介绍一款基于STM32智能家居的课程设计,其实也可以用作毕业设计啦,视难度而定,希望能给大家一些思路,从而做出自己满意的作品。需要单片机资料什么的可以拉到文末进行领取哈~

实物图

1,器件准备

  1. 采用STM32F103C8T6单片机
  2. 使用DHT11检测温湿度
  3. 使用MQ-2传感器检测烟雾浓度
  4. 使用CO2传感器检测二氧化碳浓度
  5. OLED显示温度,湿度,烟雾浓度,CO2浓度
  6. 烟雾浓度、二氧化碳浓度超标时蜂鸣器报警,同时打开风扇通风
  7. ESP8266模块实现 WIFI通讯数据传输,wifi通讯需借助一个有网络wifi热点
  8. 中国移动物联网平台可实时查看传感器数据控制风扇,蜂鸣器和LED

在这里插入图片描述

2,硬件功能

在硬件设计方面,系统主要包括STM32单片机、温湿度传感器、烟雾传感器、二氧化碳浓度传感器、OLED显示器、蜂鸣器、风扇以及WiFi通信模块等部件。

其中,STM32单片机负责整个系统的控制和数据处理
传感器用于采集环境参数,如温湿度、烟雾浓度和二氧化碳浓度等;OLED显示器用于实时显示采集到的环境参数;
蜂鸣器和风扇则用于在特定条件下触发报警和通风功能;

WiFi通信模块则实现系统与中国移动物联网平台等外部网络的通信,以实现远程监控和控制。

在这里插入图片描述

3,原理图

原理图是在很适合新手入门的立创画的,新手用立创,学的深入了可以用AD之类的画图软件。
在这里插入图片描述

4,硬件代码

1. 主函数main.c
int main(void)
{	
	u16 adcx;
	char buf[20];
	unsigned char *dataPtr;
	unsigned int runTime = 0;
	_Bool sendFlag = 0;
	unsigned int Num = 0;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
	delay_init();	    			//延时函数初始化	  
    LED_Init();		  				//初始化与控制设备连接的硬件接口	
 	uart_init(115200);	 			//串口初始化为9600
	
	DHT11_Init();

	printf( "开始\r\n");
	I2C_Configuration();
	OLED_Init();
	OLED_Fill(0x00);

	OLED_ShowCN(0,0,0);				//二氧化碳
	OLED_ShowCN(16,0,1);	
	OLED_ShowCN(32,0,2);	
	OLED_ShowCN(48,0,3);
	OLED_ShowStr(64,0,":---ppm",2);
	
	OLED_ShowCN(0,2,4);				//烟雾
	OLED_ShowCN(16,2,5);
	OLED_ShowStr(32,2,":--%",2);
	
	OLED_ShowCN(0,4,17);				//温度
	OLED_ShowCN(16,4,19);
	OLED_ShowStr(32,4,":--C",2);
	
	OLED_ShowCN(0,6,18);				//湿度
	OLED_ShowCN(16,6,19);
	OLED_ShowStr(32,6,":--%",2);

	
	Adc_Init();
	if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET) 								//如果是看门狗复位则提示
	{
		printf( "WARN:	IWDG Reboot\r\n");
		
		RCC_ClearFlag();														//清除看门狗复位标志位
		
		faultTypeReport = faultType = FAULT_REBOOT; 							//标记为重启错误
		
		netDeviceInfo.reboot = 1;
	}
	else
	{
		printf( "2.SSID: %s,   PSWD: %s\r\n"
								"DEVID: %s,     APIKEY: %s\r\n"
								, netDeviceInfo.staName, netDeviceInfo.staPass
								, oneNetInfo.devID, oneNetInfo.apiKey);
		
		netDeviceInfo.reboot = 0;
	}	
	Timer3_4_Init(TIM3, 49, 35999);												//72MHz,36000分频-500us,50重载值。则中断周期为500us * 50 = 25ms
	Timer3_4_Init(TIM4, 1999, 35999);											//72MHz,36000分频-500us,2000重载值。则中断周期为500us * 2000 = 1s
																				//定时检查网络状态标志位
	
	printf("3.Hardware init OK\r\n");
	NET_DEVICE_IO_Init();								//网络设备IO初始化
	NET_DEVICE_Reset();									//网络设备复位
	NET_DEVICE_Set_DataMode(DEVICE_CMD_MODE);			//设置为命令收发模式(例如ESP8266要区分AT的返回还是平台下发数据的返回)
	uart3_init(9600);				//串口三

	while(1)
	{	
	

		if(oneNetInfo.netWork == 1)
		{
		
/******************************************************************************
			数据与心跳
******************************************************************************/
			if(timInfo.timer6Out - runTime >= 400)									//25s一次(25ms中断)25*1000=25S
			{
				runTime = timInfo.timer6Out;
				
				if(sendFlag)
				{
					TIM_Cmd(OS_TIMER, DISABLE);
					OneNet_HeartBeat();												//心跳连接
					TIM_Cmd(OS_TIMER, ENABLE);
				}
				else
				{
					TIM_Cmd(OS_TIMER, DISABLE);
					OneNet_SendData(kTypeSimpleJsonWithoutTime, dataStreamLen);		//数据发送
					TIM_Cmd(OS_TIMER, ENABLE);
				}
				sendFlag = !sendFlag;
			}
			
/******************************************************************************
			平台下发命令解析
******************************************************************************/
			if(oneNetInfo.netWork && NET_DEVICE_Get_DataMode() == DEVICE_DATA_MODE)	//当有网络 且 在命令接收模式时
			{
				dataPtr = NET_DEVICE_GetIPD(0);										//不等待,获取平台下发的数据
				if(dataPtr != NULL)													//如果数据指针不为空,则代表收到了数据
				{
					printf("收到1\r\n");
					OneNet_App(dataPtr);											//集中处理
				}
			}
			
/******************************************************************************
			传感器
******************************************************************************/

			if(Num++>20)
			{
				Num = 0;
			}

			CO2=read_CO2_concentration();
			sprintf(buf,"%4dppm ",CO2);
			OLED_ShowStr(64,0,(unsigned char*)buf,2);
			
			MQ2=(Get_Adc_Average(ADC_Channel_0,10)*330*2/4096)*100/25;

			sprintf(buf,"%3d%%   ",MQ2);
			OLED_ShowStr(32,2,(unsigned char*)buf,2);
			delay_ms(10);
			
			DHT11_Read(&temp,&humi);
			sprintf(buf,"%3dC",temp);
			OLED_ShowStr(32,4,(unsigned char*)buf,2);
			sprintf(buf,"%3d%% ",humi);
			OLED_ShowStr(32,6,(unsigned char*)buf,2);
			delay_ms(10);
					
			
			if(mode==0)				//处于自动模式下?
			{
				if(MQ2>50||CO2>1000)			//烟雾或者CO2超标 开风扇
				{
					Jd0_Set(GPIO_ON);	//开风扇
					Beep_Set(GPIO_ON);	//开报警
				}	
				else
				{
					Jd0_Set(GPIO_OFF);	//关风扇
					Beep_Set(GPIO_OFF);	//关报警
				}
			}
			else					//非自动模式
			{
			
			}
			
/******************************************************************************
			错误处理
******************************************************************************/
			if(faultType != FAULT_NONE)												//如果错误标志被设置
			{
				printf( "WARN:	Fault Process\r\n");
				Fault_Process();													//进入错误处理函数
			}
			
/******************************************************************************
			数据反馈
******************************************************************************/
			if(oneNetInfo.sendData)
			{
				oneNetInfo.sendData = OneNet_SendData(kTypeSimpleJsonWithoutTime, dataStreamLen);
			}
		}
		else
		{
/******************************************************************************
			初始化网络设备、接入平台
******************************************************************************/
			if(!oneNetInfo.netWork && (checkInfo.NET_DEVICE_OK == DEV_OK))			//当没有网络 且 网络模块检测到时
			{
				//LCD_ShowString(30,20,220,24,24,"Connectting... ");

				NET_DEVICE_Set_DataMode(DEVICE_CMD_MODE);							//设置为命令收发模式
				
				if(!NET_DEVICE_Init())												//初始化网络设备,能连入网络
				{
					OneNet_DevLink(oneNetInfo.devID, oneNetInfo.apiKey);			//接入平台
					
					if(oneNetInfo.netWork)
					{
						
						//LCD_ShowString(30,20,220,24,24,"Connectted OK  ");
						
						runTime = timInfo.timer6Out;								//更新时间
					}
					else
					{
						//LCD_ShowString(30,20,220,24,24,"Not Connected    ");
					}
				}
			}
			
/******************************************************************************
			网络设备检测
******************************************************************************/
			if(checkInfo.NET_DEVICE_OK == DEV_ERR) 									//当网络设备未做检测
			{
				NET_DEVICE_Set_DataMode(DEVICE_CMD_MODE);							//设置为命令收发模式
				
				if(timerCount >= NET_TIME) 											//如果网络连接超时
				{
					printf( "Tips:		Timer Check Err\r\n");
					
					NET_DEVICE_Reset();												//复位网络设备
					timerCount = 0;													//清零连接超时计数
					faultType = FAULT_NONE;											//清除错误标志
				}
				
				if(!NET_DEVICE_SendCmd("AT\r\n", "OK"))								//网络设备检测
				{
					printf( "NET Device :Ok\r\n");
					checkInfo.NET_DEVICE_OK = DEV_OK;								//检测到网络设备,标记
					NET_DEVICE_Set_DataMode(DEVICE_DATA_MODE);						//设置为数据收发模式
				}
				else
					printf( "NET Device :Error\r\n");
			}
		}
	
	}	
}
2,DHT11模块—检测温湿度
/***注解:

1. 在dht11.h中定义了DHT11_GPIO和DHT11_PIN,分别表示DHT11传感器所连接的GPIO口和引脚号。

2. DHT11_Init函数用于初始化DHT11传感器所连接的GPIO口,将其设置为输出模式,并将引脚电平设置为高电平。

3. DHT11_Read函数用于读取DHT11传感器的温度和湿度数据。首先将DHT11_GPIO设置为输出模式,并将引脚电平设置为低电平,延时18ms,然后将引脚电平设置为高电平,延时40us,最后将DHT11_GPIO设置为输入模式,并等待DHT11传感器的响应信号。

4. 如果DHT11传感器响应信号正确,则开始读取DHT11传感器的数据。每个数据包含40个位,其中第1个字节为湿度的整数部分,第3个字节为温度的整数部分,第5个字节为校验和。读取每个位时,先等待50us的低电平,然后再等待30us的高电平,根据高电平的持续时间判断该位是0还是1。

5. 如果读取的数据校验和正确,则将湿度和温度的整数部分存储在temperature和humidity变量中,并返回1;否则返回0。
****/

#include "delay.h"
#include "dht11.h"

void DHT11_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    GPIO_InitStructure.GPIO_Pin = DHT11_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DHT11_GPIO, &GPIO_InitStructure);

    GPIO_SetBits(DHT11_GPIO, DHT11_PIN);
}

uint8_t DHT11_Read(uint8_t *temp, uint8_t *humi)
{
    uint8_t data[5];
    uint8_t i, j;

		GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);


    GPIO_InitStructure.GPIO_Pin = DHT11_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DHT11_GPIO, &GPIO_InitStructure);

    GPIO_ResetBits(DHT11_GPIO, DHT11_PIN);
    delay_ms(18);
    GPIO_SetBits(DHT11_GPIO, DHT11_PIN);
    delay_us(40);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(DHT11_GPIO, &GPIO_InitStructure);

    if (GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_PIN) == RESET)
    {
        while (GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_PIN) == RESET)
            ;

        while (GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_PIN) == SET)
            ;

        for (i = 0; i < 5; i++)
        {
            for (j = 0; j < 8; j++)
            {
                while (GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_PIN) == RESET)
                    ;

                delay_us(30);

                if (GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_PIN) == SET)
                {
                    data[i] |= (1 << (7 - j));
                }

                while (GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_PIN) == SET)
                    ;
            }
        }

        if ((data[0] + data[1] + data[2] + data[3]) == data[4])
        {
            *humi = data[0];
            *temp = data[2];
            return 1;
        }
        else
        {
            return 0;
        }
    }
    else
    {
        return 0;
    }
}

3,JW01
void uart3_init(u32 bound)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	// GPIOB时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); //串口3时钟使能

	USART_DeInit(USART3);  //复位串口3
	//USART3_TX   PB10
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
	GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB10

	//USART3_RX	  PB11
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
	GPIO_Init(GPIOB, &GPIO_InitStructure);  //初始化PB11

	USART_InitStructure.USART_BaudRate = bound;//波特率一般设置为9600;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式

	USART_Init(USART3, &USART_InitStructure); //初始化串口	3


	USART_Cmd(USART3, ENABLE);                    //使能串口 

	//使能接收中断
	USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启中断   

	//设置中断优先级
	NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
}

由于篇幅有限,只展示部分模块的部分代码~

5,软件部分

在软件设计方面,系统主要实现以下功能:首先,通过传感器采集环境参数,并将数据传输给STM32单片机进行处理;然后,单片机将处理后的数据通过OLED显示器实时显示出来;同时,根据设定的阈值,判断是否需要触发蜂鸣器报警和风扇通风功能;最后,通过WiFi通信模块将数据传输到外部网络,以便用户通过手机APP或其他方式实时查看和控制环境参数。

使用的是onenet平台,进行数据的传输~
APP界面是可以定制,也支持小程序,支持网页等形式。

当然,硬件部分也允许做一些模块的更换修改的,例如CO2不需要,换成CO,或者增加或减少模块,都是支持的~

6,应用场景

基于设计的STM32智能家居,也可以称作是环境检测的功能,以下是一些应用场景:

1,智能家居安全监控:

可以将您的设备安装在家庭中的关键区域,如厨房、客厅或卧室,以监测室内环境的温湿度、烟雾和二氧化碳浓度。一旦烟雾或二氧化碳浓度超标,蜂鸣器会发出报警,同时启动风扇通风,以减少潜在的安全风险。

2,工业自动化与监控:

在仓库、工厂或其他需要严格控制环境条件的场所,可以使用您的设备来监控环境的温湿度、烟雾和二氧化碳浓度。这些数据可以通过WiFi传输到远程监控系统,以便工作人员进行实时监控和调整。

3,农业温室监控:

在温室环境中,温湿度、烟雾和二氧化碳浓度对植物的生长至关重要。您的设备可以实时检测这些参数,并通过WiFi将数据传输到移动物联网平台,农民或农业技术人员可以根据数据调整温室内的环境,以促进植物的健康生长。

4,学校与实验室安全监控:

在学校或实验室中,可能需要进行各种实验或活动,这些活动可能会产生烟雾或二氧化碳。使用您的设备可以实时监测这些有害物质的浓度,并在超标时发出报警,确保学生和实验人员的安全。

5,公共场所空气质量监测:

这个设备也可以用于公共场所,如购物中心、博物馆、图书馆等,以监测室内空气质量。通过WiFi传输数据到移动物联网平台,管理者可以了解各个区域的空气质量情况,并采取相应的措施来改善空气质量。

6,定制化的环境监测解决方案:

对于需要特定环境监测解决方案的客户,如博物馆需要保护珍贵文物免受潮湿和污染,或医院需要确保病房内的空气质量良好,您的设备可以根据客户需求进行定制和配置。

==================

资料可以点击链接进行获取:免费领取单片机资料

在这里插入图片描述

  • 15
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值