實現與研華PCI采集卡通訊


如果使用過PCI采集卡的盆友應該對“研華”這個品牌不陌生,可以說研華還是很強大的。最近因為工作需要,使用一塊研華的PCI1714UL型號的采集卡,去高速采集電壓信號,學習了幾天后分享給各位。

采集卡

首先介紹一下這塊采集卡。品牌:研華Advantech,型號:PCI1714UL,基本參數:4通道,12位精度,采樣頻率:10MS/s,采樣:8192/通道,可采集電壓范圍有:±5、±2.5、±1、±0.5,每個范圍對應的絕對精度不同,所以視情況來決定需要什么樣的采樣范圍。支持PCI總線控制DMA數據傳輸。

工作方式

這塊采集卡有兩種工作模式:BufferedAI、InstantAI。

BufferedAI:使用PC的一個存儲塊,可以實現總線控制數據采集,不需要占用CPU;

InstantAI:瞬時值,采樣率相對沒那么高,適合一些對數據要求不算太高的場合。

資料下載

官網   資料

驅動安裝

研華提供了一款DAQNavi軟件(見“資料下載”去官網下載),有一個Navigator,可以直接打開可以看到所有支持的卡,選中你需要的卡右鍵就可以安裝驅動了。並且這款軟件也提供數據采集展示。

 

軟件二次開發:接口函數---Automation.BDaq4(見“資料下載”去官網下載)

一、使用研華提供的控件進行二次開發

研華提供了相關控件:

 WaveformAiCtrl用於BufferedAI讀取,InstantAiCtr用於InstantAI讀取。 

二、自己從底層開發

瞬時電壓讀取比較簡單,直接創建InstantAiCtrl,傳遞一個設備名稱:instantAiCtrl.SelectedDevice = new DeviceInformation(deviceCode);初始化:instantAiCtrl.Initialized,就可以開始讀取數據了:instantAiCtrl.Read(channelIndex,out data[channelIndex])。

BufferedAI代碼量多一點:首先需要創建一個線程,用於將采集卡數據讀取到內存中,再開一個線程專門見內存中的數據往本地寫入(因為數據量太大不能一下處理),最后開一個線程用於將本地的數據讀取出來,進行數據處理、分析、展示。

代碼展示

1. 創建一個AnalogCard父類,利於再添加采集卡型號的時候進行擴展

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.IO;

namespace AdvantechPCIDemo
{
    /// <summary>
    /// 數據讀取策略:
    /// 采集卡讀取速度極快(10MS/s、30MS/s),因此現將采集卡數據保存至指定文件,多線程同步將數據讀取
    /// 再對數據進行處理、顯示
    /// </summary>
    public class AnalogCard
    {
        protected int channelCount;//通道數
        protected uint readLength;//數據一次讀取長度
        protected uint readCount;

        protected ManualResetEventSlim readEvent = new ManualResetEventSlim(false);
        protected ManualResetEventSlim writeEvent = new ManualResetEventSlim(false);
        protected ManualResetEventSlim readADEvent = new ManualResetEventSlim(false);

        protected Task writeTask;//任務:將內存Queue數據寫入指定文件
        protected Task readTask;//任務:將指定文件數據讀入內存Queue
        protected Task readADTask;//任務:將采集卡數據讀取進內存Queue

        protected Queue<ushort[]> dataQueue = new Queue<ushort[]>(1000);//先進先出隊列,定義初始長度,不足自動增長
        protected CancellationTokenSource source = new CancellationTokenSource();//線程是否取消
        protected string fileName = string.Format("Data\\Data-{0}.txt", DateTime.Now.ToString("yy-MM-dd-HH-mm-ss"));//定義數據保存與讀取文件名
        protected Action<ushort[][]> ChannelDataAction { get; set; }

        public AnalogCard()
        {
            //將內存Queue數據寫入指定文件
            writeTask = Task.Factory.StartNew(() =>
            {
                using (FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read))
                {
                    while (true)
                    {
                        writeEvent.Wait(source.Token);//等待開啟寫入任務
                        if (source.IsCancellationRequested) return;

                        if (dataQueue.Count == 0) continue; ;
                        ushort[] us = dataQueue.Dequeue();//將第一個數據去除並移除
                        if (dataQueue.Count > 1000) { dataQueue.Clear(); }

                        byte[] bt = new byte[readLength * 2];

                        for (int i = 0, j = 0; i < us.Length; i++)
                        {
                            ushort temp = us[i];
                            bt[j++] = (byte)(temp >> 8);//取高八位
                            bt[j++] = (byte)temp;//取低八位
                        }
                        fs.Write(bt, 0, bt.Length);
                    }
                }
            }, source.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);

