《数据采集与总线技术》实验讲义.docx
《《数据采集与总线技术》实验讲义.docx》由会员分享,可在线阅读,更多相关《《数据采集与总线技术》实验讲义.docx(32页珍藏版)》请在冰点文库上搜索。
《数据采集与总线技术》实验讲义
《数据采集与总线技术》
课程实验指导书
机电工程学院
实验一基于ADC0804的数据采集
实验目的与要求:
掌握ADC0804的使用方法,了解其基本的电路结构和应用方法。
实验过程要点:
查阅相关ADC0804相关资料,设计电路使用单片机控制ADC0804进行数据采集与现实,并熟悉Proteus的相关使用方法。
1、ADC0804引脚功能:
:
芯片片选信号,低电平有效。
即=0时,该芯片才能正常工作,高电平时芯片不工作。
在外接多个ADC0804芯片时,该信号可以作为选择地址使用,通过不同的地址信号使能不同的ADC0804芯片,从而可以实现多个ADC通道的分时复用。
:
启动ADC0804进行ADC采样,该信号低电平有效,即信号由低电平变成高电平时,触发一次ADC转换。
:
低电平有效,即=0时,DAC0804把转换完成的数据加载到DB口,可以通过数据端口DB0~DB7读出本次的采样结果。
VIN(+)和VIN(-):
模拟电压输入端,单边输入时模拟电压输入接VIN(+)端,VIN(-)端接地。
双边输入时VIN(+)、VIN(-)分别接模拟电压信号的正端和负端。
当输入的模拟电压信号存在“零点漂移电压”时,可在VIN(-)接一等值的零点补偿电压,变换时将自动从VIN(+)中减去这一电压。
VREF/2:
参考电压接入引脚,该引脚可外接电压也可悬空,若外接电压,则ADC的参考电压为该外界电压的两倍,如不外接,则VREF与Vcc共用电源电压,此时ADC的参考电压即为电源电压Vcc的值。
CLKIN和CLKR:
外接RC振荡电路产生模数转换器所需的时钟信号,时钟频率CLK=1/1.1RC,一般要求频率范围100KHz~1460KHz。
AGND和DGND:
分别接模拟地和数字地。
:
转换结束输出信号,低电平有效,当一次A/D转换完成后,将引起=0,实际应用时,该引脚应与微处理器的外部中断输入引脚相连(如51单片机的,脚),当产生信号有效时,还需等待=0才能正确读出A/D转换结果,若ADC0804单独使用,则可以将引脚悬空。
DB0~DB7:
输出A/D转换后的8位二进制结果。
补充说明:
ADC0804片内有时钟电路,只要在外部“CLKIN(引脚4)”和“CLKR(引脚19)”两端外接一对电阻电容即可产生A/D转换所要求的时钟,其振荡频率为fCLK≈1/1.1RC。
其典型应用参数为:
R=10KΩ,C=150PF,fCLK≈640KHz,转换速度为100μs。
若采用外部时钟,则外部fCLK可从CLKIN端送入,此时不接R、C。
允许的时钟频率范围为100KHz~1460KHz。
2、ADC0804工作过程
如下图所示,ADC0804的工作时序图(TimingDiagrams):
(欲详细了解工作过程,可以结合ADC0804使用手册)
图6给出的其实就是使ADC0804正确工作的软件编程模型。
由图可见,实现一次ADC转换主要包含下面三个过程:
1.启动转换:
由图6中的上部“FIGURE10A”可知,在信号为低电平的情况下,将引脚先由高电平变成低电平,经过至少tW(WR)I延时后,再将引脚拉成高电平,即启动了一次AD转换。
注:
ADC0804使用手册中给出了要正常启动AD转换的低电平保持时间tW(WR)I的最小值为100ns,即拉低后延时大于100ns即可以,具体做法可通过插入NOP指令或者调用delay()延时函数实现,不用太精确,只要估计插入的延时大于100ns即可。
2.延时等待转换结束:
依然由图6中的上部“FIGURE10A”可知,由拉低信号启动AD采样后,经过1到8个Tclk+INTERNALTc延时后,AD转换结束,因此,启动转换后必须加入一个延时以等待AD采样结束。
注:
手册中给出了内部转换时间“INTERNALTc”的时间范围为62~73个始终周期,因此延时等待时间应该至少为8+73=81个时钟周期。
比如,若R为150K,C为150pF,则时钟频率为Fclk=1/1.1RC=606KHz,因此时钟周期约为Tclk=1/Fclk=1.65us。
所以该步骤至少应延时81*Tclk=133.65us.具体做法可通过插入NOP指令或者调用delay()延时函数实现,不用太精确,只要估计插入的延时大于133.65us即可。
3.读取转换结果:
由图6的下部“FIGURE10B”可知,采样转换完毕后,在信号为低的前提下,将脚由高电平拉成低电平后,经过tACC的延时即可从DB脚读出有效的采样结果。
注:
手册中给出了tACC的典型值和最大值分别为135ns和200ns,因此将引脚拉低后,等待大于200ns后即可从DB读出有效的转换结果。
具体做法可通过插入NOP指令或者调用delay()延时函数实现,不用太精确,只要估计插入的延时大于200ns即可。
图6:
ADC0804手册给出的ADC转换时序图
图7:
ADC0804手册给出的电器特性表
对采样值进行运算变换,换算出实际的滑动变阻器输入电压值。
对于任何一个A/D采样器而言,其转换公式如下:
其中:
:
输入ADC的模拟电压值。
:
ADC转换后的二进制值。
本试验的ADC0804为八位。
:
ADC能够表示的刻度总数。
ADC0804为八位ADC,因此
:
ADC参考电压值,本试验ADC0804的
被设置为5V
因此,对于本试验,转换公式为
3、ADC0804在单片机中的简单应用举例
如下图所示,本例ADC0804中的VCC=5V,VREF/2引脚悬空(悬空则相当于与VCC共接5V电源),因此ADC转换的参考电压为VCC的值,即5V。
VIN-接地,而VIN+连接滑动变阻器RV1的输出,因此VIN+的电压输入范围为0V~5V,正好处于参考电压范围内。
引脚接地,和分别连接单片机的P3^6和P3^7引脚,而DB0~DB7连接单片机的P1口.
P0口接数码管的段选线,P2口低四位接数码管的位选线。
程序主要实现以下功能:
(1)控制ADC0804芯片对VIN(+)引脚输入的电压值进行正确采样,读取采样结果。
(2)对采样值进行模数变换,将转换后数字量后显示在4段数码管上。
C程序如下:
#include
#include
#defineuintunsignedint
#defineucharunsignedchar
sbitwr=P3^6;
sbitrd=P3^7;
ucharcodedis[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//共阳显示代码
voiddelay(uintx)//延时函数delay
(1)延时0.992ms,大约为1ms
{
uchari;
while(x--)
for(i=0;i<120;i++);
}
voiddisplay(uchardb)//数码管显示函数,用于显示模数转换后得到的数字量
{
ucharbw,sw,gw;//bw,sw,gw分别等于db百位,十位,个位上的数
bw=db/100;
sw=db%100/10;
gw=db%10;
P2=0x01;//点亮第一只数码管
P0=dis[bw]&0x7f;//最高位置0,点亮第一只数码管的小数点,
delay(5);
P2=0x02;//点亮第二只数码管
P0=dis[sw];
delay(5);
P2=0x04;//点亮第三只数码管
P0=dis[gw];
delay(5);
P2=0x08;//点亮第四只数码管
P0=dis[0];//第四只数码管一直显示0
delay(5);
}
voidmain()
{
uchari;
while
(1)
{
wr=0;//在片选信号CS为低电平情况下(由于CS接地,所以始终为低电平),
_nop_();//WR由低电平到高电平时,即上升沿时,AD开始采样转换
wr=1;
delay
(1);//延时1ms,等待采样转换结束
P1=0xff;//这条语句不能少,我也还不知道为什么
rd=0;//将RD脚置低电平后,再延时大于135ns左右(这里延时1us),
_nop_();//即可从DB脚读出有效的采样结果,传送到P1口
for(i=0;i<10;i++)//刷新显示一段时间
display(P1);//显示从DB得到的数字量
}
}
Proteus仿真运行结果如下:
实验二在51单片机上模拟I2C总线时序
实验目的与要求:
掌握I2C总线的协议内容,了解其基本的电路结构和应用方法。
实验过程要点:
参照教材关于I2C总线的相关知识,在51单片机的I/O接口上利用软件模拟I2C总线时序,实现对相关器件的访问和控制。
一、51单片机对AT24Cxx系列E2PROM的访问
步骤:
1)参考下图,在proteus仿真软件中绘制电路图。
2)在Keil中建立工程,编写对两个E2PROM的访问程序,实现:
a)向U2的首地址为0x00开始的16个存储单元中,写入’0’~’f’的共阳极段码。
在proteus仿真过程中,可按下暂停键,然后通过菜单“调试”来查看U2内当前所存有的数据。
b)将这16个字节的数据从U2中读出,然后存入U3中以首地址0x10开始的16个存储单元中。
在proteus仿真过程中,可按下暂停键,然后通过菜单“调试”来查看U2、U3内当前所存有的数据。
二、51单片机对ADC器件PCF8591的访问
1)参考下图,在proteus仿真软件中绘制电路图,实现简单的电压测试功能。
其中,4位LED为共阴极数码管,也可以采用共阳极。
2)在Keil中建立工程,编写对PCF8591的访问程序,读入AD转换后的电压值,然后显示在LED上。
a)从PCF8591读入一个数据的函数(伪代码):
voidRd_PCF8591(ucharCMD){
起始信号;
发送一个字节(写地址);
等待响应;
发送一个字节(CMD);//控制字
等待响应;
起始信号;
发送一个字节(读地址);
等待响应;
接收一个字节;
发送非应答;
停止信号;
}
b)主函数编写思路(伪代码):
voidmain(){
while
(1){
Rd_PCF8591(0x00);//控制字为00000000B
将读取的数据换算为数字电压v
Display(v);//将v显示在LED上
}
}
三、参考代码:
基本I2C操作
/************BasicI2COperation***********/
voidStart(){//起始信号
SDA=1;
SCL=1;
NOP4();
SDA=0;
NOP4();
SCL=0;
}
voidStop(){//终止信号
SDA=0;
SCL=1;
NOP4();
SDA=1;
NOP4();
SCL=0;
}
voidSendAck(bitck){//根据数据接收情况发送应答
if(ck)SDA=0;
elseSDA=1;
NOP4();//SCL低电平保持时间大于4.7us
SCL=1;
NOP4();//SCL高电平保持时间大于4us
SCL=0;
SDA=1;//ACK后要对总线进行释放
NOP4();
}
bitWaitAck(){
SDA=1;
NOP4();
SCL=1;
NOP4();
if(SDA){//SDA为1收到非应答
SCL=0;
Stop();
return0;
}
else{//SDA为0收到应答
SCL=0;
return1;
}
}
/**********EndofBasicI2COperation***********/
共阴极LED显示
voidDisplay(uintx){
P3=0xf7;//选中千位
P1=DSY_CODE[x/1000];//DSY_CODE[i]为共阴极段码
DelayMS
(1);
P1=0x00;//消除显示残影
P3=0xfb;//选中百位
P1=DSY_CODE[x/100%10];
DelayMS
(1);
P1=0x00;
P3=0xfd;//选中十位
P1=DSY_CODE[x%100/10];
DelayMS
(1);
P1=0x00;
P3=0xfe;//选中个位
P1=DSY_CODE[x%10];
DelayMS
(1);
P1=0x00;
}
实验三在51单片机上模拟SPI总线时序
实验目的与要求:
掌握SPI总线的协议内容,了解其基本的电路结构和应用方法。
实验过程要点:
在51单片机的I/O接口上利用软件模拟SPI总线时序,实现对相关器件的访问和控制。
一、SPI总线简介
SPI总线的基本信号线为3根传输线,即SI、SO、SCK。
传输的速率由时钟信号SCK决定,MOSI为数据输入、MISO为数据输出。
采用SPI总线的系统如图4-1所示,它包含了一个主片和多个从片,主片通过发出片选信号CS来控制对哪个从片进行通信,当某个从片的CS信号有效时,能通过SI接收指令、数据,并通过SO发回数据。
而未被选中的从片的SO端处于高阻状态。
图4-1SPI总线结构
SPI是一个环形总线结构,其时序是在SCK的控制下,两个双向移位寄存器进行数据交换。
SCK提供时钟脉冲,SDI、SDO基于此脉冲完成数据传输。
数据输出通过SDO线,数据在时钟上沿或下沿时改变,在紧接着的下沿或上升沿沿被读取,完成一位数据传输。
输入原理相同。
这样,在至少8次时钟信号的改变(上沿和下沿计为1次),就可以完成8位数据的传输。
假设8位寄存器内装的是待发送的数据10101010,上升沿发送、下降沿接收、高位先发送。
那么第一个上升沿来的时候数据将会是高位数据SDO=1。
下降沿到来的时候,SDI上升沿的电平将被存到寄存器中去,那么这时寄存器=0101010SDI,这样在8个时钟脉冲以后,两个寄存器的内容互相交换一次。
这样就完成里一个SPI时序。
图4-2SPI总线主机、从机收发模块
不带SPI接口的单片机编程思路:
对于不带SPI接口的MCS51系列单片机来说,可用软件模拟SPI操作,用三个普通I/O口模拟SPI器件的SCK、MISO、MOSI。
对于不同的外围芯片,它们的时钟时序是不同的。
对于在SCK的上升沿接收数据/下降沿发送数据的从机器件,一般应将MCU的串行时钟输出口SCK的初始状态设为1,而在从机使能端有效(CS=0)后再置为0。
这样,MCU在输出1位SCK时钟(出现的是下降沿)的同时,将使从机SPI接口的移位寄存器串行左移,从而输出1位数据至MISO线。
此后再置SCK为1,使MCU从MOSI线输出1位数据(最高位)至从机的SPI接口的移位寄存器。
至此,模拟1位数据输入输出便宣告完成。
此后再置SCK为0,模拟下1位数据的输入输出……循环8次,即可完成1字节数据的传输。
对于在SCK的下降沿接收数据/上升沿发送数据的从机器件,则应取SCK的初始状态为0,即在从机使能端有效(CS=0)后,先置SCK为1,以便从机输出1位数据(MCU接收1位数据),之后再置时钟为0,使从机接收1位数据(MCU发送1位数据),从而完成1位数据传送。
二、25AA系列E2PROM简介
1)25AA系列E2PROM器件的控制指令
指令名称
指令码
描述
READ
0x03
“读”数据指令
WRITE
0x02
“写”数据指令
WRDI
0x04
禁止“写”操作
WREN
0x06
允许“写”操作
RDSR
0x05
读状态寄存器
WRSR
0x01
写状态寄存器
2)总线读写时序
(1)在CLK上升沿SI采样数据。
对于CPU写入25xx来说,应该在CLK时钟的上升沿之前准备好待写数据,CLK上升沿产生后,25xx将对SI端线采样。
(2)在CLK下降沿SO输出数据。
在读取数据周期内,在CLK时钟的下降沿将数据送出到SO引脚锁存。
对于CPU从25xx读数据,应该在CLK时钟下降沿产生之后马上读取SO端口数据。
(3)串行数据发送顺序:
先发送高字节,再发送低字节。
(4)在对25xx的访问过程中CS必须保持低电平。
HOLD保持高电平。
如果不用存取等待,在设计电路时把HOLD引脚接高电平。
(5)当CS引脚由高电平变为低电平之后的第一个上升沿结束后,25xx就会马上对SI引脚采样。
先发送的第一帧都是指令码。
3)25AA系列的状态寄存器(StateRegister)
控制指令0x05为读状态寄存器指令。
25AA器件的状态寄存器可以在任何时刻被读取,其格式为:
7
6
5
4
3
2
1
0
X
X
X
X
BP1
BP0
WEL
WIP
Write-In-Process(WIP)位为只读位,指示器件当前是否正在进行写操作。
'1'为是,'0'为否。
WriteEnableLatch(WEL)位为只读位,指示写使能锁存器状态。
当置'1'时允许向存储单元写数据,当置'0'时禁止向存储单元写数据。
该位可通过WREN和WRDI指令来刷新。
BlockProtection(BP1andBP0)位为写保护标识位。
4)存储器的“分页”管理
几乎所有的存储设备都是分页式管理的,批量写入数据的动作被称为“页写”,即批量写入数据被限制在一页的范围内。
以25AA256为例,内部存储单元共分512个页,每页64字节,地址分布:
0000H-7FFFH,可以按地址单字节存取数据,也可以页内批量存取数据。
页地址分布为:
Page0:
0000H–003FH
Page1:
0040H–007FH
…………
Page511:
7FC0H–7FFFH
批量写最多可一批写入64字节,再写第65个字节数据时其实写入到了第0个字节处(本次批量写最早写入的那个位置),覆盖掉了该位置原来的数,这样在这64个字节的空间内循环覆盖写入。
批量写操作被限制在同一个“页”内,不能跨越页边界往下一页写入数据。
如果到了页末尾,继续写入,数据将被写到本页头的第1个位置处,覆盖掉原来的数据。
5)基本读写时序
读时序:
1)将CS拉低;
2)通过SI传送8位指令到25xx的指令寄存器(读指令:
00000011)
3)紧接着马上传送16位地址。
4)通过DO引脚读取内容,该8位内容就是刚才发送的地址对应的单元的内容。
5)如果CS不拉高,持续提供CLK时钟,则内部地址指针将增加1,指向下一个数据单元,可以继续读取下一个单元的内容。
如果一直这样往下读,这样的读取将会持续,当达到最大的存储单元地址7FFFH时,地址指针重新指回0000H,如此往复以至无穷的循环往下读。
6)当CS拉为高电平后,读取操作终止。
写时序:
1)将CS拉低;
2)设置“写操作”使能寄存器。
输出“写使能指令”(00000110)。
3)将CS拉高。
(这一步很重要,只有在这里把CS拉高,才能更新“写使能”寄存器,才可以写入数据)。
4)将CS拉低。
5)发送“写指令”(00000010,0x02)
6)紧接着发送16位地址单元。
7)通过SI写入8位数据。
这样这8位数据就写入目标地址了。
8)如果写完这个字节的数据之后CS不拉高,CLK继续提供时钟,那么25xx器件内部地址指针将自动增加1,可以继续往下一个存储单元继续写入8位数据。
这就是批量“写”数据操作。
9)写操作必须在字节的最低位锁存到SI端之后才能停止(即CS拉高)。
否则,最后写入的这个字节数据将不会写入。
10)应有相应的步骤对“写操作”是否完成进行判断。
一般通过查询器件的状态寄存器来实现。
三、51单片机对25AA系列E2PROM的访问
步骤:
1)参考下图,在proteus仿真软件中绘制电路图。
2)在Keil中建立工程,编写对E2PROM的访问程序:
a)向U2的首地址为0x0000开始的16个存储单元中,写入’0’~’f’的共阳极段码。
在proteus仿真过程中,可按下暂停键,然后通过菜单“调试”来查看U2内当前所存有的数据。
b)将这16个字节的数据从U2中读出,然后在数码管上循环显示出来。
c)向U2的0x0038开始的16个单元中写入’0’~’f’的共阳极段码,在proteus仿真过程中按下暂停键,通过菜单“调试”观察这16个数据写入的实际位置。
分析解释原因。
四、参考代码
1)基本SPI操作:
/*SPI写一字节(上升沿锁存数据,先发高位,再发低位)*/
voidSPI_MOSI_Byte(ucharwdata){
uchari;
SCK=0;
for(i=0;i<8;i++){
if(wdata&0x80)MOSI=1;
elseMOSI=0;
SCK=1;//产生一个上升沿,在其前准备好待发数据
wdata<<=1;
SCK=0;
}
}
/*SPI读一字节(下降沿读取数据,先读高位,再读低位)*/
ucharSPI_MISO_Byte(){
uchari,rdata=0;
SCK=1;
for(i=0;i<8;i++){
rdata=rdata<<1;
SCK=0;//产生一个下降沿,数据将被锁存在SO端线上
rdata=rdata|MISO;
NOP4();
SCK=1;
}
returnrdata;
}
2)25AA256连续读写函数
voidSPI_WrToRom(ucharwdata[],uintstartAddr,ucharbyteLen){
uchari,flag;
ucharaddr_H,addr_L;
addr_H=startAddr>>8;
addr_L=startAddr&0x00FF;
CS=0;//CS拉低
SPI_MOSI_Byte(0x06);//发写使能指令
CS=1;//CS拉高一次,保证"写使能"数据0x06装入芯片的指令寄存器
NOP4();
CS=0;//CS重新拉低
SPI_MOSI_Byte(0x02);//发写数据指令
SPI_MOSI_Byte(addr_H);
SPI_MOSI_Byte(addr_L);
for(i=0;iSPI_MOSI_Byte(wdata[i]);
CS=1;//写操作结束,拉高CS
/*******************验证写存储器操作是否完成**************/
while
(1){
CS=0;
SPI_MOSI_Byte(0x05);//获取存储器的状态
flag=SPI_MISO_Byte();