单片机毕业设计|农家菜园自动灌溉控制系统设计

简介: 本系统是基于单片机的农家菜园自动灌溉控制系统设计,以51单片机作为控制核心,实现菜园自动灌溉及智能控制系统的设计,能够实现对土壤温湿度以及光照强度的检测,并且根据设置的阈值及时间进行自动检测与灌溉。

  作者主页:编程指南针

作者简介:Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、腾讯课堂常驻讲师

主要内容:Java项目、Python项目、前端项目、人工智能与大数据、简历模板、学习资料、面试题库、技术互助

收藏点赞不迷路  关注作者有好处

文末获取源码

项目编号:BS-DPJ-006

一,环境介绍

语言环境:C

开发技术:51单片机

二,项目简介

随着时代的发展,电子控制技术在人们的生活中得到了广泛的应用。如何运用现代的电子技术,对农家菜园温度、湿度进行自动监测,并依据相关的数据进行相应的灌溉作业。这对于促进温室作物的增产、节省劳动力都是十分必要的。该系统包括单片机STC89C52,湿度传感器,温度传感器,按键,光照传感器,液晶显示屏,水泵,蓝牙和电源。该系统以STC89C52单片机为核心,以 AltiumDesigner 10为主要硬件,以 Keil为主要开发工具,以 C语言编写。论文首先对系统方案进行了整体的描述,并提出了硬件方面的设计,其中包括控制器的选择,温湿度检测模块的硬件选择,光照强度检测模块的选择,显示模块的选择,水泵灌溉模块的选择,蓝牙模块的设计。软件模块主要包括整个软件流程图、温湿度检测、光强检测等部分流程图,并采用单片机实现对电动机的控制,最后使用 C语言编写了相应的程序。

本系统是基于单片机的农家菜园自动灌溉控制系统设计,以51单片机作为控制核心,实现菜园自动灌溉及智能控制系统的设计,能够实现对土壤温湿度以及光照强度的检测,并且根据设置的阈值及时间进行自动检测与灌溉。具体来说,本文的研究内容如下:

(1)本论文的研究内容为:自动灌溉系统的设计,包括土壤湿度检测、土壤温度检测、光照强度检测、水泵灌溉、定时自动灌溉。LCD显示屏和蓝牙无线接入。本课题的研究内容包括:灌区自动控制系统总体方案设计、硬件电路设计、软件流程设计等。本论文是一项细致而有效的自动化控制工作。其终极目的是实现自动灌溉和智能化控制,可通过设定的温度、湿度和光照强度来自动监测和灌溉。

(2)首先,本文对农户菜园自动灌溉控制系统的整体结构进行了阐述,并提出了硬件方面的设计,其中包括控制器的选择,温湿度检测模块的硬件选择,光照强度检测模块的选择,显示模块的选择,水泵灌溉模块的选择,蓝牙模块的设计。软件模块主要包括整个软件流程图、温湿度检测、光强检测等部分流程图,并采用单片机实现对电动机的控制,最后使用 C语言编写了相应的程序。

(3)根据硬件设计方案,实现了农户菜园自动灌溉控制系统的实际生产,并按“先局部后整体”的原则,对控制器模块、温湿度检测模块、光照强度检测模块、显示模块、水泵灌溉模块和蓝牙模块进行模块测试,并对整个系统进行全面测试,并将有关数据进行记录。通过试验,实现了菜园的自动灌溉和智能控制,可以检测土壤的温度、湿度和光照,并根据设定的阈值和时间,自动检测和灌溉,保证了测量精度和精度。

三,系统展示

image.gif编辑

image.gif编辑

image.gif编辑

image.gif编辑

四,核心代码展示

