一、功能介绍

项目名:基于STM32的智能绿植种植系统设计
项目编号:dz-1199
单片机:STM32F103C8T6
功能简介:
1、通过DHT11检测当前环境的温湿度;
2、通过土壤湿度检测模块检测当前土壤湿度,监测到土壤湿度小于最小值,自动打开灌溉系统,且水箱水位较低,不能打开灌溉,水位大于最小值打开灌溉直到土壤湿度大于最大值,关闭灌溉;
3、通过光照检测模块5516检测当前环境的光照强度,监测到当前的光照强度小于设置的最小值,自动打开补光;
4、通过SGP30检测模块检测当前环境的CO2浓度;
5、通过水位监测模块监测当前水箱水位,监测到当前水箱水位小于最小值,手机弹窗震动提醒“水箱水位较低;
6、通过按键可以切换当前绿植的不同生长期”育苗期“、”生长期“、“结果期”,不同的期间对应不同的土壤湿度和光照强度;
7、通过OLED显示模块显示当前环境的监测值及其当前绿植的生长期;
8、通过WiFi模块将当前监测的数据传输到手机端,手机可以设置当前绿植的生长期,手动控制灌溉和补光的开关。

二、实物演示视频

【mcu-1199】基于STM32的智能绿植种植系统设计

三、仿真演示视频

【mcu-1199】基于STM32的智能绿植种植系统设计

四、资料展示

实物资料

请添加图片描述

仿真资料

请添加图片描述

五、原理图

软件版本:AD2013
电路连线方式:采用网络标号连线方式,各功能模块之间通过统一的网络标号名称建立电气连接,避免大量走线交叉,使图纸层次更清晰、便于阅读与后期修改。
注意:原理图仅绘制了各模块的引脚图,并非模块的内部结构原理图,因此图中只体现模块对外的引脚定义与连接关系,模块内部的电路细节不在本图中展开。
在这里插入图片描述

六、PCB图

由原理图导出,封装很大一部分都是作者自己绘制,不提供封装库,只提供连接好的源文件,源文件可直接导入嘉立创进行打板。
板子采用两层板设计,上下两层均做了覆铜接地处理,一方面可以降低地线阻抗、提升抗干扰能力,另一方面也能减少走线难度、方便布线。PCB 上预留了各模块的接口与调试引脚,方便后续焊接与测试;中间还隐藏了一个项目编号,位于单片机底座下方,插入单片机后不会看到。
在这里插入图片描述

七、系统框图

绘制软件:VISIO
在这里插入图片描述

八、软件设计流程图

绘制软件:VISIO
在这里插入图片描述

九、部分程序展示

软件版本:keil5

/* USER CODE BEGIN Header */

/**********************************
**********************************/

/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

#include "./DELAY/delay.h"
#include "./OLED/oled.h"
#include "./KEY/key.h"
#include "./ALIYUN/aliyun.h"
#include "./ESP8266/esp8266.h"
#include "./MQTT/mqtt.h"
#include "./DHT11/dht11.h"
#include "./SGP30/sgp30.h"


/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

uint8_t key_num = 0;										//按键键值
uint8_t display_num = 0;								//显示界面
uint16_t time_num = 0;									//计时值
char display_buf[16] = {0};							//显示数组

extern uint8_t esp8266_rx_buf[1024];		//esp8266接收数据数组
extern uint8_t esp8266_rx_finish;				//esp8266接收完成标志位
uint8_t *esp8266_dataPtr = NULL;				//esp8266返回的格式
uint8_t *esp8266_data = NULL;						//esp8266下发的数据
char *esp8266_result = NULL;  					//esp8266解析结果

uint8_t flag_begin_5s = 0;							//5s计时开始标志位
uint8_t flag_finish_5s = 0;;						//5s计时完成标志位

uint16_t temp_value = 0;								//温度值
uint16_t humi_value = 0;								//湿度值

uint16_t tr_humi_value = 0;							//土壤湿度值
uint16_t ym_tr_min = 40;								//育苗期土壤湿度最小值
uint16_t ym_tr_max = 70;								//育苗期土壤湿度最大值
uint16_t sz_tr_min = 60;								//生长期土壤湿度最小值
uint16_t sz_tr_max = 80;								//生长期土壤湿度最大值
uint16_t jg_tr_min = 30;								//结果期土壤湿度最小值
uint16_t jg_tr_max = 60;								//结果期土壤湿度最大值

