基于STM32的智慧农业项目(物联网专业毕设)附送源码和文档材料+学习路线
概要
传统农业存在着产量受到环境因素影响较大的问题,现有的农业监测系统数据太过简单、太过理想化。而随着现代科学的持续发展,一个精准化、自动化的现代智能农产品管理系统将在农业生产中起着日益关键的角色。
本项目立足于温室大棚,设计一个能够智能控制和远程监控的智慧农业监测系统,实现了感知节点数据采集、上传,以及接收小程序发来的指令,控制水泵、排风扇、暖灯、蜂鸣器等。本系统主要采用低功率单片机stm32f103作为主控芯片,使用DHT11、MQ-2、XH-M214土壤湿度传感器、BH1750光照强度模块,采集温室大棚环境数据,esp8266作为通讯模块,上传至搭建好的MQTT服务器中。利用串口屏可以进行数据的实时显示和控制。小程序基于mpvue框架进行开发,实现了数据显示、命令下发、账户注册、账户登陆功能。使得温室大棚的环境参数能够可视化,并且能远程控制温室大棚内部的执行器。本项目解决了一些农业中信息闭塞,决策迟缓不科学的问题。可以大大提高农业生产效率,增加农业产量。推动地区温室大棚农业经济蓬勃发展。
整体架构流程
本系统基于stm32单片机和微信小程序,其主要功能包括大棚内部温度、空气湿度、光照强度、大棚内二氧化碳浓度等数据的采集、上传和显示。水泵,风扇,暖灯,报警开关的远程控制。主要模块包含:硬件系统设计(传感器数据的采集、上传、逻辑控制,液晶屏数据显示),软件系统设计(MQTT服务器使用、服务器配置、界面设计)、系统功能实现、系统测试。本系统采用使用stm32单片机和微信小程序,设计包括硬件和软件的智慧农业检测系统。基于传感器、通信、自动化等技术,对农业生产的环境参数和设备进行实时监控。
硬件选型
软件总体框架
技术细节
主函数代码
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "dht11.h"
#include "beep.h"
#include "esp8266.h"
#include "onenet.h"
#include "stdio.h"
#include "bh1750.h"
#include "adc.h"
#include "timer.h"
#include "mq2.h"
#include "relay.h"
#include "fs.h"
#include "pump.h"
/************************************************
参考正点原子工程建立的代码
************************************************/
u8 humidityH; //湿度整数部分
u8 humidityL; //湿度小数部分
u8 temperatureH; //温度整数部分
u8 temperatureL; //温度小数部分
u8 alarmFlag = 0;//是否报警的标志
u8 alarm_is_free = 10;//报警器是否被手动操作,如果被手动操作即设置为0
u8 ESP8266_INIT_OK = 0;//esp8266初始化完成标志
u8 Led_Status = 0;//led状态
//u16 adcx=0;//adc的初始值
u16 adcx1;
u16 shidu;
char PUB_BUF[256];//上传数据的buf
unsigned char HDMI_BUF[64];//HDMI发送数据buf
float Light = 0; //光照度
float co2 = 0; //二氧化碳浓度
float temp = 0;
float hum = 0;
const char* devSubTopic[] = {"/mysmartfarm/sub"};
const char devPubTopic[] = "/mysmartfarm/pub";
int main(void)
{
unsigned short timeCount = 0; //发送间隔变量
unsigned char* dataPtr = NULL;
delay_init(); //延时函数初始化
LED_Init(); //初始化与LED连接的硬件接口
DHT11_Init();//DHT11初始化
BEEP_Init();//蜂鸣器初始化
RELAY_Init();//继电器初始化
BH1750_Init();//光照传感器初始化
Adc_Init();//adc初始化
Adc2_Init();//adc2初始化
Usart1_Init(115200);//串口初始化
Usart2_Init(115200);//esp8266通讯串口初始化
Usart3_Init(9600);//HDMI串口屏初始化
ESP8266_Init();//esp8266初始化
fs_Init();
pump_Init();
HMISendstart();//HDMI清空
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
TIM3_Int_Init(4999, 7199); //10Khz的计数频率,计数到5000为500ms
while(OneNet_DevLink())
delay_ms(500);
// BEEP=0;//鸣叫表示接入成功
// delay_ms(250);
// BEEP=1;
OneNet_Subscribe(devSubTopic, 1);
while(1)
{
// delay_ms(100);
adcx1 = Get_Adc_Average(ADC_Channel_10, 10);
shidu = ((4095 - adcx1) * 100) / 3292;
// UsartPrintf(USART1,"adcx1:%d",adcx1);
// UsartPrintf(USART1,"shidu: %d",shidu);
DHT11_Read_Data(&humidityH, &humidityL, &temperatureH, &temperatureL);
temp = temperatureH + temperatureL * 0.01;
sprintf((char*)HDMI_BUF, "page0.t0.txt=\"%.1f\"", temp);
HMISends((char*)HDMI_BUF);
HMISendb(0xff);
sprintf((char*)HDMI_BUF, "page0.t2.txt=\"%d\"", shidu);
HMISends((char*)HDMI_BUF);
HMISendb(0xff);
Light = LIght_Intensity();
sprintf((char*)HDMI_BUF, "page0.t1.txt=\"%.1f\"", Light);
HMISends((char*)HDMI_BUF);
HMISendb(0xff);
co2 = MQ2_GetPPM();
sprintf((char*)HDMI_BUF, "page0.t3.txt=\"%.1f\"", co2);
HMISends((char*)HDMI_BUF);
HMISendb(0xff);
if(++timeCount >= 200) //发送间隔5s
{
Led_Status = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5); //读取LED0的状态
// hum=humidityH+humidityL*0.01;
//
// UsartPrintf(USART1,"湿度高位:%d",humidityH);
// UsartPrintf(USART1,"湿度低位:%d",humidityL);
// UsartPrintf(USART1,"湿度:%.1f",hum);
//adcx=Get_Adc_Average(ADC_Channel_1,10);
UsartPrintf(USART1, "湿度:%d温度:%d.%d 光照强度:%.1f ppm值:%.1f", shidu, temperatureH, temperatureL, Light, co2); //c格式化字符串
UsartPrintf(USART_DEBUG, "OneNet_Publish\r\n");
sprintf(PUB_BUF, "{\"Hum\":%d,\"Temp\":%d.%d,\"Light\":%.1f,\"Co2\":%.1f,\"Led\":%d,\"Beep\":%d}",
shidu, temperatureH, temperatureL, Light, co2, Led_Status ? 0 : 1, alarmFlag);
//OneNet_Publish("pcTopic", "MQTT Publish Test");
//
OneNet_Publish(devPubTopic, PUB_BUF);
timeCount = 0;
ESP8266_Clear();
}
//
dataPtr = ESP8266_GetIPD(3);
if(dataPtr != NULL)
OneNet_RevPro(dataPtr);
}
}
各种传感器驱动文件
接收平台发送的数据
//==========================================================
// 函数名称: OneNet_RevPro
//
// 函数功能: 平台返回数据检测
//
// 入口参数: dataPtr:平台返回的数据 也就是*cmd
//
// 返回参数: 无
//
// 说明:
//==========================================================
void OneNet_RevPro(unsigned char *cmd)
{
MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0}; //协议包
char *req_payload = NULL;
char *cmdid_topic = NULL;
unsigned short topic_len = 0;
unsigned short req_len = 0;
unsigned char type = 0;
unsigned char qos = 0;
static unsigned short pkt_id = 0;
short result = 0;
char *dataPtr = NULL;
char numBuf[10];
int num = 0;
cJSON *json , *json_value;
type = MQTT_UnPacketRecv(cmd);
switch(type)
{
case MQTT_PKT_CMD: //命令下发
result = MQTT_UnPacketCmd(cmd, &cmdid_topic, &req_payload, &req_len); //解出topic和消息体
if(result == 0)
{
DEBUG_LOG("cmdid: %s, req: %s, req_len: %d\r\n", cmdid_topic, req_payload, req_len);
MQTT_DeleteBuffer(&mqttPacket); //删包
}
break;
case MQTT_PKT_PUBLISH: //接收的Publish消息
result = MQTT_UnPacketPublish(cmd, &cmdid_topic, &topic_len, &req_payload, &req_len, &qos, &pkt_id);
if(result == 0)
{
DEBUG_LOG("topic: %s, topic_len: %d, payload: %s, payload_len: %d\r\n",
cmdid_topic, topic_len, req_payload, req_len);
// 对数据包req_payload进行JSON格式解析
json = cJSON_Parse(req_payload);
//if (!json)UsartPrintf(USART_DEBUG,"Error before: [%s]\n",cJSON_GetErrorPtr());
// if(json)
//{
json_value = cJSON_GetObjectItem(json , "target");
UsartPrintf(USART_DEBUG,"json_value: [%s]\n",json_value->string);//输出是什么键
UsartPrintf(USART_DEBUG,"json_value: [%s]\n",json_value->valuestring);//输出是什么值
if(strstr(json_value->valuestring,"BEEP") != NULL)
{
json_value = cJSON_GetObjectItem(json , "value");
if(json_value->valueint)
{
alarmFlag = 1;
BEEP=1;
}//打开报警器
else
{
alarmFlag = 0;//关闭报警器
alarm_is_free=0;
BEEP=0;
}//上位机控制跟手动控制具有一样的优先级 优先于自动控制,因此要把alarm_is_free 归0
}
if(strstr(json_value->valuestring,"LED") != NULL)
{
json_value = cJSON_GetObjectItem(json , "value");
if(json_value->valueint)
{
// while(1)
//{
LED0 = 0;//开灯
// pump=1; //水泵打开
RELAY=0; //继电器打开
delay_ms(20);
// }
}
else
{
LED0 = 1;//关灯
//pump=0;
RELAY=1;
delay_ms(20);
}
}
if(strstr(json_value->valuestring,"Pump") != NULL)
{
json_value = cJSON_GetObjectItem(json , "value");
if(json_value->valueint)
{
LED0 = 0;//开灯
pump=1; //水泵打开
//delay_ms(1000);
}
else
{
LED0 = 1;//关灯
pump=0;//水泵关闭
//delay_ms(1000);
}
}
if(strstr(json_value->valuestring,"Fs") != NULL)
{
json_value = cJSON_GetObjectItem(json , "value");
if(json_value->valueint)
{
//LED0 = 0;//开灯
fs=1; //风扇打开
//delay_ms(1000);
}
else
{
//LED0 = 1;//关灯
fs=0;//风扇关闭
//delay_ms(1000);
}
}
// if(json_value->valueint)//json_value > 0且为整形
// {
// LED0 = 0;//打开LED0
// }
// else
// {
// LED0 = 1;//关闭LED0
// }
// }
cJSON_Delete(json);
}
break;
case MQTT_PKT_PUBACK: //发送Publish消息,平台回复的Ack
if(MQTT_UnPacketPublishAck(cmd) == 0)
DEBUG_LOG("Tips: MQTT Publish Send OK\r\n");
break;
case MQTT_PKT_PUBREC: //发送Publish消息,平台回复的Rec,设备需回复Rel消息
if(MQTT_UnPacketPublishRec(cmd) == 0)
{
DEBUG_LOG("Tips: Rev PublishRec\r\n");
if(MQTT_PacketPublishRel(MQTT_PUBLISH_ID, &mqttPacket) == 0)
{
DEBUG_LOG("Tips: Send PublishRel\r\n");
ESP8266_SendData(mqttPacket._data, mqttPacket._len);
MQTT_DeleteBuffer(&mqttPacket);
}
}
break;
case MQTT_PKT_PUBREL: //收到Publish消息,设备回复Rec后,平台回复的Rel,设备需再回复Comp
if(MQTT_UnPacketPublishRel(cmd, pkt_id) == 0)
{
DEBUG_LOG("Tips: Rev PublishRel\r\n");
if(MQTT_PacketPublishComp(MQTT_PUBLISH_ID, &mqttPacket) == 0)
{
DEBUG_LOG("Tips: Send PublishComp\r\n");
ESP8266_SendData(mqttPacket._data, mqttPacket._len);
MQTT_DeleteBuffer(&mqttPacket);
}
}
break;
case MQTT_PKT_PUBCOMP: //发送Publish消息,平台返回Rec,设备回复Rel,平台再返回的Comp
if(MQTT_UnPacketPublishComp(cmd) == 0)
{
DEBUG_LOG("Tips: Rev PublishComp\r\n");
}
break;
case MQTT_PKT_SUBACK: //发送Subscribe消息的Ack
if(MQTT_UnPacketSubscribe(cmd) == 0)
DEBUG_LOG("Tips: MQTT Subscribe OK\r\n");
else
DEBUG_LOG("Tips: MQTT Subscribe Err\r\n");
break;
case MQTT_PKT_UNSUBACK: //发送UnSubscribe消息的Ack
if(MQTT_UnPacketUnSubscribe(cmd) == 0)
DEBUG_LOG("Tips: MQTT UnSubscribe OK\r\n");
else
DEBUG_LOG("Tips: MQTT UnSubscribe Err\r\n");
break;
default:
result = -1;
break;
}
ESP8266_Clear(); //清空缓存
if(result == -1)
return;
dataPtr = strchr(req_payload, '}'); //搜索'}'
if(dataPtr != NULL && result != -1) //如果找到了
{
dataPtr++;
while(*dataPtr >= '0' && *dataPtr <= '9') //判断是否是下发的命令控制数据
{
numBuf[num++] = *dataPtr++;
}
num = atoi((const char *)numBuf); //转为数值形式
}
if(type == MQTT_PKT_CMD || type == MQTT_PKT_PUBLISH)
{
MQTT_FreeBuffer(cmdid_topic);
MQTT_FreeBuffer(req_payload);
}
}
实现效果
小结
以下是源码资料,如果小伙伴需要一些文档材料可以关注私聊我,小程序是参考B站教程。
链接:https://pan.baidu.com/s/1YG6uVCbj4rSfrhjwZGztXg
提取码:n52f
–来自百度网盘超级会员V5的分享