基于51单片机的温度监测控制系统仿真程序原理图设计

整体方案设计

3.1.1 系统概述
整个系统以STC89C52单片机为核心器件,配合电阻电容晶振等器件,构成单片机的最小系统。其它个模块围绕着单片机最小系统展开。其中包括,传感器采用DS18B20,负责采集温度数据后发给单片机。显示设备采用4位共阴数码管,显示检测到的温度值。按键模块,主要是进行报警值的设置。报警模块采用蜂鸣器+LED的模式,超出报警范围则进行声光报警,同时还有升温和降温装置工作,使得温度恒定在一个范围之内。
在这里插入图片描述
原理图:
在这里插入图片描述

仿真图:

在这里插入图片描述

最小系统模块
3.2.1 STC89C52简介
(1)概述
STC89C52是一个低电压,高性能CMOS 8位单片机,片内含8k bytes的可反复擦写的Flash只读程序存储器和256 bytes的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内置通用8位中央处理器和Flash存储单元,功能强大的STC89C52单片机可为您提供许多较复杂系统控制应用场合。
STC89C52有40个引脚,32个外部双向输入/输出(I/O)端口,同时内含2个外中断口,3个16位可编程定时计数器,2个全双工串行通信口,2个读写口线。STC89C52有PDIP、PQFP/TQFP及PLCC等三种封装形式,以适应不同产品的需求。
(2)主要功能特性
 ◆兼容MCS51指令系统;
 ◆8k可反复擦写(>1000次)Flash ROM;
 ◆32个双向I/O口;
◆256x8bit内部RAM ;
 ◆3个16位可编程定时/计数器中断;
◆时钟频率0-24MHz;
 ◆2个串行中断;
 ◆可编程UART串行通道;
 ◆2个外部中断源;
 ◆共8个中断源;
 ◆2个读写中断口线;
 ◆3级加密位;
 ◆低功耗空闲和掉电模式;
◆软件设置睡眠和唤醒功能;

DS18B20传感器电路
3.3.1 DS18B20简介
(1)概述
DS18B20(图3-4)是美国DALLAS半导体公司推出的第一片支持“一线总线”接口的温度传感器,它具有微型化,低功耗,高性能,抗干扰能力强,易配微处理器等优点,可直接将温度转化成数字信号处理器处理。测量的温度范围是-55125℃,测温误差0.5℃。可编程分辨率912位,对应的可分辨温度分别为0.5℃,0.25℃,0.125℃和0.0625℃。相较热电偶传感器而言可实现高精度测温。

(2)特性
独特的1-Wire总线接口仅需要一个管脚来通信;
每个设备的内部ROM上都烧写了一个独一无二的64位序列号;
多路采集能力使得分布式温度采集应用更加简单;
无需外围元件;
供电范围为3.0V至5.5V;
温度可测量范围为:-55℃至+125℃(-67℉至+257℉);
温度范围超过-10℃至85℃之外时具有±0.5℃的精度;
内部温度采集精度可以由用户自定义为9-Bits至12-Bits;
温度转换时间在转换精度为12-Bits时达到最大值750ms;
用户自定义非易失性的的温度报警设置;
定义了温度报警搜索命令和当温度超过用户自定义的设定值时;
与DS1822程序兼容。
(3)管脚定义
Pin1:(VDD),可选的电源引脚;
Pin2:(DQ),单线运用的数据输入/输出引脚;
Pin3:(VDD),接地端,电源负极;
(4)应用领域
该产品适用于冷冻库,粮仓,储罐,电讯机房,电力机房,电缆线槽等。
轴瓦,缸体,纺机,空调,等狭小空间工业设备测温和控制。
汽车空调、冰箱、冷柜、以及中低温干燥箱等。
供热/制冷管道热量计量,中央空调分户热能计量和工业领域测温和控制。

