自动浇灌系统实验报告.docx
《自动浇灌系统实验报告.docx》由会员分享,可在线阅读,更多相关《自动浇灌系统实验报告.docx(31页珍藏版)》请在冰豆网上搜索。
自动浇灌系统实验报告
设计报告
2011—2012学年第一学期
项目:
自动浇灌系统的设计与实现
班级:
学号:
姓名:
授课教师:
制定日期:
年月日
项目设计报告
专业:
班级:
姓名:
一、课题名称
自动浇灌系统的设计与实现
二、设计内容和要求
第一章、总体设计
功能要求:
该课题是以51单片机P89V51RB2FN为主控芯片,利用DALAS一线式温度传感器DS18B20实现对周围温度环境的采集,单片机再根据采集的温度值来控制电磁阀的开关及持续时间等操作,从而实现在不同的温度对周围浇灌对象实施间隔性的灌溉,浇灌持续的时间与不同的温度范围有关,同时相关的状态信息要在点阵汉字液晶屏上实时的显示。
单片机实验仪组成:
USB型单片机仿真实验仪是以单片机为核心的嵌入式系统,由单片机、USB接口电路及实验电路组成。
USB接口电路完成以下功能:
直接从USB总线上获取5V电源为实验仪供电,无需外接电源;将来自PC的USB总线转换为串行口与单片机相连,不再使用PC上传统的RS-232物理串口,这样实验仪与PC的连接变得非常简单,有效地解决了实验仪在学校通用计算机房与PC连接困难的问题,即使在没有串行口的笔记本计算机上也能做单片机实验。
单片机是实验仪的核心,内嵌了在线软件仿真器,可在PC上使用Keil软件对实验仪上的硬件电路及实验程序进行实时仿真调试。
实验电路包括基本的数码管、单脉冲、独立式键盘、行列式键盘、蜂鸣器电路以及I2C总线器件、单总线器件、串行A/D转换、红外线收发、字符/点阵液晶显示电路等,可完成20多个硬件实验。
具体要求:
(1)汉字液晶屏上实时显示的信息有:
1)第一行显示:
低温:
**.*℃,或常温:
**.*℃,高温:
**.*℃。
注:
假设24℃以下为低温,25~35℃为常温,35℃以上为高温。
2)第二行显示:
电磁阀状态:
开,或关。
3)第三行显示:
浇灌时间:
**分**秒,或**时**分。
(2)浇灌时间及浇灌次数间隔要求:
在低温时,电磁阀始终关,浇灌时间为0分0秒;在常温时,浇灌时间为30分钟,浇灌次数间隔为8小时;在高温时,浇灌时间为50分钟,浇灌次数间隔为4小时。
USB接口电路将USB总线转换为串行口直接与单片机的TXD、RXD相连,并获取总线上的+5V电源作为实验仪供电,发光二极管VD10为USB借口配置指示灯,配置成功时VD10点亮。
第二章、硬件设计
硬件电路:
LCD(TG12864B)液晶模块接口:
由左右两块独立的64*64点阵液晶屏拼接而成,每半屏有一个8*64*8bitDDRAM,左右半屏驱动电路及存储器分别由片选信号CS1和CS2选择。
具有8位标准数据总线及相应的控制信号,可与单片机接口直接相连。
CS1:
片选择信号,高电平时选择前64列。
CS2:
片选择信号,高电平时选择后64列。
GND:
电源地。
VCC:
电源正极(+5V)。
VO:
液晶显示器对比度调整端。
D/I:
数据/指令选择:
当D/I为高电平时,DB0~DB7为显示数据;当D/I为低电平时,DB0~DB7为指令数据。
R/W:
读/写选择:
当R/W为高电平时,从液晶模块读数据;当R/W为低电平时,将数据写入液晶模块。
E:
读写使能,高电平有效,下降沿锁定数据。
DB0~DB7:
8位并行数据总线。
RST:
复位信号,低电平有效。
VOUT:
LCD驱动电源(-10V)。
温度传感器DS18B20:
每片DS18B20均有一个唯一的产品序列号,固化在内部的64位激光ROM中,其格式如下:
低8位是产品的工厂代码,中间是每个器件唯一的48位序列号,高8位是针对前面的56位的CRC校验码,只要单片机用匹配命令即可访问总线上指定的DS18B20。
DQ:
数据输入/输出。
在数据总线供电方式可给传感器提供电源。
VDD:
可选的电源电压。
DS18B20有两种供电方式:
数据总线供电方式和外部供电方式。
若采用数据总线供电方式,VDD应接地,这样可省一根线,但测温的时间较长。
GND:
电源地。
DS18B20与单片机的连接:
对温度进行检测,并将温度值在液晶显示屏上显示出来,单片机根据传感器的序列号来对总线上的传感器进行访问。
系统采样温度时,可先对总线上的传感器复位,并跳过ROM,发启动温度转换命令,转换结束后,单片机再发匹配ROM命令,将预先存储的传感器的序列号通过单总线送出,将温度值读入。
上拉电阻RESPACK-8:
使用P0口与液晶模块的数据线D0~D7相连,此时P0口已不再是数据总线/低8位地址总线,而作为输出口使用,因此需加上拉电阻。
单片机80C51:
用单片机的I/O口线来模拟数据总线、读/写控制信号,RD、WR、T1是作为I/O口分别控制液晶模块的RS、R/W、E引脚,产生相应的时序信号。
第三章、软件设计
液晶显示模块:
液晶屏通电后,单片机首先必须对其初始化:
发出复位信号、打开显示、设置起始行、清屏(将DDRAM所有的单元充填为00)。
为了能在屏幕的指定位置显示字符,首先必须设置DDRAM的页号和列号。
液晶模块内部没有字库,因此必须将ASCII的点阵信息放在程序存储器中,用PCtoLCD2002软件提取汉字点阵,显示时根据ASCII值找到该字符的点阵码送到液晶模块DDRAM中。
所有对液晶屏操作的函数放在模块文件LCD12864IO.C中:
先对相关I/O口线定义,用LCD_DispFill(ucharfilldata)函数对液晶屏进行充填,用LCD_DispIni()对液晶模块进行初始化,用LCD_RST=0;语句对复位芯片进行驱动,LCD_WrCmd(CS1,LCD_DISPON);LCD_WrCmd(CS1,LCD_STARTROW);这两句语句打开液晶屏显示并设置显示的起始行为0,用LCD_DispFill(00);语句清屏,用LCD_WrCmd(CS1,LCD_ADDRSTRY+0);LCD_WrCmd(CS1,LCD_ADDRSTRX+0);这两句语句对字符行、列地址进行设置;用LCD_DispChar(ucharcy,ucharcx,chardispdata)函数在液晶屏的cy(0-7)行、cx(0-15)列显示字符dispdata;用LCD_DispStr(ucharcy,ucharcx,char*disp_str)函数在液晶屏的cy(0-7)行、cx(0-15)列显示字符disp_str;用LCD_DispHZ(ucharcy,ucharcx,uchardispdata)函数在液晶屏的cy(0-3)行、cx(0-7)列显示汉字字符dispdata;用LCD_DispHZStr(ucharcy,ucharcx,uchar*disp_str)函数在液晶屏的cy(0-3)行、cx(0-7)列显示汉字字符串disp_str。
测温模块:
先检测是否有DS18B20,向总线写入一个字节,从总线上读取一个字节,复位DS18B20,发READROM命令,读取温度低字节、高字节,保存16位温度值。
用bitreset(void)函数检测是否有DS18B20;用voidwrbyte(uchard)函数向总线写入一个字节;ucharrdbyte(void)从总线上读取一个字节;err=reset();语句复位DS18B20;再根据DS18B20,发READROM命令读取和保存温度值。
当温度传感器的温度值低于24℃时,汉字显示低温,当温度达到25~35℃时,汉字显示变为常温,当温度到35℃以上时,汉字显示为高温。
定时模块:
用定时方式寄存器TMOD控制定时器/计数器的工作方式,TMOD寄存器的高4位用于T1的设定,低4位用于T0的设定。
定时器/计数器T1
定时器/计数器T0
D7
D6
D5
D4
D3
D2
D1
D0
GATE
C/T
M1
M0
GATE
C/T
M1
M0
M1、M0选择定时器/计数器的工作方式,T0有4种工作方式(方式0~方式3),T1有3种工作方式(方式0~方式2),由M1、M0设定:
M1M0=00,方式0;M1M0=01,方式1;M1M0=10,方式2;M1M0=11,方式3。
TR0/TR1定时器/计数器T0和T1启停控制位,为0时,定时器/计数器停止工作;为1时,启动定时器/计数器工作。
在使用定时器/计数器时,首先应根据要求对工作方式进行初始化,然后计算出初始值。
初始化的步骤是:
(1)向TMOD寄存器写入工作方式控制字,
(2)将计数器的初值写入TH0、TL0/TH1、TH1,(3)启动定时器/计数器:
将TR0/TR1置1,(4)采用中断方式,应将ET0/ET1、EA置1。
当读取温度值后,根据温度值用定时器控制电磁阀开关状态和浇灌时间。
当温度为低温低于24℃时,电磁阀始终为关,不浇灌;当温度达到常温25~35℃时,电磁阀开,开始浇灌,浇灌时间为5S,间隔10S后再次浇灌;当温度到35℃以上时,电磁阀开,开始浇灌,浇灌时间为10S,间隔5S后再次进行浇灌。
用voidtime0(void)interrupt1函数设定定时器/计数器T0中断;voidtime1(void)interrupt3设定定时器/计数器T1中断。
总流程图:
第四章、程序测试
调试方法:
该项目的调试可在Proteus环境下进行,温度传感器DS18B20的DQ端连接到单片机8051的P1.0,液晶屏的DI端连接到单片机的P3.4,RW端连接到单片机的P3.5,CS选择屏端连接到单片机的P3.3,E端连接到单片机的P3.6,DB0~DB7显示数据端连接到单片机的P0.0~P0.7;在Keil下新建项目,输入源程序并编译,与Proteus连接后,进入调试方式,全速运行,看仿真的显示是否正确。
调试步骤:
(1)首先要确保液晶屏的正常显示,如果程序运行时液晶屏没有显示,应仔细检查液晶屏控制线的连接是否与程序中的定义一致。
(2)检查液晶屏显示的汉字的位置是否与项目要求的一致,如果不一致,应检查在显示汉字模块时的汉字显示的位置行、列是否计算正确。
(3)检查液晶屏显示的温度是否随着温度传感器DS18B20的温度变化,如果不变,应检查接口是否连接一致。
(4)检查电磁阀开关状态和浇灌时间是否根据温度的变化而变化,如果不变化,检查定时器是否正常工作,或是定时器的中断方式是否正确。
调试过程中出现的问题和解决方法:
问题1:
液晶屏没有显示。
解决方法:
液晶屏控制线的连接与程序中的定义不一致,经检查程序和原理图发现,在Proteus原理图中,P0是作为数据口的,而在LCD12864IO.C程序中写的是sfrLCD=0xa0,这样的话定义的是P2口,当改成LCD=0x80后,再调试发现屏幕上的信息显示正确。
问题2:
调试的时候将手放在传感器上,液晶屏上的温度值与实际温度相差大。
错误原因及解决方法:
应检查发现,,当把程序中的定义改过来以后,再调试发现温度与当前温度基本一致了。
解决方法:
液晶屏控制线的连接与程序中的定义不一致,程序中对DQ脚定义的是P1脚,而实验板上连的是P3脚,把sbitLCD_RST=P1^7;sbitDI=P1^4;sbitRW=P1^5;sbitCS=P1^3;sbitEN=P1^6;中的连接口改成P3口。
问题3:
汉字显示低温、常温、高温不随着温度传感器DS18B20的温度的变化而改变。
解决方法:
没有使用定时器模块控制,添加定时器模块实现该功能。
问题4:
仿真时液晶屏上显示的浇灌时间与程序中定义的浇灌时间不一样长。
解决方法:
程序中定义的常温、高温的浇灌时间和用定时器控制时的定义的名称混淆。
原定义的语句是#definewater_time5//常温的浇灌时间,#definewater_time110//高温的浇灌时间,而判断温度时用定时器控制的语句是if(temp>0x0230),if(counter0x0230),if(counter第五章、结束语
本项目是自动浇灌系统的设计。
以单片机80C51为核心,介绍了以它为控制系统的液晶屏的显示、温度的的检测和定时器的使用等设计。
报告中详细介绍了液晶屏显示屏、温度传感器DS18B20、定时器的硬件设计思路、硬件电路各个部分的功能及原理、相应软件的程序设计,以及使用说明等。
单片机控制系统程序采用C51语言进行编辑,通过编程控制液晶屏汉字显示的位置、电磁阀开关状态、浇灌时间、浇灌间隔时间。
所显示字符的点阵数据从标准字库PCtoLCD2002软件中提取。
在开始知道自己选择的该课程时有点紧张、忐忑,因为自己从未学过这门课程,而且第一节课老师告知我们大多数学生已经学过此课程,所以我们直接开始做项目实践。
在得知第一个项目是自动浇灌系统的时候,挺替自己担心的。
根据老师发给我们的项目的要求一步一步做,我很容易就做好了基础的显示:
汉字的显示,在用定时模块控制电磁阀开关状态、浇灌时间时遇到了问题,经过自己的思考和同学的帮助下,我基本实现了自动浇灌系统的功能。
通过这次的项目实践,我发现项目并不是很难,能不能做成功一个项目,是要看个人的态度和了解的知识。
如果自己不愿意花时间去分析,不愿意动脑筋去思考,不愿意动手去写代码,不愿意动手画Proteus仿真图,不愿意一步一步调试的话,我相信这样一个项目肯定做不成功。
我能做出这个项目,除了个人的勤奋努力之外,还要感谢同学的帮助。
附录
Main()主模块:
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
#definewater_time5//常温的浇灌时间
#definewater_time110//高温的浇灌时间
externvoidLCD_DispIni(void);
externvoidLCD_DispFill(ucharfilldata);
externvoidLCD_DispChar(ucharcy,ucharcx,chardispdata);
externvoidLCD_DispStr(ucharcy,ucharcx,char*disp_str);
externvoidLCD_DispHZ(ucharcy,ucharcx,uchardispdata);
externvoidLCD_DispHZStr(ucharcy,ucharcx,uchar*disp_str);
externvoidlate();
externintreadt(void);
externvoidconvert(void);
uchardp[16]={0,0,1,1,2,3,3,4,5,5,6,6,7,8,8,9};//小数部分转换
ucharcount,count1;
uchars;
ucharm;
ucharh;
uchars1;
ucharm1;
ucharh1;
uchartime_s,time_m;
ucharcounter;//定义的一个判断浇灌时间的中间变量
uchardbuf[]="00";//小数部分转换
uchardbuf1[]="00";
voidtime0(void)interrupt1//interruptN表示函数声明为中断服务函数,1:
定时器/计数器T0中断
{TH0=-50000/256;//定时时间为50MS//取高8位
TL0=-50000%256;//取低8位
count++;//每中断一次,计数器加1
if(count==20)//每秒执行一次
{count=0;
s++;
if(s==60)
{m++;
s=0;
if(m==60)
{m=0;
h++;
}
}
}
}
voidtime1(void)interrupt3//3:
定时器/计数器T1中断
{TH1=-50000/256;
TL1=-50000%256;
count1++;
if(count1==20)
{count1=0;
s1++;
if(s1==60)
{m1++;
s1=0;
if(m1==60)
{m1=0;
h1++;
}
}
}
}
main()
{inttemp,i;//用来存放传感器的温度值
ucharstr[7]={0,0,0,0,0,0};//用于将温度值转换为字符串
ucharst[2]={0,0};
ucharbuf[]={0,1,2,3,4,5,0xff};
uchardu[]={27,0xff};
ucharchang[]={9,10,8,0xff};
uchardi[]={11,12,8,0xff};
uchargao[]={6,7,8,0xff};
ucharjgsj[]={18,19,20,21,8,0xff};
uchardcf[]={13,14,15,16,17,8,0xff};
ucharon[]={25,0xff};
ucharoff[]={26,0xff};
ucharfen[]={23,0xff};
ucharmiao[]={24,0xff};
bitzf;//正负标记温度在0度以下为1,否则为0
LCD_DispIni();
str[1]=':
';//在屏幕指定位置显示
LCD_DispHZStr(0,1,buf);
LCD_DispHZStr(1,6,du);
LCD_DispHZStr(2,0,dcf);
LCD_DispHZStr(3,0,jgsj);
LCD_DispHZStr(3,5,fen);
LCD_DispHZStr(3,7,miao);
count=0;
s=0;
TMOD=0x11;//定时器0和1都设置成方式1
TH0=-50000/256;
TL0=-50000%256;
TH1=-50000/256;
TL1=-50000%256;
ET0=1;//允许T0中断
TR0=1;//启动T0中断
ET1=1;
TR1=1;
EA=1;//开CPU中断
while
(1)
{EA=0;
convert();
for(i=0;i<10000;i++);
EA=1;
temp=readt();
zf=0;
if(temp>0x01E0)//判断温度是否大于30度
{LCD_DispHZStr(1,0,gao);
counter=m*60+s;
if(counter<=water_time1)//高温浇灌时间
{TR0=1;//打开定时器0
TR1=0;//关闭定时器1
LCD_DispHZStr(2,6,on);
s1=0;
m1=0;
h=0;
time_s=s;
time_m=m;
}
else
{TR0=0;//关闭定时器0
TR1=1;//打开定时器1
LCD_DispHZStr(2,6,off);
if(s1>5)//高温浇灌时间间隔
{s=0;
m=0;
h=0;
}
time_s=0;
time_m=0;
}
}
elseif(temp<0x01C0)//判断温度是否低于29度
{TR0=0;
TR1=0;
s=0;
m=0;
h=0;
s1=0;
m1=0;
h=0;
LCD_DispHZStr(1,0,di);
LCD_DispHZStr(2,6,off);
time_s=0;
time_m=0;
}
else
{LCD_DispHZStr(1,0,chang);
time_s=0;
time_m=0;
counter=m*60+s;
if(counter<=water_time)//常温浇灌时间
{TR0=1;
TR1=0;
s1=0;
m1=0;
h=0;
time_s=s;
time_m=m;
LCD_DispHZStr(2,6,on);
}
else
{TR0=0;
LCD_DispHZStr(2,6,off);
TR1=1;
if(s>10)//常温浇灌时间间隔
{s=0;
m=0;
h=0;
}
time_s=0;
time_m=0;
}
}
if(temp<0)//如果温度小于0
{
zf=1;//正负标志置1
temp=-temp;//求出温度的绝对值
}
str[4]=dp[temp&0x0f]+0x30;//求出一位小数的ASCII码
temp=temp>>4;//舍去小数部分
str[0]=temp/100+0x30;//求出百位的ASCII码
temp=temp%100;
str[1]=temp/10+0x30;//求出十位的ASCII码
str[2]=temp%10+0x30;//求出个位的ASCII码
str[3]='.';
dbuf[0]=(time_s%100)/10+0x30;
dbuf[1]=time_s%10+0x30;
dbuf1[0]=(time_m%100)/10+0x30;
dbuf1[1]=time_m%10+0x30;
if(zf==1)//如果是负数
{
if(str[1]=='0')//如果十位为0
{
str[0]='';//显示格式为'-x.x'
str[1]='-';
}
else//如果十位不为0
str[0]='-';//显示格式为'-xx.x'
}
else//如果是正数
{
if(str[0]=='0')//如果百位、十位都是0
{
if(str[1]=='0