定时中断与数据采集实验.docx
《定时中断与数据采集实验.docx》由会员分享,可在线阅读,更多相关《定时中断与数据采集实验.docx(16页珍藏版)》请在冰豆网上搜索。
![定时中断与数据采集实验.docx](https://file1.bdocx.com/fileroot1/2023-2/22/84bd38e9-0d07-4a5c-a332-ff088dbb7412/84bd38e9-0d07-4a5c-a332-ff088dbb74121.gif)
定时中断与数据采集实验
实验1定时中断与数据采集实验
1.1实验目的
1掌握定时器/计数器8254的工作原理与编程。
2熟悉中断控制器8259A的工作原理与使用方法。
3掌握硬件中断程序设计的原理与编程方法。
4掌握A/D、D/A转换器的使用与数据采集的方法。
5掌握建立磁盘数据文件的方法。
6掌握TC绘制曲线的方法和技巧。
1.2实验设备
1具有ISA总线插槽和USB接口的PC系列微型计算机,操作系统使用DOS或Windows98,装有TurboC2.0,DosBox。
2超低频信号发生器。
3超低频示波器。
1.3实验要求
程序运行前,配置数据文件(包括中断服务的时间间隔T,中断服务次数N,坐标系在屏幕上的位置,横(时间)纵(幅度)坐标显示范围及刻度等)。
运行后,首先,在屏幕上设定位置绘制坐标系,然后每间隔指定的时间生成设定的正弦曲线上的一个点,保存到指定数据文件并绘制在坐标系里,超过横坐标显示范围后,会滚动显示,显示N个点后,则曲线停止,如果N=0,则会无限显示下去,直到在键盘上按下指定的按键,才停止显示。
停止显示后,按指定键程序结束运行。
同时,将从A/D通道上采集到的数据通过D/A输出,在示波器上显示相应的波形曲线。
具体要求如下:
1横坐标标注为时间,纵坐标标注为幅度。
2曲线动态显示
3配置文件如有错误要能提示,不会造成程序运行报系统错误。
4编程时要尽量把具有独立功能的代码写成子程序。
4注意变量的命名要清晰,代码的注释要丰富。
5后面的数据采集要在此程序基础上编程、添加代码,注意程序的结构。
1.4设计前的分析和计算
对通道0进行操作需要对8254定时/计数器的控制字写入36H。
进行读写操作时,先读写低8位字节,再读写高8位字节,通道0工作在方式3,即方波发生器(分频器方式)。
方波的频率为1.193MHz/65536
18.2Hz,方波周期约为838ns,即8254定时器每隔838ns记一个数。
对于实验要求的Nms,此时此时计数初值为Nms/838ns=1193*N,考虑到1193*N可能超出计数器的最大计数值65536,若1.193*N小于65536,则直接设置8254计数器的初始值为需要的计数值1193*N,需要将这个计数初值转换成十六进制数。
若1193*N大于65536,首先将计数器初始值设置为1193*N和65536的余数,计满余数对应的时间,之后再计数m=1193*N/65536次,计数初值设置为0即可。
采用这样的设计方式,实现了对于任意给定时间间隔的计数。
图形的绘制:
显示器的屏幕是不能够直接进行绘图的。
因此绘图之前需要将屏幕转换为可绘图的格式,而且注意绘图模式下的屏幕坐标是以像素为单位,而二维的屏幕绘图模式,左上角是原点,向右是X轴正半轴,向下时Y轴正半轴。
要在图形坐标下的绘制转换为屏幕像素坐标下的形式才行。
数据文件的创建和数据保存:
首先在主程序中创建一个只写的文本文件,然后在采集到一个数据后将该数据的数字量和对应的电压等信息用fprintf()函数写入文件。
在退出程序时关闭数据文件。
1.6实验程序
#include
#include
#include
#include
doubleTimeInterval;
intEndStroke;
intCurInterruptTimes;
longintCurInterruptNum;
longintInterruptNum;
intLongCount;
unsignedcharL8;
unsignedcharH8;
intIWXMin,IWXMax,IWYMin,IWYMax;/*RegionofScreenPixel*/
doubleDXMin,DXMax,DYMin,DYMax;/*Regionofrealvalue*/
doubleDXStep,DYStep;/*StepofGrid*/
doubleDReferenceLine;/*realvalueofReferenceLine*/
intIGrid;/*1:
DrawGrid;0:
Don'tdrawgrid*/
intIsShowRealData;/*Doesshowtherealdata,1:
showrealdata;0:
simulatedata*/
FILE*fp;
intLastWDotX,LastWDotY;
voidinterrupt(*oldint8)(void);
voidinterruptmyint8(void);
voidCalculateInterruptPara(doubleDTimeInterval,int*ILongCount,unsignedchar*CL8,unsignedchar*CH8);
voidSetupTimerInterrupt(void);
voidRestoreTimerInterrupt(void);
voidReadSetupFromFile(void);
voidReadSetupFromFile(void);
voidProcess();
//获得屏幕X坐标
intGetScreenX(doubleRealX,intWXMin,intWXMax,doubleXMin,doubleXMax)
{
intWX=(WXMax-WXMin)/(XMax-XMin)*(RealX-XMin)+WXMin;
returnWX;
}
//获得屏幕Y坐标
intGetScreenY(doubleRealY,intWYMin,intWYMax,doubleYMin,doubleYMax)
{
intWY=WYMax-(WYMax-WYMin)/(YMax-YMin)*(RealY-YMin);
returnWY;
}
//计算定时器间隔
intGetInterval(doubleRealInterval,intWRegion,doubleRegion)
{
intInterval=WRegion/Region*RealInterval;
returnInterval;
}
//绘制坐标系
voidDrawCoordinate(intWXMin,intWXMax,intWYMin,intWYMax,doubleXMin,doubleXMax,doubleYMin,doubleYMax,doubleXStep,doubleYStep,doubleRefLine,intGrid)
{
charLabel[10];
intWYRefLine;
intWDot;
doubleDot;
inti;
/*DrawFrame*/
line(WXMin,WYMin,WXMax,WYMin);/*top*/
line(WXMin,WYMin,WXMin,WYMax);/*left*/
line(WXMin,WYMax,WXMax,WYMax);/*Bottom*/
line(WXMax,WYMin,WXMax,WYMax);/*right*/
/*DrawReferenceLine*/
WYRefLine=GetScreenY(RefLine,WYMin,WYMax,YMin,YMax);
setcolor
(1);
setlinestyle(0,0,3);
line(WXMin-25,WYRefLine,WXMax+25,WYRefLine);
line(WXMax+25,WYRefLine,WXMax,WYRefLine-13);
line(WXMax+25,WYRefLine,WXMax,WYRefLine+13);
line(WXMin,WYMax+25,WXMin,WYMin-15);
line(WXMin,WYMin-15,WXMin-13,WYMin+5);
line(WXMin,WYMin-15,WXMin+13,WYMin+5);
gcvt(RefLine,5,Label);
setcolor(63);
setlinestyle(0,0,1);
settextstyle(0,0,1);
outtextxy(WXMin-20,WYRefLine-2,Label);
/*DrawXStep*/
i=0;
while
(1)
{
Dot=XMin+i*XStep;
WDot=GetScreenX(Dot,WXMin,WXMax,XMin,XMax);
if(WDot>WXMax)
{
break;
}
if(Grid==1)
{
line(WDot,WYMin,WDot,WYMax);
}
else
{
line(WDot,WYMax,WDot,WYMax-5);
}
gcvt(Dot,5,Label);
outtextxy(WDot-5,WYMax+8,Label);
i++;
}
/*DrawyStep*/
i=0;
while
(1)
{
Dot=YMin+i*YStep;
WDot=GetScreenY(Dot,WYMin,WYMax,YMin,YMax);
if(WDot{
break;
}
if(Grid==1)
{
line(WXMin,WDot,WXMax,WDot);
}
else
{
line(WXMin,WDot,WXMin+5,WDot);
}
gcvt(Dot,5,Label);
if(Dot<0)
{
outtextxy(WXMin-30,WDot-2,Label);
}
else
{
outtextxy(WXMin-20,WDot-2,Label);
}
i++;
}
}
voidInitiateGraphic(void)
{
intDriver=DETECT,Mode;
initgraph(&Driver,&Mode,"");
setbkcolor
(2);
}
//读取配置
voidReadSetupFromFile(void)
{
FILE*fp1;
fp1=fopen("Setup.txt","r");
fscanf(fp1,"%d,%d,%d,%d\n",&IWXMin,&IWXMax,&IWYMin,&IWYMax);
fscanf(fp1,"%le,%le,%le,%le\n",&DXMin,&DXMax,&DYMin,&DYMax);
fscanf(fp1,"%le,%le\n",&DXStep,&DYStep);
fscanf(fp1,"%le\n",&DReferenceLine);
fscanf(fp1,"%d\n",&IGrid);
fscanf(fp1,"%d\n",&IsShowRealData);
fclose(fp1);
}
//计算中断定时器初值
voidCalculateInterruptPara(doubleDTimeInterval,int*ILongCount,unsignedchar*CL8,unsignedchar*CH8)
{
doubleTotalCounter=DTimeInterval*1193;
intResidue;
*ILongCount=TotalCounter/65536;
Residue=TotalCounter-65536*(*ILongCount);
*CH8=Residue>>8;
*CL8=Residue&0x0FF;
}
//设置定时器中断和初值
voidSetupTimerInterrupt(void)
{
/*StartInterrupt*/
disable();
oldint8=getvect(0x08);
outportb(0x43,0x36);
outportb(0x40,L8);
outportb(0x40,H8);
setvect(0x08,myint8);
enable();
}
//恢复原始中断映射
voidRestoreTimerInterrupt(void)
{
disable();
outportb(0x40,0x00);
outportb(0x40,0x00);
setvect(0x08,oldint8);
enable();
}
//中断程序核心任务,完成数据采集,曲线显示,数据存储和D/A输出,在中断服务程序中调用
voidProcess()
{
intIndex,IData;
doubleDData;
intADDA;
doubleDealedData;
doubleRealTime;
doubleXRegion;
intWDotX,WDotY;
intWDotZero;
Index=CurInterruptNum;
RealTime=CurInterruptNum*TimeInterval/1000.0;
if(IsShowRealData==1)
{
outportb(0x280,0x00);
do
{;
}while(!
(inportb(0x285)&0x80));
IData=inportb(0x281)|((inportb(0x282)&0x0f)<<8);/*A/D*/
DData=5-(4095-IData)*10.0/(pow(2,12));
ADDA=(DealedData-(-5))*pow(2,12)/10;/*D/A*/
outportb(0x283,(ADDA&0x00ff));
outportb(0x284,((ADDA>>8)&0x0f));
}
elseif(IsShowRealData==0)
{
IData=Index%10;
DData=50*sin(0.1*Index);
}
fprintf(fp,"%d\t%d\t%le\t%le\n",Index,IData,RealTime,DData);
if(RealTime>DXMax)
{
XRegion=DXMax-DXMin;
DXMin=DXMax;
DXMax=DXMin+XRegion;
cleardevice();
DrawCoordinate(IWXMin,IWXMax,IWYMin,IWYMax,DXMin,DXMax,DYMin,DYMax,DXStep,DYStep,DReferenceLine,IGrid);
LastWDotX=IWXMin-1;
}
if(RealTime<=DXMax)
{
WDotX=GetScreenX(RealTime,IWXMin,IWXMax,DXMin,DXMax);
WDotY=GetScreenY(DData,IWYMin,IWYMax,DYMin,DYMax);
setcolor(4);
setlinestyle(0,0,3);
if(LastWDotX{
if(LastWDotX!
=0)
{
WDotZero=LastWDotY+(WDotY-LastWDotY)*(IWXMin-WDotX)/(WDotX-LastWDotX);
line(IWXMin,WDotZero,WDotX,WDotY);
}
else
{
line(WDotX,WDotY,WDotX,WDotY);
}
}
else
{
line(WDotX,WDotY,LastWDotX,LastWDotY);
}
LastWDotX=WDotX;LastWDotY=WDotY;
setcolor(63);
setlinestyle(0,0,1);
}
}
//定时器中断服务程序
voidinterruptmyint8(void)
{
if(kbhit())
{
EndStroke=bioskey(0);
}
if(LongCount==0)
{
Process();
CurInterruptNum++;
}
elseif(LongCount>0)
{
CurInterruptTimes++;
outportb(0x40,0x00);
outportb(0x40,0x00);
if(CurInterruptTimes<=LongCount)
{
;
}
elseif(CurInterruptTimes==(LongCount+1))
{
outportb(0x40,L8);
outportb(0x40,H8);
Process();
CurInterruptTimes=0;
CurInterruptNum++;
}
}
outportb(0x20,0x20);
}
voidmain()
{
char*DataFileName;
DataFileName=(char*)malloc(sizeof(char)*100);
printf("PleaseEntertheIntervaloftheinterrupt:
\n");
scanf("%le",&TimeInterval);
printf("Pleaseinputthetimesofinterrupt:
\n");
scanf("%d",&InterruptNum);
printf("Pleaseenterthenameofdatafile:
\n");
scanf("%s",DataFileName);
fp=fopen(DataFileName,"w");
if(fp==NULL)
{
printf("can'topenthedatafile%s",DataFileName);
return;
}
CalculateInterruptPara(TimeInterval,&LongCount,&L8,&H8);
CurInterruptNum=0;
CurInterruptTimes=0;
InitiateGraphic();
ReadSetupFromFile();
DrawCoordinate(IWXMin,IWXMax,IWYMin,IWYMax,DXMin,DXMax,DYMin,DYMax,DXStep,DYStep,DReferenceLine,IGrid);
SetupTimerInterrupt();
while
(1)
{//以下是处理退出机制
if(InterruptNum==0)
{
if(EndStroke==11875)
{
break;
}
}
elseif(InterruptNum<0)
{
InterruptNum=-InterruptNum;
}
else
{
if(CurInterruptNum{
if(EndStroke==11875)
{
break;
}
}
elseif(CurInterruptNum==InterruptNum)
{
break;
}
}
}
RestoreTimerInterrupt();
fclose(fp);
free(DataFileName);
closegraph();
getch();
}
1.7实验运行结果和调试分析
图1定时中断和数据采集实验结果图
从上图可以得出,信号的输出能够真实反映实时采集的信号,当输入信号的幅值和频率都发生变化时,输出的信号也跟随着进行平滑地变化。