数码管显示模块
3.4.1 数码管简介
数码管是一类价格便宜 使用简单,通过对其不同的管脚输入相对的电流,使其发亮,从而显示出数字能够显示 时间、日期、温度等所有可用数字表示的参数的器件。在电器特别是家电领域应用极为广泛,如显示屏、空调、热水器、冰箱等等。LED数码管(LED Segment Displays)由多个发光二极管封装在一起组成“8”字型的器件,引线已在内部连接完成,只需引出它们的各个笔划,公共电极。数码管实际上是由七个发光管组成8字形构成的,加上小数点就是8个。这些段分别由字母a,b,c,d,e,f,g,dp来表示。当数码管特定的段加上电压后,这些特定的段就会发亮,以形成我们眼睛看到的字样了。如:显示一个“2”字,那么应当是a亮b亮g亮e亮d亮f不亮c不亮dp不亮。数码管的外形如图3-8所示。

LED数码管有一般亮和超亮等不同之分,也有0.5寸、1寸等不同的尺寸。小尺寸数码管的显示笔画常用一个发光二极管组成,而大尺寸的数码管由二个或多个发光二极管组成,一般情况下,单个发光二极管的管压降为1.8V左右,电流不超过30mA。发光二极管的阳极连接到一起连接到电源正极的称为共阳数码管(图3-9),发光二极管的阴极连接到一起连接到电源负极的称为共阴数码管(图3-10)。常用LED数码管显示的数字和字符是0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F。

3.4.2 数码管驱动方式的分类
LED数码管要正常显示,就要用驱动电路来驱动数码管的各个段码,从而显示出我们要的数字,因此根据LED数码管的驱动方式的不同,可以分为静态式和动态式两类。
静态驱动也称直流驱动。静态驱动是指每个数码管的每一个段码都由一个单片机的I/O端口进行驱动,或者使用如BCD码二-十进制译码器译码进行驱动。静态驱动的优点是编程简单,显示亮度高,缺点是占用I/O端口多,如驱动5个数码管静态显示则需要5×8=40根I/O端口来驱动,要知道一个89S51单片机可用的I/O端口才32个,实际应用时必须增加译码驱动器进行驱动,增加了硬件电路的复杂性。
动态显示,LED数码管动态显示接口是单片机中应用最为广泛的一种显示方式之一,动态驱动是将所有数码管的8个显示笔划"a,b,c,d,e,f,g,dp"的同名端连在一起,另外为每个数码管的公共极COM增加位选通控制电路,位选通由各自独立的I/O线控制,当单片机输出字形码时,单片机对位选通COM端电路的控制,所以我们只要将需要显示的数码管的选通控制打开,该位就显示出字形,没有选通的数码管就不会亮。通过分时轮流控制各个数码管的的COM端,就使各个数码管轮流受控显示,这就是动态驱动。在轮流显示过程中,每位数码管的点亮时间为1~2ms,由于人的视觉暂留现象及发光二极管的余辉效应,尽管实际上各位数码管并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示数据,不会有闪烁感,动态显示的效果和静态显示是一样的,能够节省大量的I/O端口,而且功耗更低。
3.4.3 数码管驱动电路
本设计由于采用了4位数码管,如果采用静态驱动的话,将会占用单片机32个IO口,导致单片机IO口不够用,因此采用数码管的动态驱动方式,电路如下图(图3-11)所示,把数码管的数据口接到单片机的PO口上,位选端则由单片机的P27、P26、P25、P24进行控制。只需12个IO口,就可以控制4位数码管的显示。在程序中需要轮流点亮每位数码管,并且保持一定的点亮时间

蜂鸣器模块
蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件。
蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型。压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、阻抗匹配器及共鸣箱、外壳等组成。当接通电源后多谐振荡器起振,输出1.5~2.5kHZ的音频信号,阻抗匹配器推动压电蜂鸣片发声。电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。接通电源后,振荡器产生的音频信号电流通过电磁线圈,使电磁线圈产生磁场。振动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声。本设计使用的是电磁式蜂鸣器。
此外,蜂鸣器还有有源蜂鸣器与无源蜂鸣器的区别。注意这里的“源”不是指电源,而是指震荡源。也就是说,有源蜂鸣器内部带震荡源,所以只要一通电就会叫;而无源内部不带震荡源,所以如果用直流信号无法令其鸣叫,必须用2K-5K的方波去驱动它。本设计使用的是有源蜂鸣器。
由于蜂鸣器工作时,需要的电流比较大,单片机的IO口输出的电流又比较小,所以这里利用三极管的开关管功能来控制蜂鸣器发音,本设计选用的三极管型号是PNP三极管S8550,而且本设计选用的蜂鸣器属于有源蜂鸣器,即在蜂鸣器内部已经内置了震荡电路,单片机无需连续发出高低电平来驱动它,而只要输出高(或低)电平即可,这大大简化了单片机程序的设计。由于选用的是PNP型而单片机上电IO口默认是高电平的,所以上电时蜂鸣器是不会发出鸣叫的。

