数据采集器的设计实验报告.docx
《数据采集器的设计实验报告.docx》由会员分享,可在线阅读,更多相关《数据采集器的设计实验报告.docx(25页珍藏版)》请在冰豆网上搜索。

数据采集器的设计实验报告
数据采集器的设计实验报告
————————————————————————————————作者:
————————————————————————————————日期:
单片机项目实践报告
数据采集器的设计
班级:
计应102
姓名:
潘琴
学号:
1008143233
一、项目名称:
数据采集器的设计
二、项目目的:
了解A/D转换的基本概念、并行A/D转换芯片ADC0809的内部结构、与单片机的接口方式,在此基础上完成数据采集器的设计与调试。
以及SPI总线的串行A/D转换芯片TLC549、串行D/A转换器件TLC5615,完成数字电压表、信号发生器的设计。
最后是用单片机的定时器/计数器实现频率与周期的测量,将被测信号的周期或频率在液晶屏上显示出来。
三、项目过程:
1、数据采集器的设计
1、1、ADC0808/0809的内部结构
STARTCLK
IN0
IN1
IN2
IN3
IN4
IN5
IN6
IN7
EOC
A
B
C
ALE
Vcc
GND
D0
D1
D2
D3
D4
D5
D6
D7
Vref(+)Vref(—)OE
图1、ADC0808/0809内部逻辑结构
1、2、数据采集器的设计过程
在Proteus环境下,用ADC0808设计一个数据采集器,通过串行口与上位机相连,如果串行口收到了上位机的采集命令(0x41),就将8路模拟量转换为数字量,通过串行口以ASCII码的形式发送给上位机.
1、2、1、硬件电路
如图所示,ADC0808的时钟信号CLK由Proteus的虚拟信号源提供,时钟频率的设置为600kHz;8路模拟量中IN0接Vcc,IN7接地,其他6路通过电位器分压获得;单片机串行口的数据收发线与虚拟终端连接.需要说明的是Proteus中ADC0808的数据线,OUT1表示最高位,OUT8表示最低位.
1、2、2、程序设计
程序的流程如图所示,主程序首先完成对串行口和外部中断的初始化,并等待上位机的采集命令,一旦收到采集命令,就启动对IN0的转换。
转换完成,ADC0808通过EOC向单片机发出中断请求,单片机响应中断,读取转换结果,并将其保存到数组adbuf中。
然后启动下一通道的转换,当8路模拟量全部采集完成时,主程序再将存放在数组adbuf中的8路数字量转换为ASCII码,通过串行口发送出去,为了能在虚拟终端上得到清楚的显示格式,相邻两路数字量之间输出空格码,每行显示8个数字量后,输出回车、换行码。
数据采集器的程序:
#includeh〉
#include〈absacc.h〉
#defineuintunsignedint
#defineucharunsignedchar
ucharidataadbuf[8];//存放A/D转换结果
uintaddr;//IN0~IN7的通道地址
ucharn;//通道计数
voidinit_serial(void)
{SCON=0x50;//0101,00008位数据位,无奇偶校验
TMOD=0x20;//定时器T1工作于方式2
PCON=PCON&0x7f;//SMOD=0
TH1=—3;//装入时间常数,波特率为9600
TL1=-3;
TR1=1;}/启动定时器T1
voidsend(uchardat)
{SBUF=dat;
while(TI==0);
TI=0;}
voidint0(void)interrupt0
{adbuf[n]=XBYTE[addr];//读取并保存当前转换结果
addr++;//指向下一通道的地址
n++;//计数器加工厂
if(n〈8)
XBYTE[addr]=0;//启动对一一通道的转换
else
EX0=0;}
voidgetadc(void)
{n=0;
addr=0x7ff8;//指向IN0通道的地址
XBYTE[addr]=0;//启动对当前通道的转换
EX0=1;//允许外部中断0中断
while(n〈8);}//等待8路模拟量转换完成
voidmain()
{uchari;
init_serial();//初始化串行口
IT0=1;//外部中断0下降沿触发
EA=1;//开中断
while
(1)
{while(RI==0);//等待接收完一个字符
RI=0;//清除接收标志
i=SBUF;//读取收到的字符
if(i==0x41)
{getadc();//依次完成对8个通道模拟量的转换
for(i=0;i<8;i++)
{send(adbuf[i]/100+0x30);//发送百位的ASCLL码
adbuf[i]=adbuf[i]%100;
send(adbuf[i]/10+0x30);//发送十位的ASCLL码
send(adbuf[i]%10+0x30);//发送个位的ASCLL码
send(0x20);//发送空格码
send(0x20);}
send(0x0d);//发送回车、换行
send(0x0a);}
}
}
1、2、3、调试方法与步骤
在Keil下建立项目,输入源程序,编译后进入调试方式全速运行,在虚拟终端的窗口中输入大写字母“A",此时8路模拟量转换结果会在一行中显示出来,依次为IN0、IN1、…、IN7,由于IN0接+5V,IN7接地,因此对应的显示值为255和000,而IN1~IN6的值由电位器RV1中心抽头的位置确定,调节RV1,然后在虚拟终端的窗口中输入大写字母“A”,IN1~IN6的值将随之变化.
如果在虚拟终端的窗口无任何显示,首先应检查串行口的初始化是否正确、虚拟终端的波特率是否与串行口一致、串行口能否收到采集命令“A"。
如果串行口能收到采集命令,应检查外部中断的初始化是否正确、启动信号START、转换结束信号EOC、输出允许信号OE的连接是否正确,ADC0808的时钟CLOCK设置不正确,也将无法完成A/D转换。
如果程序能够将IN0~IN7的转换结果存入数组adbuf,应重点检查串行口数据发送函数send()。
2、数字电压表的设计
2、1、8位串行A/D转换器TLC549
REF+
REF—
AIN
CS
CLK
DO
TLC549内部结构
2、2、数字电压表的设计过程
利用TCL549转换器设计一个简易数字电压表,用4位LED显示器将被测电压显示出来,测量范围为0。
000~5.000V(电路连接:
将ACS、ACLK、ADO分别与P10~P12相连).
2、2、1、硬件电路
如图所示,将TLC549的CS、CLK、DO接到单片机的三条I/O口线,REF+、REF-直接接到Vcc、GND,模拟输入AIN接电位器的中心抽头,调节电位器即或改变被测输入电压值.
2、2、2程序设计
程序首先读取A/D转换结果存入adin,其值在0~255之间,对应的电压值u=adin/255*5000(mV),然后将u转换为4位BCD码送显示缓存,并调用显示程序将显示出来,小数点固定在最高位.数字电压表的设计程序:
#includeh>
#defineucharunsignedchar
#defineulongunshgnedlong
ucharcodesegtab[]=
{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
0x88,0x83,0xc6,0xa1,0x86,0x8e,0x89,0x8c,0xff};
uchardbuf[4]={0,0,0,0};
sbitAD_CS=P1^0;
sbitAD_CLK=P1^1;
sbitAD_DAT=P1^2;
bdataucharadin;
sbitadin0=adin^0;
voiddelay(void)
{uchari;
for(i=0;i<20;i++);}
uchargetad(void)//A/D转换程序
{uchari;
AD_CS=0;//令CS为低选中TLC549
delay();//延时
for(i=0;i<8;i++)//循环读取8位A/D转换结果
{AD_CLK=0;//令CLK引脚为低
adin=adin<〈1;//先读取高位,后读取低位
adin=AD_DAT;//读取数据线的一位数据
AD_CLK=1;}//令CLK恢复为高位
AD_CS=1;
returnadin;}
voiddisp(void)
{uchari,n,bsel;
bsel=0xfe;//首先点亮最低位
for(n=0;n〈4;n++)
{P2=bsel;//位选口
P0=segtab[dbuf[n]];//将显示缓存的数据转换为字段码显示
if(n==3)P0=P0&0x7f;//点亮最高位的小数点
bsel=(bsel<〈1)+1;//准备显示下一位
for(i=1;i〈200;i++);//延时
P0=0xff;}//熄灭所有字段
}
voidmain()
{ulongu;
uchari;
while
(1)
{u=(ulong)getad()*5000/255;//将转换结果换成电压值
for(i=0;i<3;i++)//转换为4位BCD码送显示缓存
{dbuf[i]=u%10;
u=u/10;}
dbuf[3]=u;
disp();}//显示电压值
}
2、2、3、调试方法
在Keil下建立项目,输入源程序,编译后进入高度方式全速运行,数码管将以“X.XXX”的格式显示当前测量的电压值,调节电位器,数码管上的电压值将随之而变化.
如果数码管没有显示,应首先检查显示及显示函数。
注意,将电压值u转换成BCD码送显示缓存如果出问题,也会影响显示结果。
如果数码管能正常显示,但显示的电压值与实际值不同,一般A/D转换程序有问题,可重点检查getad()函数,如果电位器W的中心抽头从最低调到最高,该函数返回的A/D转换结果也相应地由0x00变化到0xFF,说明A/D转换是对的,应检查语句“u=(ulong)getad()*5000/255;”以及随后的BCD码转换程序.
3、信号发生器的设计
3、1、串行D/A转换器TLC5615
REFIN
AGND
Vcc
CS
SCLK
DIN
DOUT
OUT
TLC5615内部结构
3、2、用TLC5615设计信号发生器的过程
3、2、1、在Proteus环境下,用TLC5615设计一个锯齿波发生器。
(1)、硬件电路
如图所示,将TLC5615的SCLK、CS、DOUT分别与单片机的P1。
0、P1。
1、P1.2相连,基准电压接+5V。
(2)、程序设计
为了产生锯齿波,可定义一个用于计数的字符变量n,其值由0开始加1,每次加1后就将其输出,由TLC5615转换为相应的电压值,当n为255时,再加1又回到0,这样就实现了一个周期的转换.程序如下:
#include〈reg51.h〉
#includeh〉
#defineucharunsignedchar
#defineuintunsignedint
sbitSCLK=P1^0;//时钟输入
sbitCS=P1^1;//片选信号
sbitDIN=P1^2;//串行数据输入
voiddatout(uintdat)//向TL5615输出16位数据
{uchari;
CS=1;//初始化片选信号为高
SCLK=0;//初始化时钟为低
CS=0;//选中TL5615
for(i=0;i<16;i++)
{dat=dat<<1;//将最高位移入进位位CY
DIN=CY;//将数据送到DIN引脚
SCLK=1;//SCLK产生上升沿
SCLK=0;}//SCLK恢复为低
CS=1;}//片选信号恢复为高
voidmain(void)
{uchari=0;
while
(1)
{i=i++;
datout(i〈〈2);}
}
在Keil下建立项目,输入源程序,编译后进入调试方式全速运行,示波器显示的波形如图所示。
1、在Proteus环境下,设计一个正弦波发生器。
#include
#include〈intrins。
h>
#defineucharunsignedchar
#defineuintunsignedint
sbitSCLK=P1^0;
sbitCS=P1^1;
sbitDIN=P1^2;
ucharcodewavetab[60]={
0x80,0x8D,0x9A,0xA7,0xB4,0xBF,0xCB,0xD5,
0xDF,0xE7,0xEE,0xF4,0xF9,0xFD,0xFF,0xFF,
0xFF,0xFD,0xF9,0xF4,0xEE,0xE7,0xDF,0xD5,
0xCB,0xC0,0xB4,0xA7,0x9A,0x8D,0x80,0x72,
0x65,0x58,0x4C,0x40,0x34,0x2A,0x21,0x18,
0x11,0x0B,0x06,0x02,0x00,0x00,0x00,0x02,
0x06,0x0A,0x10,0x18,0x20,0x2A,0x34,0x3F,
0x4B,0x58,0x65,0x72};
voiddatout(uintdat)
{uchari;
CS=1;//初始化片选信号为高
SCLK=0;//初始化时钟为低
CS=0;//选中TL5615
for(i=0;i〈16;i++)
{dat=dat<<1;//将最高位移入进位位CY
DIN=CY;//将数据送到DIN引脚
SCLK=1;//SCLK产生上升沿
SCLK=0;}//SCLK恢复为低
CS=1;}//片选信号恢复为高}
voidmain(void)
{uinti=0;
for(i=0;i<60;i++)//从波表读取数字量输出
datout(wavetab[i]<<2);
}
运行程序,Proteus的虚拟示波器将观察到如图所示的波形.
4、频率与周期的测量
4、1、频率的测量
4、1、1、频率测量的过程
(1)、硬件电路
在Proteus环境下,设计的频率计电路如图所示,将定时器T0设置在定时方式2,定时时间为250us,满4000次中断正好1s,定时器T1工作于计数方式1,其初值为0。
在启动定时器T0开始定时后,随即送到T1(P3.5)引脚的被测脉冲进行计数,当T0定时满1s后,立即停止T1计数,关闭定时器T0,T1的计数值即为被测信号的频率。
(2)、程序设计
频率测量模块的程序:
#include〈reg52.h>
#includeh>
#defineucharunsignedchar
#defineuintunsignedint
externvoidinit_lcd(void);
externvoiddisp_str(ucharx,uchary,uchar*p);
sbitFS=P3^5;//被测信号FS输入端
bitRDY=0;//测量完成标志
uintmsn;//定时中断计数
uintcount(void)//测量FS的频率
{RDY=0;
TMOD=0X5a;//T0:
定时方式2,T1:
计数方式1;
TH0=TL0=—250;//T0定时时间为250us
msn=4000;//4000次中断正好1s
TH1=TL1=0X00;//T1工作于计数方式,初值为0
ET0=1;//允许T0中断
EA=1;//开中断
while(FS==1);//等待被测信号变低
while(FS==0);//等待被测信号变高
TR0=1;//T0开始定时
TR1=1;//T1开始计数
while(RDY==0);//等待1s
TR1=0;//关闭T1、T0
TR0=0;
return(TH1*256+TL1);//返回计数值
}
voidtimer0(void)interrupt1using1
{msn—-;
if(msn==0)//如果1s已到
RDY=1;}//设置测量完成标志位
voidmain()
{uintf;
ucharstr[9]="f=Hz”;
uchari;
init_lcd();//液晶屏初始化
while
(1)
{f=count();//测量频率
_nop_();
for(i=6;i〉2;i-—)//测量结果转换为5位ASCII码
{str[i]=f%10+0x30;
f=f/10;}
str[2]=f+0x30;
for(i=2;i〈6;i++)//用空格码替换高位的0
{if(str[i]!
='0')break;
str[i]='’;}
disp_str(0,3,str);}//显示测量结果
}
液晶显示模块1602DRV.C:
#includeh〉
#include〈intrins.h>
#defineucharunsignedchar
#defineuintunsignedint
sbitRS=P3^3;//数据/命令寄存器选择控制端
sbitRW=P3^1;//读写控制端
sbitE=P3^0;//使能控制端
sfrLCD=0x80;//P0作为总线端口
sbitBF=LCD^7;//就绪线BF,低电平有效
voidlcd_cmd(ucharcmd)//向液晶屏发送指令
{LCD=cmd;
RS=0;
RW=0;
E=1;
_nop_();
E=0;
while
(1)
{LCD=0xff;
RS=0;
RW=1;
E=0;
_nop_();
E=1;
if(BF==0)break;}
}
voidlcd_dat(uchardat)//向液晶屏写入数据
{LCD=dat;
RS=1;
RW=0;
E=1;
_nop_();
E=0;
while
(1)
{LCD=0xff;
RS=0;
RW=1;
E=0;
_nop_();
E=1;
if(BF==0)break;
dat=LCD;}
}
voidinit_lcd(void)//初始化液晶屏
{lcd_cmd(0x01);//清屏幕
lcd_cmd(0x3c);//设置双行显示,5*10点阵
lcd_cmd(0x0c);}//开显示,关闭光标
voiddisp_str(ucharx,uchary,uchar*p)//在x行、y列显示字符串p
{if(x==0)
lcd_cmd(0x80+y);//设置写入地址
else
lcd_cmd(0xc0+y);//设置写入地址
while(*p)//将字符依次发送到液晶屏
lcd_dat(*p++);
}
(3)、调试方法
将被测信号FS用Proteus的虚拟信号源DCLOCK代替,设置其频率,切换以Keil下,全速运行程序,此时液晶屏的显示将如图所示。
停止程序的运行,回到Proteus修改DCLOCK的频率,再次切换到Keil下运行程序,液晶屏上的测量结果将随之变化。
如果液晶屏没有显示,可将语句“f=count();”注销,然后再编译运行,如果仍没有显示,就检查1602DRV。
C模块中I/O口的定义是否与线路一致,直到能正常显示时,再将注销的
语句恢复.
如果液晶屏仍没有显示,说明调用count()函数没有返回,可能是RDY变量始终无效,此时应检查定时器T0的初始化是否正确,电路的连接有无错误。
4、2、周期的测量
4、2、1、周期测量的过程
(1)、硬件电路
在Proteus环境下,用定时器/计数器测量周期的电路如图所示,用D触发器对被测量信号进行分频,这要周期的测量也变成了脉宽的测量。
(2)、程序设计(液晶屏显示模块程序与频率测量模块一样)
周期测量模块程序:
#include
#defineucharunsignedchar
#defineuintunsignedint
externvoiddisp_str(ucharx,uchary,uchar*p);
externvoidinit_lcd(void);
sbitCLR=P1^0;//触发器清0控制位
uintTs;//存放测量结果
bitRDY=0;//测量就绪标志
voidcontrol(void)
{IT0=1;//下降沿触发INT0
EX0=1;//允许外部中断0中断
TH0=0;//定时器初值为0
TL0=0;
TMOD=0x09;//定时器T0工作方式1,由TR0及INT0控制T0定时启停
CLR=0;CLR=1;//D触发器清0
TR0=1;//允许T0定时
EA=1;}//开中断,由被测信号的上升沿启动定时
voidint_0(void)interrupt0using1
{TR0=0;//关闭定时器T0
EA=0;//关中断
Ts=TH0*256+TL0;
RDY=1;}
voidmain()
{ucharstr[9]=”T=us";//用于测量结果输出
uchari;
init_lcd();
while
(1)
{control();//初始化定时器及中断
while(RDY==0);//等待INT0引脚下降沿
RDY=0;
for(i=6;i>2;i——)//测量结果转换为5位ASCII码
{str[i]=Ts%10+0x30;
Ts=Ts/10;}
str[2]=Ts+0x30;
for(i=2;i〈6;i++)//用空格码替换高位的0
{if(str[i]!
=’0')break;
str[i]=’’;}
disp_str(0,3,str);}//显示测量结果
}
(3)、调试方法
将被测信号FS用Proteus的虚拟信号源DCLOCK代替,设置其周期,如图所示,切换到Keil下,全速运行程序,此时液晶屏的显示将如图所示。
停止程序的运行,回到Proteus修改DCLOCK的周期,再次切换到Keil下运行程序,液晶屏上的