从HID C#读取数据时程序卡住 [英] Program stucks when read data from HID C#

查看:134
本文介绍了从HID C#读取数据时程序卡住的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,

我尝试开发一个可以与HID设备通信的应用程序。我可以发送和接收数据。但是当收到我的程序卡住这意味着继续发送和接收数据但其他功能,如更改标签文本,关闭程序,绘图等不会工作。单击接收按钮时,通信开始。有人可以帮帮我吗?



我尝试了什么:



< pre lang =c#>< pre> using System;
使用 System.Collections.Generic;
使用 System.ComponentModel;
使用 System.Data;
使用 System.Drawing;
使用 System.Linq;
使用 System.Text;
使用 System.Threading.Tasks;
使用 System.Windows.Forms;
使用 CyUSB;

命名空间 EGI
{
public partial class EGI_Main:表格
{
// ***********************开始计划主题******* *********************** //

USBDeviceList usbDevices = ; // 指向USB设备列表的指针
CyHidDevice myHidDevice = ; // USB设备句柄

int VID = 0x04B4; // 赛普拉斯供应商ID
int PID = 0xE177; // 示例项目产品ID

bool communic = false ; // 通讯状态

byte que = 00 ; // 命令字节
byte PGAValue = 02 ; // PGA
byte [] receivedDatas = new byte [ 128 ]。 // 用于存储来自设备的128字节接收数据的字节数组

< span class =code-comment> / *
************************* ********************************************
* NAME :EGI - Ekin通用HID通信接口
*
*描述:在启动
*应用程序时最初调用的主要功能。用于未初始化的变量,GUI应用程序,注册
*事件处理程序,并检查连接的设备。
*
***************************************** ****************************** /


public EGI_Main()
{
InitializeComponent();
// 为此应用程序创建CYUSB设备列表
usbDevices = < span class =code-keyword> new
USBDeviceList(CyConst.DEVICES_HID);
// 添加设备附件和设备删除的事件处理程序
usbDevices.DeviceAttached + = new EventHandler(usbDevices_DeviceAttached);
usbDevices.DeviceRemoved + = new EventHandler(usbDevices_DeviceRemoved);
// 连接USB设备
GetDevice();
}

/ * *********** ************************************************** ********
*姓名:EGI_Main_Load
*
*描述:在开始时加载并设置必要的组件和设置。
*
***************************************** ****************************** /


private void EGI_Main_Load( object sender,EventArgs e)
{
// 实际数据图设置
chartResult.ChartAreas [ 0 ]。AxisX.ScaleView.Zoom( 0 127 );
chartResult.ChartAreas [ 0 ]。AxisY.ScaleView.Zoom( 0 255 );
chartResult.Series [ 0 ]。ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
chartResult.Series [ 0 ]。Color = Color.Black;
chartResult.Series [ 0 ]。BorderWidth = 3 ;

// 在线平均结果图表设置
chartResult。 Series.Add( onLineAvg);
chartResult.Series [ onLineAvg]。ChartType = System.Windows.Forms.DataVisualization .Charting.SeriesChartType.Line;
chartResult.Series [ onLineAvg]。Color = Color.Red;
chartResult.Series [ onLineAvg] .BorderWidth = 3 ;

// 具有在线平均结果图设置的Multipline
chartResult.Series.Add( multOnLineAvg);
chartResult.Series [ multOnLineAvg]。ChartType = System.Windows.Forms.DataVisualization .Charting.SeriesChartType.Line;
chartResult.Series [ multOnLineAvg]。颜色= Color.Navy;
chartResult.Series [ multOnLineAvg] .BorderWidth = 3 ;

// 超出点图设置
chartResult .Series.Add( 超过);
chartResult.Series [ 超过]。Color = Color.Brown;
chartResult.Series [ 超过]。BorderWidth = 3 ;
}

/ * *********** ************************************************** ********
*姓名:usbDevices_DeviceRemoved
*
*描述:移除USB设备的事件处理程序。当检测到USB设备的删除
*时,将调用此函数,该函数将检查
*查看删除的设备是否是我们使用的设备。如果是,则重置
*设备处理程序(myHidDevice),禁用计时器,并更新GUI。
*
***************************************** ****************************** /


public void usbDevices_DeviceRemoved( object sender,EventArgs e)
{
USBEventArgs usbEvent = e as USBEventArgs;
if ((usbEvent.ProductID == PID)&&(usbEvent.VendorID == VID))
{
InputTimer.Enabled = false ; // 禁用轮询HID的中断
myHidDevice = ;
GetDevice(); // 处理设备状态
}
}

/ * *********************** **********************************************
* NAME:usbDevices_DeviceAttached
*
*说明:USB设备附件的事件处理程序。如果处理程序(myHidDevice)为null,函数
*首先通过查看
*来检查匹配的设备是否已连接。如果以前没有连接任何设备,
*该函数将调用GetDevice来检查并查看匹配的设备是否附加了
*。
*
***************************************** ****************************** /


public void usbDevices_DeviceAttached( object sender,EventArgs e)
{
if (myHidDevice == null
{
GetDevice( ); // 处理设备状态
}
}

/ * *********************** **********************************************
* NAME:GetDevice
*
*说明:功能根据应用程序中提供的VID和PID检查是否附加了匹配的USB设备
*。当找到
*的设备时,会为其分配一个处理程序(myHidDevice),并将GUI更新为
*反映连接。此外,如果设备未连接,
*该功能将更新GUI以反映断开连接。
*
***************************************** ****************************** /

public void GetDevice()
{
// 寻找匹配VID / PID的设备
myHidDevice = usbDevices [VID,PID] as CyHidDevice;
if (myHidDevice!= null / / 检查设备是否已连接
{
Status.Text = 已连接;
Status.ForeColor = Color.Green;
InputTimer.Enabled = true ; // 启用后台计时器
}
else
{
Status.Text = 断开连接;
Status.ForeColor = Color.Red;
}
}

/ * ****** ************************************************** *************
* NAME:Set_VidPid_Click
*
*说明:根据
*用户输入更新应用程序供应商ID和产品ID单击设置按钮时。这将导致默认的VID
*和0x04B4和0xE177的PID被覆盖。然后函数
*调用GetDevice()来检查匹配的USB设备。
*
***************************************** ****************************** /

私有 void Set_VidPid_Click( object sender,EventArgs e)
{
// 按设置按钮回复更新VID和PID值
VID = Convert.ToInt32(VidTextBox.Text, 16 );
PID = Convert.ToInt32(PidTextBox.Text, 16 );
GetDevice();
}

/ * *********** ************************************************** ********
*姓名:receive_Click
*
*说明:启动和停止与设备的通信。
*
***************************************** ****************************** /


private void receive_Click( object sender,EventArgs e)
{
如果(沟通)
{
communic = false ;
receive.Text = 沟通;
receive.BackColor = Color.White;
receive.ForeColor = Color.Black;
}
其他
{
// < span class =code-comment> not working

communic = true ;
receive.Text = 停止;
receive.BackColor = Color.Red;
receive.ForeColor = Color.White;
que = 00 ;
// working
communicNow();
}
}

/ * ****** ************************************************** *************
*姓名:communicNow
*
*描述:向设备发送命令。
*
***************************************** ****************************** /


private void communicNow()
{
if (沟通)
{
// 将数据加载到输出缓冲区
myHidDevice.Outputs.DataBuf [ 0 ] = 00 ; // 报告ID
myHidDevice.Outputs.DataBuf [ 1 ] =( byte )numericUpDownThreshold.Value; // 阈值
myHidDevice.Outputs.DataBuf [ 2 ] =( byte )numericUpDownPB.Value; // PB
myHidDevice.Outputs.DataBuf [ 3 ] = PGAValue; // PGA
myHidDevice.Outputs.DataBuf [ 4 ] = 87 ; // W / R
myHidDevice.Outputs.DataBuf [ 5 ] = que; // 命令字节
myHidDevice.Outputs.DataBuf [ 6 ] = 00 ;
myHidDevice.Outputs.DataBuf [ 7 ] = 00 ;
myHidDevice.Outputs.DataBuf [ 8 ] = 00 ;
myHidDevice.Outputs.DataBuf [ 9 ] = 00 ;

// 将数据发送到设备的函数调用
myHidDevice .WriteOutput();
// 从设备接收数据的函数调用
myHidDevice.ReadInput() ;

byte [] tempData = myHidDevice.Inputs.DataBuf;

for int i = 2 ; i < 34 ; i ++)
{
if (que == 0
receivedDatas [i - 2 ] = tempData [i - 2 ];
else if (que == 1
receivedDatas [ 32 + i - 2 ] = tempData [i - < span class =code-digit> 2
];
else if (que == 2
receivedDatas [ 64 + i - 2 ] = tempData [i - < span class =code-digit> 2
];
else if (que == 3
receivedDatas [ 96 + i - 2 ] = tempData [i - < span class =code-digit> 2
];
}

if (que < 03
{
que ++;
communicNow();
}
其他
{
que = 00 ;
dataProcess(receivedDatas);
}
}
}


/ * ************ **********************
*名称:dataProcess
*
*描述:重新组合数据,将它们写入特定数据textboxes和
*调用calculateAndDrawGraph来计算和绘制图形。
*
***************************************** ****************************** /


private void dataProcess( byte [] realDatas)
{
bool highLightPower = false ;
bool lowLightPower = false ;

// 清除文本框
receivedData_00.Text = ;
receivedData_01.Text = null ;
receivedData_02.Text = null ;
receivedData_03.Text = null ;

// 计算分隔到文本框的数据
int countOfDatas = 0 ;

// 将所有数据写入指定的文本框
foreach byte r in realDatas)
{
if (countOfDatas < 32
receivedData_00.AppendText(r + - );
else if (countOfDatas < 64
receivedData_01.AppendText(r + - );
else if (countOfDatas < 96
receivedData_02.AppendText(r + - );
else if (countOfDatas < 128
receivedData_03.AppendText(r + - );

// 检查光功率是高还是低。
如果(r > = 190
highLightPower = true ;
else if (r < = 20
lowLightPower = false ;

countOfDatas ++;
}

// 无效
< span class =code-keyword> if
(highLightPower)
{
labelLightPower.BackColor = Color.Red;
labelLightPower.ForeColor = Color.White;
labelLightPower.Text = 减少;
}
其他 如果(lowLightPower)
{
labelLightPower.BackColor = Color.Yellow;
labelLightPower.ForeColor = Color.Black;
labelLightPower.Text = 增加;
}
else
{
labelLightPower.BackColor = Color.Green;
labelLightPower.ForeColor = Color.White;
labelLightPower.Text = ;
}

calculateAndDrawGraph(realDatas);
}

/ * *********** ************************************************** ********
* NAME:calculateAndDrawGraph
*
*描述:计算平均值并绘制图形。回想
* communicNow()来接收新数据。
*
***************************************** ****************************** /


private void calculateAndDrawGraph( byte [] realDatas)
{
// 无法正常工作
chartResult.Series [ 0 ] Points.Clear();
for int i = 0 ; i < 128 ; i ++)
{
chartResult.Series [ 0 ]。Points.AddXY(i,realDatas [i]);
}
// 工作
communicNow();
}

/ * *********** ************************************************** ********
*姓名:radioButton_CheckedChanged
*
*描述:设置PGAValue。
*
***************************************** ****************************** /

/ / 无法点击单选按钮
private void radioButton_CheckedChanged( object sender,EventArgs e)
{
if (radioButton1.Checked)
PGAValue = 01 ;
else if (radioButton2.Checked)
PGAValue = 02 ;
else if (radioButton4.Checked)
PGAValue = 04 ;
else if (radioButton8.Checked)
PGAValue = 08 ;
}

}
}

解决方案

首先查看你的WriteOutput和(更重要的是)ReadInput方法:如果这些方法等待响应 - 我假设读取的至少一个 - 那么它就是一个阻塞调用,这意味着你的线程卡在等待远程设备响应。当发生这种情况时,您的UI线程会卡住,并且无法对显示器进行任何更新(或其他任何更新,例如响应鼠标或键盘输入)。



唯一的解决方案是完全重新设计,使用单独的线程进行通信,将信息中继到UI线程以绘制图形等等。您可能会发现BackgroundWorker类适用于此,因为它包含一个简单的事件驱动机制,用于通过Progress指示(可以包含用于保存数据的用户对象)与UI任务进行对话。


Hello everyone,
I try to develop an application that can communicate with HID device. I can send and receive data. But when receive my program stucks which means continue to send and receive data but other functions like changing label text, closing program, drawing graph etc wont work. Communication starts when I click receive button. Could anyone help me?

What I have tried:

<pre>using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using CyUSB;

namespace EGI
{
    public partial class EGI_Main : Form
    {
        // *********************** START OF PROGRAM MAIN ****************************** //

        USBDeviceList usbDevices = null;            // Pointer to list of USB devices
        CyHidDevice myHidDevice = null;             // Handle of USB device

        int VID = 0x04B4;                           // Cypress Vendor ID
        int PID = 0xE177;                           // Example Project Product ID

        bool communicate = false;                   // Communication status

        byte que = 00;                              // Command Byte
        byte PGAValue = 02;                         // PGA
        byte[] receivedDatas = new byte[128];       // Byte array to store 128 bytes of received data from device

        /**********************************************************************
        * NAME: EGI - Ekin Generic HID Communication Interface
        *
        * DESCRIPTION: Main function called initially upon the starting of the
        * application. Used to un-initialized variables, the GUI application, register
        * the event handlers, and check for a connected device.
        *
        ***********************************************************************/

        public EGI_Main()
        {
            InitializeComponent();
            // Create a list of CYUSB devices for this application
            usbDevices = new USBDeviceList(CyConst.DEVICES_HID);
            //Add event handlers for device attachment and device removal
            usbDevices.DeviceAttached += new EventHandler(usbDevices_DeviceAttached);
            usbDevices.DeviceRemoved += new EventHandler(usbDevices_DeviceRemoved);
            //Connect to the USB device
            GetDevice();
        }

        /**********************************************************************
        * NAME: EGI_Main_Load
        *
        * DESCRIPTION: Loads and sets necessary companents and settings on start.
        *
        ***********************************************************************/

        private void EGI_Main_Load(object sender, EventArgs e)
        {
            // Real data graph settings
            chartResult.ChartAreas[0].AxisX.ScaleView.Zoom(0, 127);
            chartResult.ChartAreas[0].AxisY.ScaleView.Zoom(0, 255);
            chartResult.Series[0].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
            chartResult.Series[0].Color = Color.Black;
            chartResult.Series[0].BorderWidth = 3;

            // On line average result graph settings
            chartResult.Series.Add("onLineAvg");
            chartResult.Series["onLineAvg"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
            chartResult.Series["onLineAvg"].Color = Color.Red;
            chartResult.Series["onLineAvg"].BorderWidth = 3;

            // Multipline with on line average result graph settings
            chartResult.Series.Add("multOnLineAvg");
            chartResult.Series["multOnLineAvg"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
            chartResult.Series["multOnLineAvg"].Color = Color.Navy;
            chartResult.Series["multOnLineAvg"].BorderWidth = 3;

            // Exceed point(s) graph settings
            chartResult.Series.Add("exceed");
            chartResult.Series["exceed"].Color = Color.Brown;
            chartResult.Series["exceed"].BorderWidth = 3;
        }

        /**********************************************************************
        * NAME: usbDevices_DeviceRemoved
        *
        * DESCRIPTION: Event handler for the removal of a USB device. When the removal
        * of a USB device is detected, this function will be called which will check to
        * see if the device removed was the device we were using. If so, then reset
        * device handler (myHidDevice), disable the timer, and update the GUI.
        *
        ***********************************************************************/

        public void usbDevices_DeviceRemoved(object sender, EventArgs e)
        {
            USBEventArgs usbEvent = e as USBEventArgs;
            if ((usbEvent.ProductID == PID) && (usbEvent.VendorID == VID))
            {
                InputTimer.Enabled = false; // Disable interrupts for polling HID
                myHidDevice = null;
                GetDevice(); // Process device status
            }
        }

        /**********************************************************************
        * NAME: usbDevices_DeviceAttached
        *
        * DESCRIPTION: Event handler for the attachment of a USB device. The function
        * first checks to see if a matching device is already connected by seeing
        * if the handler (myHidDevice) is null. If no device is previously attached,
        * the function will call GetDevice to check and see if a matching device was
        * attached.
        *
        ***********************************************************************/

        public void usbDevices_DeviceAttached(object sender, EventArgs e)
        {
            if (myHidDevice == null)
            {
                GetDevice(); // Process device status
            }
        }

        /**********************************************************************
        * NAME: GetDevice
        *
        * DESCRIPTION: Function checks to see if a matching USB device is attached
        * based on the VID and PID provided in the application. When a device is
        * found, it is assigned a handler (myHidDevice) and the GUI is updated to
        * reflect the connection. Additionally, if the device is not connected,
        * the function will update the GUI to reflect the disconnection.
        *
        ***********************************************************************/
        public void GetDevice()
        {
            //Look for device matching VID/PID
            myHidDevice = usbDevices[VID, PID] as CyHidDevice;
            if (myHidDevice != null) //Check to see if device is already connected
            {
                Status.Text = "Connected";
                Status.ForeColor = Color.Green;
                InputTimer.Enabled = true; //Enable background timer
            }
            else
            {
                Status.Text = "Disconnected";
                Status.ForeColor = Color.Red;
            }
        }
        
        /**********************************************************************
        * NAME: Set_VidPid_Click
        *
        * DESCRIPTION: Updates the applications Vendor ID and Product ID based on
        * user input when the "Set" button is clicked. This will cause the default VID
        * and PID of 0x04B4 and 0xE177 to be overwritten. The function will then
        * call GetDevice() to check for matching USB device.
        *
        ***********************************************************************/
        private void Set_VidPid_Click(object sender, EventArgs e)
        {
            //Respond to update of VID and PID value by pressing the "Set" button
            VID = Convert.ToInt32(VidTextBox.Text, 16);
            PID = Convert.ToInt32(PidTextBox.Text, 16);
            GetDevice();
        }

        /**********************************************************************
        * NAME: receive_Click
        *
        * DESCRIPTION: Starts and stops communication with device.
        *
        ***********************************************************************/

        private void receive_Click(object sender, EventArgs e)
        {
            if (communicate)
            {
                communicate = false;
                receive.Text = "Communicate";
                receive.BackColor = Color.White;
                receive.ForeColor = Color.Black;
            }
            else
            {
                //not working
                communicate = true;
                receive.Text = "Stop";
                receive.BackColor = Color.Red;
                receive.ForeColor = Color.White;
                que = 00;
                //working
                communicateNow();
            }
        }

        /**********************************************************************
        * NAME: communicateNow
        *
        * DESCRIPTION:Sends commands to device.
        *
        ***********************************************************************/

        private void communicateNow()
        {
            if (communicate)
            {
                // Load data into Output Buffer
                myHidDevice.Outputs.DataBuf[0] = 00;                                    // Report ID
                myHidDevice.Outputs.DataBuf[1] = (byte)numericUpDownThreshold.Value;    // Threshold
                myHidDevice.Outputs.DataBuf[2] = (byte)numericUpDownPB.Value;           // PB
                myHidDevice.Outputs.DataBuf[3] = PGAValue;                              // PGA
                myHidDevice.Outputs.DataBuf[4] = 87;                                    // W/R
                myHidDevice.Outputs.DataBuf[5] = que;                                   // Command byte
                myHidDevice.Outputs.DataBuf[6] = 00;
                myHidDevice.Outputs.DataBuf[7] = 00;
                myHidDevice.Outputs.DataBuf[8] = 00;
                myHidDevice.Outputs.DataBuf[9] = 00;

                // Function call to send data to device
                myHidDevice.WriteOutput();
                // Function call to receive data from device
                myHidDevice.ReadInput();

                byte[] tempData = myHidDevice.Inputs.DataBuf;

                for (int i = 2; i < 34; i++)
                {
                    if (que == 0)
                        receivedDatas[i - 2] = tempData[i - 2];
                    else if (que == 1)
                        receivedDatas[32 + i - 2] = tempData[i - 2];
                    else if (que == 2)
                        receivedDatas[64 + i - 2] = tempData[i - 2];
                    else if (que == 3)
                        receivedDatas[96 + i - 2] = tempData[i - 2];
                }

                if (que < 03)
                {
                    que++;
                    communicateNow();
                }
                else
                {
                    que = 00;
                    dataProcess(receivedDatas);
                }
            }
        }
        

        /**********************************************************************
        * NAME: dataProcess
        *
        * DESCRIPTION: Regroup the datas, writes them to specific textboxes and
        * calls calculateAndDrawGraph to calculate and draw graph.
        *
        ***********************************************************************/

        private void dataProcess(byte[] realDatas)
        {
            bool highLightPower = false;
            bool lowLightPower = false;

            // Clear textboxes
            receivedData_00.Text = null;
            receivedData_01.Text = null;
            receivedData_02.Text = null;
            receivedData_03.Text = null;

            // Count datas to separate to textboxes
            int countOfDatas = 0;

            // Write all datas to specified textboxes
            foreach (byte r in realDatas)
            {
                if (countOfDatas < 32)
                    receivedData_00.AppendText(r + " - ");
                else if (countOfDatas < 64)
                    receivedData_01.AppendText(r + " - ");
                else if (countOfDatas < 96)
                    receivedData_02.AppendText(r + " - ");
                else if (countOfDatas < 128)
                    receivedData_03.AppendText(r + " - ");

                // Check whether light power is high or low.
                if (r >= 190)
                    highLightPower = true;
                else if (r <= 20)
                    lowLightPower = false;

                countOfDatas++;
            }

            //not working
            if (highLightPower)
            {
                labelLightPower.BackColor = Color.Red;
                labelLightPower.ForeColor = Color.White;
                labelLightPower.Text = "Decrease";
            }
            else if (lowLightPower)
            {
                labelLightPower.BackColor = Color.Yellow;
                labelLightPower.ForeColor = Color.Black;
                labelLightPower.Text = "Increase";
            }
            else
            {
                labelLightPower.BackColor = Color.Green;
                labelLightPower.ForeColor = Color.White;
                labelLightPower.Text = "";
            }

            calculateAndDrawGraph(realDatas);
        }

        /**********************************************************************
        * NAME: calculateAndDrawGraph
        *
        * DESCRIPTION: Calculates averages and draws their graphs. Recall 
        * communicateNow() to receive new datas.
        *
        ***********************************************************************/

        private void calculateAndDrawGraph(byte[] realDatas)
        {
            //not working
            chartResult.Series[0].Points.Clear();
            for(int i = 0; i < 128; i++)
            {
                chartResult.Series[0].Points.AddXY(i, realDatas[i]);
            }
            //working
            communicateNow();
        }

        /**********************************************************************
        * NAME: radioButton_CheckedChanged
        *
        * DESCRIPTION: Sets PGAValue.
        *
        ***********************************************************************/
        //cannot click radio buttons
        private void radioButton_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButton1.Checked)
                PGAValue = 01;
            else if (radioButton2.Checked)
                PGAValue = 02;
            else if (radioButton4.Checked)
                PGAValue = 04;
            else if (radioButton8.Checked)
                PGAValue = 08;
        }

    }
}

解决方案

Start by looking at your WriteOutput and (more importantly) ReadInput methods: If these wait for a response - and I assume that the read one at least does - then it is a blocking call, which means that your thread is stuck waiting for the remote device to respond. While that is happening, your UI thread is stuck, and cannot do any updates to your display (or anything else, such as respond to mouse or keyboard input).

The only solution to that is a complete redesign, using a separate thread for communications which relays information to the UI thread to draw it's graphs and so on. You may find the BackgroundWorker class suitable for this as it includes a simple event driven mechanism for talking back to the UI task via Progress indication (which can include a user object to hold your data).


这篇关于从HID C#读取数据时程序卡住的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