八路温度巡检仪的设计 ------------原创 功能:实现八路温度循环监测,或一路温度动态监测。 设计构想:利用热敏电阻采集信号,将温度的变化体现在阻值的变化上,运放来实现电压信号放大,经过8位的模拟开关后经AD转换为数字信号,后有单片机处理数据,将温度显示在数码管上。 设计要求:实现八路温度的稳定检测,精度为0.1摄氏度,允许误差为0.1摄氏度。 |
1、一毫安电流源的设计:
结构图
一毫安电流源原理图
说明:
恒流源由稳压部分和豪兰德电流源电路组成。
稳压部分提高电路的带载能力
稳压部分:
利用运算放大电路的理想特性,以及电压串联负反馈Uo=Un=Up
Ui=Un所以
Ui=Uo
横流部分:
集成运放理想通过引入负反馈使之具有虚短和虚短的特点。所以Up=Un,R4和R3的电流相等
U6中2点的电流方程
(Ui-un)/R4=(Un-Uo)/R3
U6中3点的电流方程
(Up/R6)+io=(Uo-Up) /R5
整理可得
Io=-Ui/R6(条件是R3/R4=R5/R6)
通过调节R6的阻值,消除运放的影响使得电流源输出稳定的电流
2、电流放大部分设计:
说明:
电压放大电路放大64倍运用了电压并联负反馈
虚短:
U2=U3=0.1V
虚断(U6-U2)/R7=(U2-0)/R10
R7=63K
R10=1K
带入公式得到
Au=Uo/Ui
=6.4//0.1
=64
集成运放的高增益特性和负反馈的使用使得电路的放大倍数比较准确
3、数字处理部分设计(单片机):
单片机最小系统原理图
A/D连接原理图
说明:
AD1674为单通道,12位并行输出A/D转换器,我们通过单片机向A/D写指令,让其工作在12位并行转换工作状态(I/O口足够用),量程选择为10V,12位输出接口的低八位接P2口;高四位,接P1口低四位,读数据时让P1与上0x0f,则A/D转换数据getdata=P1*256+P2;然后将数据转化为温度,并经过处理后由数码管显示。
4、显示部分:
说明:
我们将P0口接入两个八位锁存器74hc573,并用它作为数码管的驱动电路,一个控制段选,一个控制位选,并将使能端接地,控制锁存允许端来给4位共阴极八段数码管传送数据,动态扫描数码管,不断刷新,利用人眼的视觉暂留现象来显示数字。
全局仿真图:
说明:
考虑到美观简洁,此仿真图数字电路部分连接采用网络标签,没有用连接线,且protues软件中没有找到合适的八位模拟开关,所以图中只是一路温度检测的设计,程序是按照八路循环监测写的。
详细说明:
1、在热敏电阻两端加0.1mA恒流源(用运放实现),当周围温度发生变化时引起热敏电阻阻值的变化,同时引起热敏电阻两端电压的相应变化,通过运算放大电路将其电压信号放大,再由滤波电路(采用简单的LC无源滤波电路)滤掉高频信号,信号通过八位的模拟开关后,信号接到AD转换器上,由单片机向模拟开关发送指令选择模拟电路的路数,并向A/D转换器发送命令,将其转换成数字信号,经单片机数据处理后在显示器上显示温度信息,并可实现八个路温度的循环监测,键盘选择温度巡检仪的工作模式:循环监测八路温度,或动态监测一路温度(不断获取温度信息)。
2、计划量程为0~100摄氏度,温度精确到0.1摄氏度,我们采用AD1674,是单通道,12位高速AD转换器,设计一个1mA的恒流源加在PT100两端,由PT100的线性曲线图表可知,当温度为0摄氏度时,阻值为100欧,100摄氏度时,阻值为138欧,故取得的信号为0.1V~0.138V之间,经过64倍的运放放大器之后,电压信号变为6.4V~8.832V之间,AD参考电压为10V,故取得的步进数值在6.4/10*2^12~8.832/10*2^12之间,步进调整在1007次左右,用它显示步进为0.1的温度,误差很小,且误差分布有规律可循,应用单品机的软件矫正,采用分段标定的方法调整误差,试验后误差在会0.1摄氏度以内。
设计细节:
1、在热敏电阻两端加0.1mA恒流源(用运放实现),当周围温度发生变化时引起热敏电阻阻值的变化,同时引起热敏电阻两端电压的相应变化。
2、通过运算放大电路将其电压信号放大,再由滤波电路滤掉高频信号。
3、信号接到AD转换器上,单片机向A/D转换器发送命令,并选择转换的模拟信号的路数,并将其转换成数字信号。
3、数字信息经单片机数据处理后在数码管上显示温度信息,并可实现八个路温度的循环监测。
4、键盘可选择温度巡检仪的工作模式:循环监测八路温度,或动态监测一路温度(0.5s刷新一次)。
5、计划量程为0~100摄氏度,温度精确到0.1摄氏度。
6、细节:我们采用AD1674,是单通道,12位高速AD转换器,设计一个1mA的恒流源加在PT100两端,由PT100的线性曲线图表可知,当温度为0摄氏度时,阻值为100欧,100摄氏度时,阻值为138欧,故取得的信号为0.1V~0.138V之间,经过64倍的运放放大器之后,电压信号变为6.4V~8.832V之间,AD参考电压为10V,故取得的步进数值在6.4/10*2^12~8.832/10*2^12之间,步进调整在1007次左右,用它显示步进为0.1的温度,误差很小,且误差分布有规律可循,应用单片机的软件矫正,采用分段标定的方法调整误差,试验后误差在会0.1摄氏度以内。
设计结果及仿真分析:
仿真效果图(当温度为24摄氏度时温度显示24.0摄氏度,误差为0)
当温度为0摄氏度时,阻值为100欧,100摄氏度时,阻值为138欧,故取得的信号为0.1V~0.138V之间,经过64倍的运放放大器之后,电压信号变为6.4V~8.832V之间,AD参考电压为10V,故取得的步进数值在6.4/10*2^12~8.832/10*2^12之间,步进调整在1007次左右,用它显示步进为0.1的温度,误差很小,且误差分布有规律可循,应用单片机的软件矫正,采用分段标定的方法调整误差,试验后误差在会0.1摄氏度以内。
AD数值的获取:
低四位:getdatal=P2;
高四位:getdatah=P1& 0x0f
AD值=getdatah*256+getdatal
温度转换公式:
温度=(AD值-2650)/1.007-1
实验结果符合所期望的目标,误差.01摄氏度。实验发现,运放对模拟信号的放大倍数和AD的参考电压和精度之间有着必然的联系,不可盲目的取值,试验中放大倍数为64倍,AD参考电压为10V,精度为12位。
附设计程序:
温度巡检仪程序:
#include<reg51.h>
#include<intrins.h>
char codetable[]={0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,0x7f};
char codetable1[]={0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,0x7f,0x6f};
sbit a0=P3^5;
sbit a1=P3^6;
sbit a2=P3^7;
sbit dula=P3^0;
sbit wela=P3^1;
sbit k1=P3^3;
sbit k2=P3^4;
sbit sts=P1^4;
sbit ce=P1^5;
sbit rc=P1^6;
sbit light=P3^2;
unsigned inttemp,num,x,i,bai,shi,ge,d=1,d1;
double shu,v;
unsigned chargetdatal,getdatah;
void delay(inty)//延时函数
{
for(x=110;x>0;x--)
for(y;y>0;y--);
}
voidtimer0init()//定时器0初始化
{
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%6;
EA=1;
ET0=1;
TR0=0;
}
void ad()//AD转换
{
ce=1;
rc=0;
while(sts);
rc=1;
getdatal=P2;
getdatah=P1 & 0x0f;
shu=getdatah*256+getdatal;//数据处理
shu=(shu-2650)/1.007-1;
if(shu<=6 &shu>0)//软件矫正
shu=shu+3;
else if(shu<=16 &shu>6)
shu=shu+2;
else if(shu<=21 &shu>16)
shu=shu+1;
else if(shu<=85 &shu>=35)
shu=shu-1;
else if(shu<100 &shu>89)
shu=shu+1;
if(shu<0)//确定量程
shu=0;
else if(shu>999)
shu=0;
}
void next()//路数转换
{
i++;
if(i==8)
{
i=0;
}
switch(i)
{
case 0 :
{
a0=0;
a1=0;
a2=0;
}
break;
case 1 :
{
a0=1;
a1=0;
a2=0;
}
break;
case 2 :
{
a0=0;
a1=1;
a2=0;
}
break;
case 3 :
{
a0=1;
a1=1;
a2=0;
}
break;
case 4 :
{
a0=0;
a1=0;
a2=1;
}
break;
case 5 :
{
a0=1;
a1=0;
a2=1;
}
break;
case 6 :
{
a0=0;
a1=1;
a2=1;
}
break;
case 7 :
{
a0=1;
a1=1;
a2=1;
}
break;
}
}
void display(inttem)//数码管显示
{
bai=tem/100;
tem=tem-bai*100;
shi=tem/10;
ge=tem;
P0=0xff;
wela=1;
P0=0xfe;
wela=0;
P0=0x00;
dula=1;
P0=table1[bai];
dula=0;
delay(5);
P0=0xff;
wela=1;
P0=0xfd;
wela=0;
P0=0x00;
dula=1;
P0=table1[shi]|0x80;
dula=0;
delay(5);
P0=0xff;
wela=1;
P0=0xfb;
wela=0;
P0=0x00;
dula=1;
P0=table1[ge];
dula=0;
delay(5);
P0=0xff;
wela=1;
P0=0xf7;
wela=0;
P0=0x00;
dula=1;
P0=table[i];
dula=0;
delay(5);
}
void keyscan()//键盘扫描
{
if(k1==0 | k2==0)
{
delay(5);
if(k1==0)
{
while(!k1);
next();
num=0;
}
if(k2==0)
{
while(!k2);
d++;
if(d==100)
d=2;
if(d%2==1)
{
TR0=0;
light=0;
}
if(d%2==0)
{
TR0=1;
light=1;
}
}
}
}
void luinit()//A/D路数初始化
{
a0=0;
a1=0;
a2=0;
light=0;
}
void main()//主函数
{
luinit();
timer0init();
while(1)
{
keyscan();
ad();
display(shu);
}
}
void timer0() interrupt 1//定时器中断
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%6;
num++;
if(num==100)
{
num=0;
next();
}
}