用WPF快速设计一个简单的串口上位机

时间:2024-03-19 07:27:28

最近一直在学习UWP,其中有的技术参考了WPF,所以又回头再来学习WPF,感觉学的东西很杂,必须记录一下,不然时间长了还得忘掉,于是申请开始写博客,将学习的心得记录一下,以备后用。这次是因为公司内训,刚好想着推广一下开源硬件,所以选择了Arduino,而又结合WPF的强大功能,设计了串口上位机。

1.Arduino UNO作为下位机

利用Arduino作为下位机,理由很简单,语法很简单,上手很快。

1.电路连接

下图为电路原理图,主要利用模拟口A0读取光敏电阻和普通电阻的分压值,然后通过设定逻辑控制LED的状态。之后通过串口将数据发送给电脑。

用WPF快速设计一个简单的串口上位机

2.下位机程序

在arduino IDE里完成。代码结构非常简单,setup()中设置IO口及串口,然后在loop()中读取数值,根据数据控制LED状态,并将数值从串口发送出去。

用WPF快速设计一个简单的串口上位机
 1 void setup() {
 2   // put your setup code here, to run once:
 3   pinMode(13,OUTPUT);
 4   Serial.begin(9600);
 5 }
 6 
 7 void loop() {
 8   // put your main code here, to run repeatedly:
 9 int val=analogRead(0);
10 int time;
11 int result;
12 for(time=0;time<20;time++)
13 {
14   result+=val;
15 }
16 result=result/20;
17 
18 if(result<256)
19 {
20   digitalWrite(13,HIGH);
21 }
22 else{
23   digitalWrite(13,LOW);
24 }
25 
26 Serial.println(result);
27 delay(10);
28 }

2.WPF串口上位机。

这里主要使用WPF自带的串口控件、进度条、以及DynamicDataDisplay控件实现上位机数据显示。具体实现是:将arduino发过来的数据在页面上通过进度条显示出来,同时画出曲线。

1.串口控件SerialPort。

对于该控件,简单的使用过程如下:

  1. 实例化一个串口;
  2. 配置串口参数,例如波特率、数据位、串口号;
  3. 打开串口;
  4. 添加串口接收数据事件;
  5. 处理数据接收事件。

需要注意的是:多线程问题,由于WPF的控件都在UI线程,而串口数据在另外1个线程。一开始直接将串口数据给进度条赋值会出现错误,后来参考网上资料,使用了相应控件的dispatcher.invoke(Action()),解决了数据更新问题。关于多线程的问题,后续还需要再继续学习,搞清这一部分。

而数据曲线绘制使用了DynamicDataDisplay控件,相关使用方法可参考网上,由于第1次使用该控件,感觉效果还行。

代码写的很嫩。

程序界面如下,这里没有选择串口的选型,因为提前看了串口号。

用WPF快速设计一个简单的串口上位机

 

xaml代码:

用WPF快速设计一个简单的串口上位机
用WPF快速设计一个简单的串口上位机
 1 <Window x:Class="Communication.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 5         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 6         xmlns:local="clr-namespace:Communication"
 7         xmlns:d3="http://research.microsoft.com/DynamicDataDisplay/1.0"
 8         mc:Ignorable="d"
 9         Title="MainWindow" Height="350" Width="525"
10         Loaded="Window_Loaded">
11     <Grid>
12         <Grid.RowDefinitions>
13             <RowDefinition Height="40"/>
14             <RowDefinition Height="auto"/>
15             <RowDefinition Height="auto"/>
16             <RowDefinition Height="auto"/>
17             <RowDefinition Height="*"/>
18         </Grid.RowDefinitions>
19         <Grid.ColumnDefinitions>
20             <ColumnDefinition Width="*"/>
21             <ColumnDefinition Width="*"/>
22         </Grid.ColumnDefinitions>
23         <TextBlock HorizontalAlignment="Center"
24                    Text="光照度显示程序"
25                    Grid.ColumnSpan="2"
26                    FontSize="30"/>
27         <StackPanel Orientation="Horizontal" 
28                     Grid.Row="1" >
29             <TextBlock HorizontalAlignment="Left"
30                    Grid.Row="1"
31                    Text="光照值:"/>
32             <TextBlock HorizontalAlignment="Left"
33                    Grid.Row="1"
34                    Name="light_result"/>
35         </StackPanel>
36 
37         <StackPanel Grid.Row="1"
38                     Grid.Column="1" 
39                     Orientation="Horizontal"
40                     HorizontalAlignment="Center">
41             <Button x:Name="开始" 
42                     Content="开始"
43                     Click="开始_Click"
44                     Height="20"
45                     Width="60"
46                     Margin='10,0,10,0'/>
47             <Button x:Name="关闭"
48                 Content="关闭"
49                 Click="关闭_Click"
50                 Height="20"
51                 Width="60"/>
52         </StackPanel>
53        
54         <ProgressBar Grid.Row="2" Grid.ColumnSpan="2" 
55                      Minimum="0" Maximum="1023" 
56                      Height="20" Width="300" 
57                      HorizontalAlignment="Left"
58                      x:Name="light_value"/>
59         <d3:ChartPlotter x:Name="plotter" 
60                          Margin="10,20,10,10"
61                          Grid.Row="3"
62                          Grid.ColumnSpan="2">
63             <d3:HorizontalAxis>
64                 <d3:HorizontalIntegerAxis/>
65             </d3:HorizontalAxis>
66             <d3:VerticalAxis>
67                 <d3:VerticalIntegerAxis/>
68             </d3:VerticalAxis>
69             <d3:Header Content="光照曲线"/>
70             <d3:VerticalAxisTitle Content="光照强度"/>
71         </d3:ChartPlotter>
72     </Grid>
73 </Window>
用WPF快速设计一个简单的串口上位机