            Thread.Sleep(500);

            //將指定文件的數據流寫入內存隊列Queue
            readTask = Task.Factory.StartNew(() =>
            {
                using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Write))
                {
                    int currentLength = 0;
                    byte[] bt=null;
                    while (true)
                    {
                        readEvent.Wait(source.Token);//等待開啟讀取
                        if (source.IsCancellationRequested) break;//任務被取消

                        if (bt == null)
                        {
                            bt = new byte[readLength * 2];//byte數組為需要讀取數據的兩倍:兩個字節轉換為一個字符
                        }
                        
                        if (currentLength < bt.Length)
                        {
                            currentLength = fs.Read(bt, currentLength, bt.Length - currentLength);
                        }
                        else
                        {
                            currentLength = 0;

                            if (ChannelDataAction == null)
                                throw new Exception("無通道數據接收方法!");

                            ushort[][] us;
                            if (!GetChannelData(bt, out us))
                                throw new Exception("");

                            ChannelDataAction(us);//將讀取到的數據向上傳遞
                        }
                    }
                }
            });
        }

        protected virtual void StartWriteReadTxt()
        {
            writeEvent.Set();
            readEvent.Set();
            readADEvent.Set();

            dataQueue.Clear();
        }

        protected virtual void StopWriteReadTxt()
        {
            writeEvent.Reset();
            readEvent.Reset();
            readADEvent.Reset();
        }

        public virtual void CancelWriteReadTxt()
        {
            source.Cancel();
        }

        /// <summary>
        /// 將讀取的數據分到各通道
        /// 數據順序:temp[0]+temp[1]=ch1va1;temp[2]+temp[3]=ch2va1...
        /// </summary>
        /// <param name="temp"></param>
        /// <returns></returns>
        private bool GetChannelData(byte[] temp, out ushort[][] us)
        {
            us = new ushort[channelCount][];

            int index = 0;
            for (int i = 0; i < temp.Length; i+=2*channelCount)
            {
                
                for (int j = 0; j < channelCount; j++)
                {
                    if (us[j] == null)
                    {
                        us[j] = new ushort[readLength / channelCount];
                    }

                    us[j][index] = (ushort)((temp[i + j * 2] << 8) + temp[i + j * 2 + 1]);
                }
                index++;
            }
            return true;
        }


    }
}
View Code

在父類設置卡的一些基本字段,並創建了兩個線程:writeTask、readTask,分別是將內存Queue中數據寫入本地txt,將本地txt文件讀取進內存Queue。用ManualResetEventSlim對象現將該線程堵塞,等待開啟。

2. 創建一個PCI1714UL子類

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Automation.BDaq;
using System.Threading;
using System.Threading.Tasks;

namespace AdvantechPCIDemo
{
    public class PCI1714UL:AnalogCard
    {
        private string deviceCode = "";
        private const int bufferLength = 2048;
        private int channelMax=0;
        private BufferedAiCtrl bufferedCtrl = null;
        private InstantAiCtrl instantAiCtrl = null;
        private ManualResetEventSlim readADInternal = new ManualResetEventSlim(false);//有數據再開啟
        private ushort[] data;
        private object locker = new object();

        public PCI1714UL(string deviceCode):base()
        {
            this.deviceCode = deviceCode;
        }

