windows环境下高速数据采集 (提供源程序的我会在开一贴另送100-200分,如果有虚拟仪器的源程序我再加100-200分。) (200分)

  • 主题发起人 主题发起人 gaozhou
  • 开始时间 开始时间
G

gaozhou

Unregistered / Unconfirmed
GUEST, unregistred user!
如题,希望采样频率能达到5kHz以上。<br>(提供源程序的我会在开一贴另送100-200分)<br>如果有虚拟仪器的源程序我再加100-200分。
 
得用专用的数据处理芯片(DSP)吧?
 
LAbWindows/CVI或LabView有DEMO
 
Attention!<br>
 
自己编驱动程序,就可以了.
 
难道这个问题没人能解决吗?
 
转一篇 <br><br>采用多线程进行数据采集 <br><br>整理编辑:China ASP <br><br>---- 数据采集技术在工业控制及自动化等领域中发挥着重要的作用。数据采集的一般过 <br><br>程是这样的: <br><br>&nbsp; &nbsp;①向采集卡发出通道选择指令。 <br><br>&nbsp; &nbsp;②选择要采集的通道号。 <br><br>&nbsp; &nbsp;③启动A/D转换。 <br><br>&nbsp; &nbsp;④等待,直到转换完成。 <br><br>&nbsp; &nbsp;⑤从采集卡读出数据。 <br><br>&nbsp; &nbsp;对于多通道的采集,在程序的设计中,一般采用的两种方法。查询法或中断法。所谓 <br><br>查询方法就是采用一个循环,依次采集各个数据通道。查询法的优点是程序简单,易于 <br><br>实现;缺点是采集过程中,CPU多数时间是在等待,造成资源的浪费。中断法是采用硬件 <br><br>中断的形式——先启动A/D转换,在转换结束时发出一中断信号——CPU响应采集卡的中 <br><br>断时读出所采集的数据。这样,在等待转换的时间里,CPU可以进行其他的计算工作,而 <br><br>不用处于等待状态。中断法的优点是资源能充分利用;但是程序设计复杂,尤其是当系 <br><br>统的硬件中断资源紧张时,很容易造成中断冲突;另外,在Windows或Win95等操作系统 <br><br>中,不允许用户安装中断处理程序时,则无法实现。 <br><br>---- 以上讨论的两种方法都是在DOS下的方法;在Win95下,现在有了一个更好的方法— <br><br>—多线程技术。现在,我们可以利用多线程技术来进行数据采集。 <br><br>1. 采用多线程进行数据采集的优点 <br><br>---- Win95/98最让人喜爱的除了漂亮的界面以外,就是多线程与多任务了。DOS环境中 <br><br>,执行中的程序可以独占全部的资源;在Windows环境中,虽然它是一个略具雏形的多任 <br><br>务环境,但是只要你喜欢,你的程序仍然可以掌握所有的CPU时间。但是,在Windows 9 <br><br>5以及Windows NT中,一个程序无法独占所有的CPU执行时间。而且,一个程序也不是从 <br><br>头到尾一条线。相反,一个程序在执行中可以分为多个程序片段,同时执行。这些能同 <br><br>时执行的程序片段称为线程。在Windows 95以及Windows NT中,操作系统同一时间可以 <br><br>轮流执行多个程序,这就是多任务。 <br><br>---- 采用多线程进行数据采集可以有效地加快程序的反应速度、增加执行的效率。一般 <br><br>的程序中都要处理用户的输入,但用户的输入速度与CPU的执行速度相比就向走路与做飞 <br><br>机一样。这样,CPU就将浪费大量的时间用来等待用户的输入(如在DOS环境中)。如果 <br><br>采用多线程,那么就可以用一个线程等待用户的输入;另一个线程进行数据处理或其他 <br><br>的工作。对于数据采集程序,可以用一个单独的线程进行数据采集。这样,能最大限度 <br><br>的保证采集的实时性,而另外的线程同时又能及时地响应用户的操作或进行数据处理。 <br><br>否则,程序在采集数据时就不能响应用户的操作;在响应用户操作时就不能进行数据采 <br><br>集。尤其当采集的数据量很大,数据处理任务很重时,如果不采用多线程,采集时的漫 <br><br>长的等待是很让人接受的。 <br><br>---- 但是,多线程要比普通程序设计复杂得多。由于任一时刻都可能有多个线程同时执 <br><br>行,所以,许多的变量、数据都可能会被其他线程所修改。这就是多线程程序中最关键 <br><br>的线程间的同步控制问题。 <br><br>2. 多线程进行数据采集应解决的问题 <br><br>---- 其实,多线程程序设计复杂是暂时的;如果,你采用传统的C进行多线程的设计, <br><br>那么你必须自己控制线程间的同步。那将是很复杂的。但是,如果利用面向对象的设计 <br><br>方法,采用Delphi进行多线程程序设计,问题就简单多了。这是因为,Delphi已将多线 <br><br>程的复杂性替我们处理了,我们所要做的就是继承。 <br><br>---- 具体地说,多线程数据采集需要完成以下工作: <br><br>---- ① 从TThread类派生一个自己的类SampleThread。这就是我们用于数据采集的类。 <br><br>进行采集时,只需要简单地创建一个SampleThread的实例。 <br><br>---- ② 重载超类TThread的Execute方法。在这一方法中将具体地执行数据采集任务。 <br><br>&nbsp; <br><br>---- ③ 如果希望一边采集一边显示,就在编写几个用于显示采集进度的过程,供Exec <br><br>ute方法调用。 <br><br>---- TThread类中最常用的属性/方法如下: <br><br>&nbsp; &nbsp; &nbsp; ①Create方法:constructor Create(CreateSuspended: Boolean); <br><br>---- 其中CreateSuspended参数确定线程在创建时是否立即执行。如果为True,新线程 <br><br>在创建后被挂起;如果为False,线程在创建后立即执行。 <br><br>&nbsp; &nbsp; &nbsp; ②FreeOnTerminate属性:property FreeOnTerminate: Boolean; <br><br>---- 该属性确定程序员是否负责撤消该线程。如果该属性为True,VCL将在该线程终止 <br><br>时自动撤消线程对象。它的缺省值为False。 <br><br>&nbsp; &nbsp;③OnTerminate属性:property OnTerminate: TNotifyEvent; <br><br>---- 该属性指定一个当线程终止时发生的事件。 <br><br>---- 下面看一个具体的例子: <br><br>3. 多线程数据采集的实现 <br><br>---- 这是笔者开发的一个测抽油机功图的程序。它的功能是采集抽油机悬点的载荷及位 <br><br>移数据,经过处理后做出抽油机的功图。图1(略)所示是数据采集时的界面。点“采集数 <br><br>据”按钮后,程序将创建一新的线程,并设置其属性。这一新线程将完成数据采集任务 <br><br>。程序如下: <br><br>Procedure TsampleForm.DoSampleBtnClick(Sender: TObject); <br><br>Begin <br><br>&nbsp; &nbsp; &nbsp;ReDrawBtn.Enabled := True; <br><br>&nbsp; &nbsp; &nbsp;DoSampleBtn.Enabled := False; <br><br>&nbsp; &nbsp; &nbsp;FFTBtn.Enabled := True; <br><br>&nbsp; &nbsp; TheSampler := SampleThread.Create(False); // &nbsp;创建采集线程 <br><br>&nbsp; &nbsp; TheSampler.OnTerminate := FFTBtnClick; &nbsp; //采集完成后要执行的任务 <br><br>&nbsp; &nbsp; &nbsp;TheSampler.FreeOnTerminate := True; &nbsp;// &nbsp; &nbsp;采集完成后撤消 <br><br>End; <br><br>采集线程的类定义如下: <br><br>Type <br><br>&nbsp; SampleThread = class(TThread) <br><br>&nbsp; Public <br><br>&nbsp; &nbsp; &nbsp; function AdRead(ach: byte): integer; safecall; &nbsp;读A/D卡的函数 <br><br>&nbsp; &nbsp; &nbsp; procedure UpdateCaption; //显示采集所用时间 <br><br>&nbsp; private <br><br>&nbsp; &nbsp; { Private declarations } <br><br>&nbsp; protected <br><br>&nbsp; &nbsp; thes, thep: real; <br><br>&nbsp; &nbsp; dt: real; <br><br>&nbsp; &nbsp; id: integer; <br><br>&nbsp; &nbsp; st, ed: LongInt; <br><br>&nbsp; &nbsp; procedure Execute; override; //这是关键。 <br><br>&nbsp; End; <br><br>---- 在这个类中定义了一个函数AdRead用于操作A/D卡,两个过程用于显示采集的进度 <br><br>与所用时间。需要注意的是AdRead函数是用汇编写的,参数调用格式必须是safecall。 <br><br>&nbsp; <br><br>---- 关键的重载方法Execute的代码如下: <br><br>Procedure SampleThread.Execute; <br><br>Begin <br><br>&nbsp; &nbsp; StartTicker := GetTickCount; <br><br>&nbsp; &nbsp; id := 0; <br><br>&nbsp; &nbsp; Repeat <br><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;thes := Adread(15) * ad2mv * mv2l; //采集第15通道 <br><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;thep := Adread(3) * ad2mv * mv2n; &nbsp; //采集第3通道 <br><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dt := GetTickCount - StartTicker; <br><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;sarray[id] := thes; <br><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;parray[id] := thep; <br><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tarray[id] := dt; <br><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;inc(id); <br><br><br><br>&nbsp; &nbsp; &nbsp; &nbsp; Synchronize(UpdateCaption); &nbsp;//注意:显示采集进度 <br><br>&nbsp; Until id &gt;=4096; <br><br>&nbsp; ed := GetTickCount; <br><br>&nbsp; Synchronize(ShowCostTime); &nbsp;// 注意:显示所用时间 <br><br>end; <br><br>---- 从以上代码中可见,Execute与一般的代码并无本质区别。仅有的区别是显示采集 <br><br>进度和显示所用时间时,不能直接调用各自的过程,而是通过调用Synchronize间接地调 <br><br>用。这样作是为了保持进程间的同步。 <br><br>4. 结论 <br><br>---- 以上的程序采用Delphi 4.0编程,在AMD-K6-2/300上实现。测试结果是这样的:采 <br><br>用多线程,采集4096个点一般耗用10~14s的时间;如果不采用多线程则需要1分钟到1分 <br><br>半。可见多线程可明显提高程序的执行效率。 <br><br>&nbsp;
 
