4

好的,所以我有一个名为 readSensor 的函数,你猜对了……读取传感器。

但传感器通常需要大约 100 毫秒才能做出响应。所以在 readSensor 函数中,我基本上只是在启动一个计时器。

在定时事件中,我读取了串口并得到了回复。

然而,这意味着当我希望它位于 readSensor 函数中时,我的响应位于 onTimedEvent 中。

基本上从我希望能够做到这一点的主要形式。

值 = 读取传感器()

此刻我所能做的就是 readSensor() ,然后一旦 timedEvent 触发,我就可以通过在消息框中显示响应来看到响应正在返回。

这是我的代码。(我错过了很多串口设置和东西,但希望你能看到我遇到的问题)

我不想在函数中等待 100 毫秒,尽管轮询计时器,因为这会使我的程序变慢..

我想以某种方式将响应返回到 readSensor 函数,然后返回到表单。

    using System;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.IO.Ports;
    using System.Timers;

    namespace readSensor
    {
      public partial class readSens : UserControl
      {
        public readSens()
        {
          InitializeComponent();
        }

        private System.Timers.Timer rTimer;
        SerialPort sp = new SerialPort();

        private void setupTimer()
        {
          // Create a timer with a 100ms response.
          rTimer = new System.Timers.Timer(100);
          rTimer.SynchronizingObject = this;
          // Hook up the Elapsed event for the timer.
          rTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
        }

        private void OnTimedEvent(object source, ElapsedEventArgs e)
        {
          string response = getResponse();
        }

        public string getResponse()
        {
          string status = "";
          byte[] readBuffer = new byte[255];
          if (sp.IsOpen)
          {
            if (sp.BytesToRead > 0) //there is data to read
            {
              int length = sp.BytesToRead;

              for (int i = 0; i < length; i++)
              {
                readBuffer[i] = (byte)sp.ReadByte();
                status = "pass";
                return status;
              }
            }
         }

        public void readSensor(byte addr)
        {
          if (!sp.IsOpen)
          {
            openPort();
            readSensor(addr); // calls itself again once port is opened
          }
          else if (sp.IsOpen)
          {
            rTimer.Start();
          }
          else
          {
            MessageBox.Show("Port not opened yet");
          }
        }
      }
    }

在主要形式中,我基本上只是在说

setupTimer();
readSensor(); 

单击按钮。

4

3 回答 3

2

我不认为没有一些回调机制你可以做到这一点。您可以实现一个while循环,但这并不高效,因为它会引入旋转。

我的建议是实现适当的异步模式或类似的简单方法:

ReadSensor(addr, DoSomethingWithResult);

public void DoSomethingWithResult(string result)
{
    Console.WriteLine (result);
}

public partial class ReadSens : UserControl
{
    private Action<string> _responseCallback;

    public void ReadSensor(byte addr, Action<string> responseCallback)
    {   
        _responseCallback = responseCallback;

        // initiate timer
    }

    private void OnTimedEvent(object source, ElapsedEventArgs e)
    {
        string response = getResponse();

        _responseCallback(response);
    }
}
于 2013-07-10T09:36:58.787 回答
1

启动一个单独的线程,然后从该线程将结果写入主线程中的队列。

class Game1
{
    //We declare a queue, which is like an array that we can extract and enter data easily in a FIFO (first in, first out) style list.
    Queue<string> q = new Queue<string>();

    public void threadStart(object obj)
    {
        //We get the result of your function, while our main function is still looping and waiting.
        string result = readInput()
        //We tell C# that the parameter we passed in, is in fact the Game1 class passed from "t.Start"
        Game1 game = (Game1)obj;
        //This puts our "result" into the queue.
        game.q.Enqueue(result);
    }

    public void start()
    {
        //Declares a new thread, which will run "threadStart" function.
        System.Threading.Thread t = new System.Threading.Thread(threadStart);

        //We start the other thread (that will run in parallel) and pass "this" as the parameter.
        t.Start(this);

        //We loop over and over, sleeping, whilst the other function runs at the same time. This is called "multi- threading"
        while (q.Count == 0)
        {
            System.Threading.Thread.Sleep(10);
        }

        //This gets the last-entered (oldest) value from the queue q.
        string result = q.Deque();
    }
}

所以这会启动一个线程来获取结果,然后在我的版本中,轮询队列一段时间,直到结果回来,但在你的版本中可以做很多事情,只要你不时检查队列对于新数据。

编辑:添加了评论,希望能缓解您的一些问题。

于 2013-07-10T09:26:56.167 回答
1

这种方法对您来说是一个有效的解决方案吗?我认为你只是Timer用来等待serialPort打开,但它可以通过引发事件进行自我控制。

public class SensorReader
{
    private Sensor sensor;
    private string lastResponse;

    public SensorReader(SerialPort serialPort)
    {
        this.serialPort = aSerialPort.
        this.sensor = new Sensor(serialPort);
        this.sensor.PortOpen += PortOpenEventHandler(OnPortOpen);
    }

    private void OnPortOpen()
    {
        this.ReadPort();
    }

    public string ReadPort(byte address)
    {
        if (!this.sensor.IsOpen)
        {
            this.sensor.OpenPort();
            this.lastResponse = "The serial port doesn't respond... yet!";
        }
        else
        {
            // Read response at this point.
            this.lastResponse = this.GetResponse();
        }           

        return this.lastResponse;
    }
}

public class Sensor
{
    private SerialPort serialPort;

    public Sensor(SerialPort aSerialPort)
    {
        this.serialPort = aSerialPort;
    }

    public bool IsOpen
    {
        get { return this.serialPort.IsOpen; }
    }

    public delegate void PortOpenEventHandler(object sender, EventArgs e);

    public event PortOpenEventHandler PortOpen;

    public void OpenPort()
    {
        // Open port here...

        // ... and throw the PortOpen event.
        if (this.PortOpen != null)
        {
            this.PortOpen(this, EventArgs.Empty);
        }
    }
}
于 2013-07-10T09:54:12.303 回答