        public void StartBufferedAI(int channelCount,Action<ushort[][]> channelDataAction)
        {
            bufferedCtrl = new BufferedAiCtrl();
            bufferedCtrl.SelectedDevice = new DeviceInformation(deviceCode);
            
            this.channelCount = channelCount;
            this.readLength = (uint)(bufferLength * channelCount);
            this.readCount = bufferLength;
            this.data = new ushort[readLength];
            this.ChannelDataAction = channelDataAction;

            ScanChannel channel = bufferedCtrl.ScanChannel;
            channel.ChannelCount = channelCount;
            channel.ChannelStart = 0;
            channel.IntervalCount = bufferLength; // each channel 觸發DataReady事件的采樣個數,即到了指定個數之后便觸發DataReady事件,可以跟windows的定時器控件類似
            channel.Samples = bufferLength;//采樣的個數。例如,我設定采樣個數為1024個,Rate是1024/s,那么也就是說采樣經過了1秒   

            bufferedCtrl.DataReady += new EventHandler<BfdAiEventArgs>(BufferedReady);
            this.channelMax = bufferedCtrl.Features.ChannelCountMax;
            bufferedCtrl.Streaming = false;
            ErrorCode ret = bufferedCtrl.Prepare();//初始化所選設備,准備開始
            if (ret != ErrorCode.Success) throw new InvalidOperationException("Failed to prepare AD!");

            //將采集卡數據讀取到Queue
            readADTask = Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    readADEvent.Wait(source.Token);//等待開啟
                    if (source.IsCancellationRequested) return;

                    if (!StartDevice()) return;//查看設備是否已運行
                    readADInternal.Wait(source.Token);//先等待,有數據傳遞觸發BufferedReady后再開啟

                    if (dataQueue.Count > 1000) dataQueue.Clear();

                    dataQueue.Enqueue(data);
                }
            }, source.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);

            StartWriteReadTxt();
        }

        public void StopBufferedAI()
        {
            bufferedCtrl.Stop();
            //bufferedCtrl.Dispose();
            StopWriteReadTxt();
        }

        public double[] StartInstantAI()
        {
            instantAiCtrl = new InstantAiCtrl();
            instantAiCtrl.SelectedDevice = new DeviceInformation(deviceCode);
            if (!instantAiCtrl.Initialized)
            {
                throw new Exception("No device be selected or device open failed!");
            }
            double[] data=new double[4] ;
            ErrorCode er0 = instantAiCtrl.Read(0,out data[0]);
            ErrorCode er1 = instantAiCtrl.Read(1, out data[1]);
            ErrorCode er2 = instantAiCtrl.Read(2, out data[2]);
            ErrorCode er3 = instantAiCtrl.Read(3, out data[3]);

            return data;
        }

        public void StopInstantAI()
        {
            if (instantAiCtrl.State == ControlState.Running)
            {
                instantAiCtrl.Dispose(); ;
            }
        }

        private bool StartDevice()
        {
            ErrorCode ret;
            if (bufferedCtrl.State != ControlState.Running)
            {
                readADInternal.Reset();

                ret = bufferedCtrl.Start();
                //Thread.Sleep(500);
                if (ret != ErrorCode.Success)
                {
                    //log.ErrorFormat("Failed to start PCI1714 first time! ErrorCode is {0}.", ret);

                    ret = bufferedCtrl.Stop();
                    if (ret != ErrorCode.Success)
                    {
                        //log.ErrorFormat("Failed to stop PCI1714! ErrorCode is {0}.", ret);
                    }

                    Thread.Sleep(500);

                    ret = bufferedCtrl.Start();
                    if (ret != ErrorCode.Success)
                    {
                        //log.ErrorFormat("Failed to start PCI1714 second time! ErrorCode is {0}.", ret);
                        return false;
                    }
                }

            }
            return true;
        }

        public void BufferedReady(object e,BfdAiEventArgs b)
        {
            short[] data = new short[b.Count];
            ErrorCode ret = bufferedCtrl.GetData(b.Count, data);//data存放的是從采集卡得到的數據
            if (ret != ErrorCode.Success)
            {                
                lock (locker)
                {
                    this.data = null;
                    readADInternal.Set();
                }
            }

            lock (locker)
            {
                this.data = data.Select(o => (ushort)o).ToArray();
                readADInternal.Set();
            }
        }
    }
}
View Code

在這個類里,先繼承上面的AnalogCard,再設置一些板卡信息。並提供兩種方式的數據讀取:StartBufferedAI,StartInstantAI。

主要說明StartBufferedAI:

在這里需要再創建一個線程readADTask,用於將采集卡數據讀取進內存Queue,同樣現將該線程堵塞等待開啟。定義一個BufferedReady事件,並進行綁定:bufferedCtrl.DataReady += new EventHandler<BfdAiEventArgs>(BufferedReady);這樣采集卡有數據后會自動觸發該事件,在該事件中將采集卡數據讀取出來。

3. 桌面數據顯示

參考研華的數據采集樣式,根據數據實時畫出數據曲線圖。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using Automation.BDaq;

namespace AdvantechPCIDemo
{
    public partial class FrmMain : Form
    {
        private ushort[][] us;//接受PCI發生來的數據
        private string deviceName = "PCI-1714UL,BID#13";
        public FrmMain()
        {
            InitializeComponent();

            OperateCustomBtn(false);

            DrawGrid(this.pbBuffCh1);
            DrawGrid(this.pbBuffCh2);
            DrawGrid(this.pbBuffCh3);
            DrawGrid(this.pbBuffCh4);

            DrawGrid(this.pbIstantCh1);
            DrawGrid(this.pbIstantCh2);
            DrawGrid(this.pbIstantCh3);
            DrawGrid(this.pbIstantCh4);
        }

