第四届-模拟智能灌溉系统

第四届-模拟智能灌溉系统一 题目概述 目的 通过电位器 Rb2 输出电压信号 模拟湿度传感器输出信号 再通过 AD 采集完成湿度测量功能 通过 DS1302 芯片提供时间信息 通过按键完成灌溉系统控制和湿度阈值调整功能 通过 LED 完成系统工作状态指示功能 元器件

大家好,我是讯享网,很高兴认识大家。

一. 题目概述:

  1. 目的:
    通过电位器 Rb2 输出电压信号,模拟湿度传感器输出信号,再通过AD 采集完成湿度测量功能;
    通过 DS1302 芯片提供时间信息;
    通过按键完成灌溉系统控制和湿度阈值调整功能,通过 LED 完成系统工作状态指示功能。
  2. 元器件:
    系统硬件电路主要由单片机:控制电路、显示单元、ADC 采集单元、RTC 单元、EEPROM 存储单元、继电器控制电路及报警输出电路组成。
  3. 具体操作:
  4. 系统工作及初始化状态说明
    1.1 自动工作状态,根据湿度数据自动控制打开或关闭灌溉设备,以 L1 点亮指示;
    1.2 手动工作状态,通过按键控制打开或关闭灌溉设备,以 L2 点亮指示;
    1.3 系统上电后处于自动工作状态,系统初始湿度阈值为 50%,此时若湿度低于50%,灌溉设备自动打开,达到 50%后,灌溉设备自动关闭;
    1.4 灌溉设备打开或关闭通过继电器工作状态模拟。
  5. 数码管单元
    时间及湿度数据显示格式如图 2 所示:
    0 8 - 3 0 8 0 5
    时(8时) 分隔符 分(30分) 熄灭 湿度(5%)
    数码管DS1 数码管DS2

图 2. 显示格式(8 点 30 分,土壤湿度 5%)
3. 报警输出单元
系统工作于手动工作状态下时,若当前湿度低于湿度阈值,蜂鸣器发出提示音,并可通过按键 S6 关闭提醒功能。
4. 功能按键
2.1 按键 S7 设定为系统工作状态切换按键;
2.2 手动工作状态下按键 S6、S5、S4 功能设定如下:
按下 S6 关闭蜂鸣器提醒功能,再次按下 S6 打开蜂鸣器提醒功能,如此循环;
S5 功能设定为打开灌溉系统;
S4 功能设定为关闭灌溉系统。
2.3 自动工作状态下按键 S6、S5、S4 功能设定如下:
S6 功能设定为湿度阈值调整按键,按下 S6 后,进入湿度阈值调整界面(如图 3
所示),此时按下 S5 为湿度阈值加 1,按下 S4 湿度阈值减 1,再次按下 S6 后,系统将新的湿度阈值保存到 EEPROM 中,并退出湿度阈值设定界面。

    • 8 8 8 8 5 2
      湿度阈值设置提示符 熄灭 湿度阈值(52%)
      数码管DS1 数码管DS2

图 3. 湿度阈值设定界面
5. 实时时钟
“模拟智能灌溉系统”通过读取 DS1302 时钟芯片相关寄存器获得时间,DS1302芯片时、分、秒寄存器在程序中设定为系统进行初始化设定,时间为 08 时 30 分。
6. 湿度检测单元
以电位器 Rb2 输出电压信号模拟湿度传感器输出信号,且假定电压信号与湿度成正比例关系 H 湿度 = KVRb2(K 为常数),Rb2 电压输出为 5V 时对应湿度为 99%。
7. EEPROM 存储单元
系统通过 EEPROM 存储湿度阈值,自动工作状态下,可通过按键 S6、S5、S4 设置和保存阈值信息。

二.对问题的解读


