聚丰项目 > SmartGarden

SmartGarden

SmartGarden是一款智能的植物养殖系统,可实现智能的灌溉,环境温湿度的实时检测,土壤湿度和水库水位的实时检测;意义在于针对在校学生或工作匆忙人群,经常出差等无法对植株进行即时养护,防止植物干枯或死亡,而实时的APP上位机可通过系统上搭建的Wifi模块用来实现信息回传,包括环境温湿,水位土壤情况,以及系统工作状态,而随系统附带的Oled也可实时展示信息给用户,Oled不管在刺眼的阳光下,还是在暗室,既不会影响人的休息也不妨碍信息显示,相信这套系统可以给用户一个安心的体验。

小影效应 小影效应

分享
1 喜欢这个项目
团队介绍

小影效应 小影效应

团队成员

纪翔 学生

分享
项目简介
SmartGarden是一款智能的植物养殖系统,可实现智能的灌溉,环境温湿度的实时检测,土壤湿度和水库水位的实时检测;意义在于针对在校学生或工作匆忙人群,经常出差等无法对植株进行即时养护,防止植物干枯或死亡,而实时的APP上位机可通过系统上搭建的Wifi模块用来实现信息回传,包括环境温湿,水位土壤情况,以及系统工作状态,而随系统附带的Oled也可实时展示信息给用户,Oled不管在刺眼的阳光下,还是在暗室,既不会影响人的休息也不妨碍信息显示,相信这套系统可以给用户一个安心的体验。
硬件说明

主控

采用大赛提供的Stm32F401-Nucleo开发板,支持Arduino板型扩展以及Mbed在线开发,极大的减轻了学习负担,高性能的主控给代码一个宽广的跑道可以任他狂奔,86Mhz的主频,体验下来很简单也很易用,在这感谢组委会

用了个自己的L476的图片,和F401差不多

1.png



Wifi模块

Wifi模块采用了大赛提供的Ewm3080,板型跟随Nucleo设计,模块采用板上天线,EMW3080是单3.3V供电的、集成Wi-Fi和Cortex-M4F MCU的嵌入式Wi-Fi模块,最高支持133M主频和256K RAM,强大的浮点运算。在这写入了AT穿透固件,SDK2.0下的开发模式,更加简单,为了释放开发者的创意,厂家没少封装那些晦涩难懂的东西,在这再次感谢大赛

2.jpg


Oled显示

这里采用了SSD1306驱动的128X64的Oled,接口方式SPI,本想用的128X32的I2C的小屏幕,可惜最后可能由于第三方显示驱动出了些问题放弃了,改用这个压箱底的屏幕工作电压2.2V-5.5V因为无须加背光或偏置电压所以功耗很低,满足适用场景

3.png


温湿传感器

温湿传感器采用了数字读取的DHT11,支持数据校验,最大的减小误差,本来想用更加精确的DHT22,但手残买错了,手动笑Cry

工作电压:3.3V-5V

工作电流:<2.5ma

湿度范围:20%~90%(+-5%)

温度范围:0-50℃(+-2℃)

4.jpg


土壤湿度传感

工作类似根据土壤不同湿度直接读取土壤电阻,放大后ADC读出模拟量,或采用可调电阻调整数字量上升或下降阀值

工作电压:3.3V~5V

5.png


水位传感器

通过水内电阻,读出模拟量的值来测试水位值,但同上模拟器一样都需要校准,后面软件调试有涉及

工作电压3.3V~5V

6.png


动作水泵

看的出来,水泵买大了,385的水泵,可以当洗衣机的抽水泵了,后期会改小,争取实现无噪音工作

工作电压:6V-12V

7.jpg







软件说明

开发平台采用了官方推荐的Mbed,极大简化了开发步骤,本来还打算用MDK开发的,后来发现Mbed平台和Arduino的函数操作及其类似,好用到停不下来,在线编译,随便找个电脑都可以直接下载编译好的固件,不用担心环境出错而导致的编译失败的问题,简直爽歪歪,,而对于我熟悉Arduino开发,给我省了不少事情,

       因为下半年的安全比赛太多了,被拉去凑数,所以代码是随便写写的,后面会一点点精致,把该细化的地方搞定

       先上代码了,下面再细说

#include "mbed.h"
#include "Adafruit_SSD1306.h"
#include "DHT.h"
 
Serial pc(SERIAL_TX, SERIAL_RX);
//sensor
DHT dht11(PC_10,DHT11); // Use the DHT11 sensor
AnalogIn SoilValue(A0);
AnalogIn WaterValue(A1);
 
DigitalOut myled_R(LED_RED);//work status Led
DigitalOut pump(PC_11);
SPI spi(D11,NC,D13,NC);
//I2C i2c(I2C_SDA,I2C_SCL);
 
//Adafruit_SSD1306_I2c myOled(i2c,NC,0x78,32,128);
Adafruit_SSD1306_Spi myOled(spi,D12,PA_11,NC,64,128);
 