uint16_t light_value = 0;								//光照值
uint16_t ym_light = 150;								//育苗期光照值
uint16_t sz_light = 200;								//生长期光照值
uint16_t jg_light = 100;								//结果期光照值

int16_t level_value = 0;								//水位值
uint16_t level_min = 30;								//水位最小值

uint16_t CO2_value = 0;									//CO2值

uint8_t flag_sq = 0;										//时期标志位
uint8_t select_num = 0;									//选择标志位
_Bool flag_gz = 0;											//光照标志位
_Bool flag_sw = 0;											//水位标志位


/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

void Key_Function(void);								//按键函数
void Monitor_Function(void);						//监测函数
void Display_Function(void);						//显示函数
void Manage_Function(void);							//处理函数
void Aliyun_Send_Data(void);						//数据上报函数

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/**********************************
函数名:按键函数
传参值:无
返回值:无
**********************************/
void Key_Function(void)
{
	key_num = Chiclet_Keyboard_Scan(0);		//按键扫描,获取键值
	if(key_num != 0)								      //有按键按下
	{
		switch(key_num)
		{
			case 1:								            //按键1:切换界面
				display_num++;
				if(display_num >= 11)
				{
					display_num = 0;
				}
				
				Oled_Clear_All();					      //清屏
			break;

			case 2:											      //按键2
				switch(display_num)
				{
					case 0:                       //界面0:选择控制
						select_num++;
						if(select_num >= 3)
						{
							select_num = 0;
						}
					break;
					
					case 1:												//界面1:育苗期土壤湿度最大值+1
						if(ym_tr_max < 100)
						{
							ym_tr_max++;
						}
					break;
					
					case 2:												//界面2:育苗期土壤湿度最小值+1
						if(ym_tr_min < ym_tr_max-1)
						{
							ym_tr_min++;
						}
					break;
						
					case 3:												//界面3:生长期土壤湿度最大值+1
						if(sz_tr_max < 100)
						{
							sz_tr_max++;
						}
					break;
					
					case 4:												//界面4:生长期土壤湿度最小值+1
						if(sz_tr_min < sz_tr_max-1)
						{
							sz_tr_min++;
						}
					break;
						
					case 5:												//界面5:结果期土壤湿度最大值+1
						if(jg_tr_max < 100)
						{
							jg_tr_max++;
						}
					break;
						
					case 6:												//界面6:结果期土壤湿度最小值+1
						if(jg_tr_min < jg_tr_max-1)
						{
							jg_tr_min++;
						}
					break;
					
					case 7:												//界面7:育苗期光照值+10
						if(ym_light < 500)
						{
							ym_light += 10;
						}
					break;
					
					case 8:												//界面8:成长期光照值+10
						if(sz_light < 500)
						{
							sz_light += 10;
						}
					break;
					
					case 9:												//界面9:结果期光照值+10
						if(jg_light < 500)
						{
							jg_light += 10;
						}
					break;
						
					case 10:											//界面10:水位最小值+1
						if(level_min < 100)
						{
							level_min++;
						}
					break;
						
					default:
					break;
				}
			break;

			case 3:														//按键3
				switch(display_num)
				{
					case 0:                      	//界面0:控制选择
						switch(select_num)
						{
							case 0:										//选择时期期
								flag_sq++;
								if(flag_sq >= 3)
								{
									flag_sq = 0;
								}
							break;
						
							case 1:										//手动控制浇水
								if(flag_sq == 0)																								
								{
									if(ym_tr_min <= tr_humi_value && tr_humi_value <= ym_tr_max && level_value >= level_min)
									{
										RELAY_JS = !RELAY_JS;
									}
								}
								else if(flag_sq == 1)																										
								{                                                                   
									if(sz_tr_min <= tr_humi_value && tr_humi_value <= sz_tr_max && level_value >= level_min)          
									{                                                                 
										RELAY_JS = !RELAY_JS;                                                   
									}                                                                 
								}
								else												
								{                                                                   
									if(jg_tr_min <= tr_humi_value && tr_humi_value <= jg_tr_max && level_value >= level_min)          
									{                                                                 
										RELAY_JS = !RELAY_JS;                                                  
									}
								}
							break;
							
							case 2:										//手动控制补光
								if(flag_sq == 0)																								
								{
									if(light_value >= ym_light)																				
									{
										RELAY_BG = !RELAY_BG;
										flag_gz = 1;
									}
								}
								else if(flag_sq == 1)																								
								{                                                                   
									if(light_value >= sz_light)																				
									{
										RELAY_BG = !RELAY_BG;
										flag_gz = 1;
									}                                                                
								}
								else												
								{                                                                   
									if(light_value >= jg_light)																				
									{
										RELAY_BG = !RELAY_BG;
										flag_gz = 1;
									}                                                                 
								}
							break;
							
							default:
							break;
						}
					break;
					
					case 1:												//界面1:育苗期土壤湿度最大值-1
						if(ym_tr_max > ym_tr_min+1)
						{
							ym_tr_max--;
						}
					break;
					
					case 2:												//界面2:育苗期土壤湿度最小值-1
						if(ym_tr_min > 0)
						{
							ym_tr_min--;
						}
					break;
						
					case 3:												//界面3:成长期土壤湿度最大值-1
						if(sz_tr_max > sz_tr_min+1)
						{
							sz_tr_max--;
						}
					break;
					
					case 4:												//界面4:成长期土壤湿度最小值-1
						if(sz_tr_min > 0)
						{
							sz_tr_min--;
						}
					break;
						
					case 5:												//界面5:结果期土壤湿度最大值-1
						if(jg_tr_max > jg_tr_min+1)
						{
							jg_tr_max--;
						}
					break;
						
					case 6:												//界面6:结果期土壤湿度最小值-1
						if(jg_tr_min > 0)
						{
							jg_tr_min--;
						}
					break;
					
					case 7:												//界面7:育苗期光照值-10
						if(ym_light > 0)
						{
							ym_light -= 10;
						}
					break;
					
					case 8:												//界面8:成长期光照值-10
						if(sz_light > 0)
						{
							sz_light -= 10;
						}
					break;
					
					case 9:												//界面9:结果期光照值-10
						if(jg_light > 0)
						{
							jg_light -= 10;
						}
					break;
						
					case 10:											//界面10:水位最小值-1
						if(level_min > 0)
						{
							level_min--;
						}
					break;
						
					default:
					break;
				}
			break;

			default:
			break;
		}
	}
}


