基于单片机的液位水温控制

更新时间:2024-06-06 03:40:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

课 程 设 计 报 告

课程名称_单片机综合应用设计 题目名称基于单片机的水位水温控制系统 学生学院_电气与信息工程学院 _ 专业班级___ 学 号 学生姓名_________

2014 年 7 月 4 日

课程设计题目: 基于单片机的水位水温控制系统设计

一、设计项目简介

1. 设计意义及目的

早期温度和水位的参数控制是通过模拟电路实现的。这种方式不仅电路复杂成本高而且误差大,系统的稳定性不好。单片机及微型计算机技术的发展和应用有效地解决了这些缺点,特别是传感器的发展更好的提高了检测参数的精度。选择基于单片机的水温水位控制系统是因为它不仅在人们生活中具有显著的意义,更重要的是能系统地聚温度和水位参数于一身,对于更好的掌握和认识单片机的应用和传感器的应用,系统地深刻认识自动控制的实际应用,掌握复杂的多子系统地设计起到了很强的锻炼作用。

2. 系统功能描述

本设计的控制系统由水位控制模块和水温控制模块组成。水位控制部分主要由水位检测、按键调整、水位控制和显示等组成。水温控制部分主要由温度检测、按键调整和显示等组成。本设计的控制系统测量水位水温方便、直观成本较低较好地解决了工程应用问题。

3. 设计达到目标

对水池内的温度水位进行监测,用lcd1602进行显示,当水位低于某个程度时,输出

启动抽水的控制信号,达到水位标准时停止抽水;当温度低于某个温度时,输出启动加热装置控制信号,达到指定温度时,停止加热。

二、系统硬件设计

1. 系统设计方案

用51单片机作为中心处理器,用lcd1602显示数据,用ds18b20测量温度,用继电器控制加热工具加热温度,用超声波测水液位,当温度到达一定温度停止加热,水位低于标准水位就启动水泵加水。

图1

2. 系统电路原理图设计及说明

①本次设计用的是AT85C51作为主控制芯片

AT89C51是一种带4K字节FLASH存储器(FPEROM—Flash Programmable and Erasable Read Only Memory)的低电压、高性能CMOS 8位微处理器,俗称单片机。AT89C2051是一种带2K字节闪存可编程可擦除只读存储器的单片机。单片机的可擦除只读存储器可以反复擦除1000次。该器件采用ATMEL高密度非易失存储器制造技术制造,与工业标准的MCS-51指令集和输出管脚相兼容。由于将多功能8位CPU和闪速存储器组合在单个芯片中,ATMEL的AT89C51是一种高效微控制器,AT89C2051是它的一种精简版本。AT89C51单片机为很多嵌入式控制系统提供了一种灵活性高且价廉的方案。外形及引脚排列如图2所示。

②LCD1602是本次用来显示数据的显示硬件

液晶显示器1602(Liquid Crytal Display)简称LCD1602,其主要原理是以电流刺激液晶分子产生点、线、面并配合背部灯光构成画面。1602表示每行显示16个字符,共有2行。LCD与51单片机连接如图3

图3

本次用的DS18B20测温度,经过cpu再转换到LCD1602显示 DSl8B20[4]数字温度计提供9位(二进制)温度读数,指示器件的温度。信息经过单线接口送入DSl8B20或从DSl8B20送出,因此从主机CPU到DSl8B20仅需一条线(和地线)。DSl8B20的电源可以由数据线本身提供而不需要外部电源,这允许在许多不同的地方放置温度敏感器件。DSl8B20的测量范围从-55摄式度到+125摄式度,增量值为0.5摄式度,可在l s(典型值)内把温度变换成数字。 ④用HC-SR04声波测液位

HC-SR04超声波测距模块可提供2cm-400cm的非接触式距离感测功能,测距精度可达高到3mm;模块包括超声波发射器、接收器与控制电路。 基本工作原理:

