✌️✌️大家好,这里是5132单片机毕设设计项目分享,今天给大家分享的是基于《基于STM32的农业监控设计》。

目录

一、系统功能

2.1、硬件清单

2.2、功能介绍

2.3、控制模式

二、演示视频和实物

三、软件设计流程图

四、原理图

五、主程序

六、总结

 七、资料内


一、系统功能

2.1、硬件清单

STM32+OLED+光照强度+温湿度+CO2+土壤湿度+蜂鸣器+LED+水泵+风扇+舵机(遮阳棚)+WIFI

2.2、功能介绍

(1)STM32F103C8T6 核心控制板:作为系统核心,协调各模块工作,处理传感器数据并控制执行设备。
(2)土壤湿度传感器:实时检测土壤湿度,当土壤湿度小于设定阈值(如 70%)时,触发水泵灌溉;大于阈值时,关闭水泵。
(3)DHT11 温湿度传感器:检测环境温度和湿度,为系统提供温湿度数据,温度大于设定阈值时,自动打开风扇降温。
(4)光敏传感器:检测光照强度,当光照强度小于设定阈值时,自动开启 LED 灯补光;大于阈值时,关闭 LED 灯并打开遮阳棚(由舵机控制)。
(5)二氧化碳传感器:实时监测二氧化碳浓度,当浓度超过设定阈值(如 200)时,触发蜂鸣器报警。
(6)舵机:控制遮阳棚的开合,根据光照强度阈值自动调节(光照过强时打开遮阳棚,反之关闭)。
(7)水泵与风扇:水泵根据土壤湿度阈值自动启停,实现灌溉控制;风扇根据温度阈值自动运行,降低环境温度。
(8)ESP8266 WIFI 模块:连接预设热点(名称 “viv”,密码 “1234567890”),支持手机 APP 远程控制,实时上传温湿度、光照强度、土壤湿度、二氧化碳浓度等数据至 APP。
(9)按键模块:用于模式切换(手动 / 自动)及功能控制,手动模式下可通过按键直接控制风扇、遮阳棚、水泵等设备;自动模式下系统根据传感器阈值自动运行。
(10)LED 灯:作为补光设备,受光敏传感器和手动控制双重调节,光照不足时自动开启或手动强制开启。
(11)蜂鸣器:当二氧化碳浓度超过阈值或系统异常时触发报警,提醒用户注意环境异常。
(12)显示屏:实时显示传感器数据(温度、湿度、光照强度、土壤湿度、二氧化碳浓度)及系统工作状态(当前模式、设备启停状态等)。

2.3、控制模式

  1. 远程模式:通过手机 APP 连接 WIFI 模块,实时查看环境数据并远程控制 LED 灯、水泵、风扇、遮阳棚等设备启停。
  2. 手动模式:按下按键切换至手动,通过按键直接控制各执行设备(如风扇、遮阳棚),灵活干预系统运行。
  3. 自动模式:系统根据预设阈值(如土壤湿度 70%、光照强度阈值、温度阈值等)自动调节设备,实现灌溉、补光、降温、遮阳等功能的智能化控制。

二、演示视频和实物

基于STM32的智慧农业监测系统(智慧农场)-(远程+自动+手动模式)-(土壤湿度+CO2监测)-(补光灯+遮阳棚+水泵灌溉)


三、软件设计流程图


四、原理图


五、主程序

#include "main.h"

uint8_t KeyNum;// 存储按键值
u8 t = 0;// 传感器读取时间间隔
uint16_t RTC_Time[] = {0, 0, 0};// RTC时间
uint16_t RTC_Time1[] = {7, 0, 0};// 定时时间---开
uint16_t RTC_Time2[] = {19, 0, 0};// 定时时间---关
u8 S_Mode; // 按键状态标志
u8 S_Shou_1 = 2;     //手动模式控制设备1
u8 S_Shou_2;     //手动模式控制设备2
u8 S_Shou_3;     //手动模式控制设备2
u8 S_YuZhi;       //阈值设置里用的,用来切换阈值
// 其他状态标志
u8 qingping = 1;   //清屏标志
u8 S_ShiShi_Time_1;     //设置实时时间用,用来切换时间显示和设置时间
u8 S_ShiShi_Time_2;    //设置实时时间用,用来切换设置的时分秒
u8 S_DingShi_Switch;    //设置定时时间里用到,切换时分秒
uint16_t co2;
// 定义传感器数据和阈值结构体变量
SensorDataAndThreshold sensorData;