我是做数据采集的,我的采样率是1G,信号是500M。<br><br>虚拟一起我已经作成了,你的速率很低,应该很简单,不知道是不是允许数据丢失。
 
只要是丢失不过分就行。<br>我的分不是问题。只要你能提供解决方法。
 
硬件是我自己作的,你的不知道是怎样来得?<br>如果也是自己搞,就简单了。<br>直接分配地址,读内存<br><br>
 
当然是自己搞。<br>你能详细的说一下吗?<br>也可以通过Email同我联系mlzhougao@163.com
 
5KHZ简单,声卡录音能到20KHZ,不会有数据丢失。<br><br>学习一下mmsystem的API,或者用mmtools都可以了。
 
我做的是PCI采集卡,如果你懂,就可以。
 
to power_lei,<br>能详细的说一下吗?<br>方便的话,请留下你的Email。 <br><br>其他的人还有什么好建议吗?
 
mail:little_lei@sina.com<br>最近很忙,很少上网
 
请大家继续参与回答。
 
这个简单,AD/DA转换的时间是纳秒级的,关键是你的延时的处理。<br><br>我这里将去年做的东西的一个模块贴出来,建议你将延时用For循环来代替。<br><br>这样的速度非常高<br><br>{ -----------------------------------------------------------------------------}<br>{ 更新日期: &nbsp;22/4/2002 &nbsp; &nbsp; &nbsp;<br>&nbsp; 作者:司马华鹏}<br>{ -----------------------------------------------------------------------------} &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br>{ 多线程采集与多线程绘制模块 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>{------------------------------------------------------------------------------}<br><br>unit UnitTThread;<br><br>interface<br><br>uses<br>&nbsp; Classes, Windows, Sysutils,Graphics,SyncObjs;<br><br>const<br>&nbsp; &nbsp;Pie:Single=3.14159;<br>&nbsp; &nbsp;<br>type<br>&nbsp; //采集线程<br>&nbsp; TCollectThread = class(TThread)<br>&nbsp; private<br>&nbsp; &nbsp; W,H:integer;<br>&nbsp; &nbsp; procedure DoPaint; //绘制仿真动画<br>&nbsp; &nbsp; function ChangeAngle(xOld,yOld:integer;Rotation:single):Tpoint;//角度旋转转换<br>&nbsp; &nbsp; procedure PlaySound(le_son : pchar);//播放资源文件中的声音<br>&nbsp; protected<br>&nbsp; &nbsp; procedure Execute; override;<br>&nbsp; public<br>&nbsp; &nbsp; constructor Create;//构造函数<br>&nbsp; end;<br><br>implementation<br><br>uses UnitMain,UnitAD,MMsystem;<br><br>{------------------------------------------------------------------------------}<br>{----采集线程----}<br>{------------------------------------------------------------------------------}<br>Constructor TCollectThread.Create;//构造函数<br>begin<br>&nbsp; &nbsp;W:=frmMain.imgPlay.Width;<br>&nbsp; &nbsp;H:=frmMain.imgPlay.Height;<br>&nbsp; &nbsp;FreeOnTerminate:=True; &nbsp;//退出时自动释放<br>&nbsp; &nbsp;inherited Create(False); //创建即可运行<br>end;<br><br>procedure TCollectThread.Execute;//执行函数<br>var<br>&nbsp; &nbsp;V:single;//电压值<br>&nbsp; &nbsp;H,L:Byte;//高位、低位<br>&nbsp; &nbsp;K:Byte;<br>begin<br>&nbsp; &nbsp;while not Terminated do begin<br><br>&nbsp; &nbsp; &nbsp; PortWriteByte($100,0); &nbsp;//初始化 &nbsp;outp(0x100,0);<br>&nbsp; &nbsp; &nbsp; PortWriteByte($101,0); //开始转换 outp(0x101,0);<br><br>&nbsp; &nbsp; &nbsp; repeat<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;K:=(PortReadByte($101) and 1); //k=intp(0x101) &amp; 1<br>&nbsp; &nbsp; &nbsp; until (k=0); //软件查询(基于转换速度) //if (k==0) <br><br>&nbsp; &nbsp; &nbsp; H:=PortReadByte($102); // intp(0x102);<br>&nbsp; &nbsp; &nbsp; L:=PortReadByte($103); // intp(0x103);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br>&nbsp; &nbsp; &nbsp; V:=10*(H*16+L/16)/4096-5;//转换为电压信号<br>&nbsp; &nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; iAngle:=V*2;//转换为角度信息(角度值)<br><br>&nbsp; &nbsp; &nbsp; if iAngle&gt;=5 then PlaySound('Wrong');//发出警告<br>&nbsp; &nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; Synchronize(DoPaint);//绘图<br>&nbsp; end;<br>end;<br><br>procedure TCollectThread.doPaint;//绘图<br>var<br>&nbsp; &nbsp;P: Array[0..3] of TPoint;<br>&nbsp; &nbsp;R:TRect;<br>&nbsp; &nbsp;strTmp:string;<br>&nbsp; &nbsp;sglTmp:single;<br>begin<br><br>&nbsp; &nbsp;strTmp:=Floattostr(iAngle); //浮点型转换为字符型<br>&nbsp; &nbsp;sglTmp:=iAngle*Pie/180; //角度转弧度<br>&nbsp; &nbsp; &nbsp; <br>&nbsp; &nbsp;with frmMain.imgPlay do begin//使用双缓冲<br>&nbsp; &nbsp; &nbsp;Canvas.FillRect(Canvas.ClipRect);//刷新<br>&nbsp; &nbsp; &nbsp;P[0]:=ChangeAngle(40,20,sglTmp);<br>&nbsp; &nbsp; &nbsp;P[1]:=ChangeAngle(40,H-60,sglTmp);<br>&nbsp; &nbsp; &nbsp;P[2]:=ChangeAngle(W-40,H-60,sglTmp);<br>&nbsp; &nbsp; &nbsp;P[3]:=ChangeAngle(W-40,20,sglTmp);<br>&nbsp; &nbsp; &nbsp;Canvas.Polygon(P);//画小车<br><br>&nbsp; &nbsp; &nbsp;R.Left:=75;<br>&nbsp; &nbsp; &nbsp;R.Top:=H-60;<br>&nbsp; &nbsp; &nbsp;R.Right:=W-75;<br>&nbsp; &nbsp; &nbsp;R.Bottom:=H-30;<br>&nbsp; &nbsp; &nbsp;Canvas.Ellipse(R);//画圆形<br><br>&nbsp; &nbsp; &nbsp;SetBkMode(Canvas.Handle,1);//透明字体<br>&nbsp; &nbsp; &nbsp;Canvas.TextOut((W-Canvas.TextWidth(strTmp)) div 2,H-20,strTmp);//打印角度<br>&nbsp; &nbsp;end;<br><br>&nbsp; &nbsp;frmMain.pbMain.Invalidate;<br>end;<br><br>//角度旋转变换<br>function TCollectThread.ChangeAngle(xOld,yOld:integer;Rotation:single):Tpoint;<br>var<br>&nbsp; &nbsp;cX,cY:integer;<br>begin<br>&nbsp; &nbsp;cX:=W div 2;<br>&nbsp; &nbsp;cY:=H -15;<br>&nbsp; &nbsp;Result.X:=Round((xOld-cX)*cos(Rotation)-(cY-yOld)*sin(Rotation)+cX);<br>&nbsp; &nbsp;Result.Y:=Round(cy-(xOld-cx)*sin(Rotation)-(cY-yOld)*cos(Rotation));<br>end;<br><br>//播放资源文件中的声音<br>procedure TCollectThread.PlaySound(le_son : pchar);<br>var<br>&nbsp; h: THandle;<br>&nbsp; p: pointer;<br>begin<br>&nbsp; h := FindResource(hInstance,le_son,'WAV');<br>&nbsp; h := LoadResource(hInstance, h);<br>&nbsp; p := LockResource(h);<br>&nbsp; sndPlaySound(p,SND_MEMORY or SND_ASYNC);<br>&nbsp; UnLockResource(h);<br>&nbsp; FreeResource(h);<br>end; &nbsp; <br>end.<br>&nbsp;
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
2K
DelphiTeacher的专栏
D
后退
顶部