/**********************************
函数名:读取指定ADC通道的数据
传参值:通道
返回值:ADC值
**********************************/
uint32_t ADC_Get_Value(uint32_t Channel)
{
	ADC_ChannelConfTypeDef sConfig;
	
  sConfig.Channel = Channel;
  sConfig.Rank = 1;
  HAL_ADC_ConfigChannel(&hadc1, &sConfig);
  
  HAL_ADC_Start(&hadc1);									//启动转换并等待结束
  HAL_ADC_PollForConversion(&hadc1, 10); 	//等待转换完成,10是超时时间(单位ms)
  
  return HAL_ADC_GetValue(&hadc1);				//返回转换后的数据
}


/**********************************
函数名:监测函数
传参值:无
返回值:无
**********************************/
void Monitor_Function(void)
{
	if(time_num % 100 == 0)								//监测数据
	{
		Dht11_Get_Temp_Humi_Value(&temp_value,&humi_value);															//DHT11读取温湿度函数
		
		SGP30_Get_Co2_Tvoc_Value(&CO2_value,NULL);																			//获取CO2浓度
		
		light_value = 495 - 150 * ((ADC_Get_Value(ADC_CHANNEL_4) / 4096.0) * 3.3);			//获取光照值
		
		tr_humi_value = 30 * ((ADC_Get_Value(ADC_CHANNEL_0) / 4096.0) * 3.3);						//获取土壤湿度值
		
		level_value = 60 * ((ADC_Get_Value(ADC_CHANNEL_1 ) / 4096.0) * 3.3) - 20;				//获取水位值
		if(level_value > 100)
		{
			level_value = 100;
		}
		else if(level_value < 0)
		{
			level_value = 0;
		}
	}
	
	esp8266_dataPtr = ESP8266_GetIPD(0);													//获取平台返回的数据
	if(esp8266_dataPtr != NULL)
	{
		Aliyun_RevPro(esp8266_dataPtr);															//平台返回数据检测

		esp8266_result = strstr((char *)esp8266_data, "ym_tr_max");	//判断是否为改变育苗期土壤湿度最大值
		if(esp8266_result != NULL)
		{
			esp8266_result = strstr(esp8266_result, ":") + 1;
			ym_tr_max = atoi((const char *)esp8266_result);
			if(ym_tr_max <= ym_tr_min)
			{
				ym_tr_max = ym_tr_min + 1;
			}
			
		}
		
		esp8266_result = strstr((char *)esp8266_data, "ym_tr_min");	//判断是否为改变育苗期土壤湿度最小值
		if(esp8266_result != NULL)
		{
			esp8266_result = strstr(esp8266_result, ":") + 1;
			ym_tr_min = atoi((const char *)esp8266_result);
			if(ym_tr_min >= ym_tr_max)
			{
				ym_tr_min = ym_tr_max - 1;
			}
			
		}
		
		esp8266_result = strstr((char *)esp8266_data, "sz_tr_max");	//判断是否为改变生长期土壤湿度最大值
		if(esp8266_result != NULL)
		{
			esp8266_result = strstr(esp8266_result, ":") + 1;
			sz_tr_max = atoi((const char *)esp8266_result);
			if(sz_tr_max <= sz_tr_min)
			{
				sz_tr_max = sz_tr_min + 1;
			}
			
		}
		
		esp8266_result = strstr((char *)esp8266_data, "sz_tr_min");	//判断是否为改变生长期土壤湿度最小值
		if(esp8266_result != NULL)
		{
			esp8266_result = strstr(esp8266_result, ":") + 1;
			sz_tr_min = atoi((const char *)esp8266_result);
			if(sz_tr_min >= sz_tr_max)
			{
				sz_tr_min = sz_tr_max - 1;
			}
			
		}
		
		esp8266_result = strstr((char *)esp8266_data, "jg_tr_max");	//判断是否为改变结果期土壤湿度最大值
		if(esp8266_result != NULL)
		{
			esp8266_result = strstr(esp8266_result, ":") + 1;
			jg_tr_max = atoi((const char *)esp8266_result);
			if(jg_tr_max <= jg_tr_min)
			{
				jg_tr_max = jg_tr_min + 1;
			}
			
		}
		
		esp8266_result = strstr((char *)esp8266_data, "jg_tr_min");	//判断是否为改变结果期土壤湿度最小值
		if(esp8266_result != NULL)
		{
			esp8266_result = strstr(esp8266_result, ":") + 1;
			jg_tr_min = atoi((const char *)esp8266_result);
			if(jg_tr_min >= jg_tr_max)
			{
				jg_tr_min = jg_tr_max - 1;
			}
			
		}
		
		esp8266_result = strstr((char *)esp8266_data, "ym_light");	//判断是否为改变育苗期光照值
		if(esp8266_result != NULL)
		{
			esp8266_result = strstr(esp8266_result, ":") + 1;
			ym_light = atoi((const char *)esp8266_result);

		}
		
		esp8266_result = strstr((char *)esp8266_data, "sz_light");	//判断是否为改变生长期光照值
		if(esp8266_result != NULL)
		{
			esp8266_result = strstr(esp8266_result, ":") + 1;
			sz_light = atoi((const char *)esp8266_result);

		}
		
		esp8266_result = strstr((char *)esp8266_data, "jg_light");	//判断是否为改变结果期光照值
		if(esp8266_result != NULL)
		{
			esp8266_result = strstr(esp8266_result, ":") + 1;
			jg_light = atoi((const char *)esp8266_result);

		}
		
		esp8266_result = strstr((char *)esp8266_data, "level_min"); //判断是否为改变水位最小值
		if(esp8266_result != NULL)
		{
			esp8266_result = strstr(esp8266_result, ":") + 1;
			level_min = atoi((const char *)esp8266_result);

		}
		
		esp8266_result = strstr((char *)esp8266_data, "RELAY_JS");	//判断是否为改变浇水继电器状态
		if(esp8266_result != NULL)
		{
			esp8266_result = strstr(esp8266_result, ":") + 1;
			if(flag_sq == 0)																								
			{
				if(ym_tr_min <= tr_humi_value && tr_humi_value <= ym_tr_max && level_value >= level_min)
				{
					RELAY_JS = atoi((const char *)esp8266_result);
				}
			}
			else if(flag_sq == 1)																										
			{                                                                   
				if(sz_tr_min <= tr_humi_value && tr_humi_value <= sz_tr_max && level_value >= level_min)          
				{                                                                 
					RELAY_JS = atoi((const char *)esp8266_result);                                                   
				}                                                                 
			}
			else												
			{                                                                   
				if(jg_tr_min <= tr_humi_value && tr_humi_value <= jg_tr_max && level_value >= level_min)          
				{                                                                 
					RELAY_JS = atoi((const char *)esp8266_result);                                                  
				}
			}
		}
		
		esp8266_result = strstr((char *)esp8266_data, "RELAY_BG");	//判断是否为改变照明继电器状态
		if(esp8266_result != NULL)
		{
			esp8266_result = strstr(esp8266_result, ":") + 1;	
			if(flag_sq == 0)																								
			{
				if(light_value >= ym_light)																				
				{
					RELAY_BG = atoi((const char *)esp8266_result);
					flag_gz = 1;
				}
			}
			else if(flag_sq == 1)																								
			{                                                                   
				if(light_value >= sz_light)																				
				{
					RELAY_BG = atoi((const char *)esp8266_result);
					flag_gz = 1;
				}                                                                
			}
			else												
			{                                                                   
				if(light_value >= jg_light)																				
				{
					RELAY_BG = atoi((const char *)esp8266_result);
					flag_gz = 1;
				}                                                                 
			}
		}
		
		esp8266_result = strstr((char *)esp8266_data, "flag_sq"); //判断下发数据
		if(esp8266_result != NULL)
		{
			esp8266_result = strstr(esp8266_result, ":") + 1;
			flag_sq = atoi((const char *)esp8266_result);

		}
	}
	
	MQTT_FreeBuffer(esp8266_data);																//释放内存
}