        #region 數據列表定義
        private List<Point[]> pointFromBuffAI = new List<Point[]>();
        private List<double[]> dataFromBuffAI = new List<double[]>();

        private List<Point[]> pointFromInstantAI = new List<Point[]>();
        private List<double[]> dataFromInstantAI = new List<double[]>();
        #endregion

        #region 畫網格和曲線
        /// <summary>
        /// 畫網格
        /// </summary>
        /// <param name="pb"></param>
        private void DrawGrid(PictureBox pb)
        {
            int width = pb.Width, height = pb.Height;
            int cellWidth = height / 4;
            Color color = Color.Green;//綠色線條

            Bitmap bp = new Bitmap(width, height);
            Graphics objG = Graphics.FromImage(bp);
            objG.FillRectangle(new SolidBrush(Color.Black), 0, 0, width, height);//黑色背景

            //網格列
            for (int i = 0; i < width; i += cellWidth)
            {
                objG.DrawLine(new Pen(new SolidBrush(color)), i + cellWidth, 0, i + cellWidth, height);
            }

            //網格行
            for (int i = 0; i < width; i += cellWidth)
            {
                objG.DrawLine(new Pen(new SolidBrush(color)), 0, i + cellWidth, width, i + cellWidth);
            }

            pb.Image = bp;
        }


        /// <summary>
        /// 畫動態曲線
        /// </summary>
        /// <param name="channelIndex"></param>
        /// <param name="pb"></param>
        private void DrawBufferedAICurve()
        {
            for (int channel = 0; channel < 4; channel++)
            {
                PictureBox pbTemp = null;
                switch (channel)
                {
                    case 0:
                        pbTemp = this.pbBuffCh1; break;
                    case 1:
                        pbTemp = this.pbBuffCh2; break;
                    case 2:
                        pbTemp = this.pbBuffCh3; break;
                    case 3:
                        pbTemp = this.pbBuffCh4; break;
                }

                int width = pbTemp.Width, height = pbTemp.Height;

                if (pointFromBuffAI.Count == 0)
                {
                    for (int i = 0; i < 4; i++)
                    {
                        pointFromBuffAI.Add(new Point[width]);
                    }
                }
                lock (locker)
                {


                    while (dataFromBuffAI.Count >= width + 2)
                    {
                        dataFromBuffAI.RemoveAt(0);
                    }
                }

                int count = dataFromBuffAI.Count;

                if (count != 0)
                {
                    pointFromBuffAI[channel] = new Point[count];
                }

                for (int i = 0; i < width + 1; i++)
                {
                    if (i >= count) break;

                    if (dataFromBuffAI[i] == null) continue;

                    pointFromBuffAI[channel][i] = new Point(i, (int)(height - ((dataFromBuffAI[i][channel] + 5) * height) / 10));//從負到正                                                                                                                   //prData[channelIndex][i] = new Point(i, (int)(((Math.Abs(showData[i][channelIndex])) * height) / 10));//全負數
                }

                pbTemp.Refresh();
            }
        }

        private void ClearBufferedAICurve()
        {
            Graphics g = Graphics.FromImage(this.pbBuffCh1.Image);
            g.Clear(this.pbBuffCh1.BackColor);

            //DrawGrid(this.pbBuffCh1);
            //DrawGrid(this.pbBuffCh2);
            //DrawGrid(this.pbBuffCh3);
            //DrawGrid(this.pbBuffCh4);
        }

        private void DrawInstantAICurve()
        {
            for (int channel = 0; channel < 4; channel++)
            {
                PictureBox pbTemp = null;
                switch (channel)
                {
                    case 0:
                        pbTemp = this.pbIstantCh1; break;
                    case 1:
                        pbTemp = this.pbIstantCh2; break;
                    case 2:
                        pbTemp = this.pbIstantCh3; break;
                    case 3:
                        pbTemp = this.pbIstantCh4; break;
                }

                int width = pbTemp.Width, height = pbTemp.Height;

                if (pointFromInstantAI.Count == 0)
                {
                    for (int i = 0; i < 4; i++)
                    {
                        pointFromInstantAI.Add(new Point[width]);
                    }
                }
                lock (locker)
                {
                    while (dataFromInstantAI.Count >= width + 2)
                    {
                        dataFromInstantAI.RemoveAt(0);
                    }
                }

                int count = dataFromInstantAI.Count;

                if (count != 0)
                {
                    pointFromInstantAI[channel] = new Point[count];
                }

                for (int i = 0; i < width + 1; i++)
                {
                    if (i >= count) break;

                    if (dataFromInstantAI[i] == null) continue;

                    pointFromInstantAI[channel][i] = new Point(i, (int)(height - ((dataFromInstantAI[i][channel] + 5) * height) / 10));//從負到正                                                                                                                   //prData[channelIndex][i] = new Point(i, (int)(((Math.Abs(showData[i][channelIndex])) * height) / 10));//全負數
                }

                pbTemp.Refresh();
            }
        }