#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char   // 以后unsigned char就可以用uchar代替
#define uint  unsigned int    // 以后unsigned int 就可以用uint 代替
sbit ADC_CS     = P1^6;       // ADC0832的CS引脚
sbit ADC_CLK    = P1^7;       // ADC0832的CLK引脚
sbit ADC_DAT    = P3^2;       // ADC0832的DI/DO引脚
sbit SCK_P      = P1^0;       // 时钟芯片DS1302的SCK管脚
sbit SDA_P      = P1^1;       // 时钟芯片DS1302的SDA管脚
sbit RST_P      = P1^2;       // 时钟芯片DS1302的RST管脚
sbit LcdRs_P    = P1^3;       // 1602液晶的RS管脚       
sbit LcdRw_P    = P1^4;       // 1602液晶的RW管脚 
sbit LcdEn_P    = P1^5;       // 1602液晶的EN管脚
sbit KeyMode_P  = P3^3;       // 模式切换
sbit KeySet_P   = P3^4;       // 设置时间按键
sbit KeySet2_P  = P3^5;       // 设置时间模式的开关时间和光照控制强度
sbit KeyDown_P  = P3^6;       // 减按键
sbit KeyUp_P    = P3^7;       // 加按键
sbit Led_P      = P2^0;       // 指示灯
sbit led2=P2^1;
sbit fm=P2^2;
bit bjflag;
sbit ds=P3^1;
bit closeflag,openflag;
uchar gMode=1;                // 
uchar OpenHour    = 12;       // 开启水泵的小时
uchar OpenMinute  = 00;       // 开启水泵的分钟
uchar CloseHour   = 12;       // 关闭水泵的小时
uchar CloseMinute = 30;       // 关闭水泵的分钟
uchar gLight      = 30;       // 水泵开关的阈值
uchar wDu=20;
uchar X_sd=40;
uint wd=13,t;
uchar xsflag;
uchar bjcount;
uchar TimeBuff[7]={17,9,1,6,18,30,40};          // 时间数组,默认2017年9月1日,星期五,18:30:40
// TimeBuff[0] 代表年份,范围00-99
// TimeBuff[1] 代表月份,范围1-12
// TimeBuff[2] 代表日期,范围1-31
// TimeBuff[3] 代表星期,范围1-7
// TimeBuff[4] 代表小时,范围00-23
// TimeBuff[5] 代表分钟,范围00-59
// TimeBuff[6] 代表秒钟,范围00-59
/*********************************************************/
// 毫秒级的延时函数,time是要延时的毫秒数
/*********************************************************/
void DelayMs(uint time)
{
  uint i,j;
  for(i=0;i<time;i++)
    for(j=0;j<112;j++);
}
void delay(uint z)              //延时函数
{
  uint x,y;
  for(x=z;x>0;x--)
    for(y=110;y>0;y--);
}
/*********************************************************/
// 1602液晶写命令函数,cmd就是要写入的命令
/*********************************************************/
void LcdWriteCmd(uchar cmd)
{ 
  LcdRs_P = 0;
  LcdRw_P = 0;
  LcdEn_P = 0;
  P0=cmd;
  DelayMs(2);
  LcdEn_P = 1;    
  DelayMs(2);
  LcdEn_P = 0;  
}
/*********************************************************/
// 1602液晶写数据函数,dat就是要写入的数据
/*********************************************************/
void LcdWriteData(uchar dat)
{
  LcdRs_P = 1; 
  LcdRw_P = 0;
  LcdEn_P = 0;
  P0=dat;
  DelayMs(2);
  LcdEn_P = 1;    
  DelayMs(2);
  LcdEn_P = 0;
}
/*********************************************************/
// 1602液晶初始化函数
/*********************************************************/
void LcdInit()
{
  LcdWriteCmd(0x38);        // 16*2显示,5*7点阵,8位数据口
  LcdWriteCmd(0x0C);        // 开显示,不显示光标
  LcdWriteCmd(0x06);        // 地址加1,当写入数据后光标右移
  LcdWriteCmd(0x01);        // 清屏
}
/*********************************************************/
// 液晶光标定位函数
/*********************************************************/
void LcdGotoXY(uchar line,uchar column)
{
  // 第一行
  if(line==0)        
    LcdWriteCmd(0x80+column); 
  // 第二行
  if(line==1)        
    LcdWriteCmd(0x80+0x40+column); 
}
/*********************************************************/
// 液晶输出字符串函数
/*********************************************************/
void LcdPrintStr(uchar *str)
{
  while(*str!='\0')
      LcdWriteData(*str++);
}
/*********************************************************/
// 液晶输出数字(0-99)
/*********************************************************/
void LcdPrintNum(uchar num)
{
  LcdWriteData(num/10+48);    // 十位
  LcdWriteData(num%10+48);    // 个位
}
/*********************************************************/
// 显示模式
/*********************************************************/
void LcdPrintMode(uchar num)
{
  switch(num)     
  {
    case 1: LcdPrintStr("sdms");  break;
    case 2: LcdPrintStr("dsms");  break;
    default:                        break;
  }
}
/*********************************************************/
// 液晶显示内容的初始化
/*********************************************************/
void LcdShowInit()
{
  LcdGotoXY(0,0);
  LcdPrintStr("20du   -     :  ");
  LcdGotoXY(1,0);
  LcdPrintStr("      sd:  gz:  ");
  LcdGotoXY(1,0);
  LcdPrintMode(gMode);
}
/*********************************************************/
// 刷新时间显示
/*********************************************************/
void FlashTime()
{
  LcdGotoXY(0,0);                   // 年份
  LcdPrintNum(wd);
  LcdGotoXY(0,5);                   // 月份
  LcdPrintNum(TimeBuff[1]);
  LcdGotoXY(0,8);                   // 日期
  LcdPrintNum(TimeBuff[2]);
  LcdGotoXY(0,11);                  // 小时
  LcdPrintNum(TimeBuff[4]);
  LcdGotoXY(0,14);                  // 分钟
  LcdPrintNum(TimeBuff[5]);
  LcdGotoXY(0,13);                  // 秒钟
  if(TimeBuff[6]%2==0)              // 秒钟是偶数显示冒号
    LcdWriteData(':');
  else                              // 秒钟是奇数显示空格
    LcdWriteData(' ');
}
/*********************************************************/
// 初始化DS1302
/*********************************************************/
void DS1302_Init(void)
{
  RST_P=0;      // RST脚置低
  SCK_P=0;      // SCK脚置低
  SDA_P=0;      // SDA脚置低       
}
/*********************************************************/
// 从DS1302读出一字节数据
/*********************************************************/
uchar DS1302_Read_Byte(uchar addr) 
{
  uchar i;
  uchar temp;
  RST_P=1;                
  /* 写入目标地址:addr*/
  for(i=0;i<8;i++) 
  {     
    if(addr&0x01) 
      SDA_P=1;
    else 
      SDA_P=0;
    SCK_P=1;
    _nop_();
    SCK_P=0;
    _nop_();
    addr=addr>> 1;
  }
  /* 读出该地址的数据 */
  for(i=0;i<8;i++) 
  {
    temp=temp>>1;
    if(SDA_P) 
      temp|= 0x80;
    else 
      temp&=0x7F;
    SCK_P=1;
    _nop_();
    SCK_P=0;
    _nop_();
  }
  RST_P=0;
  return temp;
}
/*********************************************************/
// 向DS1302写入一字节数据
/*********************************************************/
void DS1302_Write_Byte(uchar addr, uchar dat)
{
  uchar i;
  RST_P = 1;
  /* 写入目标地址:addr*/
  for(i=0;i<8;i++) 
  { 
    if(addr&0x01) 
      SDA_P=1;
    else 
      SDA_P=0;
    SCK_P=1;
    _nop_();
    SCK_P=0;
    _nop_();
    addr=addr>>1;
  }
  /* 写入数据:dat*/
  for(i=0;i<8;i++) 
  {
    if(dat&0x01) 
      SDA_P=1;
    else 
      SDA_P=0;
    SCK_P=1;
    _nop_();
    SCK_P=0;
    _nop_();
    dat=dat>>1;
  }
  RST_P=0;          
}
/*********************************************************/
// 向DS1302写入时间数据
/*********************************************************/
void DS1302_Write_Time() 
{
  uchar i;
  uchar temp1;
  uchar temp2;
  for(i=0;i<7;i++)      // 十进制转BCD码
  {
    temp1=(TimeBuff[i]/10)<<4;
    temp2=TimeBuff[i]%10;
    TimeBuff[i]=temp1+temp2;
  }
  DS1302_Write_Byte(0x8E,0x00);               // 关闭写保护 
  DS1302_Write_Byte(0x80,0x80);               // 暂停时钟 
  DS1302_Write_Byte(0x8C,TimeBuff[0]);        // 年 
  DS1302_Write_Byte(0x88,TimeBuff[1]);        // 月 
  DS1302_Write_Byte(0x86,TimeBuff[2]);        // 日 
  DS1302_Write_Byte(0x8A,TimeBuff[3]);        // 星期
  DS1302_Write_Byte(0x84,TimeBuff[4]);        // 时 
  DS1302_Write_Byte(0x82,TimeBuff[5]);        // 分
  DS1302_Write_Byte(0x80,TimeBuff[6]);        // 秒
  DS1302_Write_Byte(0x80,TimeBuff[6]&0x7F);   // 运行时钟
  DS1302_Write_Byte(0x8E,0x80);               // 打开写保护  
}
/*********************************************************/
// 从DS1302读出时间数据
/*********************************************************/
void DS1302_Read_Time()  
{ 
  uchar i;
  TimeBuff[0]=DS1302_Read_Byte(0x8D);           // 年 
  TimeBuff[1]=DS1302_Read_Byte(0x89);           // 月 
  TimeBuff[2]=DS1302_Read_Byte(0x87);           // 日 
  TimeBuff[3]=DS1302_Read_Byte(0x8B);           // 星期
  TimeBuff[4]=DS1302_Read_Byte(0x85);           // 时 
  TimeBuff[5]=DS1302_Read_Byte(0x83);           // 分 
  TimeBuff[6]=(DS1302_Read_Byte(0x81))&0x7F;    // 秒 
  for(i=0;i<7;i++)    // BCD转十进制
  {           
    TimeBuff[i]=(TimeBuff[i]/16)*10+TimeBuff[i]%16;
  }
}
/*********************************************************/
// ADC0832的时钟脉冲
/*********************************************************/
void WavePlus()
{
  _nop_();
  ADC_CLK = 1;
  _nop_();
  ADC_CLK = 0;
}
/*********************************************************/
// 获取指定通道的A/D转换结果
/*********************************************************/
uchar Get_ADC0832()
{ 
  uchar i;
  uchar dat1=0;
  uchar dat2=0;
  ADC_CLK = 0;        // 电平初始化
  ADC_DAT = 1;
  _nop_();
  ADC_CS = 0;
  WavePlus();         // 起始信号 
  ADC_DAT = 1;
  WavePlus();         // 通道选择的第一位
  ADC_DAT = 0;      
  WavePlus();         // 通道选择的第二位
  ADC_DAT = 1;
  for(i=0;i<8;i++)    // 第一次读取
  {
    dat1<<=1;
    WavePlus();
    if(ADC_DAT)
      dat1=dat1|0x01;
    else
      dat1=dat1|0x00;
  }
  for(i=0;i<8;i++)    // 第二次读取
  {
    dat2>>= 1;
    if(ADC_DAT)
      dat2=dat2|0x80;
    else
      dat2=dat2|0x00;
    WavePlus();
  }
  _nop_();            // 结束此次传输
  ADC_DAT = 1;
  ADC_CLK = 1;
  ADC_CS  = 1;   
  if(dat1==dat2)      // 返回采集结果
    return dat1;
  else
    return 0;
} 
uchar Get_ADC08322()
{ 
  uchar i;
  uchar dat1=0;
  uchar dat2=0;
  ADC_CLK = 0;        // 电平初始化
  ADC_DAT = 1;
  _nop_();
  ADC_CS = 0;
  WavePlus();         // 起始信号 
  ADC_DAT = 1;
  WavePlus();         // 通道选择的第一位
  ADC_DAT = 1;      
  WavePlus();         // 通道选择的第二位
  ADC_DAT = 1;
  for(i=0;i<8;i++)    // 第一次读取
  {
    dat1<<=1;
    WavePlus();
    if(ADC_DAT)
      dat1=dat1|0x01;
    else
      dat1=dat1|0x00;
  }
  for(i=0;i<8;i++)    // 第二次读取
  {
    dat2>>= 1;
    if(ADC_DAT)
      dat2=dat2|0x80;
    else
      dat2=dat2|0x00;
    WavePlus();
  }
  _nop_();            // 结束此次传输
  ADC_DAT = 1;
  ADC_CLK = 1;
  ADC_CS  = 1;   
  if(dat1==dat2)      // 返回采集结果
    return dat1;
  else
    return 0;
} 
/*********************************************************/
unsigned char UART_data; //定义串口接收数据变量
/*********************************************************/
// 按键扫描(设置当前时间)
/*********************************************************/
void KeyScanf1()
{
  if(KeySet_P==0 || UART_data == 'b')
  {
    UART_data = 'z';
    LcdGotoXY(0,13);        // 显示秒钟的冒号
    LcdWriteData(':');
    DelayMs(10);            // 延时等待,消除按键按下的抖动
    while(!KeySet_P);       // 等待按键释放
    DelayMs(10);            // 延时等待,消除按键松开的抖动
    LcdGotoXY(0,6);         // 定位光标到月份闪烁
    LcdWriteCmd(0x0f);      // 启动光标闪烁
    DelayMs(10);            // 延时等待,消除按键按下的抖动
    while(!KeySet_P);       // 等待按键释放
    DelayMs(10);            // 延时等待,消除按键松开的抖动
    /* 调整月份 */
    while(1)
    {
      if(KeyDown_P==0 || UART_data == 'd')              // 如果减按键被下去
      {
        UART_data = 'z';
        if(TimeBuff[1]>1)           // 判断月份是否大于1    
          TimeBuff[1]--;            // 是的话就减去1
        LcdGotoXY(0,5);             // 光标定位到月份的位置
        LcdPrintNum(TimeBuff[1]);   // 刷新显示改变后的月份
        LcdGotoXY(0,6);             // 定位光标到月份闪烁
        DelayMs(300);               // 延时0.3秒左右
      }
      if(KeyUp_P==0 || UART_data == 'e')                // 如果加按键被下去
      {
        UART_data = 'z';
        if(TimeBuff[1]<12)          // 判断月份是否小于12
          TimeBuff[1]++;            // 是的话就加上1
        LcdGotoXY(0,5);             // 光标定位到月份的位置
        LcdPrintNum(TimeBuff[1]);   // 刷新显示改变后的月份
        LcdGotoXY(0,6);             // 定位光标到月份闪烁
        DelayMs(300);               // 延时0.3秒左右
      }
      if(KeySet_P==0 || UART_data =='b')
      {
        UART_data = 'z';
        break;
      }
    }
    LcdGotoXY(0,9);         // 定位光标到日期闪烁
    DelayMs(10);            // 延时等待,消除按键按下的抖动
    while(!KeySet_P);       // 等待按键释放
    DelayMs(10);            // 延时等待,消除按键松开的抖动
    /* 调整日期 */
    while(1)
    {
      if(KeyDown_P==0 || UART_data == 'd')              // 如果减按键被下去
      {
        UART_data = 'z';
        if(TimeBuff[2]>1)           // 判断日期是否大于1    
          TimeBuff[2]--;            // 是的话就减去1
        LcdGotoXY(0,8);             // 光标定位到日期的位置
        LcdPrintNum(TimeBuff[2]);   // 刷新显示改变后的日期
        LcdGotoXY(0,9);             // 定位光标到日期闪烁
        DelayMs(300);               // 延时0.3秒左右
      }
      if(KeyUp_P==0 || UART_data == 'e')                // 如果加按键被下去
      {
        UART_data = 'z';
        if(TimeBuff[2]<31)          // 判断日期是否小于31
          TimeBuff[2]++;            // 是的话就加上1
        LcdGotoXY(0,8);             // 光标定位到日期的位置
        LcdPrintNum(TimeBuff[2]);   // 刷新显示改变后的日期
        LcdGotoXY(0,9);             // 定位光标到日期闪烁
        DelayMs(300);               // 延时0.3秒左右
      }
      if(KeySet_P==0 || UART_data == 'b')
      {
        UART_data = 'z';
        break;
      }
    }
    LcdGotoXY(0,12);        // 定位光标到小时闪烁
    DelayMs(10);            // 延时等待,消除按键按下的抖动
    while(!KeySet_P);       // 等待按键释放
    DelayMs(10);            // 延时等待,消除按键松开的抖动
    /* 调整小时 */
    while(1)
    {
      if(KeyDown_P==0 || UART_data == 'd')              // 如果减按键被下去
      {
        UART_data = 'z';
        if(TimeBuff[4]>0)           // 判断小时是否大于0
          TimeBuff[4]--;            // 是的话就减去1
        LcdGotoXY(0,11);            // 光标定位到小时的位置
        LcdPrintNum(TimeBuff[4]);   // 刷新显示改变后的小时
        LcdGotoXY(0,12);            // 定位光标到小时闪烁
        DelayMs(300);               // 延时0.3秒左右
      }
      if(KeyUp_P==0 || UART_data == 'e')                // 如果加按键被下去
      {
        UART_data = 'z';
        if(TimeBuff[4]<23)          // 判断小时是否小于23
          TimeBuff[4]++;            // 是的话就加上1
        LcdGotoXY(0,11);            // 光标定位到小时的位置
        LcdPrintNum(TimeBuff[4]);   // 刷新显示改变后的小时
        LcdGotoXY(0,12);            // 定位光标到小时闪烁
        DelayMs(300);               // 延时0.3秒左右
      }
      if(KeySet_P==0 || UART_data == 'b')
      {
        UART_data = 'z';
        break;
      }
    }
    LcdGotoXY(0,15);        // 定位光标到分钟闪烁
    DelayMs(10);            // 延时等待,消除按键按下的抖动
    while(!KeySet_P);       // 等待按键释放
    DelayMs(10);            // 延时等待,消除按键松开的抖动
    /* 调整分钟 */
    while(1)
    {
      if(KeyDown_P==0 || UART_data == 'd')              // 如果减按键被下去
      {
        UART_data = 'z';
        if(TimeBuff[5]>0)           // 判断分钟是否大于0
          TimeBuff[5]--;            // 是的话就减去1
        LcdGotoXY(0,14);            // 光标定位到分钟的位置
        LcdPrintNum(TimeBuff[5]);   // 刷新显示改变后的分钟
        LcdGotoXY(0,15);            // 定位光标到分钟闪烁
        DelayMs(300);               // 延时0.3秒左右
      }
      if(KeyUp_P==0 || UART_data == 'e')                // 如果加按键被下去
      {
        UART_data = 'z';
        if(TimeBuff[5]<59)          // 判断分钟是否小于59
          TimeBuff[5]++;            // 是的话就加上1
        LcdGotoXY(0,14);            // 光标定位到分钟的位置
        LcdPrintNum(TimeBuff[5]);   // 刷新显示改变后的分钟
        LcdGotoXY(0,15);            // 定位光标到分钟闪烁
        DelayMs(300);               // 延时0.3秒左右
      }
      if(KeySet_P==0 || UART_data == 'b')
      {
        UART_data = 'z';
        break;
      }
    }
    /* 退出前的设置 */
    LcdWriteCmd(0x0C);      // 关闭光标闪烁
    DS1302_Write_Time();    // 把新设置的时间值存入DS1302芯片
    DelayMs(10);            // 延时等待,消除按键按下的抖动
    while(!KeySet_P);       // 等待按键释放
    DelayMs(10);            // 延时等待,消除按键松开的抖动
  }
}
uint temp,mm;uchar i;float f_temp;
/*******************************************************
温度函数
*******************************************************/
void dsreset(void)             //下边是温度获取子程衼E
{
  uint i;
  ds=0;
  i=103;
  while(i>0)i--;
  ds=1;
  i=4;
  while(i>0)i--;
}
bit tempreadbit(void)          //读一位
{
  uint i;
  bit dat;
  ds=0;i++;
  ds=1;i++;i++;
  dat=ds;
  i=8;while(i>0)i--;
  return(dat);
}
uchar tempread(void)           //获取温度
{
  uchar i,j,dat;
  dat=0;
  for(i=1;i<=8;i++)
  {
    j=tempreadbit();
    dat=(j<<7)|(dat>>1);
  }
  return(dat);
}
void tempwritebyte(uchar dat)        //写一个字节
{
  uint i;
  uchar j;
  bit testb;
  for(j=1;j<=8;j++)
  {
    testb=dat&0x01;
    dat=dat>>1;
    if(testb)
    {
      ds=0;
      ds=1;
      i=8;while(i>0)i--;
    }
    else
    {
      ds=0;
      i=8;while(i>0)i--;
      ds=1;
      i++;i++;
    }
  }
}
void tempchange(void)            //温度转换
{
  dsreset();
  delay(1);
  tempwritebyte(0x44);
}
uint get_temp()             //获取温度
{
  uchar a,b;
  dsreset();
  delay(1);
  tempwritebyte(0xcc);
  tempwritebyte(0xbe);
  a=tempread();
  b=tempread();
  temp=b;
  temp<<=8;
  temp=temp|a;
  f_temp=temp*0.0625;
  temp=f_temp*10+0.5;
  f_temp=f_temp+0.05;
  return temp;
}
/***********************************/
/*********************************************************/
// 按键扫描(设置水泵的动作)
/*********************************************************/
void KeyScanf2()
{
  if(KeySet2_P==0 || UART_data == 'c')
  {
    UART_data = 'z';
    LcdGotoXY(0,0);                   // 光标定位
    LcdPrintStr(" OpenTime   :   ");  // 显示第1行内容
    LcdGotoXY(1,0);                   // 光标定位
    LcdPrintStr("CloseTime   :   ");  // 显示第2行内容
    LcdGotoXY(0,10);                  // 光标定位
    LcdPrintNum(OpenHour);            // 显示开启水泵的小时
    LcdGotoXY(0,13);                  // 光标定位
    LcdPrintNum(OpenMinute);          // 显示开启水泵的分钟
    LcdGotoXY(1,10);                  // 光标定位
    LcdPrintNum(CloseHour);           // 显示关闭水泵的小时
    LcdGotoXY(1,13);                  // 光标定位
    LcdPrintNum(CloseMinute);         // 显示关闭水泵的分钟    
    LcdWriteCmd(0x0f);              // 启动光标闪烁
    LcdGotoXY(0,11);                // 定位光标
    DelayMs(10);                    // 延时等待,消除按键按下的抖动
    while(!KeySet2_P);              // 等待按键释放
    DelayMs(10);                    // 延时等待,消除按键松开的抖动
    /* 调整开启的小时 */
    while(1)
    {
      if(KeyDown_P==0 || UART_data == 'd')              // 如果减按键被下去
      {
        UART_data ='z';
        if(OpenHour>0)              // 判断小时是否大于0    
          OpenHour--;               // 是的话就减去1
        LcdGotoXY(0,10);            // 光标定位
        LcdPrintNum(OpenHour);      // 刷新显示改变后的小时
        LcdGotoXY(0,11);            // 定位光标
        DelayMs(300);               // 延时0.3秒左右
      }
      if(KeyUp_P==0 || UART_data == 'e')                // 如果加按键被下去
      {
        UART_data = 'z';
        if(OpenHour<23)             // 判断小时是否小于23
          OpenHour++;               // 是的话就加上1
        LcdGotoXY(0,10);            // 光标定位
        LcdPrintNum(OpenHour);      // 刷新显示改变后的小时
        LcdGotoXY(0,11);            // 定位光标
        DelayMs(300);               // 延时0.3秒左右
      }
      if(KeySet2_P==0 || UART_data == 'c')
      {
        UART_data = 'z';
        break;
      }
    }
    LcdGotoXY(0,14);                // 定位光标
    DelayMs(10);                    // 延时等待,消除按键按下的抖动
    while(!KeySet2_P);              // 等待按键释放
    DelayMs(10);                    // 延时等待,消除按键松开的抖动
    /* 调整开启的分钟 */
    while(1)
    {
      if(KeyDown_P==0 || UART_data == 'd')              // 如果减按键被下去
      {
        UART_data = 'z';
        if(OpenMinute>0)            // 判断分钟是否大于0
          OpenMinute--;             // 是的话就减去1
        LcdGotoXY(0,13);            // 光标定位
        LcdPrintNum(OpenMinute);    // 刷新显示改变后的分钟
        LcdGotoXY(0,14);            // 定位光标
        DelayMs(300);               // 延时0.3秒左右
      }
      if(KeyUp_P==0 || UART_data == 'e')                // 如果加按键被下去
      {
        UART_data = 'z';
        if(OpenMinute<59)           // 判断分钟是否小于59
          OpenMinute++;             // 是的话就加上1
        LcdGotoXY(0,13);            // 光标定位
        LcdPrintNum(OpenMinute);    // 刷新显示改变后的分钟
        LcdGotoXY(0,14);            // 定位光标
        DelayMs(300);               // 延时0.3秒左右
      }
      if(KeySet2_P==0 || UART_data == 'c')
      {
        UART_data = 'z';
        break;
      }
    }
    LcdGotoXY(1,11);                // 定位光标
    DelayMs(10);                    // 延时等待,消除按键按下的抖动
    while(!KeySet2_P);              // 等待按键释放
    DelayMs(10);                    // 延时等待,消除按键松开的抖动
    /* 调整关闭的小时 */
    while(1)
    {
      if(KeyDown_P==0 || UART_data == 'd')              // 如果减按键被下去
      {
        UART_data = 'z';
        if(CloseHour>0)             // 判断小时是否大于0    
          CloseHour--;              // 是的话就减去1
        LcdGotoXY(1,10);            // 光标定位
        LcdPrintNum(CloseHour);     // 刷新显示改变后的小时
        LcdGotoXY(1,11);            // 定位光标
        DelayMs(300);               // 延时0.3秒左右
      }
      if(KeyUp_P==0 || UART_data == 'e')                // 如果加按键被下去
      {
        UART_data = 'z';
        if(CloseHour<23)            // 判断小时是否小于23
          CloseHour++;              // 是的话就加上1
        LcdGotoXY(1,10);            // 光标定位
        LcdPrintNum(CloseHour);     // 刷新显示改变后的小时
        LcdGotoXY(1,11);            // 定位光标
        DelayMs(300);               // 延时0.3秒左右
      }
      if(KeySet2_P==0 || UART_data == 'c')
      {
        UART_data = 'z';
        break;
      }
    }
    LcdGotoXY(1,14);                // 定位光标
    DelayMs(10);                    // 延时等待,消除按键按下的抖动
    while(!KeySet2_P);              // 等待按键释放
    DelayMs(10);                    // 延时等待,消除按键松开的抖动
    /* 调整关闭的分钟 */
    while(1)
    {
      if(KeyDown_P==0 || UART_data == 'd')              // 如果减按键被下去
      {
        UART_data = 'z';
        if(CloseMinute>0)           // 判断分钟是否大于0
          CloseMinute--;            // 是的话就减去1
        LcdGotoXY(1,13);            // 光标定位
        LcdPrintNum(CloseMinute);   // 刷新显示改变后的分钟
        LcdGotoXY(1,14);            // 定位光标
        DelayMs(300);               // 延时0.3秒左右
      }
      if(KeyUp_P==0 || UART_data == 'e')                // 如果加按键被下去
      {
        UART_data = 'z';
        if(CloseMinute<59)          // 判断分钟是否小于59
          CloseMinute++;            // 是的话就加上1
        LcdGotoXY(1,13);            // 光标定位
        LcdPrintNum(CloseMinute);   // 刷新显示改变后的分钟
        LcdGotoXY(1,14);            // 定位光标
        DelayMs(300);               // 延时0.3秒左右
      }
      if(KeySet2_P==0 || UART_data == 'c')
      {
        UART_data = 'z';
        break;
      }
    }
    DelayMs(10);                    // 延时等待,消除按键按下的抖动
    while(!KeySet2_P);              // 等待按键释放
    DelayMs(10);                    // 延时等待,消除按键松开的抖动
    /* 光照强度的设置 */
    LcdWriteCmd(0x0C);                // 关闭光标闪烁
    LcdGotoXY(0,0);                   // 光标定位
    LcdPrintStr("   Light Set    ");  // 显示第1行内容
    LcdGotoXY(1,0);                   // 光标定位
    LcdPrintStr("                ");  // 显示第2行内容
    LcdGotoXY(1,7);                   // 光标定位
    LcdPrintNum(gLight);              // 显示水泵的光线控制强度阈值
    while(1)
    {
      if(KeyDown_P==0 || UART_data == 'd')              // 如果减按键被下去
      {
        UART_data = 'z';
        if(gLight>0)                // 判断光线阈值是否大于0
          gLight--;                 // 是的话就减去1
        LcdGotoXY(1,7);             // 光标定位
        LcdPrintNum(gLight);        // 刷新显示改变后的光线阈值
        DelayMs(300);               // 延时0.3秒左右
      }
      if(KeyUp_P==0 || UART_data == 'e')                // 如果加按键被下去
      {
        UART_data = 'z';
        if(gLight<99)               // 判断光线阈值是否小于59
          gLight++;                 // 是的话就加上1
        LcdGotoXY(1,7);             // 光标定位
        LcdPrintNum(gLight);        // 刷新显示改变后的光线阈值
        DelayMs(300);               // 延时0.3秒左右
      }
      if(KeySet2_P==0 || UART_data == 'c')
      {
        UART_data = 'z';
        break;
      }
    }
    DelayMs(10);                    // 延时等待,消除按键按下的抖动
    while(!KeySet2_P);              // 等待按键释放
    DelayMs(10);                    // 延时等待,消除按键松开的抖动
  //    设置温度
    LcdWriteCmd(0x0C);                // 关闭光眮E了?
    LcdGotoXY(0,0);                   // 光眮Eㄎ?
    LcdPrintStr("   Wendu Set    ");  // 显示第1行内容
    LcdGotoXY(1,0);                   // 光眮Eㄎ?
    LcdPrintStr("                ");  // 显示第2行内容
    LcdGotoXY(1,7);                   // 光眮Eㄎ?
    LcdPrintNum(wDu);             // 显示水泵的光线控制强度阈值  
    while(1){
      LcdGotoXY(1,7);                   // 光眮Eㄎ?
      LcdPrintNum(wDu);             // 显示水泵的光线控制强度阈值
      if(KeyDown_P==0 || UART_data == 'd')              // 如果减按紒E幌氯?
      {
        UART_data = 'z';
        if(wDu>0)               // 判断光线阈值是否大于0
          wDu--;                  // 是的话就减去1
        DelayMs(300);               // 延时0.3脕E笥?
      }
      if(KeyUp_P==0 || UART_data == 'e')                // 如果加按紒E幌氯?
      {
        UART_data = 'z';
        if(wDu<99)                // 判断光线阈值是否小于59
          wDu++;                  // 是的话就加上1
        DelayMs(300);               // 延时0.3脕E笥?
      }
      if(KeySet2_P==0 || UART_data == 'c')
      {
        UART_data = 'z';
        break;
      }
    }
      DelayMs(10);                    // 延时等待,消除按键按下的抖动
    while(!KeySet2_P);              // 等待按键释放
    DelayMs(10);                    // 延时等待,消除按键松开的抖动
  //    设置湿度
    LcdWriteCmd(0x0C);                // 关闭光眮E了?
    LcdGotoXY(0,0);                   // 光眮Eㄎ?
    LcdPrintStr("   Shidu Set    ");  // 显示第1行内容
    LcdGotoXY(1,0);                   // 光眮Eㄎ?
    LcdPrintStr("                ");  // 显示第2行内容
    LcdGotoXY(1,7);                   // 光眮Eㄎ?
    LcdPrintNum(X_sd);              // 显示水泵的光线控制强度阈值  
    while(1){
      LcdGotoXY(1,7);                   // 光眮Eㄎ?
      LcdPrintNum(X_sd);              // 显示水泵的光线控制强度阈值
      if(KeyDown_P==0 || UART_data == 'd')              // 如果减按紒E幌氯?
      {
        UART_data = 'z';
        if(X_sd>0)                // 判断光线阈值是否大于0
          X_sd--;                 // 是的话就减去1
        DelayMs(300);               // 延时0.3脕E笥?
      }
      if(KeyUp_P==0 || UART_data == 'e')                // 如果加按紒E幌氯?
      {
        UART_data = 'z';
        if(X_sd<99)               // 判断光线阈值是否小于59
          X_sd++;                 // 是的话就加上1
        DelayMs(300);               // 延时0.3脕E笥?
      }
      if(KeySet2_P==0 || UART_data == 'c')
      {
        UART_data = 'z';
        break;
      }
    }
    /* 退出前的设置 */
    LcdShowInit();          // 液晶显示内容初始化
    DelayMs(10);            // 延时等待,消除按键按下的抖动
    while(!KeySet2_P);      // 等待按键释放
    DelayMs(10);            // 延时等待,消除按键松开的抖动
  }
}
/*********************************************************/
// 按键扫描(模式切换)
/*********************************************************/
void KeyScanf3()
{
  if(KeyMode_P==0 || UART_data == 'a')
  {
    UART_data = 'z';
    gMode++;              // 切换到下一模式
    if(gMode==3)        // 如果到尽头了
      gMode=1;            // 回到第一种模式
    LcdGotoXY(1,0);       // 光标定位
    LcdPrintMode(gMode);  // 显示模式
    DelayMs(10);          // 去除按键按下的抖动
    while(!KeyMode_P);    // 等待按键是否
    DelayMs(10);          // 去除按键松开的抖动
  Led_P=1;
  bjflag=0;
  }
}
/*********************************************************/
// 开窗
/*********************************************************/
void Open()
{
  Led_P=0;
  bjflag=1;
}
/*********************************************************/
// 关窗
/*********************************************************/
void Close()
{
  Led_P=1;
  bjflag=0;
}
/*********************************************************/
// 主函数
/*********************************************************/
void main()
{
  uchar light;
  uchar sd;
  LcdInit();      // 执行液晶初始化  
  DS1302_Init();  // 时钟芯片的初始化
  LcdShowInit();  // 液晶显示内容的初始化
  TMOD=0x21;//定时器0  模式1  16位定时模式
  EA=1;        //开启总中断  
  ES = 1; //允许UART串口的中断
  PCON = 0x80;  //波特率倍频(屏蔽本句波特率为2400)
  SCON = 0x50;  //串口工作方式1,允许串口接收(SCON = 0x40 时禁止串口接收)
  TH1 = 0xFa; //定时器初值高8位设置   //12MHZ晶振,波特率为4800 0xf3
  TL1 = 0xFa; //定时器初值低8位设置   //11.0592MHZ晶振,波特率为4800 0xf4   9600  0xfa   19200  0xfd
  TR1=1;
  if(DS1302_Read_Byte(0x81)>=128)     // 判断时钟芯片是否正在运行
  {
    DS1302_Write_Time();              // 如果没有,则初始化一个时间
  }
  while(1)
  {
    tempchange();
    t=get_temp();
    if(t>=0&&t<=1250)  //温度合法范围,不在这个范围就是没有获取到合适的值
    {
      wd=t/10;
    }
    DS1302_Read_Time();       // 获取当前时钟芯片的时间,存在数组time_buf中
    FlashTime();              // 刷新时间显示
    light=Get_ADC08322();     // 读取光照强度
    sd=Get_ADC0832();
    sd=sd/2.5;
    light=light/2.5;          // 缩小光照检测结果(在0-99)
    if(light>99)              // 如果大于99
      light=99;               // 则依然保持99
    LcdGotoXY(1,14);          // 光标定位
    LcdPrintNum(light);       // 显示光照强度
    LcdGotoXY(1,9);         // 光标定位
    LcdPrintNum(sd);        // 显示湿度
    KeyScanf1();              // 按键扫描(时间的设置)
    KeyScanf2();              // 按键扫描(阈值的设置)
    KeyScanf3();              // 按键扫描(模式切换)
    /*土壤湿度控制模式*/
    if(gMode==1)
    {
      if(sd<X_sd)  //湿度小于阈值开启
        Open();
      else
        Close();  
    }
    /*时间控制模式*/
    if(gMode==2)
    {
      if((TimeBuff[4]==CloseHour)&&(TimeBuff[5]==CloseMinute)&&(TimeBuff[6]==0))  // 如果到了关的时间 
      {
        Close();
      }
      if((TimeBuff[4]==OpenHour)&&(TimeBuff[5]==OpenMinute)&&(TimeBuff[6]==0))    // 如果到了开的时间 
      {
        Open();
      } 
    }
    if(light<gLight)    // 当前光线小于设置的阈值
    {
      led2=0;//开灯
    }else{
      led2=1;
    }
    if(wd<wDu || light<gLight)    // 当前温度小于设置的阈值
    {
      bjflag=1;
    }else{
      bjflag=0;
    }
    if(bjflag==1){
      bjcount++;
      if(bjcount>5){
        bjcount=0;
        fm=0;DelayMs(100);DelayMs(100);fm=1;
      }
    }else{
      fm=1;
    }
    DelayMs(100);             // 延时0.1秒
  }
}
void UART_R ( ) interrupt 4  using 1  //切换寄存器组到1
{ 
  RI = 0;     //令接收中断标志位为0(软件清零)
    UART_data = SBUF; //将接收到的数据送入变量 UART_data
}