(1)采用IO口TRIG触发测距,给最少10us的高电平信呈。

(2)模块自动发送8个40khz的方波,自动检测是否有信号返回;

(3)有信号返回,通过IO口ECHO输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。测试距离=(高电平时间*声速(340M/S))/2; ⑤图6为蜂鸣器与单片机连接图

图6

⑥图7为按键电路

图7

⑦图8为时钟电路和复位电路

时钟电路用于产生单片机工作所需要的时钟信号,单片机本身就是一个复杂的同步时序电路,为了保证同步工作方式的实现,电路应在唯一的时钟信号控制下严格地按时序进行工作。 在51芯片内部有一个高增益反相放大器,其输入端为芯片引脚1XTAL,输出端为引脚2XTAL,在芯片的外部跨接晶体振荡器和微调电容,形成反馈电路,就构成了一个 稳定的自激振荡器。 此电路采用12MHz的石英晶体。 复位电路:

复位是单片机的初始化操作。除了进入系统的正常初始化之外,当由于程序运行出错或操作错误是系统处于死锁状态时,为摆脱困境,也需要按复位键以重新启动。

RST引脚是单片机复位信号的输入端,复位信号是高电平有效,其有效时间应持续24个振荡周期(即2个机器周期)以上,若使用频率为12MHz的晶振,则复位信号持续时间应超过

才能完成复位操作。复位操作有上电自动复位和按键手动复位两种方式。上电自动复位是通过外部复位电路的电容充电来实现的

三、系统软件设计

1. 软件设计方案

图11

2. 软件设计框图及说明

本系统中,主程序主要分两部分,分别是设置部分和工作部分。设置部分需要调用设置子程序,工作时需要调用显示屏初始化、键盘扫描、错误检验、温度读取、显示、继电器控制、延时子程序。

因为系统开始工作时需要先设置目标温度,所以需要设置子程序。目标温度设置好之后可以在工作中微调。工作时首先要将显示屏初始化,这样才能保证显示屏的工作。因为需要微调,所以除了设置子程序之外,主程序也需要调用键盘扫描和错误检验程序。之后,需要显示目标温度和实际温度的比较,于是需要从传感器读取温度值,即温度读取子程序。读到温度之后,需要将两个温度显示出来,于是需要调用显示子程序。当然,因为要控制升温降温设备,所有还需要继电器控制子程序。最后,延时,否则屏幕会持续闪动系统无法正常

使用。

温度传感器

图13

四、设计调试及结果分析(做实物的同学给出实际调试结果,附结果图片;仿真的同学写仿真结果分析,给出仿真结果图)

五、 结束语

本次设计优点:

本系统简单可行,所用原件均为市场主流原件,造价低廉并能准确完成我们需要的对温度的显示和控制等功能。并且通过LCD液晶显示明确直观地将目标温度和现场实际温度显示出来,便于我们观察和记录。

本次设计缺点:焊接电路的时候有虚焊,有的元件连接不好,控制系统部署很灵敏

通过这次课题设计,我对单片机的工作原理有了更深一步的了解,对于I/O工作方式更

加明确,并且在应用上掌握了不少方法。在与同学们交流中,也发现不少问题,并且及时的做出相应的更改,还有一些应用巧妙的方法,这些使我对单片机技术能更灵活的应用。

致谢:多谢老师在课堂上传授的知识,感谢队员的各方面的帮助,让我可以完成这个

课程设计,让我学到了很多东西,以前不懂的地方经过同学指点已经基本可以明白。

六、 附录

1. 电路原理图整体绘制图

2. 电路PCB图整体绘制图

3. 相关程序代码

#include #include

#define uint unsigned int #define uchar unsigned char

#define NOP() {_nop_();_nop_();_nop_();_nop_();} #define LCD_DATA P2