继电器电路
继电器是一种电控制器件,是当输入量(激励量)的变化达到规定要求时,在电气输出电路中使被控量发生预定的阶跃变化的一种电器。它具有控制系统(又称输入回路)和被控制系统(又称输出回路)之间的互动关系。通常应用于自动化的控制电路中,它实际上是用小电流去控制大电流运作的一种“自动开关”。故在电路中起着自动调节、安全保护、转换电路等作用。
按继电器的工作原理或结构特征分类的不同,大致可将继电器分为电磁继电器、固体继电器、温度继电器、舌簧继电器、时间继电器、高频继电器、极化继电器、光继电器、声继电器、热继电器、仪表式继电器、霍尔效应继电器、差动继电器等。
本设计中采用的继电器属于电磁式继电器。电磁继电器一般由铁芯、线圈、衔铁、触点簧片等组成的。只要在线圈两端加上一定的电压,线圈中就会流过一定的电流,从而产生电磁效应,衔铁就会在电磁力吸引的作用下克服返回弹簧的拉力吸向铁芯,从而带动衔铁的动触点与静触点(常开触点)吸合。当线圈断电后,电磁的吸力也随之消失,衔铁就会在弹簧的反作用力返回原来的位置,使动触点与原来的静触点(常闭触点)释放。这样吸合、释放,从而达到了在电路中的导通、切断的目的。对于继电器的“常开、常闭”触点,可以这样来区分:继电器线圈未通电时处于断开状态的静触点,称为“常开触点”;处于接通状态的静触点称为“常闭触点”。继电器一般有两股电路,为低压控制电路和高压工作电路。
继电器模块的电路如下图(图3-15)所示。继电器使用的是5V电压触发的。由于继电器由导通到关断瞬间,由于工作线圈有电感的性质,所以会在继电器的线圈的低电压端产生一个瞬间电压尖峰,通常能高达数十倍的线圈额定工作电压。所以这里接入一个二极管在继电器两端,因为二极管的负端通常接到VCC,因此电压尖峰将被抑制。保护了板上的电子元件。当单片机的IO口给PNP三极管一个低电平后后,三极管导通,继电器供电,因此继电器从断开变为闭合,最终将小风扇或加热膜接入5V电压,这样就实现了单片机控制加温或降温的效果。
在这里插入图片描述

程序设计

在这里插入图片描述


#include <reg52.h>			// 包含头文件
#include <intrins.h>

#define uchar unsigned char		// 以后unsigned char就可以用uchar代替
#define uint  unsigned int		// 以后unsigned int 就可以用uint 代替

sbit DQ = P1^1;						// DS18B20传感器的引脚定义
sbit w1 = P2^4; 					// 数码管第1位的控制引脚
sbit w2 = P2^5;						// 数码管第2位的控制引脚
sbit w3 = P2^6;						// 数码管第3位的控制引脚
sbit w4 = P2^7;			 			// 数码管第4位的控制引脚
sbit Buzzer  = P1^0;			// 蜂鸣器引脚
sbit JdqLow  = P2^0;			// 温度过低继电器控制(加热)
sbit JdqHig  = P2^1;			// 温度过高继电器控制(降温)
sbit LedLow  = P2^2;			// 温度低指示灯
sbit LedHig  = P2^3;			// 温度高指示灯
sbit KeySet  = P3^2;			// 设置按键
sbit KeyDown = P3^3;			// 减按键
sbit KeyUp   = P3^4;			// 加按键



/*   数码管的显示值:  0    1    2    3    4    5     6   7    8    9    -   */
uchar code Array1[]={ 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40 };

/*                     0.   1.   2.   3.   4.   5.    6.  7.   8.   9.  */
uchar code Array2[]={ 0xBf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef };


