快速設計一個簡單的WPF串口上位機


最近一直在學習UWP,其中有的技術參考了WPF,所以又回頭再來學習WPF,感覺學的東西很雜,必須記錄一下,不然時間長了還得忘掉,於是申請開始寫博客,將學習的心得記錄一下,以備后用。這次是因為公司內訓,剛好想着推廣一下開源硬件,所以選擇了Arduino,而又結合WPF的強大功能,設計了串口上位機。

1.Arduino UNO作為下位機

利用Arduino作為下位機,理由很簡單,語法很簡單,上手很快。

1.電路連接

下圖為電路原理圖,主要利用模擬口A0讀取光敏電阻和普通電阻的分壓值,然后通過設定邏輯控制LED的狀態。之后通過串口將數據發送給電腦。

2.下位機程序

在arduino IDE里完成。代碼結構非常簡單,setup()中設置IO口及串口,然后在loop()中讀取數值,根據數據控制LED狀態,並將數值從串口發送出去。

 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次使用該控件,感覺效果還行。

代碼寫的很嫩。

程序界面如下,這里沒有選擇串口的選型,因為提前看了串口號。

 

xaml代碼:

 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>
View Code

后台代碼:

  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 }
View Code

程序運行效果:

以上就是軟硬件系統的全部細節,歡迎拍磚!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM