【mcu-1199】基于STM32的智能绿植种植系统设计【单片机毕业设计项目参考】
一、功能介绍
项目名:基于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 */
更多推荐

所有评论(0)