uchar Buff[4];					// 显示缓冲区
uchar ShowID=1;					// 当前显示的是哪一个数码管

int AlarmLow=150;				// 默认报警的温度下限值是15度
int AlarmHig=300;				// 默认报警的温度上限值是30度


/*********************************************************/
// 毫秒级的延时函数,time是要延时的毫秒数
/*********************************************************/
void DelayMs(uint time)
{
	uint i,j;
	for(i=0;i<time;i++)
		for(j=0;j<112;j++);
}


/*********************************************************/
// 延时15微秒
/*********************************************************/
void Delay15us(void)
{
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
}


/*********************************************************/
// 复位DS18B20(初始化)
/*********************************************************/
void DS18B20_ReSet(void)
{
	uchar i;
	DQ=0;

	i=240;
	while(--i);

	DQ=1;

	i=30;
	while(--i);

	while(~DQ);

	i=4;
	while(--i);
}


/*********************************************************/
// 向DS18B20写入一个字节
/*********************************************************/
void DS18B20_WriteByte(uchar dat)
{
	uchar j;
	uchar btmp;
	
	for(j=0;j<8;j++)
	{
		btmp=0x01;
		btmp=btmp<<j;
		btmp=btmp&dat;
		
		if(btmp>0)		// 写1
		{
			DQ=0;
			Delay15us();
			DQ=1;
			Delay15us();
			Delay15us();
			Delay15us();
			Delay15us();
		}
		else			// 写0
		{
			DQ=0;
			Delay15us();
			Delay15us();
			Delay15us();
			Delay15us();
			DQ=1;
			Delay15us();
		}
	}
}


/*********************************************************/
// 读取温度值
/*********************************************************/
int DS18B20_ReadTemp(void)
{
	uchar j;
	int b,temp=0;	

	DS18B20_ReSet();							// 产生复位脉
	DS18B20_WriteByte(0xcc);			// 忽略ROM指令
	DS18B20_WriteByte(0x44);			// 启动温度转换指令

	DS18B20_ReSet();							// 产生复位脉
	DS18B20_WriteByte(0xcc);			// 忽略ROM指令
	DS18B20_WriteByte(0xbe);			// 读取温度指令

	for(j=0;j<16;j++)							// 读取温度数量
	{						
		DQ=0;
		_nop_();
		_nop_();
		DQ=1;	
		Delay15us();
		b=DQ;
		Delay15us();
		Delay15us();
		Delay15us();
		b=b<<j;
		temp=temp|b;
	}
	
	temp=temp*0.0625*10;					// 合成温度值并放大10倍					
	
	return (temp);								// 返回检测到的温度值
}


/*********************************************************/
// 定时器初始化
/*********************************************************/
void TimerInit()
{
	TMOD = 0x01;					// 使用定时器0,工作方式1	 
	TH0  = 248;						// 给定时器0的TH0装初值
	TL0  = 48;						// 给定时器0的TL0装初值
	ET0  = 1;							// 定时器0中断使能
	EA   = 1;							// 打开总中断
	TR0	 = 1;							// 启动定时器0
}


/*********************************************************/
// 显示温度值
/*********************************************************/
void ShowTemp(int dat)
{
	if(dat<0)												// 负号
	{
		Buff[0]=Array1[10];
		dat=0-dat;
	}
	else														// 百位
	{
		Buff[0]=Array1[dat/1000];
	}
	
	Buff[1]=Array1[dat%1000/100];		// 十位
	Buff[2]=Array2[dat%100/10];			// 个位
	Buff[3]=Array1[dat%10];					// 小数后一位
}