/**********************************
函数名:显示函数
传参值:无
返回值:无
**********************************/
void Display_Function(void)
{
	if(time_num % 100 == 0)
	{
		switch(display_num)											//根据不同的显示界面,显示不同的内容
		{
			case 0:									      				//界面0:显示测量数据
				Oled_ShowString(1,0,"T:");
				sprintf(display_buf,"%d.%dC ",temp_value/10,temp_value%10);
				Oled_ShowString(1,2,display_buf);
				
				Oled_ShowString(1,8,"H:");
				sprintf(display_buf,"%d.%d%% ",humi_value/10,humi_value%10);
				Oled_ShowString(1,10,display_buf);
			
				Oled_ShowString(2,0,"S:");
				sprintf(display_buf,"%d%%  ",tr_humi_value);
				Oled_ShowString(2,2,display_buf);
				
				Oled_ShowString(2,8,"W:");
				sprintf(display_buf,"%d%%  ",level_value);
				Oled_ShowString(2,10,display_buf);
			
				Oled_ShowString(3,0,"C:");
				sprintf(display_buf,"%dppm   ",CO2_value);
				Oled_ShowString(3,2,display_buf);
				
				if(select_num == 0)
				{
					Oled_ShowCHinese(3,6,"时期");
					if(flag_sq == 0)
					{
						Oled_ShowCHinese(4,6,"育苗");
					}
					else if(flag_sq == 1)
					{
						Oled_ShowCHinese(4,6,"成长");
					}
					else
					{
						Oled_ShowCHinese(4,6,"结果");
					}
				}
				else if(select_num == 1)
				{
					Oled_ShowCHinese(3,6,"浇水");
					if(RELAY_JS == 1)
					{
						Oled_ShowCHinese(4,6,"开启");
					}
					else
					{
						Oled_ShowCHinese(4,6,"关闭");
					}
				}
				else
				{
					Oled_ShowCHinese(3,6,"补光");
					if(RELAY_BG == 1)
					{
						Oled_ShowCHinese(4,6,"开启");
					}
					else
					{
						Oled_ShowCHinese(4,6,"关闭");
					}
				}
					
				Oled_ShowString(4,0,"L:");
				sprintf(display_buf,"%dLux  ",light_value);
				Oled_ShowString(4,2,display_buf);			
				
			break;
			
			case 1:																//界面1:设置育苗期土湿最大值
				Oled_ShowCHinese(1,0,"育苗期土湿最大值");
				if(time_num % 100 == 0)
				{
					sprintf(display_buf,"%d  ",ym_tr_max); 
					Oled_ShowString(2,7,display_buf);
				}
				if(time_num % 200 == 0)
				{
					Oled_ShowString(2,7,"    ");
				}
			break;
				
			case 2:																//界面2:设置育苗期土湿最小值
				Oled_ShowCHinese(1,0,"育苗期土湿最小值");
				if(time_num % 100 == 0)
				{
					sprintf(display_buf,"%d  ",ym_tr_min); 
					Oled_ShowString(2,7,display_buf);
				}
				if(time_num % 200 == 0)
				{
					Oled_ShowString(2,7,"    ");
				}
			break;
				
			case 3:																//界面3:设置成长期土湿最大值
				Oled_ShowCHinese(1,0,"成长期土湿最大值");
				if(time_num % 100 == 0)
				{
					sprintf(display_buf,"%d  ",sz_tr_max); 
					Oled_ShowString(2,7,display_buf);
				}
				if(time_num % 200 == 0)
				{
					Oled_ShowString(2,7,"    ");
				}
			break;
				
			case 4:																//界面4:设置成长期土湿最小值
				Oled_ShowCHinese(1,0,"成长期土湿最小值");
				if(time_num % 100 == 0)
				{
					sprintf(display_buf,"%d  ",sz_tr_min); 
					Oled_ShowString(2,7,display_buf);
				}
				if(time_num % 200 == 0)
				{
					Oled_ShowString(2,7,"    ");
				}
			break;
			
			case 5:																//界面5:设置结果期土湿最大值
				Oled_ShowCHinese(1,0,"结果期土湿最大值");
				if(time_num % 100 == 0)
				{
					sprintf(display_buf,"%d  ", jg_tr_max); 
					Oled_ShowString(2,7,display_buf);
				}
				if(time_num % 200 == 0)
				{
					Oled_ShowString(2,7,"    ");
				}
			break;
				
			case 6:																//界面6:设置结果期土湿最小值
				Oled_ShowCHinese(1,0,"结果期土湿最小值");
				if(time_num % 100 == 0)
				{
					sprintf(display_buf,"%d  ", jg_tr_min); 
					Oled_ShowString(2,7,display_buf);
				}
				if(time_num % 200 == 0)
				{
					Oled_ShowString(2,7,"    ");
				}
			break;
			
			case 7:																//界面7:设置育苗期光照值
				Oled_ShowCHinese(1,0,"设置育苗期光照值");
				if(time_num % 100 == 0)
				{
					sprintf(display_buf,"%d  ", ym_light); 
					Oled_ShowString(2,7,display_buf);
				}
				if(time_num % 200 == 0)
				{
					Oled_ShowString(2,7,"    ");
				}
			break;
			
			case 8:																//界面8:设置生长期光照值
				Oled_ShowCHinese(1,0,"设置生长期光照值");
				if(time_num % 100 == 0)
				{
					sprintf(display_buf,"%d  ", sz_light); 
					Oled_ShowString(2,7,display_buf);
				}
				if(time_num % 200 == 0)
				{
					Oled_ShowString(2,7,"    ");
				}
			break;
				
			case 9:																//界面9:设置结果期光照值
				Oled_ShowCHinese(1,0,"设置结果期光照值");
				if(time_num % 100 == 0)
				{
					sprintf(display_buf,"%d  ", jg_light); 
					Oled_ShowString(2,7,display_buf);
				}
				if(time_num % 200 == 0)
				{
					Oled_ShowString(2,7,"    ");
				}
			break;
			
			case 10:															//界面10:设置水位最小值
				Oled_ShowCHinese(1,0,"设置水位最小值");
				if(time_num % 100 == 0)
				{
					sprintf(display_buf,"%d  ",level_min); 
					Oled_ShowString(2,7,display_buf);
				}
				if(time_num % 200 == 0)
				{
					Oled_ShowString(2,7,"    ");
				}
			break;
			
			default:
			break;
		}
	}
}