// 初始化相关硬件和机智云
void System_Init()
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    uart_init(9600);       // 串口初始化为9600
    delay_init();      // 延时函数初始化
    LED_Init();            // 初始化与LED连接的硬件接口
    DHT11_Init();
    Buzzer_Init();             // 外设初始化
    OLED_Init();
    Key_Init();
    AD_Init();
    MyRTC_Init();
    USART2_Config();
    Servo_Init();
    MY_Gizwits_Init();   // 机智云初始化
    // 初始化传感器阈值
    sensorData.TempYu = 35;
    sensorData.HumiYu = 30;
    sensorData.TuRangYu = 70;
    sensorData.GuangYu = 50;
    sensorData.CO2 = 500;
}

int main(void)
{
    System_Init();

    Servo_SetAngle(90);
    delay_ms(1000);
    Servo_SetAngle(0);

    while (1)
    {
        userHandle();    // 数据上传
        gizwitsHandle((dataPoint_t *)&currentDataPoint);   // 后台处理,必须放在while里

        ReadSensorData();
        HandleModes();
    }
}

// 读取传感器数据
void ReadSensorData()
{
    DHT11_Read_Data(&sensorData.temp, &sensorData.humi);  // 读取温湿度并显示在OLED上

    sensorData.Guang = TS_GetData(ADC_Channel_4);    // 光照传感器     PA4
    sensorData.TuRang = TS_GetData(ADC_Channel_5);    // 土壤湿度传感器     PA5
    if (t % 10 == 0)
    {
        CO2GetData(&co2);
    }
    t++;
}

// 处理不同模式
void HandleModes()
{
    KeyNum = Key_GetNum();
    if (KeyNum == 1 && DebounceKey(1))
    {
        qingping = 0;
        S_Shou_2 = 2;            //每次初始化手动模式的标志,这样进入手动模式是一样的
        S_Mode = (S_Mode + 1) % 4;
    }
    switch (S_Mode)
    {
    case 0: // 远程模式
        if (qingping == 0)
        {
            OLED_Clear();
            FENG_OFF();
            ShuiBen_OFF();
            Buzzer_OFF();
            LED_OFF();
            qingping = 1;
        }
        TimeRead();
        ChuangGan();
        OLED_ShowChinese(1, 7, 49);
        OLED_ShowChinese(1, 8, 50);
        break;
    case 2: // 自动模式
        OLED_ShowChinese(1, 7, 51);
        OLED_ShowChinese(1, 8, 52);
        TimeRead();
        zhidong();
        ChuangGan();
        break;
    case 1: // 手动模式
        OLED_ShowChinese(1, 7, 18);
        OLED_ShowChinese(1, 8, 52);
        TimeRead();
        ChuangGan();
        shoudong();
        break;
    case 3: // 阈值设置
        if (qingping == 0)
        {
            OLED_Clear();
            qingping = 1;
        }
        YuZhiSet();
        break;
    }
}


// 手动模式函数
void shoudong()
{
    if (qingping == 0)
    {
        OLED_Clear();
        FENG_OFF();
        ShuiBen_OFF();
        Buzzer_OFF();
        LED_OFF();
        qingping = 1;
    }
    if (KeyNum == 2 && DebounceKey(2))
    {
        S_Shou_1 = (S_Shou_1 + 1) % 2;
    }
    if (S_Shou_1 == 0)
    {
        FENG_ON();// 外设操作
    }
    if (S_Shou_1 == 1)
    {
        FENG_OFF();// 外设操作
    }
    if (KeyNum == 3 && DebounceKey(3))
    {
        S_Shou_2 = (S_Shou_2 + 1) % 2;
    }
    if (S_Shou_2 == 1)
    {
        LED_ON(); // 外设操作
        Servo_SetAngle(90);
    }
    if (S_Shou_2 == 0)
    {
        LED_OFF(); // 外设操作
        Servo_SetAngle(0);
    }
    if (KeyNum == 4 && DebounceKey(4))
    {
        S_Shou_3 = (S_Shou_3 + 1) % 2;
    }
    if (S_Shou_3 == 1)
    {
        ShuiBen_ON(); // 外设操作
    }
    if (S_Shou_3 == 0)
    {
        ShuiBen_OFF(); // 外设操作
    }
}

