资源描述
巡回检测报警控制系统设计
序
随着电子测量技术与计算机技术的发展,而对各种检测对象和大量的测试点,需要利用数据采集系统将多路被测量转换成数字量,在经过单片机或微型计算机进行数据处理,实现实时测控。
在工业生产中,往往也需要对各种生产过程参数进行控制,而要进行控制的前提条件是必须对各参数进行数据采集。数据采集系统一般具有定时采样(A/D转换)、数据转换、参数显示、超限报警等功能。
在本次课设中,将设计一个多路数据采集测控系统,采用单片机为核心器件,配合相应的外围电路、ADC0809模/数转换器、LED数码管及发光二极管等组成单片机数据采集系统。
第一部分 系统设计要求
一、设计的性质与目的
该设计是在我们学完《单片机原理及应用》和电子学相关课程的基础上,综合运用所学知识,进行单片机测控系统设计,进一步加强对所学知识的理解,使学生掌握单片机测控系统开发的方法、步骤,具备一定的设计能力、动手能力。
二、设计任务和要求
根据题目要求,设计一个单片机应用系统,完成相应的控制和显示功能。完成该单片机应用系统的硬件原理图,设计相应的控制软件,实现硬件及软件的调试。
三、巡回检测报警控制系统设计要求
设计一个多路数据采集测控系统,具有控制及显示功能:
1、对多路模拟信号进行采集,将采集到的电压值通过LED显示出来。
2、设置被测量的阈值,对被测量进行临控,当达到阈值时,启动报警(如指示灯)或启动相应的设备(如直流电机)。
3、键盘可以控制在LED上显示哪一路被测量的值。
第二部分 系统设计
一、设计思路
根据题目要求,程序需要实现以下几个功能:
1、可以通过LED显示电压值。
2、可以通过键盘控制当前显示何路电压。。
3、对采集来的电压值进行阈值判断,在超出范围的情况下启动相应的报警程序。
4、可以实时监控电压的变化。
有以上几种功能,可以知道程序中需要包括以下几个子程序及对应的功能:
1、A/D转换子程序,对四路模拟电压作循环转换。
2、阈值判断子程序,分别对四路电压进行对应的阈值判断。
3、报警子程序,当输入电压超出阈值范围时调用此程序,使程序可以输出不同的报警信号。
4、显示通道选择子程序,用于判断当前需要显示何路电压值。
5、电压值转换至显示用BCD码子程序,用于将A/D转换所得的电压值转换所得的电压值转换为对应BCD码,以使得LED显示的电压值更直观。
6、显示子程序,用于将转换后的BCD码在LED上显示出来,同时显
示所选择的通道数。
根据程序设计思路,可知需要用到的器件除8051外,还需要用A/D转换器件AD0809,可编程键盘显示接口HD7279,小键盘,LED数码管,LED发光二极管,以及其它附属器件。各器件间需要进行I/O扩展及硬件的联接。
二、硬件系统框图
系统核心是89C51与ADC0809组成的数据采集系统,外部控制输入与显示主要是通过HD7279来与8051进行数据的输入与输出,HD7279相当于一个外部中断,当有键按下时。HD7279向CPU提出中断,80C51响应中断,读入键盘数据,做出相应的控制反应。实现了键盘间接控制和向CPU输入信号的目的。同时也会输出显示指令,让HD7279控制各数码管,从而得到所要的显示。
三、软件系统组成框图
四、硬件原理图(连线图)
注:P3.4接LED10作为高电平报灯,P3.5接LED9作为低电平报警灯。
注:在实验之前,应将8单元的U7(7406)和U6(74LS245)芯片取下,因7279已经有直接驱动数码管的能力,如果另外放置驱动芯片,反而会影响数码管的显示效果。
五、子程序设计与调试
1、A/D转换子程序(带报警)[IN0]
①.相关知识
模/数转换器ADC0809的认识
虽然单片机可以对各种数字数据做快速而精确的处理,但是人类在日常生活中所遇到的各种物理量(例如温度、亮度、质量)都是模拟的,因此若令单片机处理模拟信号,必须将模拟信号转换成数字信号再送入单片机。
A/D转换器(analog to digital converter)的功能是将输入的模拟信号转换成数字信号输出。本次课设采用ADC0809.
8位A/D转换器芯片ADC0809
ADC0809是典型的8位8通道逐次逼近式A/D转换器,采用CMOS工艺制造。
ADC0809芯片为28引脚双列直插式封装,其引脚排列见下图。
(1)IN7~IN0:模拟量输入通道。(2)ADDA、ADDB、ADDC:模拟通道地址线。(3)ALE:地址锁存信号。(4)START:转换启动信号。
(5)D7~D0:数据输出线。(6)OE:输出允许信号。(7)CLK:时钟信号。
ADC0809的内部逻辑结构如下图所示。
③. 程序流程图
④.程序调试及说明
ADC0809是8位逐次逼近型A/D转换器,带8个模拟量输入通道,芯片内带通道地址译码锁存器,输出带三态数据锁存器,启动信号为脉冲启动方式,每一通道的转换大约100us。因此模拟量转化为数字量不能马上输出,转换过程要延时。
如:delay(10)
void delay(unsigned int t)
{
unsigned int i;
for(i=0;i<t;i++);
}
结果说明:模拟电压值可以通过数字万用表测出,然后与LED显示经转换后的值做比较,误差小于0.2伏即可。如果某一路电压超过4伏,则显示高报警(P3.4)如果某一路电压低于1伏,则显示低报警(P3.5)。
2、键盘显示子程序
①.相关知识
②. 电路原理图
③.程序结果说明
初始显示为 0000087;
按下“1”时,显示111111;按下“2”时,显示222222;
按下“3”时,显示333333;按下“4”时,显示444444;
按下“5”时,显示555555;按下“6”时,显示666666;
按下“7”时,显示777777;按下“8”时,显示888888;
按下“9”时,显示999999;按下“0”时,显示000000;
④.程序流程图
五、总程序
1、程序软件流程图
2、总程序调试及说明
数码显示不能实时跟随模拟电压的变化,当电压改变时,需要重新运行程序才能显示变化后的电压值,解决办法是改变主函数中程序的运行方式,改为无条件的死循环。而锁程序的死循环必需嵌套在主函数中的无条件的死循环内,只有这样才能实现功能。
程序运行结果说明如下:
按下1时,显示1通道、A、-及其电压值;
按下2时,显示2通道、b、-及其电压值;
按下3时,显示3通道、C、-及其电压值;
按下4时,显示4通道、d、-及其电压值;
按下0时,锁程序;
按下#时,解锁程序,并保持上一个按键状态;
如果电压值超过4伏特,则LED10亮;
如果电压值低于1伏特,则LED9亮;
改变输入电压的值,电压显示能实时跟踪输入电压的值而变化,并在LED上显示。
第三部分 收获、体会及改进建议
通过本次的单片机课程设计,使我们第一次把硬件与软件结合起来开发一个完整的系统,不但把书本上的理论知识与实际操作相结合,而且也提高了我们的动手能力,是一次非常好的宝贵的锻炼机会。
本次课程设计,使我对单片机系统有了更深的了解,并能将所学到的知识用于实践,灵活应用单片机中断,包括定时器中断和外部中断。对A/D转换的应用——ADC0809芯片,以及HD7279控制键盘的显示,基本掌握并熟悉。
对于单片机学习的收获与体会具体如下:
1.在程序设计之前,要对所用单片机的内部结构有一个系统的了解,
知道该单片机片内有哪些资源及其能实现的功能。
2.设计程序采要有一个清晰的思路和一个完整的软件流程图.
3.设计程序时,不能企图一次就将整个程序设计好,“由子程序到总程序,反复修改,不断改进"是程序设计的必经之路. 采用子程序设计,可以使程序有条理,简洁清楚。
4.要养成注释程序的好习惯,一个程序的完美与否不仅仅是实现功能,还应该直观,便于理解,同时也为资料的保存和交流提供了方便.
5.在设计程序过程中会遇到很多问题,我们应该将每次遇到的问题记录下来,并分析清楚,以免下次再碰到同样的问题。
建议如下:
该系统是对四路模拟电压进行采样监控,如果要是硬件条件允许的条件下,可在此基础上扩展至八路模拟电压的采样监控;还可以加入变阈值电压的子程序及循环显示四路模拟电压值的子程序;还有当高报警时,将数据锁存一定时间让人们知道便于采取防备措施;在显示上也可以采用hd61202液晶显示。
第四部分 参考书目
一、《单片机的C语言应用程序设计》
马忠梅、籍顺心、张凯、马岩编著 北京航空航天大学出版社
二、《单片机C语言编程与实例》
赵亮、侯国锐著 人民邮电出版社
三、《C程序设计》
谭浩强著 清华大学出版社
附录:
1、A/D转换子程序(带报警)[IN0]
#include <reg51.h>
#include <absacc.h>
unsigned char chADData[20];
unsigned char ADC(unsigned char channel);
void AD();
void delay(unsigned int t);
void init();
sbit P3_4=P3^4;
sbit P3_5=P3^5;
unsigned int timecount=0;
unsigned char xdata *pADAdrr;
void time0int();
main()
{ init();
AD();
}
void AD()
{
int i;
do
{
for(i=0;i<1;i++)
{ chADData[i]=ADC(i);
P1=chADData[i];
if(chADData[i]>0xcc)
P3_4=0;
else P3_4=1;
if(chADData[i]<0x33)
P3_5=0;
else P3_5=1;
}
}while(1);
}
void init()
{ TMOD=0x01;
TH0=0x3C;
TL0=0xB0;
ET0=1;
TR0=1;
EA=1;
}
void time0int() interrupt 1 using 1
{ TH0=0x3C;
TL0=0xB0;
timecount++;
}
unsigned char ADC(unsigned char channel)
{
unsigned char chADResult;
pADAdrr=0x0800+channel;
*pADAdrr=0;
delay(10);
chADResult=*pADAdrr;
return(chADResult);
}
void delay(unsigned int t)
{
unsigned int i;
for(i=0;i<t;i++);
}
2、键盘显示子程序
#include <reg51.h>
#define CMD_RESET 0xa4
#define CMD_TEST 0xbf
#define DECODE0 0x80
#define DECODE1 0xc8
#define CMD_READ 0x15
#define UNDECODE 0x90
#define RTL_CYCLE 0xa3
#define RTR_CYCLE 0xa2
#define RTL_UNCYL 0xa1
#define RTR_UNCYL 0xa0
#define ACTCTL 0x98
#define SEGON 0xe0
#define SEGOFF 0xc0
#define BLINKCTL 0x88
void init();
void keyint();
void long_delay(void);
void short_delay(void);
void write7279(unsigned char cmd, unsigned char dta);
unsigned char read7279(unsigned char command);
void send_byte(unsigned char out_byte);
unsigned char receive_byte(void);
void display();
//*** I/O ***
sbit cs=P1^0;
sbit dat=P1^1;
sbit clk=P1^2;
sbit key=P3^2;
//****** HD7279A ******
unsigned char chKey;
bit bNewKey;
unsigned char dispdata[6]={7,8,0,0,0,0};
main()
{
unsigned char i;
bit bt;
bt=dat;
init();
bNewKey=0;
display();
while(1)
{
if(bNewKey)
{
for(i=0;i<6;i++)
{
dispdata[i]=chKey;
}
display();
bNewKey=0;
}
}
}
void init()
{
PX0=0; /*外部中断0优先级*/
IT0=0; /*外部中断0,低电平触发*/
IE0=0; /*外部中断0中断申请标志位*/
EX0=1; /*允许外部中断0*/
EA=1;
send_byte(CMD_RESET);
}
//1:0x04;2:0x05;3:0x06;4:0x0c;5:0x0d;6:0x0e;7:0x14;8:0x15;9:0x0x16;*:0x1c;0:0x1d;#:0x1e
void keyint() interrupt 0 using 1
{
unsigned char temp;
temp=read7279(0x15);
switch(temp)
{
case 0x04:
chKey=3;
break;
case 0x05:
chKey=2;
break;
case 0x06:
chKey=1;
break;
case 0x0c:
chKey=6;
break;
case 0x0d:
chKey=5;
break;
case 0x0e:
chKey=4;
break;
case 0x14:
chKey=9;
break;
case 0x15:
chKey=8;
break;
case 0x16:
chKey=7;
break;
case 0x1d:
chKey=0;
break;
case 0x1c:
chKey=10;
break;
case 0x1e:
chKey=11;
break;
}
bNewKey=1;
}
void display()
{
unsigned char j;
for(j=0;j<6;j++)
{
write7279((0x80+j),dispdata[j]);
}
}
void send_byte( unsigned char out_byte)
{
unsigned char i;
// EA=0;
clk=0;
long_delay();
for (i=0;i<8;i++)
{
if (out_byte&0x80)
{
dat=1;
}
else
{
dat=0;
}
clk=1;
short_delay();
clk=0;
short_delay();
out_byte=out_byte*2;
}
dat=0;
// EA=1;
}
unsigned char receive_byte(void)
{
unsigned char i, in_byte;
dat=1; //
long_delay();
for (i=0;i<8;i++)
{
clk=1;
short_delay();
in_byte=in_byte*2;
if (dat)
{
in_byte=in_byte|0x01;
}
clk=0;
short_delay();
}
dat=0;
return (in_byte);
}
void long_delay(void)
{
unsigned char i;
for (i=0;i<0x30;i++);
}
void short_delay(void)
{
unsigned char i;
for (i=0;i<8;i++);
}
void write7279(unsigned char cmd, unsigned char dta)
{
cs=0;
long_delay();
send_byte(cmd);
send_byte(dta);
cs=1;
}
unsigned char read7279(unsigned char command)
{
cs=0;
send_byte(command);
return(receive_byte());
cs=1;}
3、总程序及注释
#include <reg51.h>
#include <absacc.h> //绝对地址访问头文件
unsigned char chADData[8];//存放转换结果的数组
unsigned char ADC(unsigned char channel); //转换程序
void AD();//开启转换及报警程序
void delay(unsigned int t); //短延时程序
unsigned char xdata *pADAdrr;
#define CMD_RESET 0xa4 //复位命令
#define CMD_TEST 0xbf //测试命令
#define DECODE0 0x80 //译码方式0
#define DECODE1 0xc8 //译码方式1
#define CMD_READ 0x15 //读键盘命令
#define UNDECODE 0x90 //非译码方式
#define RTL_CYCLE 0xa3 //循环左移
#define RTR_CYCLE 0xa2 //循环右移
#define RTL_UNCYL 0xa1 //左移
#define RTR_UNCYL 0xa0 //右移
#define ACTCTL 0x98 //消隐控制
#define SEGON 0xe0 //段点亮
#define SEGOFF 0xc0 //段关闭
#define BLINKCTL 0x88 //闪烁控制
void init(); //初始化程序
void keyint(); //键盘中断服务程序
void long_delay(void); //长延时程序
void short_delay(void); //短延时程序
void write7279(unsigned char cmd, unsigned char dta); // 往HD7279A中写命令
unsigned char read7279(unsigned char command);// 从HD7279A中读键值
void send_byte(unsigned char out_byte); //往HD7279A中写入一个字节
unsigned char receive_byte(void); //从HD7279A中读出一个字节
void display();//显示程序
void dispcode(unsigned char chData); //形成显示代码
//*** I/O ***
sbit cs=P1^0; //片选信号接P1.0
sbit dat=P1^1; //DATA信号接P1.1
sbit clk=P1^2; //CLK信号接P1.2
sbit key=P3^2; //键盘中断信号接P3.2
sbit P3_4=P3^4;
sbit P3_5=P3^5;
//****** HD7279A ******
unsigned int chtemp[6]={0,0,0,0,0,0},chKey,keep,in;
unsigned char dispdata[6];
main()
{
unsigned char i;
init();
display();
while(1)
{
AD();
while(in){};//死循环
switch(chKey)
{
case 1:
chtemp[5]=chKey;
chtemp[4]=0x0a;//显示A(译码方式1)
chtemp[3]=0x0a;//显示-(译码方式0)
dispcode(chADData[0]);
break;
case 2:
chtemp[5]=chKey;
chtemp[4]=0x0b;//显示b
chtemp[3]=0x0a;
dispcode(chADData[1]);
break;
case 3:
chtemp[5]=chKey;
chtemp[4]=0x0c;//显示C
chtemp[3]=0x0a;
dispcode(chADData[2]);
break;
case 4:
chtemp[5]=chKey;
chtemp[4]=0x0d;//显示d
chtemp[3]=0x0a;
dispcode(chADData[3]);
break;
}
for(i=0;i<6;i++) //在显示器中显示出键值
{
dispdata[i]=chtemp[i];
}
display();//显示
}
}
void init()
{
PX0=0; /*外部中断0优先级*/
IT0=0; /*外部中断0,低电平触发*/
IE0=0; /*外部中断0中断申请标志位*/
EX0=1; /*允许外部中断0*/
EA=1; /*开总中断*/
send_byte(CMD_RESET);//HD7279A复位
}
//显示程序
void display()
{
unsigned char j;
for(j=0;j<6;j++)
{
if((j<3||j==4)||(j==5))
write7279((0xc8+j),dispdata[j]);//译码方式1
else write7279((0x80+j),dispdata[j]);//译码方式0
}
}
//1:0x06;2:0x05;3:0x04;4:0x0e;5:0x0d;6:0x0c;7:0x16;8:0x15;9:0x14;*:0x1e;0:0x1d;#:0x1c
void keyint() interrupt 0 using 1
{
unsigned char temp;
temp=read7279(0x15); //读出键值
switch(temp)
{
case 0x06:
chKey=1;
break;
case 0x05:
chKey=2;
break;
case 0x04:
chKey=3;
break;
case 0x0e:
chKey=4;
break;
case 0x1d://锁
in=1;
keep=chKey;
break;
case 0x1c:
in=0;//解锁
chKey=keep;//保持上一个按键状态
break;
}
}
//显示一个3位数,将8位数据转换成AD采样电压值显示出来。参数为AD采样值
void dispcode(unsigned char chData)
{
unsigned int nTemp,t;
float fAdreault;
fAdreault=((float)chData/255)*5;//将AD采样值转换成对应的电压值
nTemp=fAdreault*100; //先转换成整数,变成0~500之间
chtemp[2]=nTemp/100|0x80; //得到百位数
t=nTemp/100;
chtemp[1]=(nTemp-t*100)/10; //得到十位数
chtemp[0]=nTemp-t*100-chtemp[1]*10; //得到个位数
}
//往HD7279A中写入一个字节.
void send_byte( unsigned char out_byte)
{
unsigned char i;
// EA=0;
clk=0;//CLK变低电平
long_delay();
for (i=0;i<8;i++)
{
if (out_byte&0x80)//得到要输出的数据位,高位在先
{
dat=1;
}
else
{
dat=0;
}
clk=1; //CLK变高电平,这一位写入HD7279A寄存器
short_delay();//延时
clk=0;//CLK变低,为下一次写入数据作准备
short_delay();//延时
out_byte=out_byte*2;//数据左移一位
}
dat=0;
// EA=1;
}
//从HD7279A中读出一个字节.
unsigned char receive_byte(void)
{
unsigned char i, in_byte;
unsigned char intemp;
dat=1; //DATA=1;单片机要读入引脚状态先输出1。
long_delay();
for (i=0;i<8;i++)
{
clk=1; //时钟CLK变高电平,它变成高电平以后,HD7279延时T6才输出数据
short_delay();
in_byte=in_byte*2;//读入数据左移一位,因为是高位先出
intemp=P1;
dat=(intemp&0x04);
if (dat)//读DATA引脚的状态
{
in_byte=in_byte|0x01;//读入数据,数据引脚接在P1.0
}
clk=0;//CLK变低电平
short_delay(); //延时T7
}
dat=0;
return (in_byte);//返回键值
}
void long_delay(void)
{
unsigned char i;
for (i=0;i<0x30;i++);
}
void short_delay(void)
{
unsigned char i;
for (i=0;i<8;i++);
}
//往HD7279A中写入一个双字节命令
void write7279(unsigned char cmd, unsigned char dta)
{
cs=0;
long_delay();
send_byte(cmd);//写入命令
send_byte(dta);//写入数据
cs=1;
}
//从HD7279A中读出键值。
unsigned char read7279(unsigned char command)
{
cs=0;
send_byte(command); //写入命令
return(receive_byte()); //读取键值
cs=1;
}
//*** ***
void AD()
{
switch(chKey)
{
case 1:
chADData[0]=ADC(0);
P1=chADData[0];
if(chADData[0]>0xcc)//上阈值判断
{ P3_4=0;} //报警
展开阅读全文