串行端口 - 读取数据/更新画布元素

时间:2015-05-11 12:16:36

标签: c# wpf canvas serial-port

我几周来一直遇到问题,现在从串口读取数据并根据收到的消息更新canvas元素。要更新的画布元素是一个小图像,应根据接收到的消息的第三部分旋转到某个角度。我不确定出了什么问题,似乎并不总是收到完整的信息。我将详细介绍端口和数据。 结构 - 8个数据位,1个起始位,1个停止位,无奇偶校验。消息频率为15 Hz(每秒写入的行数)。默认波特率为9,600。

共有五个部分: 1.第1节 - 小数点后两位。 2.第2节 - 小数点后两位。 角度 - 乘以10 - 即256.0度显示为2560。 4. Section4乘以-100 - 即6.66度是-666。 5. Section5乘以100 - 即55.5度是555。 消息以冒号(:)开头,以<结尾。 CR>< LF> 。包含星号“***”的字段表示没有为该字段定义任何值。

举例说明:

Column 
1 15 22 29 36 43 
1.00 *** 0 0 0 
: 1.00 20.20 2460 0 0
: 2.40 20.45 2460 10000 -10000 
: 3.00 20.45 2355 1000 554

我收到的最新消息显示在窗口顶部,以确保用户正在接收数据,但我注意到该消息只显示应该是什么的一些部分,从而弄乱了旋转画布元素。因此,例如,消息可能是:首先是20 500,然后获得完整的消息。

以下是发送数据的屏幕截图: Data received

这是我的MainWindow.cs中的相关代码:

    private Port port = new Port();
    private double rovHeading;
    Point rotate_Origin = new Point(0.5, 0.5);
    public string LastCOMMessage
    {
        get { return (string)this.GetValue(LastCoMMessageProperty); }
        set { this.SetValue(LastCoMMessageProperty, value); }

    }
    private void Connect_Port(object sender, RoutedEventArgs e)
    {
        if (port.Status == Port.PortStatus.Disconnected)
        {
            try
            {
                port.Connect("COM1", 9600, false, 250); //When set to false, test data is used on Connect. Last parameter is how often the UI is updated. Closer to 0, the faster it updates.

                //Sets button State and Creates function call on data recieved
                Connect_btn.Content = "Disconnect";

                port.OnMessageReceived += new Port.MessageReceivedHandler(port_OnMessageReceived);
            }

            catch (Exception)
            {
                System.Windows.MessageBox.Show("Port is not available.");
            }
        }

        else
        {
            try // just in case serial port is not open, could also be achieved using if(serial.IsOpen)
            {
                port.Disconnect();
                Connect_btn.Content = "Connect";
            }

            catch
            {
            }
        }
    }

    /// <summary>
    /// Reads in the data streaming from the port, taking out the third value which is the ROV's heading and assigning it to rovHeading.
    /// It then calls orientRovImage.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void port_OnMessageReceived(object sender, Port.MessageEventArgs e)
    {
        LastCOMMessage = e.Message;

        if (rovImage != null && e.Message.EndsWith("\r\n")) //messages end in <CR><LF>. Was having issues where only half a message would be received and updated the heading to wrong number.
        {
            string[] messageComponents = LastCOMMessage.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

            if (messageComponents.Length >= 3)
            {
                double.TryParse(messageComponents[3], out rovHeading);

                if (rovHeading > 0)
                {
                    rovHeading /= 10;

                    orientRovImage();
                }
            }
        }
    }

    /// <summary>
    /// Rotates the ROV icon based on the heading being streamed in.
    /// </summary>
    private void orientRovImage()
    {
        RotateTransform rotateRov = new RotateTransform(rovHeading + angle_Offset);
        rovImage.RenderTransformOrigin = rotate_Origin;
        rovImage.RenderTransform = rotateRov;
    }

这是我的Port.cs:

class Port
{
    private SerialPort serial = null;
    private DispatcherTimer testTimer;
    private string[] testData = new string[] { ": 3.00 20.45 2355   1000 554\r\n", ": 5.00 78.09 1725 3200 121\r\n", ": 9.20 10.12 1492 8820 197\r\n" }; //test data to be sent when liveData is set to false.
    private int testDataIndex = -1;
    private DateTime dateOflastMessageHandled;

    public enum PortStatus
    {
        Connected,
        Disconnected
    }
    public PortStatus Status { get; private set; }
    public bool LiveData { get; private set; }
    public int MillisecondsDelayBetweenMessages { get; private set; }

    public class MessageEventArgs : EventArgs
    {
        public string Message { get; private set; }

        public MessageEventArgs(string message)
        {
            Message = message;
        }
    }
    public delegate void MessageReceivedHandler(object sender, MessageEventArgs e);
    public event MessageReceivedHandler OnMessageReceived;


    private void MessageReceived(string message)
    {
        if (OnMessageReceived == null)
        {
            return;
        }

        OnMessageReceived(this, new MessageEventArgs(message));
    }


    public Port()
    {
        Status = PortStatus.Disconnected;
    }

    public void Connect(string portName, int baudRate, bool liveData, int millisecondsDelayBetweenMessages)
    {
        LiveData = liveData;
        MillisecondsDelayBetweenMessages = millisecondsDelayBetweenMessages;

        Disconnect();

        if (liveData)
        {
            serial = new SerialPort();

            serial.PortName = portName;
            serial.BaudRate = baudRate;
            serial.Handshake = Handshake.None;
            serial.Parity = Parity.None;
            serial.DataBits = 8;
            serial.StopBits = StopBits.One;
            serial.ReadTimeout = 200;
            serial.WriteTimeout = 50;

            serial.Open();

            serial.DataReceived += new SerialDataReceivedEventHandler(Receive);
        }

        else
        {
            testTimer = new DispatcherTimer();
            testTimer.Interval = new TimeSpan(0, 0, 0, 0, 3);
            testTimer.Tick += new EventHandler(testTimer_Tick);
            testTimer.Start();
        }

        Status = PortStatus.Connected;
    }


    private void testTimer_Tick(object sender, EventArgs e)
    {
        if (dateOflastMessageHandled == null || DateTime.Now.Subtract(dateOflastMessageHandled).TotalMilliseconds >= MillisecondsDelayBetweenMessages)
        {
            dateOflastMessageHandled = DateTime.Now;
            MessageReceived(testData[testDataIndex]);

            testDataIndex++;
            if (testDataIndex >= testData.Length)
            {
                testDataIndex = 0;
            }
        }
    }


    private void Receive(object sender, SerialDataReceivedEventArgs e)
    {
        if (dateOflastMessageHandled == null || DateTime.Now.Subtract(dateOflastMessageHandled).TotalMilliseconds >= MillisecondsDelayBetweenMessages)
        {
            dateOflastMessageHandled = DateTime.Now;

            Application.Current.Dispatcher.BeginInvoke(new Action(
                delegate()
                {
                    //MessageReceived(serial.ReadLine());
                    MessageReceived(serial.ReadExisting());
                }));
        }
    }


    public void Disconnect()
    {
        if (testTimer != null)
        {
            testTimer.Stop();
        }

        testDataIndex = 0;

        Status = PortStatus.Disconnected;

        if (serial != null)
        {
            serial.Close();
        }
    }
}

最后在我的MainWindow.xaml中,这只显示收到的最后一条消息:

        <Button Content="Connect" Click="Connect_Port" Name="Connect_btn" />
        <TextBlock Text="{Binding LastCOMMessage, ElementName=this}" />

任何提示或帮助都会非常感激,因为这是我第一次使用w / ports。谢谢!

0 个答案:

没有答案