// 自动模式函数
void zhidong()
{
    if (qingping == 0)
    {
        OLED_Clear();
        FENG_OFF();
        ShuiBen_OFF();
        Buzzer_OFF();
        LED_OFF();
        qingping = 1;
    }
    if (sensorData.temp > sensorData.TempYu)
    {
        FENG_ON();
    }
    else
    {
        FENG_OFF();
    }
    if (sensorData.humi < sensorData.TuRangYu)
    {
        ShuiBen_ON();
    }
    else
    {
        ShuiBen_OFF();
    }
    if (sensorData.Guang < sensorData.GuangYu)
    {
        LED_ON();
        Servo_SetAngle(90);
    }
    else
    {
        LED_OFF();
        Servo_SetAngle(0);
    }
    if (co2 > sensorData.CO2)
    {
        Buzzer_Turn();
    }
    else
    {
        Buzzer_OFF();
    }
}

// 设置阈值函数
void YuZhiSet()
{
    if (qingping == 0)
    {
        OLED_Clear();
        FENG_OFF();
        ShuiBen_OFF();
        Buzzer_OFF();
        LED_OFF();
        qingping = 1;
    }
    zhidong();
    OLED_ShowChinese(1, 3, 72);
    OLED_ShowChinese(1, 4, 73);
    OLED_ShowChinese(1, 5, 74);
    OLED_ShowChinese(1, 6, 75);
    OLED_ShowString(2, 1, "W:");
    OLED_ShowNum(2, 3, sensorData.TempYu, 2);
    OLED_ShowString(2, 7, "G:");
    OLED_ShowNum(2, 9, sensorData.GuangYu, 2);
    OLED_ShowString(3, 1, "T_S:");
    OLED_ShowNum(3, 5, sensorData.TuRangYu, 2);
    OLED_ShowString(4, 1, "CO2:");
    OLED_ShowNum(4, 5, sensorData.CO2, 4);
    if (KeyNum == 2 && DebounceKey(2))
    {
        S_YuZhi = (S_YuZhi + 1) % 4;
    }
    switch (S_YuZhi)
    {
    case 0:
        if (KeyNum == 3) sensorData.TempYu += 5;
        if (KeyNum == 4) sensorData.TempYu -= 5;
        break;
    case 1:
        if (KeyNum == 3) sensorData.GuangYu += 5;
        if (KeyNum == 4) sensorData.GuangYu -= 5;
        break;
    case 2:
        if (KeyNum == 3) sensorData.TuRangYu += 5;
        if (KeyNum == 4) sensorData.TuRangYu -= 5;
        break;
    case 3:
        if (KeyNum == 3) sensorData.CO2 += 50;
        if (KeyNum == 4) sensorData.CO2 -= 50;
        break;
    }
}


