├── README.md
├── SerialAssistant.sln
├── SerialAssistant
├── App.xaml
├── App.xaml.cs
├── AssemblyInfo.cs
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── Properties
│ └── PublishProfiles
│ │ ├── FolderProfile.pubxml
│ │ └── FolderProfile.pubxml.user
├── SerialAssistant.csproj
├── SerialAssistant.csproj.user
├── icon-logo.ico
└── icon-uninstall.ico
└── 串口助手2.0
└── Release
└── setup.exe
/README.md:
--------------------------------------------------------------------------------
1 | Serial Assistant
2 |
3 |
4 | C# serial assistant, a WPF program developed based on .Net5.0, realizes serial communication function, has settings for sending and receiving information, and also includes WPF packaging program, no advertisements and open source.
5 |
6 |
7 | Feature:
8 |
9 |
10 | • Automatically find and list available serial ports.
11 |
12 | • Set whether to accept newline, display the content to be sent, display time and other settings.
13 |
14 | • Can set automatic interval to send.
15 |
16 | • Switchable Hex and String display.
17 |
18 | • No additional dependencies.
19 |
20 | 串口助手
21 |
22 | C#串口助手,基于.Net5.0开发的WPF程序,实现串口通信功能,具有收发信息的设置,其中还包含WPF打包程序,无广告及开源。
23 |
24 | 特点:
25 |
26 | • 自动查找并列出可用串口。
27 |
28 | • 设置接受是否换行、显示发送内容、显示时间等设置。
29 |
30 | • 可设置自动间隔时间去发送。
31 |
32 | • 可切换Hex和String显示。
33 |
34 | • 无附加依赖库。
35 |
36 |
37 | 备注:
38 |
39 | 其中含有的将WPF打包成安装程序的项目,但鉴于各人电脑文件位置设置的不一样,不能保证这个打包项目一定能跑起来,需要帮助可以联系我。
40 | 因为是一路学习摸索地去开发,有不好的地方或者建议,欢迎大家提出了,我虚心接受学习。
41 |
42 | 如果觉得还可以,欢迎给我个小星星!
43 |
44 | 
45 |
--------------------------------------------------------------------------------
/SerialAssistant.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.31727.386
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SerialAssistant", "SerialAssistant\SerialAssistant.csproj", "{4E0848AD-6322-4D5B-93E0-00BF472D76AB}"
7 | EndProject
8 | Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "串口助手2.0", "串口助手2.0\串口助手2.0.vdproj", "{2A9D1167-05EE-4560-982D-539D9E706A5D}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {4E0848AD-6322-4D5B-93E0-00BF472D76AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {4E0848AD-6322-4D5B-93E0-00BF472D76AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {4E0848AD-6322-4D5B-93E0-00BF472D76AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {4E0848AD-6322-4D5B-93E0-00BF472D76AB}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {2A9D1167-05EE-4560-982D-539D9E706A5D}.Debug|Any CPU.ActiveCfg = Debug
21 | {2A9D1167-05EE-4560-982D-539D9E706A5D}.Release|Any CPU.ActiveCfg = Release
22 | EndGlobalSection
23 | GlobalSection(SolutionProperties) = preSolution
24 | HideSolutionNode = FALSE
25 | EndGlobalSection
26 | GlobalSection(ExtensibilityGlobals) = postSolution
27 | SolutionGuid = {C3169C75-B246-494D-97E4-C619C1717468}
28 | EndGlobalSection
29 | EndGlobal
30 |
--------------------------------------------------------------------------------
/SerialAssistant/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/SerialAssistant/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 |
9 | namespace SerialAssistant
10 | {
11 | ///
12 | /// Interaction logic for App.xaml
13 | ///
14 | public partial class App : Application
15 | {
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/SerialAssistant/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
11 |
--------------------------------------------------------------------------------
/SerialAssistant/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
14 |
19 |
22 |
27 |
28 |
33 |
34 |
42 |
49 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
70 |
71 |
77 |
78 |
87 |
92 |
93 |
100 |
105 |
106 |
110 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
--------------------------------------------------------------------------------
/SerialAssistant/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Windows;
4 | using System.Windows.Controls;
5 | using System.Windows.Media;
6 |
7 | using System.IO.Ports;
8 | using System.Text.RegularExpressions;
9 | using System.Timers;
10 |
11 | namespace SerialAssistant
12 | {
13 | ///
14 | /// Interaction logic for MainWindow.xaml
15 | ///
16 | public partial class MainWindow : Window
17 | {
18 | SerialPort serialPort = new SerialPort();
19 | int receiveCount = 0;
20 | StringBuilder message = new StringBuilder();
21 | string currentSendMsgASCII;
22 | string currentSendMsgHexStr;
23 | byte[] currentSendMsgHex;
24 |
25 | string portV, baudV, dataBitV, verifyBitV, StopBitV, flowControlV, receiveFormat = "Hex", sendFormat = "Hex";
26 | int reSendTime = 1000;
27 | bool autoWrap = true, showSend = true, showTime = true, autoReSend = false;
28 |
29 | Timer mainTimer;
30 | public MainWindow()
31 | {
32 | InitializeComponent();
33 |
34 | initTimer();
35 | initControls();
36 | InitData();
37 | }
38 | private void initTimer()
39 | {
40 | mainTimer = new Timer();
41 | mainTimer.Elapsed += new ElapsedEventHandler(AutoReSendMsg);
42 | mainTimer.AutoReset = true;
43 | mainTimer.Enabled = false;
44 | mainTimer.Interval = reSendTime;
45 |
46 | }
47 | private void initControls()
48 | {
49 | AutoWrap.IsChecked = true;
50 | ShowSend.IsChecked = true;
51 | ShowTime.IsChecked = true;
52 | AutoReSend.IsChecked = false;
53 | }
54 |
55 | private void InitData()
56 | {
57 | var portNames = SerialPort.GetPortNames();
58 | if(portNames.Length < 1)
59 | {
60 | MessageBox.Show("当前没有可用的端口连接");
61 | return;
62 | }
63 | ComboBoxPort.ItemsSource = portNames;
64 | ComboBoxPort.SelectedIndex = 0;
65 | portV = portNames[0];
66 |
67 | string[] baud = { "9600", "19200", "38400", "57600", "115200"};
68 | ComboBoxBaud.ItemsSource = baud;
69 | ComboBoxBaud.SelectedIndex = 4;
70 | baudV = baud[4];
71 |
72 | string[] dbit ={ "5", "6", "7", "8" };
73 | ComboBoxDataBit.ItemsSource = dbit;
74 | ComboBoxDataBit.SelectedIndex = 3;
75 | dataBitV = dbit[3];
76 |
77 | string[] vbit = { "None", "Even", "Odd", "Mark", "Space" };
78 | ComboBoxVeriBit.ItemsSource = vbit;
79 | ComboBoxVeriBit.SelectedIndex = 0;
80 | verifyBitV = vbit[0];
81 |
82 | string[] sbit = { "1", "1.5", "2"};
83 | ComboBoxStopBit.ItemsSource = sbit;
84 | ComboBoxStopBit.SelectedIndex = 0;
85 | StopBitV = sbit[0];
86 |
87 | string[] fc = { "None", "RTS/CTS", "XON/XOFF" };
88 | ComboBoxFlowControl.ItemsSource = fc;
89 | ComboBoxFlowControl.SelectedIndex = 0;
90 | flowControlV = fc[0];
91 |
92 | }
93 | private void ConnectSerial_Click(object sender, RoutedEventArgs e)
94 | {
95 | Button btn = sender as Button;
96 | try
97 | {
98 | if (serialPort.IsOpen)
99 | {
100 | serialPort.Close();
101 | btn.Content = "打开串口";
102 | btn.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("Green"));
103 | SerialStatus.Text = "Closed";
104 | message.Clear();
105 | MessageReceive.Text = "";
106 | }
107 | else
108 | {
109 | serialPort.PortName = ComboBoxPort.Text;
110 | serialPort.BaudRate = Convert.ToInt32(ComboBoxBaud.Text);
111 | serialPort.DataBits = Convert.ToInt32(ComboBoxDataBit.Text);
112 | Parity parity = Parity.None;
113 | switch (ComboBoxVeriBit.Text)
114 | {
115 | case "None":
116 | parity = Parity.None;
117 | break;
118 | case "Odd":
119 | parity = Parity.Odd;
120 | break;
121 | case "Even":
122 | parity = Parity.Even;
123 | break;
124 | case "Space":
125 | parity = Parity.Space;
126 | break;
127 | case "Mark":
128 | parity = Parity.Mark;
129 | break;
130 | }
131 | serialPort.Parity = parity;
132 | StopBits stopBits = StopBits.One;
133 | switch (ComboBoxStopBit.Text)
134 | {
135 | case "1":
136 | stopBits = StopBits.One;
137 | break;
138 | case "1.5":
139 | stopBits = StopBits.OnePointFive;
140 | break;
141 | case "2":
142 | stopBits = StopBits.Two;
143 | break;
144 | }
145 | serialPort.StopBits = stopBits;
146 |
147 | serialPort.DataReceived += new SerialDataReceivedEventHandler(SerialDataReceive);
148 |
149 | serialPort.Open();
150 | btn.Content = "关闭串口";
151 | btn.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("Red"));
152 | SerialStatus.Text = $"Connected, {serialPort.PortName}, {serialPort.BaudRate}, {serialPort.DataBits}, {serialPort.Parity}, {serialPort.StopBits}";
153 |
154 | }
155 | }catch(Exception ex)
156 | {
157 | serialPort = new SerialPort();
158 | btn.Content = "打开串口";
159 | btn.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("Green"));
160 | SerialStatus.Text = "CLOSED";
161 | message.Clear();
162 | MessageReceive.Text = "";
163 | }
164 | }
165 |
166 | private void SerialDataReceive(object sender, SerialDataReceivedEventArgs e)
167 | {
168 | int num = serialPort.BytesToRead;
169 | byte[] buffer = new byte[num];
170 | receiveCount += num;
171 | serialPort.Read(buffer, 0, num);
172 | ReceiveLength.Text = num.ToString();
173 |
174 | string msg = "";
175 | if (showTime == true)
176 | {
177 | msg += $"[{DateTime.Now.ToString("HH:mm:ss.fff")}] ";
178 | }
179 |
180 | if (receiveFormat.Equals("Hex"))
181 | {
182 | foreach (byte b in buffer)
183 | {
184 | msg += $"{b.ToString("X2")} ";
185 |
186 | }
187 | }else if (receiveFormat.Equals("ASCII"))
188 | {
189 | msg += $"{Encoding.ASCII.GetString(buffer)} ";
190 | }
191 |
192 | message.Append(msg);
193 | if(autoWrap == true)
194 | {
195 | message.Append("\r\n");
196 | }
197 |
198 | try
199 | {
200 | this.Dispatcher.Invoke(new Action(() =>
201 | {
202 | MessageReceive.Text = message.ToString();
203 | }));
204 | }catch(Exception ex)
205 | {
206 |
207 | }
208 | }
209 |
210 | private void SendMsg_Click(object sender, RoutedEventArgs e)
211 | {
212 | byte[] data;
213 | if (serialPort.IsOpen)
214 | {
215 | string msg = MessageSend.Text.ToString();
216 | if (!string.IsNullOrWhiteSpace(msg))
217 | {
218 | try
219 | {
220 | if (sendFormat.Equals("ASCII"))
221 | {
222 | serialPort.Write(msg);
223 | HandleSendFormat(msg, "ASCII");
224 |
225 | currentSendMsgASCII = msg;
226 | if (ComboBoxSendRecord.Items.Count == 0 || !ComboBoxSendRecord.Items.Contains(msg))
227 | {
228 | ComboBoxSendRecord.Items.Insert(0, msg);
229 | ComboBoxSendRecord.SelectedIndex = 0;
230 | }
231 | SendLength.Text = Encoding.Default.GetBytes(msg).Length.ToString();
232 | }
233 | else if (sendFormat.Equals("Hex"))
234 | {
235 | string pattern = @"\s";
236 | string relacement = "";
237 | Regex rgx = new Regex(pattern);
238 | string msg1 = rgx.Replace(msg, relacement);
239 | int len = Convert.ToInt32(Math.Ceiling((double)msg1.Length / 2));
240 | data = new byte[len];
241 |
242 | for (int i = 0; i < data.Length; i++)
243 | {
244 | int s = 0;
245 | try
246 | {
247 | s = Convert.ToInt32(msg1.Substring(i * 2, 2), 16);
248 | }catch(Exception ex)
249 | {
250 | s = Convert.ToInt32(msg1.Substring(i * 2, 1) + "0", 16);
251 | }
252 | data[i] = Convert.ToByte(s);
253 | }
254 | serialPort.Write(data, 0, data.Length);
255 | HandleSendFormat(msg1, "Hex");
256 |
257 | currentSendMsgHexStr = msg1;
258 | currentSendMsgHex = data;
259 | if (ComboBoxSendRecord.Items.Count == 0 || !ComboBoxSendRecord.Items.Contains(msg1))
260 | {
261 | ComboBoxSendRecord.Items.Insert(0, msg1);
262 | ComboBoxSendRecord.SelectedIndex = 0;
263 | }
264 | SendLength.Text = data.Length.ToString();
265 | }
266 |
267 | if(autoReSend == true)
268 | {
269 | if (reSendTime > 0)
270 | {
271 | mainTimer.Interval = reSendTime;
272 | mainTimer.Start();
273 | }
274 | else
275 | {
276 | MessageBox.Show("自动重发时间需大于0ms");
277 | }
278 | }
279 |
280 |
281 | }
282 | catch(Exception ex)
283 | {
284 | MessageBox.Show(ex.Message);
285 | }
286 | }
287 | }
288 | else
289 | {
290 | MessageBox.Show("请先打开串口");
291 | }
292 | }
293 | private void HandleSendFormat(string msg, string format)
294 | {
295 | if (showSend == true)
296 | {
297 | if (showTime == true)
298 | {
299 | message.Append($"[{DateTime.Now.ToString("HH:mm:ss.fff")}] ");
300 | }
301 | if (format.Equals("Hex")){
302 | for (int i = 2; i < msg.Length; i += 2 + 1)
303 | {
304 | msg = msg.Insert(i, " ");
305 | }
306 | }
307 | message.Append(msg);
308 | if (autoWrap == true)
309 | {
310 | message.Append("\r\n");
311 | }
312 | try
313 | {
314 | this.Dispatcher.Invoke(new Action(() =>
315 | {
316 | MessageReceive.Text = message.ToString();
317 | }));
318 | }
319 | catch (Exception ex)
320 | {
321 |
322 | }
323 | }
324 | }
325 |
326 | private void AutoReSendMsg(object source, System.Timers.ElapsedEventArgs e)
327 | {
328 | if (serialPort.IsOpen)
329 | {
330 | try
331 | {
332 | if (sendFormat.Equals("ASCII"))
333 | {
334 | serialPort.Write(currentSendMsgASCII);
335 | Dispatcher.Invoke(new Action(() =>
336 | {
337 | SendLength.Text = Encoding.Default.GetBytes(currentSendMsgASCII).Length.ToString();
338 | }));
339 |
340 | HandleSendFormat(currentSendMsgASCII, "ASCII");
341 |
342 | }
343 | else if (sendFormat.Equals("Hex"))
344 | {
345 | serialPort.Write(currentSendMsgHex, 0, currentSendMsgHex.Length);
346 | Dispatcher.Invoke(new Action(() =>
347 | {
348 | SendLength.Text = currentSendMsgHex.Length.ToString();
349 | }));
350 |
351 | string msg = currentSendMsgHexStr;
352 | HandleSendFormat(msg, "Hex");
353 | }
354 | }
355 | catch (Exception ex)
356 | {
357 |
358 | }
359 | }
360 | else
361 | {
362 | MessageBox.Show("请先打开串口");
363 | }
364 | }
365 |
366 |
367 | private void RadioButton_Checked(object sender, RoutedEventArgs e)
368 | {
369 | RadioButton rb = sender as RadioButton;
370 | string s = rb.Content.ToString();
371 | if (s.Equals("ASCII"))
372 | {
373 | receiveFormat = s;
374 | }else if (s.Equals("Hex"))
375 | {
376 | receiveFormat = s;
377 | }
378 | }
379 |
380 | private void RadioButton1_Checked(object sender, RoutedEventArgs e)
381 | {
382 | RadioButton rb = sender as RadioButton;
383 | string s = rb.Content.ToString();
384 | if (s.Equals("ASCII"))
385 | {
386 | sendFormat = s;
387 | }
388 | else if (s.Equals("Hex"))
389 | {
390 | sendFormat = s;
391 | }
392 | }
393 |
394 | private void AutoWrap_Checked(object sender, RoutedEventArgs e)
395 | {
396 | autoWrap = true;
397 | }
398 |
399 | private void ShowSend_Checked(object sender, RoutedEventArgs e)
400 | {
401 | showSend = true;
402 | }
403 |
404 | private void ShowTime_Checked(object sender, RoutedEventArgs e)
405 | {
406 | showTime = true;
407 | }
408 |
409 | private void AutoReSend_Checked(object sender, RoutedEventArgs e)
410 | {
411 | autoReSend = true;
412 | }
413 |
414 | private void AutoWrap_Unchecked(object sender, RoutedEventArgs e)
415 | {
416 | autoWrap = false;
417 | }
418 |
419 | private void ShowSend_Unchecked(object sender, RoutedEventArgs e)
420 | {
421 | showSend = false;
422 | }
423 |
424 | private void ShowTime_Unchecked(object sender, RoutedEventArgs e)
425 | {
426 | showTime = false;
427 | }
428 |
429 | private void AutoReSend_Unchecked(object sender, RoutedEventArgs e)
430 | {
431 | autoReSend = false;
432 | mainTimer.Stop();
433 | }
434 |
435 | private void ComboBoxSendRecord_SelectionChanged(object sender, RoutedEventArgs e)
436 | {
437 |
438 | MessageSend.Text = ComboBoxSendRecord.SelectedItem.ToString();
439 | }
440 |
441 | private void ReSendTime_TextChanged(object sender, TextChangedEventArgs e)
442 | {
443 | TextBox tb = sender as TextBox;
444 | string temp = tb.Text.ToString();
445 | reSendTime = Convert.ToInt32(temp);
446 | }
447 |
448 | private void MessageSend_GotFocus(object sender, RoutedEventArgs e)
449 | {
450 | if(mainTimer.Enabled == true)
451 | {
452 | mainTimer.Stop();
453 | }
454 | }
455 |
456 | }
457 | }
458 |
--------------------------------------------------------------------------------
/SerialAssistant/Properties/PublishProfiles/FolderProfile.pubxml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Release
8 | Any CPU
9 | E:\Personal\0.1PersonalProject\SVN\Licj_SerialAssistant\publish
10 | FileSystem
11 | net5.0-windows
12 | win-x64
13 | true
14 | True
15 | False
16 | False
17 |
18 |
--------------------------------------------------------------------------------
/SerialAssistant/Properties/PublishProfiles/FolderProfile.pubxml.user:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/SerialAssistant/SerialAssistant.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WinExe
5 | net5.0-windows
6 | true
7 | icon-logo.ico
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/SerialAssistant/SerialAssistant.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <_LastSelectedProfileId>E:\Personal\0.1PersonalProject\SVN\Licj_SerialAssistant\SerialAssistant\Properties\PublishProfiles\FolderProfile.pubxml
5 |
6 |
--------------------------------------------------------------------------------
/SerialAssistant/icon-logo.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/superleej/SerialAssistant/9d4bacfab9616a879fe5885adba903a62548ebda/SerialAssistant/icon-logo.ico
--------------------------------------------------------------------------------
/SerialAssistant/icon-uninstall.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/superleej/SerialAssistant/9d4bacfab9616a879fe5885adba903a62548ebda/SerialAssistant/icon-uninstall.ico
--------------------------------------------------------------------------------
/串口助手2.0/Release/setup.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/superleej/SerialAssistant/9d4bacfab9616a879fe5885adba903a62548ebda/串口助手2.0/Release/setup.exe
--------------------------------------------------------------------------------