        private List<int> data = new List<int>();

        private Pen redPen = new Pen(Color.Red, 1);
        private void pBCh_Paint(object sender, PaintEventArgs e)
        {
            PictureBox pb = (PictureBox)sender;
            string pbName = pb.Name;

            if (pbName.Contains("pbBuffCh"))
            {
                if (pointFromBuffAI.Count == 4)
                {
                    switch (pbName)
                    {
                        case "pbBuffCh1":
                            if (pointFromBuffAI[0].Count() < 3) break;//畫曲線至少需要三個點
                            e.Graphics.DrawCurve(redPen, pointFromBuffAI[0]); break;
                        case "pbBuffCh2":
                            if (pointFromBuffAI[1].Count() < 3) break;
                            e.Graphics.DrawCurve(redPen, pointFromBuffAI[1]); break;
                        case "pbBuffCh3":
                            if (pointFromBuffAI[2].Count() < 3) break;
                            e.Graphics.DrawCurve(redPen, pointFromBuffAI[2]); break;
                        case "pbBuffCh4":
                            if (pointFromBuffAI[3].Count() < 3) break;
                            e.Graphics.DrawCurve(redPen, pointFromBuffAI[3]); break;
                    }
                }
            }
            else if (pbName.Contains("pbIstantCh"))
            {
                if (pointFromInstantAI.Count == 4)
                {
                    switch (pbName)
                    {
                        case "pbIstantCh1":
                            if (pointFromInstantAI[0].Count() < 3) break;//畫曲線至少需要三個點
                            e.Graphics.DrawCurve(redPen, pointFromInstantAI[0]); break;
                        case "pbIstantCh2":
                            if (pointFromInstantAI[1].Count() < 3) break;
                            e.Graphics.DrawCurve(redPen, pointFromInstantAI[1]); break;
                        case "pbIstantCh3":
                            if (pointFromInstantAI[2].Count() < 3) break;
                            e.Graphics.DrawCurve(redPen, pointFromInstantAI[2]); break;
                        case "pbIstantCh4":
                            if (pointFromInstantAI[3].Count() < 3) break;
                            e.Graphics.DrawCurve(redPen, pointFromInstantAI[3]); break;
                    }
                }
            }


        }
        #endregion

        #region 界面按鈕控制
        private void OperateCustomBtn(bool b)
        {
            this.btnCustomBufferedAI.Enabled = b;
            this.btnCustomInstantAI.Enabled = b;
        }

        private void OperateCtrBtn(bool b)
        {
            this.btnControlInstantAI.Enabled = b;
            this.btnControlBufferedAI.Enabled = b;
        }
        #endregion

        #region 自定義BufferedAI
        PCI1714UL objPCI1714 = null;
        private void btnConfirm_Click(object sender, EventArgs e)
        {
            try
            {
                objPCI1714 = new PCI1714UL(deviceName);
                
                OperateCustomBtn(true);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }         
        }