// 定时模式函数
void DingShiMoShi()
{
    if (qingping == 0)
    {
        OLED_Clear();
        qingping = 1;
    }
    // 定时模式判断
    if ((MyRTC_Time[3] == RTC_Time1[0]) && (MyRTC_Time[4] == RTC_Time1[1]) && (MyRTC_Time[5] == RTC_Time1[2]))
    {
        // 外设操作
    }
    if ((MyRTC_Time[3] == RTC_Time2[0]) && (MyRTC_Time[4] == RTC_Time2[1]) && (MyRTC_Time[5] == RTC_Time2[2]))
    {
        // 外设操作
    }
    // 显示定时时间
    OLED_ShowChinese(3, 1, 31);
    OLED_ShowString(3, 3, ":");
    OLED_ShowNum(3, 5, RTC_Time1[0], 2);
    OLED_ShowString(3, 7, ":");
    OLED_ShowNum(3, 8, RTC_Time1[1], 2);
    OLED_ShowString(3, 10, ":");
    OLED_ShowNum(3, 11, RTC_Time1[2], 2);
    OLED_ShowChinese(4, 1, 32);
    OLED_ShowString(4, 3, ":");
    OLED_ShowNum(4, 5, RTC_Time2[0], 2);
    OLED_ShowString(4, 7, ":");
    OLED_ShowNum(4, 8, RTC_Time2[1], 2);
    OLED_ShowString(4, 10, ":");
    OLED_ShowNum(4, 11, RTC_Time2[2], 2);

    // 修改定时时间操作
    if (KeyNum == 2 && DebounceKey(2))
    {
        S_DingShi_Switch = (S_DingShi_Switch + 1) % 6;
    }
    switch (S_DingShi_Switch)
    {
    case 0: // 时
        if (KeyNum == 3) RTC_Time2[0]++;
        if (KeyNum == 4) RTC_Time2[0]--;
        break;
    case 1: // 分
        if (KeyNum == 3) RTC_Time2[1]++;
        if (KeyNum == 4) RTC_Time2[1]--;
        break;
    case 2: // 秒
        if (KeyNum == 3) RTC_Time2[2]++;
        if (KeyNum == 4) RTC_Time2[2]--;
        break;
    case 3: // 时
        if (KeyNum == 3) RTC_Time1[0]++;
        if (KeyNum == 4) RTC_Time1[0]--;
        break;
    case 4: // 分
        if (KeyNum == 3) RTC_Time1[1]++;
        if (KeyNum == 4) RTC_Time1[1]--;
        break;
    case 5: // 秒
        if (KeyNum == 3) RTC_Time1[2]++;
        if (KeyNum == 4) RTC_Time1[2]--;
        break;
    }
}

void YuYingMode()   //先说小杰唤醒,然后说打开窗户和关闭窗户
{
//    if (qingping == 0)
//    {
//        OLED_Clear();
//        qingping = 1;
//    }
//    if (Serial2_RxFlag == 1)        //串口接收到数据包的标志位,若是收到数据包,会置1
//    {
//        if (strcmp(Serial2_RxPacket, "JIASHI_ON") == 0)
//        {
//            // 外设操作
//        }
//        else if (strcmp(Serial2_RxPacket, "JIASHI_OFF") == 0)
//        {
//            // 外设操作
//        }
//        Serial2_RxFlag = 0; //将标志位清零,不清零就接收不到下一个数据包了
//    }
}


// 机智云初始化函数
void MY_Gizwits_Init(void)
{
    TIM3_Int_Init(9, 7199); // 1MS系统定时
    usart3_init(9600); // WIFI初始化
    memset((uint8_t *)&currentDataPoint, 0, sizeof(dataPoint_t)); // 设备状态结构体初始化
    gizwitsInit(); // 环形缓冲区初始化
    gizwitsSetMode(2);   // 设置模式
    userInit();
}

// 按键消抖函数
uint8_t DebounceKey(uint8_t key)
{
    delay_ms(20);
    return KeyNum == key;
}