后台代码:

用WPF快速设计一个简单的串口上位机
用WPF快速设计一个简单的串口上位机
  1 using Microsoft.Research.DynamicDataDisplay;
  2 using Microsoft.Research.DynamicDataDisplay.DataSources;
  3 using System;
  4 using System.IO.Ports;
  5 using System.Threading;
  6 using System.Windows;
  7 using System.Windows.Media;
  8 using System.Windows.Threading;
  9 
 10 namespace Communication
 11 {
 12     /// <summary>
 13     /// MainWindow.xaml 的交互逻辑
 14     /// </summary>
 15     /// 
 16 
 17     public partial class MainWindow : Window
 18     {
 19 
 20         SerialPort myPort = new SerialPort();
 21         double result;
 22         bool portClosing;
 23         string lightValue;
 24 
 25         private ObservableDataSource<Point> dataSource = new ObservableDataSource<Point>();
 26         private DispatcherTimer timer = new DispatcherTimer();
 27         int i = 0;
 28 
 29         public MainWindow()
 30         {
 31             InitializeComponent();
 32         }
 33 
 34         private void 开始_Click(object sender, RoutedEventArgs e)
 35         {
 36             try
 37             {
 38                 myPort.BaudRate = 9600;
 39                 myPort.DataBits = 8;
 40                 myPort.PortName = "COM3";
 41                 myPort.NewLine = "\r\n";
 42                 myPort.Open();
 43                 portClosing = false;
 44             }
 45             catch (Exception err)
 46             {
 47                 MessageBox.Show(err.Message);
 48 
 49             }
 50 
 51             myPort.DataReceived += MyPort_DataReceived;
 52 
 53             timer.Interval = TimeSpan.FromMilliseconds(200);
 54             timer.Tick += drawPoint;
 55             timer.IsEnabled = true;
 56             plotter.Viewport.FitToView();
 57 
 58         }
 59 
 60         private void MyPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
 61         {
 62             if (portClosing)
 63             {
 64                 return;
 65             }
 66 
 67             try
 68             {
 69                 lightValue = myPort.ReadLine();
 70                 result = double.Parse(lightValue);
 71             }
 72 
 73             catch(Exception err1)
 74             {
 75                 //MessageBox.Show(err1.Message);
 76                 
 77             }
 78 
 79             light_value.Dispatcher.BeginInvoke(new Action(() =>
 80             {
 81                 light_value.Value = result;
 82             }));
 83 
 84             light_result.Dispatcher.BeginInvoke(new Action(() =>
 85             {
 86                 light_result.Text = result.ToString();
 87             }));
 88         }
 89 
 90         private void 关闭_Click(object sender, RoutedEventArgs e)
 91         {
 92             portClosing = true;
 93 
 94             Thread.Sleep(10);
 95 
 96             if (myPort.IsOpen)
 97             {               
 98                 myPort.Close();
 99                 
100             }
101             else
102             {
103                 MessageBox.Show("串口已关闭");
104             }
105 
106             timer.Stop();
107         }
108 
109         private void Window_Loaded(object sender, RoutedEventArgs e)
110         {
111             plotter.AddLineGraph(dataSource, Colors.Green, 2, "光照度");
112 
113         }
114 
115         private void drawPoint(object sender, EventArgs e)
116         {
117             double x = i;
118             double y = result;
119 
120             Point point = new Point(x,y);
121             dataSource.AppendAsync(base.Dispatcher, point);
122             i++;
123         }
124     }
125 }
用WPF快速设计一个简单的串口上位机

程序运行效果:

用WPF快速设计一个简单的串口上位机

以上就是软硬件系统的全部细节,欢迎拍砖!