/*********************************************************/
// 报警判断
/*********************************************************/
void AlarmJudge(int dat)
{
	if(dat<AlarmLow)				// 判断温度是否过低
	{
		LedLow=0;							// 温度低指示灯亮
		LedHig=1;							// 温度高指示灯灭
		JdqLow=0;							// 温度过低的继电器闭合(开始加热)
		JdqHig=1;							// 温度过高的继电器断开(停止降温)
		Buzzer=0;							// 蜂鸣器报警
	}
	else if(dat>AlarmHig)		// 判断温度是否过高
	{
		LedLow=1;							// 温度低指示灯灭
		LedHig=0;							// 温度高指示灯亮
		JdqLow=1;							// 温度过低的继电器断开(停止加热)
		JdqHig=0;							// 温度过高的继电器闭合(开始降温)
		Buzzer=0;							// 蜂鸣器报警
	}
	else										// 温度正常
	{
		LedLow=1;							// 温度低指示灯灭
		LedHig=1;							// 温度高指示灯灭
		JdqLow=1;							// 温度过低的继电器断开(停止加热)
		JdqHig=1;							// 温度过高的继电器断开(停止降温)
		Buzzer=1;							// 蜂鸣器停止报警
	}
}


/*********************************************************/
// 按键扫描
/*********************************************************/
void KeyScanf()
{
	if(KeySet==0)									// 如果设置按键被按下
	{
		/* 设置温度下限 */
		LedLow=0;										// 点亮绿色灯(代表当前正在设置温度下限)
		LedHig=1;										// 熄灭红色灯
		Buzzer=1;										// 关闭蜂鸣器
		ShowTemp(AlarmLow);					// 显示温度下限值
		DelayMs(10);								// 延时去抖
		while(!KeySet);							// 等待按键释放
		DelayMs(10);								// 延时去抖
		
		while(1)
		{
			if(KeyDown==0)								// 如果“减”按键被按下
			{
				if(AlarmLow>-550)						// 判断当前温度下限是否大于-55度
				{
					AlarmLow--;								// 温度下限值减去0.1度
					ShowTemp(AlarmLow);				// 刷新显示改变后的温度下限值
					DelayMs(200);							// 延时
				}
			}
			
			if(KeyUp==0)									// 如果“加”按键被按下					
			{
				if(AlarmLow<1250)						// 判断当前温度下限是否小于125度
				{
					AlarmLow++;								// 温度下限值加上0.1度
					ShowTemp(AlarmLow);				// 刷新显示改变后的温度下限值
					DelayMs(200);							// 延时
				}
			}
			
			if(KeySet==0)									// 如果“设置”按键被按下
			{
				break;											// 退出温度下限值的设置,准备进入上限值的设置
			}
		}
		
		/* 设置温度上限 */
		LedLow=1;										// 熄灭绿色灯
		LedHig=0;										// 点亮红色灯(代表当前正在设置温度上限)
		ShowTemp(AlarmHig);					// 显示温度上限值
		DelayMs(10);								// 延时去抖
		while(!KeySet);							// 等待按键释放
		DelayMs(10);								// 延时去抖
		
		while(1)
		{
			if(KeyDown==0)							// 如果“减”按键被按下							
			{
				if(AlarmHig>-550)					// 判断当前温度上限是否大于-55度
				{
					AlarmHig--;							// 温度上限值减去0.1度
					ShowTemp(AlarmHig);			// 刷新显示改变后的温度上限值
					DelayMs(200);						// 延时
				}
			}
			
			if(KeyUp==0)								// 如果“加”按键被按下					
			{
				if(AlarmHig<1250)					// 判断当前温度上限是否小于125度
				{
					AlarmHig++;							// 温度上限值加上0.1度
					ShowTemp(AlarmHig);			// 刷新显示改变后的温度上限值
					DelayMs(200);
				}
			}
			
			if(KeySet==0)								// 如果“设置”按键被按下
			{
				break;										// 准备退出设置模式
			}
		}
		
		/* 退出设置模式 */
		LedLow=1;									// 熄灭绿灯
		LedHig=1;									// 熄灭红灯
		DelayMs(10);							// 延时去抖
		while(!KeySet);						// 等待按键释放
		DelayMs(10);							// 延时去抖
	}
}


