功能简述
要求“模拟智能灌溉系统” 能够实现土壤湿度测量、 土壤湿度和时间显示、 湿度阈值设定及存储等基本功能。 通过电位器 Rb2 输出电压信号,模拟湿度传感器输出信号,再通过AD 采集完成湿度测量功能;通过 DS1302 芯片提供时间信息;通过按键完成灌溉系统控制和湿度阈值调整功能,通过 LED 完成系统工作状态指示功能。系统硬件电路主要由单片机控制电路、 显示单元、 ADC 采集单元、 RTC 单元、 EEPROM 存储单元、 继电器控制电路及报警输出电路组成,系统框图如图 1 所示:
MCS-51 单片机资料、 I2C 总线驱动程序和 DS1302 时钟芯片驱动程序、 CT107D 单片机综合训练平台电路原理图以及本题所涉及到的芯片数据手册, 可参考计算机上的电子文档。程序流程图及相关工程文件请以考生准考证号命名,并保存在计算机上的考生文件夹中,文件夹位于 Windows 桌面上。
设计任务及要求
1. 系统工作及初始化状态说明
1.1 自动工作状态,根据湿度数据自动控制打开或关闭灌溉设备, 以 L1 点亮指示;
1.2 手动工作状态,通过按键控制打开或关闭灌溉设备, 以 L2 点亮指示;
1.3 系统上电后处于自动工作状态,系统初始湿度阈值为 50%,此时若湿度低于
50%,灌溉设备自动打开, 达到 50%后,灌溉设备自动关闭;
1.4 灌溉设备打开或关闭通过继电器工作状态模拟。
2. 数码管单元
时间及湿度数据显示格式如图 2 所示:
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 中, 并退出湿度阈值设定界面。
5. 实时时钟
“模拟智能灌溉系统”通过读取 DS1302 时钟芯片相关寄存器获得时间, DS1302
芯片时、 分、秒寄存器在程序中设定为系统进行初始化设定,时间为 08 时 30 分。
6. 湿度检测单元
以电位器 Rb2 输出电压信号模拟湿度传感器输出信号, 且假定电压信号与湿度成正比例关系 H 湿度 = KVRb2(K 为常数), Rb2 电压输出为 5V 时对应湿度为 99%。
7. EEPROM 存储单元
系统通过 EEPROM 存储湿度阈值, 自动工作状态下,可通过按键 S6、 S5、 S4 设置和保存阈值信息。
8. 电路设计部分
使用 PTC 热敏电阻、场效应管、继电器及简单阻容元件设计“智能灌溉系统” 中置于电机内部的过热保护电路, 当电机内部温度超过 70℃,断开电机电源,设计电路原理图并简述设计思路与电路工作原理。
PTC 热敏电阻参数说明:
当温度小于 68℃时, 热敏电阻阻值小于 100 欧姆;温度超过 68℃后,电阻值随温度升高呈阶跃性增高, 温度到达 70℃后, 热敏电阻阻值接近 10kΩ。
主函数
#include<stc15f2k60s2.h>
#include"ds1302.h"
#include "iic.h"
typedef unsigned char uchar;
typedef unsigned int uint;
uchar code SMG_duan[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //0~9
uchar code SMG_wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
sbit beep=P0^6;
sbit Relay=P0^4;
void Timer0Init();
void datpross();
void delayms(uint ms);
uchar SMG_count;
uchar Time_display[8];
uchar set_display[8];
uchar shidu; //湿度
uchar shidu_limit=50; //湿度阈值
uchar mode; //mode=0 自动,mode=1 手动 S7控制
bit realy_flag; //继电器标志位
bit beep_flag; //蜂鸣器标志位
bit beep_buzzer; //手动模式下,S6控制蜂鸣器
bit set_flag; //阈值设置标志位
uchar Key_init()
{
uchar key=0; //不清零会让按键按下后,一直执行
if(P33==0)
{
delayms(10);
if(P33==0)
key=4;
while(!P33);
}
if(P32==0)
{
delayms(10);
if(P32==0)
key=5;
while(!P32);
}
if(P31==0)
{
delayms(10);
if(P31==0)
key=6;
while(!P31);
}
if(P30==0)
{
delayms(10);
if(P30==0)
key=7;
while(!P30);
}
return key;
}
void main()
{
uchar key_val;
P2=0XA0;P0=0X00;
P2=0X80;P0=0XFF;
shidu_limit=Read_2402(0x01);
Timer0Init();
Ds1302_init();
Write_adc(0x03);
set_display[0]=0x40;
set_display[1]=0x40;
set_display[2]=0x00;
set_display[3]=0x00;
set_display[4]=0x00;
set_display[5]=0x00;
while(1)
{
Ds1302_read();
key_val=Key_init();
Time_display[0]=SMG_duan[TIME[2]/16];
Time_display[1]=SMG_duan[TIME[2]%16];
Time_display[2]=0x40;
Time_display[3]=SMG_duan[TIME[1]/16];
Time_display[4]=SMG_duan[TIME[1]%16];
Time_display[5]=0x00;
ET0=0;
shidu=(Read_adc(0x03)/2.57f);
ET0=1;
Time_display[6]=SMG_duan[shidu/10];
Time_display[7]=SMG_duan[shidu%10];
set_display[6]=SMG_duan[shidu_limit/10];
set_display[7]=SMG_duan[shidu_limit%10];
if(mode==1) //手动
{
P2=0X80;P0=0XFD;
if(shidu<shidu_limit)
{
if(beep_buzzer==0)
beep_flag=1;
else
beep_flag=0;
}
else
{
beep_flag=0;
}
}
else //自动
{
P2=0X80;P0=0XFE;
if(shidu<shidu_limit)
{
realy_flag=1;
}
else
{
realy_flag=0;
}
}
switch(key_val)
{
case 4:
if(mode)
{
realy_flag=0;
beep_flag=0;
}
else
{
if(set_flag)
shidu_limit--;
}
break;
case 5:
if(mode)
{
realy_flag=1;
beep_flag=0;
}
else
{
if(set_flag)
shidu_limit++;
}
break;
case 6:
if(mode)
{
beep_buzzer=~beep_buzzer;
}
else
{
set_flag=~set_flag;
if(set_flag==0)
{
Write_2402(0x01,shidu_limit);
}
}
break;
case 7:
mode++;
if(mode==2)
mode=0;
break;
}
if(realy_flag==0&beep_flag==0)
{ P2=0XA0;beep=0;Relay=0; }
if(realy_flag==0&beep_flag==1)
{ P2=0XA0;beep=1;Relay=0; }
if(realy_flag==1&beep_flag==0)
{ P2=0XA0;beep=0;Relay=1; }
if(realy_flag==1&beep_flag==1)
{ P2=0XA0;beep=1;Relay=1; }
}
}
void Timer0Init() //1毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初值
TH0 = 0xD4; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA=1;
ET0=1;
}
void Timer0() interrupt 1
{
uchar i;
SMG_count++;
if(SMG_count==3)
{
SMG_count=0;
P2=0Xc0;P0=0X00;P2=0X00;
P2=0XC0;P0=SMG_wei[i];
if(set_flag)
{
P2=0XE0;P0=~set_display[i];
}
else
{
P2=0XE0;P0=~Time_display[i];
}
i++;
if(i==8)
i=0;
}
}
void delayms(uint ms)
{
int i,j;
for(i=0;i<ms;i++)
for(j=845;j>0;j--);
}
DS1302时钟模块
#include "ds1302.h"
unsigned char Write_add[]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
unsigned char READ_add[]={0x81,0x83,0x85,0x87,0x89,0x8B,0x8D};
unsigned char TIME[]={0X50,0X30,0X08,0X14,0X02,0X20,0X19};
void Write_Ds1302_Byte(unsigned char dat)
{
unsigned char i;
SCK = 0;
_nop_();
for (i=0;i<8;i++)
{
if (dat & 0x01) // 等价于if((addr & 0x01) ==1)
{
SDA_SET; //#define SDA_SET SDA=1 /*电平置高*/
}
else
{
SDA_CLR; //#define SDA_CLR SDA=0 /*电平置低*/
}
SCK_SET;
_nop_();
SCK_CLR;
_nop_();
dat = dat >> 1;
}
}
/********************************************************************/
/*单字节读出一字节数据*/
unsigned char Read_Ds1302_Byte(void)
{
unsigned char i, dat=0;
for (i=0;i<8;i++)
{
dat = dat >> 1;
if (SDA_R) //等价于if(SDA_R==1) #define SDA_R SDA /*电平读取*/
{
dat |= 0x80;
}
else
{
dat &= 0x7F;
}
SCK_SET;
_nop_();
SCK_CLR;
_nop_();
}
return dat;
}
/********************************************************************/
/*向DS1302 单字节写入一字节数据*/
void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat)
{
RST_CLR;
_nop_();
SCK_CLR;
_nop_();
RST_SET;
_nop_();
addr = addr & 0xFE;
Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是写操作,写之前将最低位置零*/
Write_Ds1302_Byte(dat); /*写入数据:dat*/
RST_CLR;
_nop_();
}
/********************************************************************/
/*从DS1302单字节读出一字节数据*/
unsigned char Ds1302_Single_Byte_Read(unsigned char addr)
{
unsigned char temp;
RST_CLR;
_nop_();
SCK_CLR;
_nop_();
RST_SET;
_nop_();
addr = addr | 0x01;
Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是读操作,写之前将最低位置高*/
temp=Read_Ds1302_Byte(); /*从DS1302中读出一个字节的数据*/
RST_CLR; /*停止DS1302总线*/
_nop_();
SD=0;
_nop_();
SD=1;
_nop_();
return temp;
}
void Ds1302_init()
{
unsigned char i;
Ds1302_Single_Byte_Write(0x8e,0x00);
for(i=0;i<7;i++)
{
Ds1302_Single_Byte_Write(Write_add[i],TIME[i]);
}
Ds1302_Single_Byte_Write(0x8e,0x81);
}
void Ds1302_read()
{
unsigned char i;
for(i=0;i<7;i++)
{
TIME[i]=Ds1302_Single_Byte_Read(READ_add[i]);
}
}
EEPROM模块
/*
程序说明: IIC总线驱动程序
软件环境: Keil uVision 4.10
硬件环境: CT107单片机综合实训平台(12MHz)
日 期: 2011-8-9
*/
#include "iic.h"
void IIC_delay(unsigned char i)
{
do
{
_nop_();
}while(i--);
}
//总线启动条件
void IIC_Start(void)
{
SDA = 1;
SCL = 1;
IIC_delay(5);
SDA = 0;
IIC_delay(5);
SCL = 0;
}
//总线停止条件
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
IIC_delay(5);
SDA = 1;
}
//等待应答
bit IIC_WaitAck(void)
{
SDA = 1;
IIC_delay(5);
SCL = 1;
IIC_delay(5);
if(SDA)
{
SCL = 0;
IIC_Stop();
return 0;
}
else
{
SCL = 0;
return 1;
}
}
//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
unsigned char i;
for(i=0;i<8;i++)
{
if(byt&0x80)
{
SDA = 1;
}
else
{
SDA = 0;
}
IIC_delay(5);
SCL = 1;
byt <<= 1;
IIC_delay(5);
SCL = 0;
}
}
//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++)
{
SCL = 1;
IIC_delay(5);
da <<= 1;
if(SDA)
da |= 0x01;
SCL = 0;
IIC_delay(5);
}
return da;
}
void Write_adc(unsigned char dat)
{
IIC_Start();
IIC_SendByte(0x90); //从设备地址
IIC_WaitAck();
IIC_SendByte(dat); //控制字
IIC_WaitAck();
IIC_Stop();
}
unsigned char Read_adc(unsigned char dat)
{
unsigned char temp;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
temp=IIC_RecByte();
IIC_Stop();
return temp;
}
void Write_2402(unsigned char addr,unsigned char dat)
{
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(addr);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
unsigned char Read_2402(unsigned char dat)
{
unsigned char temp;
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0xa1);
IIC_WaitAck(); //一定要跟应答
temp=IIC_RecByte();
//IIC_WaitAck();
IIC_Stop();
return temp;
}
以上就是代码的全部内容,欢迎交流,共同学习~
附上工程包下载——蓝桥杯第五届省赛模拟试题