// 设置时间函数
void TimeSet()
{
    if (KeyNum == 2 && DebounceKey(2))
    {
        S_ShiShi_Time_1 = (S_ShiShi_Time_1 + 1) % 3;
    }
    if (S_ShiShi_Time_1 == 0)   // 时间显示模式
    {
        MyRTC_ReadTime();
        OLED_ShowNum(1, 5, MyRTC_Time[3], 2);    // 时
        OLED_ShowString(1, 7, ":");
        OLED_ShowNum(1, 8, MyRTC_Time[4], 2);    // 分
        OLED_ShowString(1, 10, ":");
        OLED_ShowNum(1, 11, MyRTC_Time[5], 2);   // 秒
        RTC_Time[0] = MyRTC_Time[3];
        RTC_Time[1] = MyRTC_Time[4];
        RTC_Time[2] = MyRTC_Time[5];
    }
    else if (S_ShiShi_Time_1 == 1)     // 修改时间
    {
        if (KeyNum == 5 && DebounceKey(5))
        {
            S_ShiShi_Time_2 = (S_ShiShi_Time_2 + 1) % 3;
        }
        switch (S_ShiShi_Time_2)
        {
        case 0: // 修改时
            if (KeyNum == 4)
            {
                RTC_Time[0] = (RTC_Time[0] + 1) % 24; // 加 1 后取模 24,确保在 0 - 23 范围内
            }
            if (KeyNum == 3)
            {
                if (RTC_Time[0] == 0)
                {
                    RTC_Time[0] = 23; // 当为 0 时,减操作变为 23
                }
                else
                {
                    RTC_Time[0]--;
                }
            }
            OLED_ShowNum(1, 5, RTC_Time[0], 2);  // 时
            break;
        case 1: // 修改分
            if (KeyNum == 4)
            {
                RTC_Time[1] = (RTC_Time[1] + 1) % 60; // 加 1 后取模 60,确保在 0 - 59 范围内
            }
            if (KeyNum == 3)
            {
                if (RTC_Time[1] == 0)
                {
                    RTC_Time[1] = 59; // 当为 0 时,减操作变为 59
                }
                else
                {
                    RTC_Time[1]--;
                }
            }
            OLED_ShowNum(1, 8, RTC_Time[1], 2);  // 分
            break;
        case 2: // 修改秒
            if (KeyNum == 4)
            {
                RTC_Time[2] = (RTC_Time[2] + 1) % 60; // 加 1 后取模 60,确保在 0 - 59 范围内
            }
            if (KeyNum == 3)
            {
                if (RTC_Time[2] == 0)
                {
                    RTC_Time[2] = 59; // 当为 0 时,减操作变为 59
                }
                else
                {
                    RTC_Time[2]--;
                }
            }
            OLED_ShowNum(1, 11, RTC_Time[2], 2);  // 秒
            break;
        }
    }
    else if (S_ShiShi_Time_1 == 2)
    {
        MyRTC_Time[3] = RTC_Time[0];
        MyRTC_Time[4] = RTC_Time[1];
        MyRTC_Time[5] = RTC_Time[2];
        MyRTC_SetTime();
        S_ShiShi_Time_1 = 0;
    }
}

// 读取时间函数
void TimeRead()
{
    MyRTC_ReadTime();
    OLED_ShowNum(1, 5, MyRTC_Time[3], 2);    // 时
    OLED_ShowString(1, 7, ":");
    OLED_ShowNum(1, 8, MyRTC_Time[4], 2);    // 分
    OLED_ShowString(1, 10, ":");
    OLED_ShowNum(1, 11, MyRTC_Time[5], 2);   // 秒
}


// 显示传感器信息
void ChuangGan()
{
    OLED_ShowChinese(2, 1, 4);
    OLED_ShowChinese(2, 2, 6);
    OLED_ShowString(2, 5, ":");
    OLED_ShowNum(2, 6, sensorData.Guang, 2);
    OLED_ShowString(2, 9, "CO2:");
    OLED_ShowNum(2, 13, co2, 4);

    OLED_ShowChinese(3, 1, 78);
    OLED_ShowChinese(3, 2, 80);
    OLED_ShowString(3, 5, ":");
    OLED_ShowNum(3, 6, sensorData.TuRang, 3);

    OLED_ShowChinese(4, 1, 26);
    OLED_ShowChinese(4, 2, 28);
    OLED_ShowString(4, 5, ":");
    OLED_ShowChinese(4, 5, 27);
    OLED_ShowChinese(4, 6, 28);
    OLED_ShowString(4, 13, ":");
    OLED_ShowNum(4, 6, sensorData.temp, 2);
    OLED_ShowNum(4, 14, sensorData.humi, 2);
}

uint16_t TS_GetData(uint8_t ADC_Channel)
{
    uint32_t  tempData = 0;
    for (uint8_t i = 0; i < 10; i++)
    {
        tempData += AD_GetValue(ADC_Channel);
        delay_ms(5);
    }

    tempData /= 10;
    return 100 - (float)tempData / 40.96;
}

六、总结

本文介绍了一种基于STM32F103C8T6的智能农业监控系统设计方案。系统通过多种传感器(温湿度、光照、CO2、土壤湿度)采集环境数据,采用远程、自动和手动三种控制模式,实现智能灌溉、补光、降温等功能。硬件包括STM32主控板、OLED显示屏、执行设备(水泵、风扇、舵机等)和WiFi模块,支持手机APP远程监控。软件采用模块化设计,包含数据采集、阈值判断、模式切换等核心功能。该系统实现了农业环境的智能化管理,具有实用价值和推广意义。项目提供完整的硬件清单、原理图、程序代码等资料,适合作为单片机设计实践案例。

 七、资料内容

Logo

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

更多推荐