image.gif

五,相关作品展示

基于Java开发、Python开发、PHP开发、C#开发等相关语言开发的实战项目

基于Nodejs、Vue等前端技术开发的前端实战项目

基于微信小程序和安卓APP应用开发的相关作品

基于51单片机等嵌入式物联网开发应用

基于各类算法实现的AI智能应用

基于大数据实现的各类数据管理和推荐系统

image.gif编辑

image.gif编辑image.gif编辑

image.gif编辑

image.gif编辑image.gif编辑

image.gif编辑

image.gif编辑


相关文章
|
7月前
|
传感器 C语言 智能硬件
基于单片机的温度控制系统
基于单片机的温度控制系统
130 0
|
7月前
|
传感器 编解码 数据处理
毕业设计|基于STM32单片机的水位浑浊度检测设计
毕业设计|基于STM32单片机的水位浑浊度检测设计
872 0
|
7月前
|
传感器 监控 IDE
基于单片机的温度监控系统设计
基于单片机的温度监控系统设计
263 0
|
2月前
|
传感器 数据采集 存储
基于51单片机的大棚环境检测系统设计
基于51单片机的大棚环境检测系统设计
185 0
|
7月前
基于51单片机的模拟交通灯控制系统
该文档描述了一个基于51单片机的交通灯控制系统的设计要求和实现。系统应用于十字路口,控制主干道(东西方向)和支干道(南北方向)的交通流量。主干道绿灯时间为15秒,支干道为10秒,转换时黄灯闪烁3秒。用户可以通过按键设置通行时间和进行交通管制。系统包括四个状态:主干道绿灯、主干道黄灯、支干道绿灯和支干道黄灯,循环运行。此外,还提供了仿真电路图、原理图和实物照片,以及C代码示例。
191 1
|
7月前
|
IDE 开发工具
基于单片机的简易步进电机控制系统
基于单片机的简易步进电机控制系统
101 0
|
7月前
|
传感器 数据处理
基于单片机的室内空气质量检测系统设计_kaic
基于单片机的室内空气质量检测系统设计_kaic
|
7月前
|
传感器 人工智能 前端开发
单片机毕业设计|农家菜园自动灌溉控制系统设计
单片机毕业设计|农家菜园自动灌溉控制系统设计
120 0
|
7月前
|
人工智能 安全 搜索推荐
单片机毕业设计|基于stm32智能快递箱设计
单片机毕业设计|基于stm32智能快递箱设计
143 0
|
7月前
|
传感器 测试技术 数据处理
单片机开发|基于单片机的婴儿睡眠监测系统设计
单片机开发|基于单片机的婴儿睡眠监测系统设计
114 0