int main()
{  
    int sta;
    float soilV;
    float waterV;
    int err;//DH11 Error
    uint16_t   x=0;
    myOled.begin();
//    myOled.printf("%ux%u \nThis is Failed Test\r\n", myOled.width(), myOled.height());
    //myOled.printf("This is Test Line \r\n");
    //myOled.fillScreen(1);
    myOled.display();
    wait(3);
    int CX;
    int CY;
//    myOled.fillScreen(0);
    myOled.clearDisplay();
    //for(int i=0;i<3;i++){
//    myOled.printf("\r\n");
//    }
//    pc.printf("CX:%d CY%d \r\n",myOled.get_cursor_x(),myOled.get_cursor_y());
   
//    pc.printf("CX:%d CY%d \r\n",myOled.get_cursor_x(),myOled.get_cursor_y());
//    myOled.drawRect(myOled.get_cursor_x(), myOled.get_cursor_y()+1, 70, 5, 1);
   
   
//    pc.printf("CX:%d CY%d \r\n",myOled.get_cursor_x(),myOled.get_cursor_y());
   
    float tmp;
    float hum;
    int timelast;
    bool dov=0;  
    while(1)
    {  
        myOled.clearDisplay();
        float sa1=0,wa1=0,sa2=0,wa2=0;
        for(int i=0;i<3;i++)
        {
            sa1=SoilValue.read();
            wa1=WaterValue.read();
            sa2=sa2+sa1;
            wa2=wa2+wa1;
            wait(0.05);
            }
        soilV=sa2/3;
        waterV=wa2/3;
       
        myled_R = !myled_R;
       
        err = dht11.readData();
        myOled.setTextCursor(0,0);
        myOled.printf("Runtime %d \r\n",x);
        myOled.setTextSize(0.5);
//        pc.printf("The ERROR is %d \r\n,err");
        if (err == 0) {
//            myOled.setTextCursor(0,30);
            //tmp=int(dht11.ReadTemperature(CELCIUS));
            //hum=int(dht11.ReadHumidity());
            tmp=dht11.ReadTemperature(CELCIUS);
            hum=dht11.ReadHumidity();
            }
           
            
            else{
                //myOled.printf("ERROR Read");
                }
           
           
            //Display soil water
            myOled.printf("Tem:%4.2f C \r\n",tmp);
            myOled.printf("Hum:%4.2f %%\r\n",hum);
            myOled.setTextCursor(0,24);
            myOled.printf("Soil:");
            myOled.setTextCursor(30,24);
            myOled.printf("%d%%",int(soilV*100));
            myOled.drawRect(myOled.get_cursor_x(), myOled.get_cursor_y()+1, myOled.width()-myOled.get_cursor_x(), 5, 1);
            myOled.fillRect(myOled.get_cursor_x(), myOled.get_cursor_y()+2, int((myOled.width()-myOled.get_cursor_x())*soilV), 3, 1);
            myOled.printf("\r\n");
            myOled.printf("Water:%d%%",int(waterV*100));
            myOled.drawRect(myOled.get_cursor_x(), myOled.get_cursor_y()+1, myOled.width()-myOled.get_cursor_x(), 5, 1);
            myOled.fillRect(myOled.get_cursor_x(), myOled.get_cursor_y()+2, int((myOled.width()-myOled.get_cursor_x())*waterV), 3, 1);
            pc.printf("%d  %f \r\n",int((myOled.width()-myOled.get_cursor_x())*soilV),soilV);
            myOled.printf("\r\n");
            //
            myOled.printf("SysStatus:");
           
            //
            if(waterV0.4f&& waterV>0.4f&&dov){
                    pump=1;
                    dov=0;
                    timelast=x;
                    }
            if(soilV<0.4f||waterV20){
                dov=0;
                pump=0;
                timelast=0;
                }
               
            if(x%100==0){
                dov=1;
                }
           
           
           
        x = x + 1;                 
        wait(0.5);
        if(x>20000)
        {
            x=0;
            }
       
        myOled.display();
    }
}
/*
int err;
    printf("\r\nDHT Test program");
    printf("\r\n******************\r\n");
    wait(1); // wait 1 second for device stable status
    while (1) {
        myled = 1;
        err = sensor.readData();
        if (err == 0) {
            printf("Temperature is %4.2f C \r\n",sensor.ReadTemperature(CELCIUS));
            //printf("Temperature is %4.2f F \r\n",sensor.ReadTemperature(FARENHEIT));
            //printf("Temperature is %4.2f K \r\n",sensor.ReadTemperature(KELVIN));
            printf("Humidity is %4.2f \r\n",sensor.ReadHumidity());
            //printf("Dew point is %4.2f  \r\n",sensor.CalcdewPoint(sensor.ReadTemperature(CELCIUS), sensor.ReadHumidity()));
            printf("Dew point (fast) is %4.2f  \r\n",sensor.CalcdewPointFast(sensor.ReadTemperature(CELCIUS), sensor.ReadHumidity()));
        } else
            printf("\r\n read err val %i \n",err);
        myled = 0;
        wait(1);
*/

        这套作品使用了两个第三方的库,Mbed的第三方库不少,这点让开发能简化好多,但是和Arduino相比,库资源还是少了很多的

       第一个库是: Adafruit_Oled, 这是一个第三方的显示库,从Arduino的U8glib移植过来的,开发人下了心思,但是和U8g比起来,这个库还是有一定距离的,不过大幅度简化了显示难度,在这感谢作者