/**********************************
函数名:处理函数
传参值:无
返回值:无
**********************************/
void Manage_Function(void)
{
	if(display_num == 0)								  			//测量界面
	{
		if(flag_sq == 0)													//在育苗期,土壤湿度小于最小值并且水箱水位大于最小值时进行浇水
		{
			if(level_value > level_min)
			{
				if(tr_humi_value < ym_tr_min)
				{
					RELAY_JS = 1;
				}
				else if(tr_humi_value > ym_tr_max)		//直到土壤湿度大于最大值关闭浇水
				{
					RELAY_JS = 0;
				}
			}
			else
			{
				RELAY_JS = 0;
			}
			
			if(light_value < ym_light)							//在育苗期时,光照小于最小值进行补光
			{
				RELAY_BG = 1;
				
				flag_gz = 0;
			}
			else
			{
				if(flag_gz == 0)
				{
					RELAY_BG = 0;
				}
			}
		}
		else if(flag_sq == 1)											//在生长期,土壤湿度小于最小值并且水箱水位大于最小值时进行浇水																					
		{                                                                   
			if(level_value > level_min)
			{
				if(tr_humi_value < sz_tr_min)
				{
					RELAY_JS = 1;
				}
				else if(tr_humi_value > sz_tr_max)		//直到土壤湿度大于最大值关闭浇水		
				{
					RELAY_JS = 0;
				}
			}
			else
			{
				RELAY_JS = 0;
			}
			
			if(light_value < sz_light)							//在生长期时,光照小于最小值进行补光
			{
				RELAY_BG = 1;
				
				flag_gz = 0;
			}
			else
			{
				if(flag_gz == 0)
				{
					RELAY_BG = 0;
				}
			}
		}
		else																			//在结果期,土壤湿度小于最小值并且水箱水位大于最小值时进行浇水
		{                                                                   
			if(level_value > level_min)
			{
				if(tr_humi_value < jg_tr_min)
				{
					RELAY_JS = 1;
				}
				else if(tr_humi_value > jg_tr_max)		//直到土壤湿度大于最大值关闭浇水		
				{
					RELAY_JS = 0;
				}
			}
			else
			{
				RELAY_JS = 0;
			}
			
			if(light_value < jg_light)							//在结果期时,光照小于最小值进行补光
			{
				RELAY_BG = 1;
				
				flag_gz = 0;
			}
			else
			{
				if(flag_gz == 0)
				{
					RELAY_BG = 0;
				}
			}
		}
		
		if(level_value < level_min)								//水位小于最小值,水位标志位置1
		{
			flag_sw = 1;
		}
		else
		{
			flag_sw = 0;
		}
	}
	else																				//设置界面,关闭浇水和补光
	{
		RELAY_JS = 0;
		
		RELAY_BG = 0;
	}
	
	if(flag_finish_5s == 1)											//5秒上传一次数据
  {
    flag_begin_5s = 0;
    Aliyun_Send_Data();
    flag_begin_5s = 1;
  }
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM1_Init();
  MX_USART1_UART_Init();
  MX_ADC1_Init();
  /* USER CODE BEGIN 2 */

	Delay_Init();													//延时初始化
	Oled_Init();													//OLED初始化
	Key_Init();														//KEY初始化
	DHT11_Init();  												//DHT11初始化函数
	SGP30_Init();													//SGP30初始化

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
	
	Oled_Clear_All();											//清屏
	
	HAL_TIM_Base_Start_IT(&htim1);				//启动定时器
	
	HAL_UARTEx_ReceiveToIdle_IT(&ESP8266_HUART, esp8266_rx_buf, sizeof(esp8266_rx_buf) / sizeof(esp8266_rx_buf[0]));		//获取串口接收数据
	
	Oled_ShowString(1,6,"WIFI ");
	Oled_ShowCHinese(2, 2, "初始化中");
	ESP8266_Init();											//初始化ESP8266
	Oled_ShowString(3,4,"........");
	while(Aliyun_DevLink())							//接入阿里云
	Delay_ms(500);
	Oled_ShowString(4,4,"........");
	Aliyun_Subscribe(topics_set, 1);		//订阅主题
	Delay_ms(500);
	Aliyun_Send_Data();									//数据上报初始状态
  flag_begin_5s = 1;									//开启定时
  Oled_Clear_All();										//清屏

  while (1)
  {
		Key_Function();										  //按键函数
		Monitor_Function();									//监测函数
		Display_Function();									//显示函数
		Manage_Function();									//处理函数
		
		if(time_num % 100 == 0)							//指示灯闪烁
		{
			SYSTEM_LED = !SYSTEM_LED;
		}
		
		Delay_ms(1);												//延时1ms
		time_num++;											    //计时值+1
		if(time_num >= 10000)
		{
			time_num = 0;
		}

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
  PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */


/**********************************
函数名:定时器中断回调函数
传参值:无
返回值:无
**********************************/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	static uint32_t time_count_5s = 0;

	if(htim->Instance == htim1.Instance)		//定时器1触发中断
	{
		if(flag_begin_5s == 1)
		{
			time_count_5s++;
			
			if(time_count_5s >= 5000)						//5s计时
			{
				time_count_5s = 0;
				
				flag_finish_5s = 1;
			}
		}
		else
		{
			time_count_5s = 0;
			flag_finish_5s = 0;
		}
	}
}

/**********************************
函数名:串口事件回调函数
传参值:huart:串口号		Size:数据大小
返回值:无
**********************************/
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if(huart->Instance == ESP8266_HUART.Instance)				//4g串口触发中断
	{
		HAL_UARTEx_ReceiveToIdle_IT(&ESP8266_HUART, esp8266_rx_buf, sizeof(esp8266_rx_buf) / sizeof(esp8266_rx_buf[0]));
		esp8266_rx_finish = 1;
	}
}