/*********************************************************/
// 主函数
/*********************************************************/
void main()
{
	int temp;
	uchar i;
	
	TimerInit();										// 定时器0的初始化(数码管的动态扫描)
	
	Buff[0]=Array1[0];							// 刚上电显示4个0
	Buff[1]=Array1[0];
	Buff[2]=Array1[0];
	Buff[3]=Array1[0];
	
	for(i=0;i<8;i++)								// 由于传感器刚上电读出的温度不稳定,因此先进行几次温度的读取并丢弃
	{
		DS18B20_ReadTemp();
		DelayMs(120);
	}
	
	while(1)
	{
		EA=0;													// 屏蔽中断
		temp=DS18B20_ReadTemp();			// 读取温度值
		EA=1;													// 恢复中断
		
		ShowTemp(temp);								// 显示温度值
		
		AlarmJudge(temp);							// 判断是否需要报警
		
		for(i=0;i<100;i++)						// 延时并进行按键扫描
		{
			KeyScanf();					
			DelayMs(10);								
		}
	}
}


/*********************************************************/
// 定时器0服务程序
/*********************************************************/
void Timer0(void) interrupt 1
{
	TH0  = 248;				// 给定时器0的TH0装初值
	TL0  = 48;				// 给定时器0的TL0装初值

	P0=0x00;					// 先关闭所有显示
	w1=1;
	w2=1;
	w3=1;
	w4=1;

	if(ShowID==1)  			// 判断是否显示第1位数码管
	{
		w1=0;		   				// 打开第1位数码管的控制开关
		P0=Buff[0];	   		// 第1位数码管显示内容	
	}
	
	if(ShowID==2)  			// 判断是否显示第2位数码管
	{
		w2=0;		   				// 打开第2位数码管的控制开关
		P0=Buff[1];	   		// 第2位数码管显示内容	
	}
	
	if(ShowID==3)  			// 判断是否显示第3位数码管
	{
		w3=0;		   				// 打开第3位数码管的控制开关
		P0=Buff[2];	   		// 第3位数码管显示内容	
	}
	
	if(ShowID==4)  			// 判断是否显示第4位数码管
	{
		w4=0;		   				// 打开第4位数码管的控制开关
		P0=Buff[3];	   		// 第4位数码管显示内容	
	}	
	
	ShowID++;	  				// 切换到下一个数码管的显示
	if(ShowID==5)
		ShowID=1;
}

附: http://www.jh-tec.cn/archives/7212

.