        private void btnStartRead_Click(object sender, EventArgs e)
        {
            try
            {
                //ClearBufferedAICurve();

                objPCI1714.StartBufferedAI(4, ChannelDataAction);
                OperateCtrBtn(false);
                OperateCustomBtn(false);

                bufferedAITimer.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void btnStopCusBuffAI_Click(object sender, EventArgs e)
        {
            try
            {                
                //if (objPCI1714 != null)
                //{
                //    objPCI1714.StopBufferedAI();
                //    //objPCI1714 = null;
                //    bufferedAITimer.Stop();

                //    OperateCustomBtn(true);
                //    OperateCtrBtn(true);
                //}
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void ChannelDataAction(ushort[][] us)//動作方法:接受與處理數據,並交給數據展示列表
        {
            this.us = us;

            if (us == null || us[0] == null) return;

            dataFromBuffAI.Add(this.us.Select(u1 =>
            {
                return GetVoltage(u1.Select(u => (double)u).ToList().Average());
            }).ToArray());
        }

        private double GetVoltage(double data)
        {
            return data * 10 / 4095 - 5.0190516943459;
        }


        private void customBufferedAI_Tick(object sender, EventArgs e)
        {
            DrawBufferedAICurve();
        }
        #endregion

        #region 自定義InstantAI
        private void btnCustomInstantAI_Click(object sender, EventArgs e)
        {
            try
            {
                customInstantAI.Start();

                OperateCustomBtn(false);
                OperateCtrBtn(false);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            
        }

        private void btnStopCusInstantAI_Click(object sender, EventArgs e)
        {
            try
            {
                //if (objPCI1714 != null)
                //{
                //    objPCI1714.StopInstantAI();
                //    objPCI1714 = null;
                //    customInstantAI.Stop();
                //}
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void customInstantAI_Tick(object sender, EventArgs e)
        {
            dataFromInstantAI.Add(objPCI1714.StartInstantAI());

            DrawInstantAICurve();
        }
        #endregion

        #region 控件BufferedAI
        //private double[] d;
        private void btnControlBufferedAI_Click(object sender, EventArgs e)
        {
            try
            {
                waveformAiCtrl1.SelectedDevice = new DeviceInformation(deviceName);
                if (!waveformAiCtrl1.Initialized)
                {
                    MessageBox.Show("No device be selected or device open failed!");
                    return;
                }

                int channelCount = waveformAiCtrl1.Conversion.ChannelCount;
                int sectionLength = waveformAiCtrl1.Record.SectionLength;

                //d = new double[channelCount*sectionLength];

                waveformAiCtrl1.Prepare();
                ErrorCode er=ErrorCode.Success;
                if (waveformAiCtrl1.State != ControlState.Running)
                {
                    er = waveformAiCtrl1.Start();
                }
                 
                if (er != ErrorCode.Success)
                {
                    MessageBox.Show("設備打開失敗!");
                    return;
                }

                OperateCtrBtn(false);
                OperateCustomBtn(false);

                bufferedAITimer.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
           
        }

        private void btnStopCtrBuffAI_Click(object sender, EventArgs e)
        {
            //if (waveformAiCtrl1.State == ControlState.Idle)
            //{
            //    return;//has been disposed
            //}
            //waveformAiCtrl1.Stop();
            //waveformAiCtrl1.Dispose();
        }

        private object locker = new object();
        private void waveformAiCtrl1_DataReady(object sender, BfdAiEventArgs e)
        {
            double[] data = new double[e.Count];
            ErrorCode er = waveformAiCtrl1.GetData(e.Count, data);
            if (er != ErrorCode.Success)
            {
                return;
            }

            lock (locker)
            {
                for (int i = 0; i < data.Length; i += 4)
                {
                    double[] temp = new double[4];
                    for (int j = 0; j < 4; j++)
                    {
                        temp[j] = data[i + j];
                    }
                    dataFromBuffAI.Add(temp);
                }
            }
        }
        #endregion

        #region 控件InstantAI

        private void btnControlInstantAI_Click(object sender, EventArgs e)
        {
            try
            {
                instantAiCtrl1.SelectedDevice = new DeviceInformation(deviceName);
                if (!instantAiCtrl1.Initialized)
                {
                    MessageBox.Show("No device be selected or device open failed!");
                    return;
                }

                OperateCtrBtn(false);
                OperateCustomBtn(false);

                ctrInstant.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }          
        }

        private void btnStopCtrInstantAI_Click(object sender, EventArgs e)
        {
            try
            {
                //ctrInstant.Stop();
            }
            catch (Exception ex)
            {
                MessageBox.Show( ex.Message);
            }
        }

        private void ctrInstant_Tick(object sender, EventArgs e)
        {
            double[] data = new double[4]; ;
            ErrorCode er0 = instantAiCtrl1.Read(0, out data[0]);
            ErrorCode er1 = instantAiCtrl1.Read(1, out data[1]);
            ErrorCode er2 = instantAiCtrl1.Read(2, out data[2]);
            ErrorCode er3 = instantAiCtrl1.Read(3, out data[3]);

            dataFromInstantAI.Add(data);

            DrawInstantAICurve();           
        }
        #endregion              
    }
}
View Code

樣式如下圖所示:

 

 GitHub

歡迎各位留言討論!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM