Plotting data stream received by a serial port using WPF

Oystein Bjorke 10 years ago 0
This discussion was imported from CodePlex

JohnnyPP wrote at 2012-11-24 13:49:

Hello Objo,

 

I would like to continue the discussion: http://oxyplot.codeplex.com/discussions/401597. The idea remains the same - plotting data received by serial port but this time using WPF. My program connects successfully to the serial port and receives temperature data. The data is ready to use in private void LineReceived.

How can I plot the data point by point (sample number vs. temperature data) so that old points remain on the plot when a new point is added? How can I use MainViewModel.cs? Could you provide a code example?

 

MainWindow.xaml.cs

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using OxyPlot.Wpf;
using System.IO.Ports;
using System.Threading;
using System.Windows.Threading;

namespace WpfAreaOxyPlot
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// http://oxyplot.codeplex.com/SourceControl/changeset/view/52946448ea08#Source%2fExamples%2fWPF%2fWpfExamples%2fExamples%2fAreaDemo%2fMainViewModel.cs
    /// </summary>
    public partial class MainWindow : Window
    {
        SerialPort serialPort1 = new SerialPort();
        string recieved_data;

        public MainWindow()
        {
            InitializeComponent();
            var vm = new MainViewModel();
            DataContext = vm;
        }

       

        private void button1Connect_Click(object sender, RoutedEventArgs e)
        {
            label1Temperature.Content = "Connecting to COM3 @ 9600 baud rate";

            serialPort1.PortName = "COM3";
            serialPort1.BaudRate = 9600;
            serialPort1.DtrEnable = true;
            serialPort1.Open();
            
            serialPort1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(Recieve);


            if (serialPort1.IsOpen)
            {
                button1.IsEnabled = false;
                button2.IsEnabled = true;
            }

            label1Temperature.Content = "Connected";
        }

      

        private delegate void UpdateUiTextDelegate(string text);
        private void Recieve(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            recieved_data = serialPort1.ReadLine();
            Dispatcher.Invoke(DispatcherPriority.Send, new UpdateUiTextDelegate(LineReceived), recieved_data);
        }

        private void LineReceived(string line)
        {        
            try
            {
                label1Temperature.Content = line;   
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
            
        }

        private void button2Disconnect_Click(object sender, RoutedEventArgs e)
        {
            if (serialPort1.IsOpen)
            {
                serialPort1.Close();

                button1.IsEnabled = true;
                button2.IsEnabled = false;
            }
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (serialPort1.IsOpen)
            {
                serialPort1.Close();
            }
        }
      
    }
}

MainWindow.xaml

 

<Window x:Class="WpfAreaOxyPlot.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:oxy="clr-namespace:OxyPlot.Wpf;assembly=OxyPlot.Wpf"
        Title="AreaDemo" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Height="500" Width="1000" Closing="Window_Closing">
    <Grid>
        <oxy:Plot x:Name="plot1" Title="Texas Instruments TMP102 Temperature Sensor" Height="461" Width="783" VerticalAlignment="Top" HorizontalAlignment="Right">
            <oxy:Plot.Axes>
                <oxy:LinearAxis Title="Sample number" Position="Bottom" Minimum="0" Maximum="100" />
                <oxy:LinearAxis Title="Temperature [°C]" Position="Left" Minimum="0" Maximum="100" FontSize="12" TicklineColor="#FF190000" TickStyle="Crossing" />
            </oxy:Plot.Axes>
        </oxy:Plot>
        <Button Content="Connect to sensor" Height="23" Name="button1" Width="116" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10" Click="button1Connect_Click" IsEnabled="True"/>
        <Label Content="Temperature" Height="28" Name="label1Temperature" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,130,0,0" Width="73" />
        <Button Content="Disconnect" Height="23" HorizontalAlignment="Left" Margin="12,61,0,0" Name="button2" VerticalAlignment="Top" Width="114" Click="button2Disconnect_Click" IsEnabled="False"/>
    </Grid>
</Window>

objo wrote at 2012-12-03 07:56:

Add a ScatterSeries or LineSeries and bind it to a collection of your points. Set the DataFieldX/DataFieldY to the properties you want to plot. Update the plot control when the data has changed (OxyPlot is currently not subscribing to collection change notifications).