多路数据采集器设计1.设计要求所设计的数据采集器,共有16路信号输入,每路信号都是直流0~20mV信号,每秒钟采集一遍,将其数据传给上位PC计算机。
本采集器地址为50H。
要求多路模拟开关用4067,A/D转换用ADC0809,运算放大器用OP07,单片机用89C51,通信用RS232接口,通信芯片用MAX232。
与PC机的RS232串口进行通信。
设计采集器的电原理图,用C51语言编制采集器的工作程序。
2.方案设计按要求,设计数据采集器方案如下所示:数据采集器采用AT89C51单片机作为微控制器,模拟开关4067的地址A、B、C、D分别与P1.0~P1.3连接,通过控制P1口输出来选择输入信号,将直流信号依次输入ADC0809的模拟信号输入端,ADC0809共有8路输入通道,在使用模拟开关时,仅将模拟开关的输出端连接到ADC0809的1路输入通道即可,本方案中使用0通道。
ADC0809的转换结果通过P0口传给单片机,单片机将采集结果通过串行通信RS232接口上传给上位PC机,实现数据的采集。
数据采集器方案示意图3.电路原理图a)AT89C51单片机电路本实验中选取8位单片机AT89C51作为微控制器,需要片外11.0592MHz的振荡器,4K字节EPROM,128字节RAM,与51单片机有很好的兼容性。
在本此实验中程序及数据不多,故无需另加外部程序存储器。
单片机部分的电路如下所示:AT89C51单片机电路b)数据输入部分数据输入部分由模拟开关4067实现多路信号的切换。
CD4067是单16路(单刀16位)模拟开关,各开关由外部输入二进制的地址码A、B、C、D来切换。
其中脚10、11、14和13是地址码A(LSB)、B、C、D(MSB)的输入端;脚2~9和16~23是开关的输入/输出端(开关位);脚1是开关的输出/输入公共端(开关刀);脚15为控制端,低电平有效(选通),高电平禁止(开关开路)。
输入脚A、B、C、D分别与单片机P1.0~P1.3相连,改变P1输出即可切换输入通道,控制脚与P2.4相连。
输出脚1后接电压放大电路。
c)电压调理放大电路电压调理电路由于输入信号均为0~20mV的微弱电压信号,而模数转换器ADC0809的输入量要求为0~5V 直流电压,所以必须后接电压放大电路。
放大器选用OP07,将0~20mV电压放大到0~5V,其放大倍数为250倍,一般情况下,放大器的放大倍数最好小于200倍,安全起见,选用两个OP07进行两级放大,前级放大25倍,后级放大10倍,放大电路如上图所示。
d)模数转换部分ADC0809数模转换电路模数转换元件选用ADC0809,其主要特性有:8路8位A/D转换器,即分辨率8位;具有转换起停控制端;转换时间为100s;单个+5V电源供电;模拟输入电压范围0~+5V,不需零点和满刻度校准;工作温度范围为-40~85;低功耗,约15mW。
选择参考电压为+5V,当输入电压为+5V时,转换数据为#FFH,当输入电压为0V时,转换数据为#00H。
ADC0809片内没有时钟,用于51单片机系统时,时钟信号可由51单片机ALE端口经过一个2分频电路获得。
一般情况下,ALE信号频率是51单片机时钟频率的1/6。
若采用11.0592MHz 的晶振,则ALE的输出频率为1.8432MHz,经2分频后为921.6KHz,这个频率符合ADC0809对时钟频率的要求。
2分频电路由于多路输入信号切换由模拟开关4067实现,所以ADC0809的8路输入开关实际只使用1路,为方便起见,使用0通道输入,所以电路中将A、B、C脚接地处理,并且将IN1~IN7同样做接地处理。
IN0与电压放大输出相连。
转换结果的读取有3种方法:延时法:不利用EOC信号,启动A/D转换,等待130us后读取转换结果。
查询法:将EOC信号接到IO口,检测EOC, 若EOC=0, 则A/D转换没有结束, 继续检测; 当EOC=1 时, A/D 转换已经结束,可读取A/D转换结果。
中断法:将EOC信号接到INT0口,利用中断程序获取结果。
实际应用中,通常采用跳变触发方式。
EOC经过一个反向器接到单片机INT0上。
启动A/D转换后,单片机可以做其它工作, A/D转换结束时, EOC端产生一个由低到高的正跳变, 经反向器传输到INT0,若此时单片机的CPU处于开中断状态,并且允许INT0中断, 又没有高一级的或同一级的其他中断正在服务,则CPU立即执行中断服务程序, 在中断服务程序中读取A/D转换结果。
本次试验中,采取中断法实现转换结果的读取。
e) 串行通信部分串行数据通信单片机串口通信采用RS232C 标准,由于RS232C 标准采用正负电压表示逻辑状态,与TTL 以高低电平表示逻辑状态的规定不同,必须使用电平转换器件进行装换,本方案采用Maxim 公司的MAX232芯片实现接口的电平转换。
MAX232的11、12脚分别与单片机P3.0、P3.1脚相连,13、14脚与电脑串口相连接。
串行口工作于工作方式1下,使用定时器1作为波特率发生器,定时器1工作于定时器方式2下,由于系统使用11.0592MHz 晶振,所以取初值为FDH ,得,系统工作的波特率为9600bps 。
4. 软件设计程序流程如下图所示,详细程序见附录一。
TMOD x SCON x ⎧⎪⎪定时器模式设置,=020通信方式设置,=050程序流程图5.仿真实验采用Proteus7.1可以很方便地进行单片机单路的仿真,本方案中需要用到串口通讯仿真,由两个MAX232器件连接模拟单片机和PC机的通信,如下图所示,左边虚线框中Max232与单片机相连,右边实线框中Max232与PC机相连,模拟上位机。
串口通信模拟电路测试输入信号由Proteus中电压探针工具提供,如图所示:各通道相应测试输入电压值如下表所示:测试输入电压值串口通信调试时实现方式有两种:1)通过虚拟串口软件VSPDXP5.0设置两个相关联的串口如COM3和COM4,在Proteus中增加一个虚拟串口控件COMPIM,通过串口调试软件如串口调试小助手进行串口调试,其过程如下:虚拟串口软件及设置在虚拟串口软件中添加一对关联的串口,本次添加的为COM1和COM2,并将红色方框处勾上。
COMPIM控件及其属性设置在Proteus中添加一个COMPIM控件,并按上图设置其属性后,运行仿真电路.。
打开串口调试小助手,按下图设置后就可以进行串口通信的调试了。
串口调试小助手及其设置运行效果图2)通过Proteus中的虚拟终端仿真串口通信过程,如下图所示,运行后,在PTXD窗口中点鼠标右键,在弹出菜单中选上“Echo Typed Characters”和“Hex Display Mode”,在PRXD窗口中同样选中“Hex Display Mode”,后在PTXD窗口中按Shift+p(即输入大写字母P,其对应ASCII码为50H),结果如下:虚拟终端结果运行效果图6. 实验结果分析上表中:测试电压V1为由电压探头提供的测试电压值; 仿真结果为ADC0809输出的结果;仿真电压V2为由仿真结果计算所得的电压值,公式为:200V2256-=⨯()mV仿真结果;模拟开关输出端电压V3为直流毫安表测量得到电压值(接调理放大电路时);由结果看,随着输入电压的升高,仿真电压值V2与测试电压V1的误差逐渐变大,尤其当输入为满量程的20mV 时,误差达到0.781mV ;V3电压同样与V1误差越来越大,满量程时误差值最大为0.7mV ;V3与V2电压则始终相差不超过0.1mV ,较为精确。
由V2和V3的关系可以看出ADC0809的转换精度基本能够满足要求,测量电压V2与测试电压V1之间的误差并非由ADC0809造成。
进一步分析电路,当将模拟开关输出端与后面的放大电路断开时,毫安表输出值V3’完全与测试电压V1相同;当与放大电路再次连接时,再次出现上表中的较大误差值。
误差是由于电压放大电路等效电阻分压造成电压值的损失。
解决方案有2种:由上面测量结果通过插值多项式拟合出误差与测量结果的关系式,在单片机的测量程序中修正测量结果。
通过硬件电路进行电压补偿。
比较两种方案,可以看出第一种方案比较方便,下面计算插值公式:根据理论输出值和误差值计算插值公式,插值公式为0.304810.04Y X=+,由于单片机不适合做浮点运算,所以将插值公式改为=,经过插值修正后,实际输出应为X+Y,即ADC0809转换值加上实时误差值。
40/1000Y X经过修正后,结果如下:可以看出,修正后精度大幅提高。
附录一:main.c文件#include<reg51.h>#define uchar unsigned char#define uint unsigned intsbit m_enable = P2^4; //低电平有效sbit adc_a = P2^5; //ALE:上升沿锁存通道地址,地址已固定为0通道sbit adc_s = P2^6; //START:上升沿清除ADC寄存器,下降沿启动ADC sbit adc_oe = P2^7; //OE:高电平有效uchar data adc_result[16] = 0;uchar adc_in = 0;void delay(unsigned int t){ //延时t x 0.1msdo{TH0 = 0xFF;TL0 = 0xA3;TR0 = 1;while ( !TF0 );TF0 = 0;TR0 = 0;}while(--t);}void send_char(uchar ch){SBUF=ch;while(TI==0);TI= 0 ;}void INT0_SVC(void) interrupt 0 using 0{EA = 0;adc_oe = 1;adc_result[adc_in] = P0;adc_oe = 0;EA = 1;}void sirial_SVC(void) interrupt 4 using 2{uchar i;EA = 0;if(RI==1){RI = 0;i = SBUF;if(SBUF==0x50){TI = 0;for(i=0;i<16;i++){send_char(adc_result[i]);}}TI = 0;}EA = 1;}void adc_start(uchar i){uchar t;m_enable = 1; //初始化使模拟开关不工作adc_a = 0; //初始化0809 ALE=0adc_s = 0; //初始化0809 START=0adc_oe = 0; //初始化0809 OE=0P1=(i & 0x0F); //输出模拟开关通道信号m_enable = 0; //打开模拟开关for(t=200;t>0;t--); //使电压信号稳定adc_a = 1; //ALE上升沿,锁存地址,通道0adc_s = 1; //START脚上升沿,0809清除寄存器adc_a = 0; //下降沿adc_s = 0; //START下降沿启动ADCdelay(50); //T_EOC信号延时8+2us 及适电压有效}void main(){P1 = adc_in; //初始化通道为0(0-15)m_enable = 1; //初始化使模拟开关不工作adc_a = 0; //初始化0809 ALE=0adc_s = 0; //初始化0809不工作START=0adc_oe = 0; //初始化0809输出关闭EA = 0;//设置0809中断INT0IT0 = 1; //负边沿触发中断EX0 = 1; //允许外部中断//设置串口通信TMOD = 0x21; //定时器模式设置SCON = 0x50; //通信方式0,1位起始位,8位数据,1位停止位 PCON = 0x00; //设置SMOD=0TH1 = 0xfd;RI = 0;TI = 0; //清收发标志ET1 = 0; //C/T 禁止T1中断TR1 = 1; //启动T1计时器PS = 1; //串行口中断为较高中断优先级ES = 1; //允许串行口中断EA = 1;adc_in=0;while(1){adc_start(adc_in);delay(400);//对结果进行修正adc_result[adc_in]=adc_result[adc_in]+40*adc_result[adc_in]/1000;adc_in=(adc_in+1)%16;}}。