sbit DSPORT=P1^0; sbit Heat = P0^0; sbit Push = P0^1; //------Beep----- sbit BEEP = P1^1; //sbit LED = P1^4; //------Key----- sbit AUTO = P3^4; sbit MOV = P3^5; sbit ADD = P3^6; sbit DEC = P3^7; //sbit EN = P2^4;

sbit INT = P3^3; //------LCD引脚----- sbit LCD_RS=P0^4; sbit LCD_RW=P0^5; sbit LCD_EN=P0^6; //------超声波引脚------- sbit Tx=P3^1; sbit Rx=P3^2;

//触发控制信号输入 //回响信号输出

//

//DS18b20 //温度控制继电器 //抽水控制

uchar temp_dis[] = {\ uchar table[] = {\ uchar Hand_table[]= {\ push \//uchar Auto_table[]= {\

uchar Set_Table[7] ={3,6,0,0,2,0,0}; uchar Con_Flag=0;

uchar aa=0, bb=0;

//LCD第一行 //LCD第二行显示

//设定温度值,水位值数组

//控制标志位1为自动,0为手动

long int t,distance,S_Distance=0,R_Distance=0;//L=500; //distance=超声波安装点 与 水面的距离,水深=

超声波安装点-distance

long int temp = 0,S_Temp=0,R_Temp=0; int TError=0,DError=0; uchar cache[4]={0,0,0,0};

uchar datas[3] = { 0,0,0}; //定义数组 //double Kp=0.0;

//PID控制的比例、积分、微分常数

/******************************************************************************* * 函 数 名 : Delay1ms * 函数功能

: 延时函数

* 输 入 : 无 * 输 出 : 无

*******************************************************************************/ void Delay1ms(uint ms) { }

/******************************************************************************* * 函 数 名 : Init_Config * 函数功能

: 中断配置

uint t; while(ms--)

for(t=0;t<120;t++);

* 输 入 : 无 * 输 出 : 无

*******************************************************************************/ void Init_Config(void) {

TMOD=0x19; TR0=1; EX0=1; IT0=1;

//启动定时器 //开外部中断

}

EX1=1; IT1=1; PX0=1; PX1=0; EA=1;

//开总中断

/******************************************************************************* * 函 数 名 : read_lcd_state * 函数功能

: 读取LCD状态

* 输 入 : 无 * 输 出 : 无

*******************************************************************************/ uchar read_lcd_state() { }

/******************************************************************************* * 函 数 名 : lcd_busy_wait * 函数功能

: LCD测忙

uchar state; LCD_RS=0; LCD_RW=1; LCD_EN=1; _nop_();

state=LCD_DATA; LCD_EN=0; _nop_(); return state;

* 输 入 : 无 * 输 出 : 无

*******************************************************************************/ void lcd_busy_wait() {

while((read_lcd_state() & 0x80)==0x80); NOP();

}

/***************************************************************************** * 函 数 名 : lcd_write_com * 函数功能

: 写命令入LCD

* 输 入 : 无 * 输 出 : 无

*****************************************************************************/ void lcd_write_com(uchar com) { }

/***************************************************************************** * 函 数 名 : lcd_write_data * 函数功能

: 写数据入LCD

lcd_busy_wait(); LCD_RS=0; LCD_RW=0; LCD_DATA=com; NOP(); LCD_EN=1; NOP(); LCD_EN=0;

//RS为0时,写指令,RS为1时,写数据

* 输 入 : dat * 输 出 : 无

*****************************************************************************/ void lcd_write_data(uchar dat) { }

lcd_busy_wait(); LCD_RS=1; LCD_RW=0; LCD_DATA=dat; NOP(); NOP(); LCD_EN=0;

LCD_EN=1;

/****************************************************************************** * 函 数 名 : lcd_init * 函数功能

: LCD初始化

* 输 入 : 无 * 输 出 : 无

*****************************************************************************/ void lcd_init() { }

/***************************************************************************** * 函 数 名 : set_lcd_pos * 函数功能

: 设置LCD显示地址

LCD_EN=0;

lcd_write_com(0x38); lcd_write_com(0x0c); lcd_write_com(0x06); lcd_write_com(0x01);

//LCD显示模式设置 //LCD显示开/关及光标设置

//当写一个字符后地址指针加1,且光标加1 //显示清屏

* 输 入 : p * 输 出 : 无

*****************************************************************************/ void set_lcd_pos(uchar p) { }

/***************************************************************************** * 函 数 名 : lcd_print * 函数功能

: 打印显示字符

lcd_write_com(p|0x80);

* 输 入 : p,*s,low * 输 出 : 无

*****************************************************************************/ void lcd_print(uchar p,uchar *s,uint low) { }

void HC05_Init() { // }

/***************************************************************************** * 函 数 名 : distance_convert * 函数功能

: 距离装换

Tx=1;

//触发脉冲

uint num; set_lcd_pos(p);

for(num=0;num

lcd_write_data(s[num]); Delay1ms(1);

NOP();NOP();NOP();NOP(); Tx=0;

distance=0.17*t;

//距离计算 //水深

distance=L-distance;

* 输 入 : Ldat * 输 出 : 无

*****************************************************************************/ void distance_convert(long int Ldat) { }

temp_dis[9]=cache[0]+'0'; temp_dis[10]=cache[1]+'0'; temp_dis[11]=cache[2]+'0'; temp_dis[13]=cache[3]+'0'; cache[0]=Ldat/1000; cache[1]=Ldat/100; cache[2]=Ldat/10; cache[3]=Ldat;

/***************************************************************************** * 函 数 名 : Ds18b20Init * 函数功能

: 初始化DS18b20

* 输 入 : 无 * 输 出 : 无

*****************************************************************************/ uchar Ds18b20Init() { }

/***************************************************************************** * 函 数 名 : Ds18b20WriteByte * 函数功能

: 向18B20写入一个字节

uchar i; DSPORT = 0; i = 70;

//将总线拉低480us~960us

while(i--); //延时642us DSPORT = 1; i = 0;

while(DSPORT) //等待DS18B20拉低总线 { }

return 1;//初始化成功

i++;

if(i>5)//等待>5MS { }

Delay1ms(1);

return 0;//初始化失败

//然后拉高总线,如果DS18B20做出反应会将在15us~60us后总线拉低

* 输 入 : Tdat

* 输 出 : 无

//***************************************************************************/ void Ds18b20WriteByte(uchar Tdat) { }

/****************************************************************************** * 函 数 名 : Ds18b20ReadByte * 函数功能

: 读取一个字节

for(j=0; j<8; j++) { }

DSPORT = 0; i++;

DSPORT = Tdat & 0x01; //然后写入一个数据,从最低位开始 i=6;

while(i--); //延时68us,持续时间最少60us DSPORT = 1; Tdat >>= 1;

//然后释放总线,至少1us给总线恢复时间才能接着写入第二个数值

//每写入一位数据之前先把总线拉低1us

uint i, j;

* 输 入 : 无 * 输 出 : 无

******************************************************************************/ uchar Ds18b20ReadByte() {

uchar byte, bi; uint i, j; {

DSPORT = 0;//先将总线拉低1us i++;

DSPORT = 1;//然后释放总线 i++;

for(j=8; j>0; j--)

}

}

i++;//延时6us等待数据稳定

bi = DSPORT; //读取数据,从最低位开始读取

/*将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0。*/ byte = (byte >> 1) | (bi << 7); i = 4; while(i--);

//读取完之后等待48us再接着读取下一个数

return byte;

/******************************************************************************* * 函 数 名 : Ds18b20ChangTemp * 函数功能

: 让18b20开始转换温度

* 输 入 : 无 * 输 出 : 无

******************************************************************************/

void Ds18b20ChangTemp() { }

/****************************************************************************** * 函 数 名 : Ds18b20ReadTempCom * 函数功能

: 发送读取温度命令

Ds18b20Init(); Delay1ms(1);

Ds18b20WriteByte(0xcc);

//跳过ROM操作命令

Ds18b20WriteByte(0x44); //温度转换命令

Delay1ms(100); //等待转换成功,而如果你是一直刷着的话,就不用这个延时了

* 输 入 : 无 * 输 出 : 无

*****************************************************************************/ void Ds18b20ReadTempCom() { }

/****************************************************************************** * 函 数 名 : Ds18b20ReadTemp * 函数功能

: 读取温度

Ds18b20Init(); Delay1ms(1);

Ds18b20WriteByte(0xcc); //跳过ROM操作命令 Ds18b20WriteByte(0xbe); //发送读取温度命令

* 输 入 : 无 * 输 出 : 无

******************************************************************************/ int Ds18b20ReadTemp() { }

/**************************************************************************** * 函 数 名 : Ds1820Disp

return temp;

//

temp=temp*0.625; uchar tmh, tml;

uchar datas[3] = { 0,0,0}; //定义数组 Ds18b20ChangTemp();

//先写入转换命令

Ds18b20ReadTempCom(); tml = Ds18b20ReadByte(); tmh = Ds18b20ReadByte(); temp = tmh; temp <<= 8; temp |= tml;

//然后等待转换完后发送读取温度命令

//读取温度值共16位,先读低字节 //再读高字节

* 函数功能 : DS18b20的显示

* 输 入 : Tdata * 输 出 : 无

****************************************************************************** void LcdDisplay(int Tdata) { }

temp_dis[2]=datas[0]+'0'; temp_dis[3]=datas[1]+'0'; temp_dis[5]=datas[2]+'0'; temp_dis[6]=0xdf;

//摄氏度符号

datas[0] = Tdata % 1000 /100 ; datas[1] = Tdata % 100 / 10; datas[2] = Tdata % 10 ;

//lcd显示

/****************************************************************************** * 函 数 名 : Read_Value * 函数功能

: 写入温度值、水位值的显示

* 输 入 : 无 * 输 出 : 无

******************************************************************************/ void Write_Value(void) {

//温度值

table[2] = Set_Table[0]+'0'; //十位 table[3] = Set_Table[1]+'0'; //个位 table[5] = Set_Table[2]+'0'; //小数位 table[6] = 0xdf;

//水位值

table[9] = Set_Table[3]+'0'; table[10] = Set_Table[4]+'0'; table[11] = Set_Table[5]+'0';

}

table[13] = Set_Table[6]+'0';

/***************************************************************************** * 函 数 名 : Read_Value * 函数功能

: 读取温度值、水位值的显示

* 输 入 : 无 * 输 出 : 无

****************************************************************************** void Read_Set_Value(void) { }

/**************************************************************************** * 函 数 名 : Read_Value * 函数功能

: 读取温度值、水位值的显示

S_Distance = Set_Table[3]*1000+Set_Table[4]*100+Set_Table[5]*10+Set_Table[6]; 水位 S_Temp

= Set_Table[0]*100+Set_Table[1]*10+Set_Table[2];

温度

* 输 入 : 无 * 输 出 : 无

**************************************************************************** void Read_Real_Value(void) { }

/**************************************************************************** * 函 数 名 : Auto_Temp_Control * 函数功能

:

R_Distance = cache[0]*1000+cache[1]*100+cache[2]*10+cache[3]; R_Temp = datas[0]*100+datas[1]*10+datas[2];

* 输 入 : 无 * 输 出 : 无

*****************************************************************************

void Auto_Temp_Control(void) { }

/****************************************************************************** * 函 数 名 : Auto_Distance_Control * 函数功能

:

if(TError>20) { }

else if(TError<-20) { }

Heat=1; Heat=0;

* 输 入 : 无 * 输 出 : 无

***************************************************************************** void Auto_Distance_Control() { }

/*************************************************************************** * 函 数 名 : Auto_Activity * 函数功能

: 自动

if(DError>50) { }

else if(DError<-10) { }

Push=1;

Push=0;

* 输 入 : 无 * 输 出 : 无

**************************************************************************** void Auto_Activity(void) {

while(1) {

table[0]='S'; LcdDisplay(temp);

lcd_print(0x00,temp_dis,16);

Set_Table[bb]=aa; Write_Value();

lcd_print(0x40,table,16); HC05_Init();

distance_convert(distance); Ds18b20ReadTemp(); Set_Table[bb]=0x5f; Write_Value();

lcd_print(0x40,table,16); { }

else if(!ADD) { }

else if(!DEC) {

if(aa==0) { }

Delay1ms(1);

aa=10;

Delay1ms(1); aa++; if(aa==10) { }

Set_Table[bb]=aa;

aa=0;

Delay1ms(1); bb++; if(bb==7) { }

bb=0;

if(!MOV)

Delay1ms(1);

}

{ }

} { }

aa--;

Set_Table[bb]=aa;

else if(!AUTO)

Read_Set_Value(); break;

else if(!AUTO) }

break;

/***************************************************************************** * 函 数 名 : Hand_Activity * 函数功能

: 手动模式配置

* 输 入 : 无 * 输 出 : 无

***************************************************************************** void Hand_Activity(void) {

if(!ADD) { } else { }

if(!DEC)

//手动抽水

Heat=1;

Hand_table[3]='h'; Hand_table[4]='e'; Hand_table[5]='a'; Hand_table[6]='t'; Heat=0;

Hand_table[3]='H'; Hand_table[4]='E'; Hand_table[5]='A'; Hand_table[6]='T';

//手动加热

}

{ } else { }

Push=1;

Hand_table[9]='p'; Hand_table[10]='u'; Hand_table[11]='s'; Hand_table[12]='h'; Push=0;

Hand_table[9]='P'; Hand_table[10]='U'; Hand_table[11]='S'; Hand_table[12]='H';

/****************************************************************************** * 函 数 名 : main * 函数功能

: 主函数

* 输 入 : void * 输 出 : 无

******************************************************************************* void main(void) {

if(!AUTO) {

//触发中断,手动、自动切换

LcdDisplay(temp);

lcd_print(0x00,temp_dis,16);

lcd_init(); Delay1ms(5); Init_Config(); while(1) {

HC05_Init(); Read_Real_Value(); distance_convert(distance); Ds18b20ReadTemp();

}

}

}

INT=0; INT=1;

if(Con_Flag==1) { }

else if(Con_Flag==0) { }

lcd_print(0x40,Hand_table,16); Hand_Activity();

Read_Real_Value(); TError=S_Temp-R_Temp; DError=S_Distance-R_Distance; table[0]='A'; Write_Value();

lcd_print(0x40,table,16); Auto_Temp_Control(); Auto_Distance_Control();

//温度控制 //水位控制

//差值=设定值-实时值

/******************************************************************************* * 函 数 名 : int0 * 函数功能

: 外部中断0服务

* 输 入 : 无 * 输 出 : 无

******************************************************************************* void int0() interrupt 0 {

t=(TH0*256+TL0); //计算高电平持续的时间,上升沿到来时候开始计时,下降沿到来进入外部中断,

关闭计时器,停止计时 }

/*************************************************************************/

TH0=0; TL0=0;

* 函 数 名 : int1_key * 函数功能

: 外部中断1服务,键盘扫描

* 输 入 : 无 * 输 出 : 无

*****************************************************************************/ void int1_key() interrupt 2 { }

EX1=0; Delay1ms(10); Con_Flag++; if(Con_Flag==2) { }

if(Con_Flag==1) { }

else if(Con_Flag==0) { } EX1=1;

return;

Auto_Activity(); Con_Flag=0;

本文来源:https://www.bwwdw.com/article/qsd6.html

Top