/**********************************
函数名:串口错误回调函数
传参值:huart:串口号
返回值:无
**********************************/
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
	HAL_UART_DeInit(huart);
	HAL_UART_Init(huart);
	
	if(huart->Instance == ESP8266_HUART.Instance)
	{
		HAL_UARTEx_ReceiveToIdle_IT(&ESP8266_HUART, esp8266_rx_buf, sizeof(esp8266_rx_buf) / sizeof(esp8266_rx_buf[0]));
		esp8266_rx_finish = 1;
	}
}


/**********************************
函数名:数据上报函数
传参值:无
返回值:无
**********************************/
void Aliyun_Send_Data(void)
{
	char send_data[512];								//发送数据数组
	
	sprintf(send_data,"{\"method\":\"thing/event/property/post\",\"id\":\"203302322\",\"params\":{\"temp_value\":%.1f,\"humi_value\":%.1f,\"tr_humi_value\":%d,\"light_value\":%d,\"ym_tr_min\":%d,\"ym_tr_max\":%d,\"sz_tr_min\":%d,\"sz_tr_max\":%d,\"jg_tr_min\":%d,\"jg_tr_max\":%d,\"ym_light\":%d,\"sz_light\":%d,\"jg_light\":%d,\"level_value\":%d,\"level_min\":%d,\"CO2_value\":%d,\"RELAY_JS\":%d,\"RELAY_BG\":%d,\"flag_sw\":%d,\"flag_sq\":%d},\"version\":\"1.0.0\"}",
					temp_value/10.0,humi_value/10.0,tr_humi_value,light_value,ym_tr_min,ym_tr_max,sz_tr_min,sz_tr_max,jg_tr_min,jg_tr_max,ym_light,sz_light,jg_light,level_value,level_min,CO2_value,(_Bool)RELAY_JS,(_Bool)RELAY_BG,flag_sw,flag_sq);

	Aliyun_Publish(topics_post, send_data);  		//添加数据,发布给服务器	
}


/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

​

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