温度检测系统设计报告.(DOC)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
计算机硬件(嵌入式)综合实践
设计报告
温度检测系统设计与制作
一.系统概述
1. 设计内容
本设计主要从硬件和软件部分介绍了单片机温度控制系统的设计思路,简单说明如何实现对温度的控制,并对硬件原理图和程序框图作了简洁的描述。
还介绍了在单片机控制系统的软硬件设计中的一些主要技术关键环节,该系统主要以AT89S52单片机为核心, 同时利用DS18B20温度传感器采集温度,采用4位LED 显示管实施信息显示。
AT89S52单片机设计的温度检测电路是本次设计的主要内容,是整个单片机温度控制系统设计中不可缺少的一部分,该系统对温度进行实时采集与检测。
本设计介绍的单片机自动控制系统的主要内容包括:系统概述、元器件选择、系统理论分析、硬件设计、部分软件设计及主要技术性能参数。
2. 元器件选择
单片机AT89S52:1个
22uF电容:2个
4.7K电阻:1个
万能板:1个
杜邦线:若干
单排排针:若干
DS18B20温度传感器:2个
4位LED显示管:1个
二.软件功能设计及程序代码
1.总体系统设计思想框图如下:
单片机应用
软件调试
软件编程
系统测试和调试
系统集成
硬件调试
选择单片机芯片
定义系统性能指标
硬件设计
2.主程序流程图
3.DS18B20数据采集流程图
4.程序代码
①、温度记录仪
#include<reg52.h>
#include<intrins.h>
#include<SYSTEM.h>
#include<LCD1602.h>
#include<18B20.h>
#include<EEPROM.h>
bit rec_flag=0;//记录温度标志
uchar autobac_tim=0;//自动跳转延时
uchar code logos[]="****NT MUSIC****"; uchar incmin=0;//计分钟数
bit overflag=0;//数据溢出标志位
uchar mode=1;//系统运行模式
uchar tempmode;//模式缓存
void init()
{
lcd_init();
eeprom_init();
/***********开机效果****************/ display(l1," Starting NT",1);
longdelay(10);
display(l2," Ver 3.0.1",1);
longdelay(20);
write_cmd(0x01);//清屏
/*************************************/ sys_init();
}
void comms() //模式公共进程
{
time2times(); //时间格式转换
avtemp=gettemp();//获取温度
avtemp2avtemps();//温度格式转换
date_counter();//获取当前日期
date2dates();//日期格式转换
display(l2+1,times,0);
display(l2+11,avtemps,0);
}
void progs(uint i,uint k)//进度条
{
uint j;
write_cmd(0xc0);
for(j=0;j<(i*16/k);j++)
{
write_lcddata(0xff);
}
}
void normal_run() //无记录运行模式
{
comms();
if(time[2]%10<5)
{
display(l1,logos,1);
}
else
{display(l1,"***",0);display(l1+13,"***",0);display(l1+3,dates,0);}
incmin=0;
}
void recding_run() //记录模式运行模式
{
uint WDTPT;//临时写地址指针变量存放
comms();
recfrq2recfrqs();
if(time[2]%10<5)
{
if(mss>50) display(l1," ",0);
else
display(l1,"R",0);
display(l1+1,"-NUM",0);
display(l1+5,datcounts,0);display(l1+9,"**EV",0);display(l1+13,recfrqs,0);
}
else
{display(l1,"***",0);display(l1+13,"***",0);display(l1+3,dates,0);} /***********定时记录*************/
if(incmin>=recfrq)//触发记录功能
{
incmin=0;//1清除进入记录标志
if(WDTP>10240) //20个扇区
overflag=1;
if(overflag==0)//如果数据尚未溢出
{
if(date_recf==1)
//记录年-月-日(格式:'z'+年+月+日)为十制数值
{
date_recf=0;//清除记录日期标志
write_isp(WDTP,'z');//日期起始标志
write_isp(WDTP,date[0]);
write_isp(WDTP,date[1]);
write_isp(WDTP,date[2]);//记录年、月、日
}
/***********记录时间************/
write_isp(WDTP,time[0]);
write_isp(WDTP,time[1]);//记录时分
/***********记录温度************/
write_isp(WDTP,avtemp/100);
write_isp(WDTP,avtemp%100);
/**********记录加一*********/
datcount++;
/**********写回数据指针****************/
WDTPT=WDTP;
if(FDTP==512)
{
del_isp(0);//清空记录表
FDTP=0;
}
write_isp(FDTP,WDTPT/256);
write_isp(WDTP,WDTPT%256);
write_isp(WDTP,datcount/256);
write_isp(WDTP,datcount%256);
FDTP=WDTP;
WDTP=WDTPT;
//交互完成
}
if(overflag==1)//如果数据溢出
{
display(l1,"Error!",1);
display(l2,"Data Overflow!",1);
autobac_tim=0;
while(autobac_tim!=3);
display(l2," ",1);
}
}
}
void data_run() //查看记录模式
{
uchar i=0;
bit bacf=0;
uint cou_t=0;//计数缓存变量
uchar temp=0;//临时数据缓存
uint cd=0;//进度条统计数据
autobac_tim=0;
while(bacf==0)
{
if(autobac_tim>10)
bacf=1;
display(l1,"Ready for Export",1);
display(l2,"D-Date T-Temp L!",1);
if(RI==1)
{
autobac_tim=0;
RI=0;
ser_rec=SBUF;
switch(ser_rec)
{
case 'L': //格式化
display(l1,"Format?",1);
display(l2," Y-Yes N-No",1);
while(1)
{
if(RI==1) {RI=0;ser_rec=SBUF;autobac_tim=0;}
if(ser_rec=='Y')//确定格式化
{
display(l1,"Formatting...",1);
display(l2," ",1);
eeprom_format();
display(l1,"Format Successed",1);
longdelay(3);
break;
}
if(ser_rec=='N') break;
if(autobac_tim>10)
break;
}
autobac_tim=0;
break;
case 'D'://输出日期时间
display(l1,"Exporting Date..",1);
display(l2," ",1);
RDTP=512;//将读指针放到首位
cou_t=datcount;
cd=0;
while(cou_t!=0)
{
if(RI==1) RI=0;
if(SBUF=='B')
{
display(l1,"Export stopped",1);
cd=0;
longdelay(3);
break;
}
temp=read_isp(RDTP);// 预读判断
RDTP--;
if(temp=='z')
{
RDTP++;
prf_date();//输出年月日
}
prf_time(); //输出时间
RDTP=RDTP+2;
cou_t--;
cd++;
progs(cd,datcount);
}
if(datcount==0)
{display(l1,"No Data!",1);
longdelay(3);}
autobac_tim=0;
break;
case 'T'://温度输出
display(l1,"Exporting Temp..",1);
display(l2," ",1);
RDTP=516;//将读指针放到首位
cd=0;
cou_t=datcount;
while(cou_t!=0)
{
if(RI==1) RI=0;
if(SBUF=='B')
{
display(l1,"Export stopped",1);
cd=0;
longdelay(3);
break;
}
temp=read_isp(RDTP);// 预读判断
RDTP--;
if(temp=='z')
{
RDTP=RDTP+6;
}
else
{
RDTP=RDTP+2;
}
prf_temp();
cou_t--;
cd++;
progs(cd,datcount);
}
if(datcount==0)
{display(l1,"No Data!",1);
longdelay(3);}
autobac_tim=0;
break;
case 'B':bacf=1;break;
}
ser_rec=0;
}
}
mode=tempmode; display(l2," ",1);
}
void adj_settings() //设置模式
{
uchar i=0;//Counter
bit endadj=0;//调整完毕标志
uchar ser_temp=0;//接收缓存
write_cmd(0x01);//清屏
times[5]=':';//恢复数点
display(l1,"Set time- ",1);
display(l1+11,"hour",0);
display(l2+11,"[ ]",0);
display(l2+1,times,0);
display(l2+12,recfrqs,0);
write_cmd(0xC1+i);
write_cmd(0x0f);//显示闪烁光标
autobac_tim=0;//初始化自动返回时间常数
while(!endadj)
{
if(RI==1) //接收到数据
{
RI=0;
autobac_tim=0;//自动返回清零
ser_temp=SBUF;
if((ser_temp>47)&&(ser_temp<58))//进行数值判断
{
if(i<8)
times[i]=ser_temp;
if(i>8&&i<14)
recfrqs[i-11]=ser_temp;
if(i>=14)
dates[i-13]=ser_temp;
i++;
}
if(ser_temp=='F') i++;//往前一步
if(ser_temp=='B') endadj=1;//退出调整
switch(i) //显示处理
{
case 2:i++;display(l1+11,"min ",0);break;
case 5:i++;display(l1+11,"sec ",0);break;
case 8:i=i+3;display(l1+11,"frq ",0);break;
case 14:i++;display(l1+4,"date year ",0);
display(l2," ",1);
break;
case 17:i++;display(l1+11,"moun",0);break;
case 20:i++;display(l1+11,"day ",0);break;
case 23:endadj=1;break;
}
if(i<14)
{
display(l2+1,times,0);display(l2+12,recfrqs,0);
write_cmd(0xC1+i);
}
else
{
display(l2+3,dates,0);
write_cmd(0xC1+i-11);
}
}
if(endadj==1)//写回参数
{
time[0]=(times[0]-48)*10+times[1]-48;
time[1]=(times[3]-48)*10+times[4]-48;
time[2]=(times[6]-48)*10+times[7]-48;
recfrq=(recfrqs[0]-48)*100+(recfrqs[1]-48)*10+recfrqs[2]-48;
date[0]=(dates[2]-48)*10+dates[3]-48;
date[1]=(dates[5]-48)*10+dates[6]-48;
date[2]=(dates[8]-48)*10+dates[9]-48;
}
if(autobac_tim>10)
endadj=1;
}
display(l2," ",1);
write_cmd(0x0c);//正常显示
}
void main()
{
init();
while(1)
{
switch(mode)
{
case 1:normal_run();break;
case 2:recding_run();break;
case 3:data_run();break;
}
if(RI==1)
{
RI=0;
ser_rec=SBUF;
switch(ser_rec)
case 'A':adj_settings();break;
case 'R':mode=2;break;
case 'N':mode=1;break;
case 'H':tempmode=mode;mode=3;break;
case 'D':ser_sents(dates);break;
case 'T':times[5]=':';ser_sents(times);break;
case 'W':ser_sents(avtemps);break;
case 'C':ser_sents(datcounts);break;
case 'F':ser_sents(recfrqs);break;
}
ser_rec=0;
}
}
}
void miao() interrupt 1 //秒产生中断
{
TH0=(65535-9200)/256;
TL0=(65535-9200)%256;
mss++;
if(mss==100)
{mss=0;time[2]++;autobac_tim++;}
if(autobac_tim==255)
autobac_tim=244;//保持溢出
if(time[2]>=60)
{
time[2]=0;time[1]++;incmin++;
}
if(time[1]>=60)
{
time[1]=0;time[0]++;
}
if(time[0]>=24)
{
time[0]=0;dayincf=1;//天自增标志置位
date_recf=1;//日期需要记录
}
/*将返回时间[时分秒*/
}
②、system.h
/******系统I/O******/
/*****LCD I/O*******/
sbit RS=P1^2;
sbit LCDEN=P1^1;
/*****DS18B20*******/
sbit DS=P1^0;
#define uchar unsigned char
#define uint unsigned int
uchar code num[]={'0','1','2','3','4','5','6','7','8','9'};
/********时间相关变量************/
uchar time[]={23,28,00};//时分秒(10进制数)uchar times[]="15:37:00";//时分秒(ASCII码)uchar mss=0;
uchar date[]={11,11,11};//年月日(10进制数)uchar dates[]="2011-10-29";//年月日(ASCII码)bit dayincf=0;
bit date_recf=0;//日期记录标志
/***********记录频率变量*******************/ uchar recfrq=2; //记录频率(10进制数)
uchar recfrqs[]="001"; //记录频率(ASCII码)
uint datcount=0;//记录总数
uchar datcounts[]="0000";
/**************串口接收变量****************/ uchar ser_rec;
/*************温度相关变量****************/ uint avtemp=0;
uchar avtemps[]="00.0";
void delay(uchar z)
{
uchar x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void longdelay(uchar z)
{
for(z;z>0;z--)
delay(255);
}
void ser_sent(uchar sendata) //串口发送单字节
{
SBUF=sendata;
while(TI!=1);
TI=0;
delay(1);
}
void ser_sents(uchar strings[]) //串口发送字符串
{
uchar i=0;
while(strings[i]!='\0')
{
ser_sent(strings[i]);
delay(20);
i++;
}
ser_sent('\n');
}
void date_counter() //日期转变
{
uchar n;//月天数暂存
uint year=2000+date[0];//将年转换为标准年
if(dayincf==1)
{
dayincf=0;
switch(date[1])//根据月份制定月天数
{
case 1:n=31;break; case 2:if(year%4==0||year%400==0){n=29;} else {n=28;}break;
case 3:n=31;break; case 4:n=30;break;
case 5:n=31;break; case 6:n=30;break;
case 7:n=31;break; case 8:n=31;break;
case 9:n=30;break; case 10:n=31;break;
case 11:n=30;break; case 12:n=31;break;
}
date[2]++;
if(date[2]>n)
{
date[2]=1;
date[1]++;
}
if(date[1]>12)
{
date[1]=1;date[0]++;
}
}
}
void sys_init() //系统初始化
{
EA=1;TMOD=0x21;TR1=1;REN=1;SM0=0;SM1=1;
TH1=0xfA;
TL1=0xfA;
ET0=1;//允许定时器中断0
TH0=(65535-9200)/256;
TL0=(65535-9200)%256;// 定时器中断0初值
TR0=1;//开中断(秒)
ES=0;
}
void recfrq2recfrqs() //10进制记录频率转字符串
{
recfrqs[0]=num[recfrq/100];recfrqs[1]=num[recfrq%100/10];
recfrqs[2]=num[recfrq%100%10];
datcounts[0]=num[datcount/1000];
datcounts[1]=num[datcount%1000/100];
datcounts[2]=num[datcount%1000%100/10];
datcounts[3]=num[datcount%1000%100%10];
}
void time2times()//10进制时间转字符串
{
times[0]=num[time[0]/10];times[1]=num[time[0]%10];
times[3]=num[time[1]/10];times[4]=num[time[1]%10];
if(mss<50) times[5]=':';else times[5]=' ';
times[6]=num[time[2]/10];times[7]=num[time[2]%10];
}
void date2dates()//10进制日期转字符串
{
dates[2]=num[date[0]/10];dates[3]=num[date[0]%10];
dates[5]=num[date[1]/10];dates[6]=num[date[1]%10];
dates[8]=num[date[2]/10];dates[9]=num[date[2]%10];
}
void avtemp2avtemps()//10进制温度转字符串
{
avtemps[0]=num[avtemp/100];avtemps[1]=num[avtemp%100/10];
avtemps[3]=num[avtemp%100%10];
}
③、LED1602.H
#define l1 0x80
#define l2 0xc0
void write_cmd(uchar con)
{
LCDEN=0;
RS=0;
P2=con;
delay(2);
LCDEN=1;
delay(2);
LCDEN=0;
}
void write_lcddata(uchar dat)
{
LCDEN=0;
RS=1;
P2=dat;
delay(2);
LCDEN=1;
delay(2);
LCDEN=0;
}
void display(uchar line,uchar ttb[],bit sign) {
uchar i=0;
write_cmd(line);//第一行数据起始位while(ttb[i]!='\0')
{
write_lcddata(ttb[i]);
i++;
}
if(sign==1)//覆盖所有空白
{
for(i;i<16;i++)
write_lcddata(' ');
}
}
void lcd_init()
{
LCDEN=0;
write_cmd(0x38);//置功能
write_cmd(0x0c);//显示开启
write_cmd(0x06);//显示光标移动设置06右移04左移
write_cmd(0x01);//清屏
}
三.硬件模块设计及原理图设计
1.复位电路
常见的上电复位和按键复位电路有上电复位、按键脉冲复位、按键电平复位。
如下图所示:
2.时钟电路
时钟电路用于产生单片机的基本时钟信号。
两种时钟信号的连接电路下图所示:
3.测量部分
测量所用仪器是数字温度传感器DS18B20。
用于接收信号,转化成信号等传到单
片机内,单片机来控制显示屏内显示温度示数。
4.原理图设计
四.系统调试
整个软件通过 C 语言编程,先在 Keil C51 集成开发环境下将编好的程序进行编译、调试,调试通过后会生成.HEX 文件.具体过程如下:
新建一个项目文件,然后新建一个 C 语言程序,并把新建的 C 语言程序加到项目中,然后编译项目。
点击 Project 菜单,选择弹出的下拉式菜单中的 New Project,选择所要的单片机89C58RD。
首先我们要在项目中创建新的程序文件。
File->New 或快捷键 Ctrl+N 来实现,然后编写程序。
File-->Save 或快捷键 Ctrl+S 进行保存。
首先第一个程序命名为asd.c,鼠标放在屏幕左侧的 Source Group1 文件夹图标上右击弹出菜单,在这里可以做在项目中增加减少文件等操作。
我们选” Add File to Group ‘Source Group 1’”弹出文件窗口,选择刚刚保存的文件,按 ADD 按钮,关闭文件窗,程序文件已加到项目中了。
这时在 Source Group1 文件夹图标左边出现了一个小+号说明,文件组中有了文件,点击它可以展开查看。
C 程序文件已被加到了项目中了,下面就开始编译运行了,默认情况下,还不能产生我们需要的 asd.hex,我们还需要修改一下相关参数。
在 proteus 软件中测试一下,运行 PROTEUS 模拟仿真软件,打开已绘制好的仿真电路原理图,选中单片机 AT89C58RD,右键点击 AT89C58RD,出现对应的对话框,在 Program File 中找到编译好的“*.HEX”文件,然后点击“OK”就可以进行仿真了。
五.设计总结
经过将近两个星期的全小组成员的共同努力,终于完成了大学四年最后一个小组课程设计,在此也感谢闫老师的悉心指导。
本次课程设计主要是对单片机中定时器/计数器,延时以及硬件连线,焊接等知识的综合应用。
通过这次的课程设计进一步加深了我们对控制理论与单片机控制技术的理解,其实践过程令我们受益匪浅,因为平时学到的大部分都是理论知识,而课程设计就是将我们的理论应用到实践的过程,很好的锻炼了我们的动手实践能力,加强了将理论知识转化为工作实践的技能。
在本次实践中,主要的是我们要将所学的知识理解透,一定要有个整体的规划,这样才能实现编程;在编程的阶段,要先有了整体的规划,如设计哪些功能,如何实现,采集温度与湿度,如何显示温度与湿度,以及应急情况下如何复位等功能。
总体来说,这次课程设计我们基本实现两点(多点)温度监测显示系统的基本功能,不仅加强了我们对于编程的学习应用,同时也巩固在单片机课上所学
的知识,加深对单片机中中断,软件设计等问题认识和理解。
总之,通过这次实践,加深了我们对单片机课程的深刻理解,尤其是在通过对系统的软硬件设计和调试过程,积累了不少实践经验,开拓了创新思维,培养了良好的团队意识,细心严谨的工作态度,积极向上的精神,这为今后计算机硬件方面的学习以及日后的工作打下了较为坚实的基础。
21。