Adafruit_SSD1306_Spi myOled(spi,D12,PA_11,NC,64,128);


        创建对象后调用库函数即可,简化很多操作

myOled.printf("Tem:%4.2f C \r\n",tmp);
            myOled.printf("Hum:%4.2f %%\r\n",hum);
            myOled.setTextCursor(0,24);
            myOled.printf("Soil:");
            myOled.setTextCursor(30,24);
            myOled.printf("%d%%",int(soilV*100));
            myOled.drawRect(myOled.get_cursor_x(), myOled.get_cursor_y()+1, myOled.width()-myOled.get_cursor_x(), 5, 1);
            myOled.fillRect(myOled.get_cursor_x(), myOled.get_cursor_y()+2, int((myOled.width()-myOled.get_cursor_x())*soilV), 3, 1);
            myOled.printf("\r\n");
            myOled.printf("Water:%d%%",int(waterV*100));
            myOled.drawRect(myOled.get_cursor_x(), myOled.get_cursor_y()+1, myOled.width()-myOled.get_cursor_x(), 5, 1);
            myOled.fillRect(myOled.get_cursor_x(), myOled.get_cursor_y()+2, int((myOled.width()-myOled.get_cursor_x())*waterV), 3, 1);
            pc.printf("%d  %f \r\n",int((myOled.width()-myOled.get_cursor_x())*soilV),soilV);
            myOled.printf("\r\n");

        第二个库调用自DHT11,这是一个针对DHT系列的温室库,支持校验,这节省了大量去学习DHT传感器的时间

DHT dht11(PC_10,DHT11);
            if (err == 0) {
            //myOled.setTextCursor(0,30);
            //tmp=int(dht11.ReadTemperature(CELCIUS));
            //hum=int(dht11.ReadHumidity());
            tmp=dht11.ReadTemperature(CELCIUS);
            hum=dht11.ReadHumidity();
            }

针对传感器可能会有跳变的问题,为防止水泵重复启动,或是浇水过多溺死植株,而自己又实在懒得去设计中断和定时器,感觉效果差不多,就简单粗暴写了下,doV做时间阀标识,x指示runtime,soilV和waterV指示土壤和水位,防止水泵空转

相关代码如下

            if(soilV>0.4f&& waterV>0.4f&&dov){
                    pump=1;
                    dov=0;
                    timelast=x;
                    }
            if(soilV<0.4f||waterV20){
                dov=0;
                pump=0;
                timelast=0;
                }
                
            if(x%100==0){
                dov=1;
                }
           
           
           
        x = x + 1;                 
        wait(0.5);
        if(x>20000)
        {
            x=0;
            }


        为了能只管展示作品目前的工作状态,写了一些简单的检测用来反馈实时的状态

switch (sta){
                case 0:
                myOled.printf("Work");
                break;
               
                case 1:
                myOled.printf("Watering");
                break;
                
                case 2:
                myOled.printf("No Water");
                break;
               
                case 3:
                myOled.printf("Unknow");
                break;
                
                default:
                myOled.printf("Run");
                break;
                }


APP的代码就不放了,朋友按需求编译好的APP,结果我这里代码已经没有时间写了,比较尴尬




演示效果

        本想着定制一套亚克力外壳的。图纸和店家都商量好了,最后那头出了点问题,加上双十一,最后始终也没能用得上这套外壳,最后心一横直接快递盒了,展示就好,希望各位见谅

演示部分就比较糟心了,随便拍的,明天得出去北京比赛走好长时间,回来就错过提交时间了,所以简单写了一点


8.jpg

▲整体外观


9.jpg

安装部分

10.jpg

▲显示部分

11.jpg


▲温湿度检测,主控和动作继电器部分

12.jpg

▲土壤湿度部分

13.jpg

▲动作水泵部分

14.png

▲APP上位机部分

APP通过wifi连接后可回传相关信息,人工可设定是自动还是手动,或者人工干预水泵启动,同时针对不同的传感器和环境进行最低要求的调节和校准操作,最终实现自动化的目的,同时,系统反馈实时的工作状态,并同时可一定周期内提醒施肥等操作

作品实在简陋,无奈学生下半年实在是有些忙碌了,还望看官们不要嫌弃,同时后期会继续跟进,项目进度会更新在论坛上,请随时指正。


评论区(1 )
  • 动心忍性1234: 您好我是无线电杂志的编辑,我们对您的项目十分感兴趣,请问您有兴趣投稿吗?成为我们的作者除稿费外还有其他优厚条件。敬请参与。投稿请联系QQ260534978.

    回复