讯享网

  1. 所谓的电位器Rb2也就是滑动变阻器Rb2,目的在于让滑动变阻器模拟湿度传感器。
  2. RTC单元也就是时钟单元。
  3. AD就是数模转换器。
  4. I2c控制AD和E2PROM两部分,驱动大致一样,只是存储位置不一样。
    AD:0X90 E2PROM:0XA0
  5. 灌溉设备的开与关是以继电器的亮灭情况显示的。
  6. 在写时钟的驱动时,初始化即为写数据。
    三.问题的难点
    A. 最难的地方在于,控制系统的部分,也就是独立按键。这一部分,涉及到状态切换,继电器和蜂鸣器的状态等。极易让人混淆。
    B. 其次,就是更改官方给的驱动。

四.问题的解决
A. 控制系统:

void keyscan() { if(P30==0) { delayms(5); if(P30==0) { //手动状态 if(status==0) { status=1; P2=0x80; P0=0xfd; } //自动状态 else if(status==1) { status=0; P2=0x80; P0=0xfe; } } while(!P30); } else if(P31==0) { delayms(5); if(P31==0) { if(status==0) { if(S6==0){S6=1;} else if(S6==1){S6=0;EEPROM_write(0x10,fazhi);}//退出时将阀值记录 } else if(status==1) { kai=~kai; //手动状态时,蜂鸣器位移响应 } } while(!P31); } else if(P32==0) { delayms(5); if(P32==0) { if(status==0){jia=1;}//自动状态 加1 else if(status==1){jidian=1;}//手动状态 打开继电器 } while(!P32); } else if(P33==0) { delayms(5); if(P33==0) { if(status==0){jian=1;}//自动状态 减1 else if(status==1){jidian=0;}//手动状态 关闭继电器 } while(!P33); } } 还有主函数的部分: //自动状态 if(status==0) { if(shidu<fazhi) { P2=0xa0; P0=0x10;//打开继电器 } else { P2=0xa0; P0=0x00;//关闭继电器 } //6 自动状态下按键S6的切换 if(S6==1) { if(jia==1)//检测加是否被按下 { jia=0; fazhi++; } if(jian==1)//检测减是否被按下 { jian=0; fazhi--; } yi=10;er=10;san=11;si=11;wu=11;liu=11;qi=fazhi/10;ba=fazhi%10; } else if(S6==0) { DS_get(); yi=shijian[2]/10;er=shijian[2]%10;san=10; si=shijian[1]/10;wu=shijian[1]%10;liu=11; qi=shidu/10;ba=shidu%10; } } //手动状态 else if(status==1) { if((shidu<fazhi)&&(kai==0)) { if(jidian==1) { P2=0xa0;P0=0x10;//打开继电器 } else if(jidian==0) { P2=0xa0;P0=0x00;//关闭继电器 } //报警功能 if((shidu<fazhi)&&(kai==1)) { //开蜂鸣器 if(jidian==1)//接着判断继电器是否要打开 { P2=0xa0;P0=0x50; } else if(jidian==0) { P2=0xa0;P0=0x40;//打开报警器 } else if(shidu>fazhi) { //关闭继电器与否 if(jidian==1){P2=0xa0;P0=0x10;} else if(jidian==0){P2=0xa0;P0=0x00;} } yi=shijian[2]/10;er=shijian[2]%10;san=10; si=shijian[1]/10;wu=shijian[1]%10;liu=11; qi=shidu/10;ba=shidu%10; } } } 

讯享网
讯享网uchar AD_read(uchar add) { uchar temp; IIC_Start(); IIC_SendByte(0x90); IIC_WaitAck(); IIC_SendByte(add); IIC_WaitAck(); IIC_Stop(); IIC_Start(); IIC_SendByte(0x91); IIC_WaitAck(); temp=IIC_RecByte(); IIC_Stop(); return temp; } uchar EEPROM_read(uchar add) { uchar temp; IIC_Start(); IIC_SendByte(0xa0); IIC_WaitAck(); IIC_SendByte(add); IIC_WaitAck(); IIC_Stop(); IIC_Start(); IIC_SendByte(0xa1); IIC_WaitAck(); temp=IIC_RecByte(); IIC_Stop(); return temp; } void EEPROM_write(uchar add,uchar dat) { IIC_Start();//启动开始接受信号 IIC_SendByte(0xa0);//选择器件 IIC_WaitAck();//响应 IIC_SendByte(add);//写地址 IIC_WaitAck();//响应 IIC_SendByte(dat);//写数据 IIC_WaitAck();//响应 IIC_Stop();//停止接受信号 } 

ii. 时钟

uchar shijian[]={0,30,8,0,0,0,0}; unsigned char Read_Ds1302 ( unsigned char address ) { unsigned char i,temp=0x00,dat1,dat2;//更改 RST=0; _nop_(); SCK=0; _nop_(); RST=1; _nop_(); Write_Ds1302_Byte(address); for (i=0;i<8;i++) { SCK=0; temp>>=1; if(SDA) temp|=0x80; SCK=1; } RST=0; _nop_(); RST=0; SCK=0; _nop_(); SCK=1; _nop_(); SDA=0; _nop_(); SDA=1; _nop_(); dat1=temp/16; dat2=temp%16; temp=dat1*10+dat2; // temp=0.39*temp; return (temp); } //初始化 void DS_init(void) { uchar i,add; add=0x80;//80是写,81则是读 Write_Ds1302(0x8e,0x00);//开始对1302进行操作 for(i=0;i<7;i++) { Write_Ds1302(add,shijian[i]); add=add+2; } Write_Ds1302(0x8e,0x80);//80则是关闭 } //读取 void DS_get() { uchar i,add; add=0x81;//81是读 for(i=0;i<7;i++) { shijian[i]=Read_Ds1302(add); add=add+2; } Write_Ds1302(0x8e,0x80); } 

五.经验总结
 驱动的更改没有太大的变化,只需要将更改地方理解并记住即可。做了几次真题,驱动也就更改那么几下,大致不会改变。所以,需要平时反复的理解并加以记忆,方可将这一部分写好。需要说明的是:驱动就只有3个部分i2c总线,DS1302和DS18B20。而i2c总线只控制两个部分:ADC转换器和EEPROM(带电可擦可编程读写器),在这一届赛题中,这一部分已经定型,可以当做模板使用。
 独立按键的部分,思维卡在了如何调换模式上,自己想了两个办法,一个是逻辑关系不对,另一个是自认为逻辑正确,但实际没有实现。这个的核心在于:设立一个标志位,举个栗子:工作状态的转换,用status这样一个标志位,用0表示自动状态,用1表示手动状态。即可区分开来。那么蜂鸣器和继电器也是同样的道理。但到这里并没有完全解决这个问题,蜂鸣器和继电器的开和关的判定也是一个问题。在子函数掉用过后,主函数中尤其要注意这个问题。继电器的判断还是比较容易的,但蜂鸣器就没有那么简单了。办法和之前的一样,设置一个标志位kai,根据题意进行改动。他在子函数中,需要反复实现转换时,就要用到位移~可以实现了。这样就用不到for循环了,简便易懂。
 怎么对阀值实现加减呢?我原来的想法是:在调用IIC的程序时增加一个变量num,便可以实现。但现实是不可以。那么正确的办法是:需要定义一个变量加法:jia, 还有阀值:fazhi。在S5键盘按下后,主函数进行判断,之后立即归0 ,为的是下一次加的时候,不会多加。最后直接将阀值加1。减法也是如此。
 驱动程序怎么改动?
以时钟芯片为例:在驱动的基础上,最重要的是初始化,也相当于读的操作。当然根据程序的要求,不能合二为一,需要分开写,因为两者还是有点区别的。首先,要注意的是:0x80是写数据,0x81是读数据,之后的操作是一样的,6个字节靠for循环一个一个进去,进行操作,最后就是停止这些操作。还有一点小问题,就是延时的问题,驱动中给的是52的延时,但是51的比52的快了8-12倍,所以,需要将延时,加上7个机器周期。
 读问题时,注意元器件的转化。
 以后再做赛题时,先看有何功能,按照这样的次序写程序: 写十五分钟的模板
改驱动 看任务书写操作并逐步调试。这样的大思路三步走,基本可以写完几乎全部的程序了。

小讯
上一篇 2025-01-23 23:36
下一篇 2025-01-10 23:49

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/24974.html