多路监控报警系统单片机课程设计.docx
《多路监控报警系统单片机课程设计.docx》由会员分享,可在线阅读,更多相关《多路监控报警系统单片机课程设计.docx(31页珍藏版)》请在冰豆网上搜索。
多路监控报警系统单片机课程设计
单片机课程设计
——多路监控报警系统
多路监控报警系统
一、实验目的
1.了解A/D芯片TLC0809转换性能及编程方式。
2.把握A/D转换器与单片机的接口方式
3.学会利用A/D转换器进行电压信号搜集。
二、设计任务及要求
利用串行模/数转换芯片TLC080九、SST89E58及液晶显示器,设计完成一个数字电压多路监控报警系统。
要求:
数字电压多路监控报警系统可测量0~5V输入电压,电压值通过液晶连番显示,并依照设置的限定值对输入超出额度的路端警报提示。
三、工作原理及设计思路
多路监控报警系统的设计由A/D转换、数据处置及显示操纵等组成。
A/D转换由集成电路TLC0809完成,利用TLC0809将模拟电压转换为数字量,经单片机将数字量转换成对应的电压值,并通过液晶显示输出。
四、系统特点
本系统能够每一路独立设置最高最低的电压值,并对每一路电压进行监控报警,对超出范围内的电路显示对应路值,并用LED灯和蜂鸣器表示不同的路值。
五、硬件电路设计及原理
一、ADC0809
(1)、ADC0809管脚图及时序图:
该ADC0809数据搜集部份是单片CMOS器件,它具有8位模拟数字转换器,8通道多路复用器和微处置器兼容操纵逻辑。
8位A/D转换器采纳逐次逼近作为转换技术。
依照时序电路的分析,能够完成单片机编程。
该系统在工作时,单片机将产生串行时钟,并按时序发送和同意数据位。
由上图可知,ADC0809由一个8路模拟开关、一个地址锁存与译码器、一个A/D转换器和一个三态输出锁存器组成。
多路开关可选通8个模拟通道,许诺8路模拟量分时输入,共用A/D转换器进行转换。
三态输出锁器用于锁存A/D转换完的数字量,当OE端为高电平常,才能够从三态输出锁存器取走转换完的数据。
IN0-IN7:
8条模拟量输入通道ADC0809对输入模拟量要求:
信号单极性,电压范围是0-5V,假设信号过小,必需进行放大;输入的模拟量在转换进程中应该维持不变,如假设模拟量转变太快,那么需在输入前增加采样维持电路。
地址输入和操纵线:
4条ALE为地址锁存许诺输入线,高电平有效。
当ALE线为高电平常,地址锁存与译码器将A,B,C三条地址线的地址信号进行锁存,经译码后被选中的通道的模拟量进转换器进行转换。
A,B和C为地址输入线,用于选通IN0-IN7上的一路模拟量输入。
数字量输出及操纵线:
11条ST为转换启动信号。
当ST上跳沿时,所有内部寄放器清零;下跳沿时,开始进行A/D转换;在转换期间,ST应维持低电平。
EOC为转换终止信号。
当EOC为高电平常,说明转换终止;不然,说明正在进行A/D转换。
OE为输出许诺信号,用于操纵三条输出锁存器向单片机输出转换取得的数据。
OE=1,输出转换取得的数据;OE=0,输出数据线呈高阻状态。
D7-D0为数字量输出线。
CLK为时钟输入信号线。
因ADC0809的内部没有时钟电路,所需时钟信号必需由外界提供,通常利用频率为500KHZ,VREF(+),VREF(-)为参考电压输入。
(2)、ADC0809应用说明ADC0809内部带有输出锁存器,能够与AT89S51单片机直接相连,初始化时,使ST和OE信号全为低电平,送要转换的哪一通道的地址到A,B,C端口上,在ST端给出一个至少有100ns宽的正脉冲信号,是不是转换完毕,咱们依照EOC信号来判定,当EOC变成高电平常,这时给OE为高电平,转换的数据就输出给单片机了。
二、SST89E58RD
(1)、SST89E58RD管脚图:
3、1602液晶
引脚功能说明
第1脚:
VSS为电源地,接GND。
第2脚:
VDD接5V正电源。
第3脚:
VL为液晶显示器对照度调整端,接正电源时对照度最弱,接地电源时对照度最高。
第4脚:
RS为寄放器选择,高电平常选择数据寄放器、低电平常选择指令寄放器。
第5脚:
RW为读写信号线,高电平常进行读操作,低电平常进行写操作。
当RS和RW一起为低电平常能够写入指令或显示地址,当RS为低电平RW为高电平常能够读忙信号,当RS为高电平RW为低电平常能够写入数据。
第6脚:
E端为使能端,当E端由高电平跳变成低电平常,液晶模块执行命令。
第7~14脚:
D0~D7为8位双向数据线。
第15脚:
BLA背光电源正极(+5V)输入引脚。
第16脚:
BLK背光电源负极,接GND。
序号
指令
RS
R/W
D7
D6
D5
D4
D3
D2
D1
D0
1
清显示
0
0
0
0
0
0
0
0
0
1
2
光标返回
0
0
0
0
0
0
0
0
1
*
3
置输入模式
0
0
0
0
0
0
0
1
I/D
S
4
显示开/关控制
0
0
0
0
0
0
1
D
C
B
5
光标或字符移位
0
0
0
0
0
1
S/C
R/L
*
*
6
置功能
0
0
0
0
1
DL
N
F
*
*
7
置字符发生存贮器地址
0
0
0
1
字符发生存贮器地址
8
置数据存贮器地址
0
0
1
显示数据存贮器地址
9
读忙标志或地址
0
1
BF
计数器地址
10
写数到CGRAM或DDRAM)
1
0
要写的数据内容
11
从CGRAM或DDRAM读数
1
1
读出的数据内容
指令1:
清显示,指令码01H,光标复位到地址00H位置指令2:
光标复位,光标返回到地址00H指令3:
光标和显示模式设置I/D:
光标移动方向,高电平右移,低电平左移S:
屏幕上所有文字是不是左移或右移。
高电平表示有效,低电平那么无效指令4:
显示开关操纵。
D:
操纵整体显示的开与关,高电平表示开显示,低电平表示关显示C:
操纵光标的开与关,高电平表示有光标,低电平表示无光标B:
操纵光标是不是闪烁,高电平闪烁,低电平不闪烁指令5:
光标或显示移位S/C:
高电平常移动显示的文字,低电平常移动光标指令6:
功能设置命令DL:
高电平常为4位总线,低电平常为8位总线N:
低电平常为单行显示,高电平常双行显示F:
低电平常显示5x7的点阵字符,高电平常显示5x10的点阵字符指令7:
字符发生器RAM地址设置指令8:
DDRAM地址设置指令9:
读忙信号和光标地址BF:
为忙标志位,高电平表示忙,现在模块不能接收命令或数据,若是为低电平表示不忙。
指令10:
写数据指令11:
读数据。
读状态
输入
RS=L,R/W=H,E=H
输出
D0—D7=状态字
写指令
输入
RS=L,R/W=L,D0—D7=指令码,E=高脉冲
输出
无
读数据
输入
RS=H,R/W=H,E=H
输出
D0—D7=数据
写数据
输入
RS=H,R/W=L,D0—D7=数据,E=高脉冲
输出
无
五、软件设计
主程序设计:
1)A/D转换程序
每次5组电压值组成一个数组,数组中的值为AD进入值50次的平均值。
2)数据处置程序:
能够说是整个程序设计的最难点,数据处置显示的电压值计算公式:
V=(A*500)/255,(其中A为经0809转换后所得的数字量)如此使得计算出来的数值为整型,幸免了浮点数计算复杂的缺点,在以后的显示中加入小数点即可。
子程序设计:
由于C语言的子程序功能比较壮大,因此本程序挪用相关子程序,减少了很多编程的繁琐,相关子程序功能如下所示:
函数功能:
400ms延时延时函数功能:
5ms延时函数功能:
1602A按指定位置显示一个字符
函数功能:
1602A初始化函数功能:
1602A读状态函数功能:
1602A写指令
函数功能:
1602A读数据函数功能:
1602A写数据作用:
AD0809通道选择采样值
流程图:
否
是
六、系统C程序
依照上述软/硬件的设计,编写好的源程序如下:
/******************************************************************
**ADC0809的多路电压监视器
**ADC0809+1602LCD+单片机
**于萱格
******************************************************************/
#include<>
#include<>
#include<>
#include<>
#include<>
#defineSYSTEM_OSC1A1F1F1F1F1F1F1F1F1F1A1A1F1F1F1F1F1A1A1F1F1A1A1A1A1F1F1F1F1F1A1A1F1F1F1F1F1A1A1F1F1A0F0F1A1A1A1A1A0C0F0C1F1A1A0C1A1F1A1A1A0C0F0F0C1A0F0F1A1A1F1A1A1A1F1A1A1A1A1A1A1A1F1A1A1A1F1A1A1A1A1A1A1A1A1A0F;
DisplayOneChar(6,1,uctech[sw]);
DisplayOneChar(7,1,uctech[gw]);
if(func>5)break;
}
;
DisplayOneChar(6,1,uctech[sw]);
DisplayOneChar(7,1,uctech[gw]);
if(func_ok==1)
{
LCM_WriteCommand(0x01,1);;
DisplayOneChar(7,1,uctech[sw]);
DisplayOneChar(8,1,uctech[gw]);
}
}
}
voidEXF0()interrupt0using0//ex0入口
{
EA=0;
LCM_WriteCommand(0x01,1);//显示清屏
Delay400Ms();
if(func==10)func=0;
elsefunc++;
EA=1;
}
voidEXF1()interrupt2using0//ex1入口
{
EA=0;
LCM_WriteCommand(0x01,1);//显示清屏
Delay400Ms();
if(func_ok==1)func_ok=0;
elsefunc_ok++;
EA=1;
}
charB_UP_CHECK(void)//向上按键去抖
{
if(B_UP==0)
{
Delay5Ms();
Delay5Ms();
{
if(B_UP==0)
{
return1;
}
}
}
return0;
}
charB_DOWN_CHECK(void)//向下按键去抖
{
if(B_DOWN==0)
{
Delay5Ms();
Delay5Ms();
{
if(B_DOWN==0)
{
return1;
}
}
}
return0;
}
/*ADC0809的初始化*/
voidinit(void)
{
ST=0;
OE=0;
}
/********************************************************/
/*参数名:
AD(uintM)
/*作用:
AD0809通道选择采样值
/*输入参数:
CH0,CH1,CH2,unit型
/*输出参数:
选择参数的电压值,发在AD_DATA处
/********************************************************/
voidAD(uintM)
{
ST=0;
if(M==0)
{A=1;b=1;C=0;}
elseif(M==1)
{A=0;b=0;C=1;}
elseif(M==2)
{A=1;b=0;C=1;}
elseif(M==3)
{A=0;b=1;C=1;}
elseif(M==4)
{A=1;b=1;C=1;}
Delay(10);
ST=1;
Delay(10);
ST=0;
while(EOC==0);
OE=1;
AD_DATA=P1;
OE=0;
}
/*AD0809所用的延时*/
voidDelay(uintm)
{
while(--m);
}
voidInitialSound(void)
{
BeepIO=0;
Sound_Temp_TH1=(65535-(1/1200)*SYSTEM_OSC)/256;//计算TL1应装入的初值(10ms的初装值)
Sound_Temp_TL1=(65535-(1/1200)*SYSTEM_OSC)%256;//计算TH1应装入的初值
TH1=Sound_Temp_TH1;
TL1=Sound_Temp_TL1;
TMOD=0x11;
ET0=1;
ET1=0;
TR0=0;
TR1=0;
EA=1;
}
voidBeepTimer0(void)interrupt1//音符发生中断
{
00
}
voidPlay(unsignedchar*Sound,unsignedcharSignature,unsignedOctachord,unsignedintSpeed)
{
unsignedintNewFreTab[12];//新的频率表
unsignedchari,j;
unsignedintPoint,LDiv,LDiv0,LDiv1,LDiv2,LDiv4,CurrentFre,Temp_T,SoundLength;
unsignedcharTone,Length,SL,SH,SM,SLen,XG,FD;
for(i=0;i<12;i++)//根据调号及升降八度来生成新的频率表
{
j=i+Signature;
if(j>11)
{
j=j-12;
NewFreTab[i]=FreTab[j]*2;
}
else
NewFreTab[i]=FreTab[j];
if(Octachord==1)
NewFreTab[i]>>=2;
elseif(Octachord==3)
NewFreTab[i]<<=2;
}
SoundLength=0;
while(Sound[SoundLength]!
=0x00)//计算歌曲长度
{
SoundLength+=2;
}
Tone=Sound[Point];
Length=Sound[Point+1];//读出第一个音符和它时时值
LDiv0=12000/Speed;//算出1分音符的长度(几个10ms)
LDiv4=LDiv0/4;//算出4分音符的长度
LDiv4=LDiv4-LDiv4*SOUND_SPACE;//普通音最长间隔标准
TR0=0;
TR1=1;
while(Point{
if(B_UP_CHECK()||B_DOWN_CHECK())break;
SL=Tone%10;//计算出音符
SM=Tone/10%10;//计算出高低音
SH=Tone/100;//计算出是否升半
CurrentFre=NewFreTab[SignTab[SL-1]+SH];//查出对应音符的频率
if(SL!
=0)
{
if(SM==1)CurrentFre>>=2;//低音
if(SM==3)CurrentFre<<=2;//高音
Temp_T=65536-(50000/CurrentFre)*10/(/SYSTEM_OSC);//计算计数器初值
Sound_Temp_TH0=Temp_T/256;
Sound_Temp_TL0=Temp_T%256;
TH0=Sound_Temp_TH0;
TL0=Sound_Temp_TL0+12;//加12是对中断延时的补偿
}
SLen=LengthTab[Length%10];//算出是几分音符
XG=Length/10%10;//算出音符类型(0普通1连音2顿音)
FD=Length/100;
LDiv=LDiv0/SLen;//算出连音音符演奏的长度(多少个10ms)
if(FD==1)
LDiv=LDiv+LDiv/2;
if(XG!
=1)
if(XG==0)//算出普通音符的演奏长度
if(SLen<=4)
LDiv1=LDiv-LDiv4;
else
LDiv1=LDiv*SOUND_SPACE;
else
LDiv1=LDiv/2;//算出顿音的演奏长度
else
LDiv1=LDiv;
if(SL==0)LDiv1=0;
LDiv2=LDiv-LDiv1;//算出不发音的长度
if(SL!
=0)
{
TR0=1;
for(i=LDiv1;i>0;i--)//发规定长度的音
{
while(TF1==0);
TH1=Sound_Temp_TH1;
TL1=Sound_Temp_TL1;
TF1=0;
}
}
if(LDiv2!
=0)
{
TR0=0;BeepIO=0;
for(i=LDiv2;i>0;i--)//音符间的间隔
{
while(TF1==0);
TH1=Sound_Temp_TH1;
TL1=Sound_Temp_TL1;
TF1=0;
}
}
Point+=2;
Tone=Sound[Point];
Length=Sound[Point+1];
}
BeepIO=0;
}
/****************************1602A写数据函数**************************/
/*函数原型:
voidLCM_WriteData(ucharWDLCM)
/*函数功能:
1602A写数据
/*输入参数:
要写入的数据
/*输出参数:
无
/*挪用模块:
/*成立时刻:
2005/11/14
/*作者:
站长
/**********************************************************************/
voidLCM_WriteData(ucharWDLCM)
{
LCM_ReadStatus();//检测忙
LCM_Data=WDLCM;
LCM_RS=1;
LCM_RW=0;
LCM_E=0;//假设晶振速度太高能够在这后加小的延时
LCM_E=0;//延时
LCM_E=1;
}
/****************************1602A写指令函数**************************/
/*函数原型:
voidLCM_WriteCommand(ucharWCLCM,BuysC)
/*函数功能:
1602A写指令
/*输入参数:
要写入的指令
/*输出参数:
无
/*挪用模块:
/*成立时刻:
2005/11/14
/*作者:
站长
/**********************************************************************/
voidLCM_WriteCommand(ucharWCLCM,BuysC)//BuysC为0时忽略忙检测
{
if(BuysC)LCM_ReadStatus();//依照需要检测忙
LCM_Data=WCLCM;
LCM_RS=0;
LCM_RW=0;
LCM_E=0;
LCM_E=0;
LCM_E=1;
}
/****************************1602A读数据函数**************************/
/*函数原型:
ucharLCM_ReadData(void)
/*函数功能:
1602A读数据
/*输入参数:
无
/*输出参数:
1602A返回的数据
/*挪用模块:
/*成立时刻:
2005/11/14
/*作者:
站长
/**********************************************************************/
ucharLCM_ReadData(void)
{
LCM_RS=1;
LCM_RW=1;
LCM_E=0;
LCM_E=0;
LCM_E=1;
return(LCM_Data);
}
/****************************1602A读状态函数**************************/
/*函数原型:
ucharLCM_ReadData(void)
/*函数功能:
1602A读状态
/*输入参数:
无
/*输出参数:
1602A返回的状态
/*挪用模块:
/*成立时刻:
2005/11/14
/*作者:
站长
/**********************************************************************/
ucharLCM_ReadStatus(void)
{
LCM_Data=0xFF;
LCM_RS=0;
LCM_RW=1;
LCM_E=0;
LCM_E=0;
LCM_E=1;
while(LCM_Data&0x80);//检测忙信号
return(LCM_Data);
}
/****************************1602A初始化函数**************************/
/*函数原型:
voidLCM_Init(void)
/*函数功能:
1602A初始化
/*输入参数:
无
/*输出参数:
无
/*挪