常用的温度检测元件主要有热电偶、热电阻、热敏电阻等。热电偶主要是利用两种不同金属的热电效应,产生接触电势随温度变化而变化,从而达到测温的目的。测量准确,价格适中测温范围宽,线性度较好。但其输出电压受冷端温度影响,需要进行冷端温度补偿,使电路变得复杂,在本题中并非最佳方案。 热敏电阻由金属氧化物或半导体材料制成,灵敏度高、热惰性小、寿命长、价格便宜。但其测量的稳定性和复现性差,测量精度无法满足本题发挥部分0.2℃的要求。而且线性度差,需要进行查表线性拟合,大大浪费控制器的资源,因此不能选用。 热电阻是利用金属的电阻率随温度变化而变化的特性,将温度量转化成电阻量。其优点是准确度高,稳定性高,性能可靠,热惯性小、复现性好,价格适中。但电阻值与温度是非线性关系,Pt100热电阻,当0℃<t<850℃时可用下式表示: 其中A=3.9083╳10-3 /℃;B=-5.775╳10-7 /℃;由此可见,温度越高非线性误差越大,本题目要求温控范围是40℃~90℃,温度较低。经计算当温度为90℃时,非线性误差为0.34%,运用最小二乘法适当的进行零点和增益的调整,还可使此误差降低一倍,而本题要求精度为,0.2/90=0.22%,因此在本题中可以选用Pt100热电阻,并可近似将其电阻值与温度看作线性关系。 2、 放大电路 热电阻所测得的是电阻量,需要转化为电压量才能被控制器采集。最基本的电阻-电压转换电路是将其与另一固定电阻串联,但这种方法,当温度为量程下限时输出不为零,这样不利于小信号的放大和提高A/D转换的精度。因此,本作品采用桥路测量,电路如图2所示: 其中R1R2为10kΩ固定电阻,Rt为热电阻,Rw2为调零电阻,由于 ,因此上下两支路电流相等,并保持恒定不变,输出电压 ,可调整Rt0=Rw2,使得 由于在桥路中R1很大,使得输出量uo变化很小,当Rt从0到100℃变化时,输出仅有十几毫伏,因此还需要进行小信号放大。本作品所用低频增益可调放大电路如图3: 其中Rw1为增益电阻,用于调整测量满量程,运放采用低噪声NE5532,令R1=R2,R3=R4,R5=R6,则该放大电路总增益为 ,当Rw1从0到50kΩ变化时,Av的变化范围为150至+∞,满足所需增益要求。 3、 A/D转换 题目所要求测量度精度为0.2℃,测温的范围应该为室温到要求的最高温度,即20~90℃,这就决定了A/D转换的最低分辨率不低于0.2/(90-20)=1/350,而普通八位A/D转换芯片只能达到1/256,不能满足要求。而如果选用更高位的芯片,将大大增加成本。温度是一种变化时间常数较大的物理量,对A/D转换速度要求不高,因此,在设计中选用了压控振荡器,先将电压信号转化为频率量,再通过控制器的计数功能转化为数字信号,这样可以大大提高精度,节约成本。 压控振荡器如图4所示: 电容器C1充电周期为 ,放电周期为 ,由于 所以 ,所以其振荡频率可近似看作与输入电压Ui成正比。但当频率较高时,仍有较大(约为5%)非线性误差,不能满足题目要求。因此,在作品中利用FPGA的优点,该测频率为测正脉冲宽度,再通过单片机求倒数,这样即可完全消除非线性误差。 4、 控制器 对水温的反馈偏差控制,就必然用到经典控制理论中的PID(Proportional Integral and Derivative比例积分微分)控制,控制器可有多种选择,如模拟电路、单片机、逻辑器件等。 模拟电路控制可对偏差变化进行连续的控制,技术成熟,性能较稳定。但其缺点是不便于显示,调整PID参数需更换元器件,易受到外界干扰等,在现在这个数字化高度发展的时代已趋于淘汰。 单片机作为微型计算机的一个分支,已有二十多年的发展,在各控制领域都有广泛的应用。而近年以FPGA(现场可编程门阵列)为代表的可编程逻辑器件异军突起,其优异的性能大大弥补了单片机响应速度慢、中断源少的缺点。但FPGA的运算能力有限,因此,在我们的设计中采用FPGA与单片机相结合的控制方式,二者优势互补,性能大大提高。 在本作品中,FPGA主要负责接收压控振荡器的信号,通过测量其正脉宽而获得电压量;单片机接收FPGA发送的数据,进行显示、PID运算,和输出。 5、 输出驱动电路 控制器将其PID运算的结果转化为不同占空比的脉冲信号输出,该信号作用于执行机构还需要经过驱动电路。 本作品中采用交流调功电路,即将负载与交流电源接通几个周波,再断开几个周波,通过改变开通与断开周波的比值来调节负载所消耗的平均功率。具体实现电路如图5。 将220V/50Hz的市电,经电阻分压到5V以下,输入运放的同相输入端,运放作为过零比较器,当市电过零时,产生跳变,运放输出送到D触发器的时钟端,D触发器的输入接单片机输出的脉冲信号,输出接双向晶闸管的门极。这样,只有当交流电过零时,单片机的输出信号才对晶闸管产生作用,也就是说,只有当交流电过零时,晶闸管才能开通或关断。这样可以大大减小开通关断过程中对晶闸管的冲击,减少开通关断损耗。 二、 控制器软件设计 1、 FPGA程序设计 在本作品中,FPGA的主要功能是测量压控振荡器输出高脉宽的时间。由于压控振荡器的频率较低(0,则输出脉冲的占空比增加1%,反之减小1% 为了确定PID参数,根据容器加热、传热的公式,列出加热容器的微分方程,经拉氏变换后得到一个一阶滞后环节,其传递函数约为 ,对整个控制回路用Matlab中的Simulink工具箱进行方针,其框图如图8 图中step为输入阶跃给定信号,step1为干扰量,A中存储输出占空比,scope显示输出波形(图9a),scope1显示占空比值(图9b)。 图9a 图9b 当t=10时刻,给定值输入阶跃量,t=100时刻,输入干扰阶跃量。由此可见,本系统可以以较小的超调和较短的调节时间达到稳定状态,并对于干扰有较好的控制作用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值