一、效果展示
虚拟两串口

打包程序

配虚拟机串口



虚拟机开机

运行程序

发现找不到串口,需要设置权限

Linux串口访问权限设置:
–要查询Linux系统中的当前用户可以使用whoami命令。
whoami
–将当前用户加入dialout组。 命令:
sudo usermod -aG dialout debian
sudo adduser debian dialout
–查询所有串口
ls /dev/tty*
–发送串口消息
echo hello > /dev/ttyS0
–检查串口读写权限
ls -l /dev/ttyS0
–接收串口消息
cat /dev/ttyS0
串口权限正常了

windows串口发送消息

Linux串口接收消息

二、VS2022开发
.net8环境

NuGet 安装 Avalonia

界面编写

三、代码展示
MainWindow.axaml
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:BaoYuanSerial.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Lan="clr-namespace:BaoYuanSerial.Util"
xmlns:i="using:Avalonia.Xaml.Interactivity"
xmlns:ia="using:Avalonia.Xaml.Interactions.Core"
mc:Ignorable="d" d:DesignWidth="900" d:DesignHeight="500"
x:Class="BaoYuanSerial.Views.MainWindow"
WindowStartupLocation="CenterScreen"
Width="900" Height="700"
MinWidth="900" MinHeight="700"
Icon="/Assets/yinyang_64.png"
Title="AvaloniaSerial"
>
<Design.DataContext>
<vm:MainWindowViewModel/>
</Design.DataContext>
<Window.Styles>
<Style Selector="ComboBoxItem">
<Setter Property="FontSize" Value="15"/>
</Style>
</Window.Styles>
<Grid RowDefinitions="30,32,*,25" >
<Menu Background="LightGray">
<MenuItem Header="{Lan:Localize menuTool}" Margin="5,5,0,0">
<MenuItem Header="{Lan:Localize menuToolBox}" Name="ToolBoxMenu" />
<MenuItem Header="{Lan:Localize menuAscii}" Name="AsciiCodeMenu" />
<Separator/>
<MenuItem Name="OptionsMenu" Header="{Lan:Localize menuOptions}" />
</MenuItem>
<MenuItem Header="{Lan:Localize menuHelp}" Margin="5,5,0,0">
<MenuItem Header="{Lan:Localize menuDoc}" />
<Separator/>
<MenuItem Name="AboutMenu" Header="{Lan:Localize menuAbout}" />
</MenuItem>
<MenuItem Header="{Lan:Localize menuLanguage}" Name="LanguageMenu" Margin="5,5,0,0">
<MenuItem Name="ChineseMenu" Header="{Lan:Localize menuCh}" />
<Separator/>
<MenuItem Name="EnglishMenu" Header="{Lan:Localize menuEn}" Margin="5,5,0,0" />
</MenuItem>
<MenuItem Header="{Lan:Localize menuDonate}" Name="DonateMenu" Margin="5,5,0,0">
</MenuItem>
</Menu>
<Grid Grid.Row="1" ColumnDefinitions="32,32,32,32,32,32,32,100,*">
<Button Grid.Column="0" ToolTip.Tip="{Lan:Localize mvTipSaveLog}"
HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch"
Command="{Binding OnLogCommand}"
Background="{Binding LogBtnBackColor}"
>
<Image Source="/Assets/save.png"/>
</Button>
<Button Grid.Column="1" ToolTip.Tip="{Lan:Localize mvTipStart}"
HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch"
Command="{Binding OnStartCommand}" IsEnabled="{Binding IsStartCan}"
>
<Image Source="/Assets/start.png"/>
</Button>
<Button Grid.Column="2" ToolTip.Tip="{Lan:Localize mvTipPause}"
HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch"
Command="{Binding OnPauseCommand}" IsEnabled="{Binding IsPauseCan}"
Background="{Binding PauseBtnBackColor}"
>
<Image Source="/Assets/pause.png"/>
</Button>
<Button Grid.Column="3" ToolTip.Tip="{Lan:Localize mvTipStop}"
HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch"
Command="{Binding OnStopCommand}" IsEnabled="{Binding IsStopCan}"
>
<Image Source="/Assets/stop.png"/>
</Button>
<Button Grid.Column="4" ToolTip.Tip="{Lan:Localize mvTipClear}"
HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch"
Command="{Binding OnClearCommand}"
>
<Image Source="/Assets/clear.png"/>
</Button>
<Button Grid.Column="5" ToolTip.Tip="{Lan:Localize mvTipHideLeft}"
HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch"
Name="btnHideLeft"
>
<Image Source="/Assets/hide-left.png"/>
</Button>
<Button Name="tlbtnOptions" Grid.Column="6" ToolTip.Tip="{Lan:Localize mvTipOption}"
HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch"
HorizontalContentAlignment="Stretch" >
<Image Source="/Assets/options.png"/>
</Button>
<ComboBox Grid.Column="7" SelectionChanged="OnLanguageChanged" IsVisible="False">
<ComboBoxItem>English</ComboBoxItem>
<ComboBoxItem>Chinese</ComboBoxItem>
</ComboBox>
</Grid>
<SplitView Grid.Row="2" IsPaneOpen="True"
DisplayMode="Inline" Name="viewSplit"
OpenPaneLength="300">
<SplitView.Pane>
<Grid RowDefinitions="9*,9*,6*">
<Grid RowDefinitions="*,*,*,*,*,*,*" ColumnDefinitions="*,3*">
<TextBlock Grid.Row="0" Grid.ColumnSpan="2" VerticalAlignment="Center"
Text="{Lan:Localize mwSPS}" Margin="5,0"/>
<Border Grid.Row="1" Grid.RowSpan="6" Grid.ColumnSpan="2"
BorderThickness="1" BorderBrush="Black" Margin="5,0,5,-5"
CornerRadius="2"/>
<TextBlock Grid.Row="1" Text="{Lan:Localize mwPort}" TextAlignment="Right"
VerticalAlignment="Center" Margin="5,2,0,0"/>
<ComboBox Grid.Row="1" Grid.Column="1" HorizontalAlignment="Stretch"
VerticalAlignment="Center" Margin="5,2,10,0"
Items="{Binding SerialPortList}" SelectedIndex="{Binding PortNameIndex}"
/>
<TextBlock Grid.Row="2" Text="{Lan:Localize mwBaudRate}" TextAlignment="Right"
VerticalAlignment="Center" Margin="5,0,0,0"/>
<ComboBox Grid.Row="2" Grid.Column="1" HorizontalAlignment="Stretch"
VerticalAlignment="Center" Margin="5,2,10,0"
Items="{Binding BaudRateList}" SelectedIndex="{Binding BaudRateIndex}"/>
<TextBlock Grid.Row="3" Text="{Lan:Localize mwDataBits}" TextAlignment="Right"
VerticalAlignment="Center" Margin="5,0,0,0"/>
<ComboBox Grid.Row="3" Grid.Column="1" HorizontalAlignment="Stretch"
VerticalAlignment="Center" Margin="5,2,10,0"
Items="{Binding DataBitsList}"
SelectedIndex="{Binding DataBitsIndex}"
/>
<TextBlock Grid.Row="4" Text="{Lan:Localize mwParity}" TextAlignment="Right"
VerticalAlignment="Center" Margin="5,0,0,0"/>
<ComboBox Grid.Row="4" Grid.Column="1" HorizontalAlignment="Stretch"
VerticalAlignment="Center" Margin="5,2,10,0"
SelectedIndex="{Binding Parity}">
<ComboBoxItem Content="None"/>
<ComboBoxItem Content="Odd"/>
<ComboBoxItem Content="Even"/>
<ComboBoxItem Content="Mark"/>
<ComboBoxItem Content="Space"/>
</ComboBox>
<TextBlock Grid.Row="5" Text="{Lan:Localize mwStopBits}" TextAlignment="Right"
VerticalAlignment="Center" Margin="5,0,0,0"/>
<ComboBox Grid.Row="5" Grid.Column="1" HorizontalAlignment="Stretch"
VerticalAlignment="Center" Margin="5,2,10,0"
SelectedIndex="{Binding StopBits}"
>
<ComboBoxItem Content="1"/>
<ComboBoxItem Content="1.5"/>
<ComboBoxItem Content="2"/>
</ComboBox>
<TextBlock Grid.Row="6" Text="{Lan:Localize mwFlowType}" TextAlignment="Right"
VerticalAlignment="Center" Margin="5,0,0,0"/>
<ComboBox Grid.Row="6" Grid.Column="1" HorizontalAlignment="Stretch"
VerticalAlignment="Center" Margin="5,2,10,0"
SelectedIndex="{Binding FlowType}"
>
<ComboBoxItem Content="None"/>
<ComboBoxItem Content="RTS/CTS"/>
<ComboBoxItem Content="DTR/CTS"/>
</ComboBox>
</Grid>
<Grid Grid.Row="1" RowDefinitions="3*,0.2*,2*,*,*,*" ColumnDefinitions="*,*">
<TextBlock Grid.Row="0" Grid.ColumnSpan="2" VerticalAlignment="Bottom"
Text="{Lan:Localize mwReceiveSet}" Margin="5,0"/>
<Border Grid.Row="1" Grid.RowSpan="5" Grid.ColumnSpan="2"
BorderThickness="1" BorderBrush="Black" Margin="5,0,5,0"
CornerRadius="2"/>
<RadioButton Grid.Row="2" Grid.Column="0" GroupName="Receive"
Content="ASCII" Margin="10,5"
IsChecked="{Binding ReceivePara.IsText}"/>
<RadioButton Grid.Row="2" Grid.Column="1" GroupName="Receive"
Content="Hex" Margin="10,5"
IsChecked="{Binding ReceivePara.IsHex}"/>
<CheckBox Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2"
Content="{Lan:Localize mwAutoFL}" Margin="10,5"
IsChecked="{Binding ReceivePara.AutoFeed}"/>
<CheckBox Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2"
Content="{Lan:Localize mwDisSend}" Margin="10,5"
IsChecked="{Binding ReceivePara.DisplaySend}"/>
<CheckBox Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="2"
Content="{Lan:Localize mwDisTime}" Margin="10,5"
IsChecked="{Binding ReceivePara.DisplayTime}"/>
</Grid>
<Grid Grid.Row="2" RowDefinitions="*,0.2*,2*,1.5*" ColumnDefinitions="*,1.5*,40">
<TextBlock Grid.Row="0" Grid.ColumnSpan="2" VerticalAlignment="Bottom"
Text="{Lan:Localize mwSendSet}" Margin="5,0"/>
<Border Grid.Row="1" Grid.RowSpan="5" Grid.ColumnSpan="3"
BorderThickness="1" BorderBrush="Black" Margin="5,0,5,5"
CornerRadius="2"/>
<RadioButton Grid.Row="2" Grid.Column="0" GroupName="Send"
Content="ASCII" Margin="10,5"
IsChecked="{Binding SendPara.IsText}"
/>
<RadioButton Grid.Row="2" Grid.Column="1" GroupName="Send"
Content="Hex" Margin="10,5"
IsChecked="{Binding SendPara.IsHex}"/>
<CheckBox Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2"
Content="{Lan:Localize mwLoop}" Margin="10,0,0,10"
VerticalAlignment="Stretch"
Name="chbLoop" >
</CheckBox>
<NumericUpDown Grid.Row="3" Grid.Column="1" VerticalAlignment="Stretch"
Margin="10,0,0,10" Padding="5"
Value="{Binding SendPara.LoopInterval}"
VerticalContentAlignment="Center"
/>
<TextBlock Grid.Row="3" Grid.Column="2"
Text="ms" VerticalAlignment="Center" Margin="5,5,5,10" />
</Grid>
</Grid>
</SplitView.Pane>
<Grid RowDefinitions="*,70,40" ColumnDefinitions="*,100">
<TextBox Grid.Row="0" Grid.ColumnSpan="2" IsReadOnly="False" Margin="0,0,5,5"
ScrollViewer.VerticalScrollBarVisibility="Auto" VerticalContentAlignment="Top" HorizontalContentAlignment="Left"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
TextWrapping="Wrap" Text="{Binding Path=ReceiveTxt}"
/>
<TextBox Grid.Row="1" Grid.ColumnSpan="2" Margin="0,0,5,5"
ScrollViewer.VerticalScrollBarVisibility="Auto"
TextWrapping="Wrap"
Text="{Binding SendTxt}"
/>
<ComboBox Grid.Row="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,5,5"
SelectedIndex="{Binding SendTxtHisSelIndex}" Items="{Binding SendTxtHistory}"
Name="CbbHistory"
/>
<Button Grid.Row="2" Grid.Column="1" VerticalAlignment="Stretch"
HorizontalAlignment="Stretch" Margin="0,0,5,5"
Content="{Lan:Localize mwSend}" FontSize="15" Padding="0"
VerticalContentAlignment="Center" HorizontalContentAlignment="Center"
Command="{Binding OnSendCommand}"
IsEnabled="{Binding SendCmdIsEnable}"
/>
</Grid>
</SplitView>
<Grid Grid.Row="3" ColumnDefinitions="200,200,200">
<TextBlock Grid.Column="0" Text="{Binding ComPortState}"
VerticalAlignment="Bottom" Margin="5"
Foreground="{Binding ComPortStateColor}"
/>
<TextBlock Grid.Column="1" Text="{Binding ReceiveBytesStr}"
Foreground="{Binding ReceiveBytesColor}"
VerticalAlignment="Bottom" Margin="5"/>
<TextBlock Grid.Column="2" Text="{Binding SendBytesStr}"
Foreground="{Binding SendBytesColor}"
VerticalAlignment="Bottom" Margin="5"/>
</Grid>
</Grid>
</Window>
MainWindow.axaml.cs
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using BaoYuanSerial.ViewModels;
using ReactiveUI;
using System.Reactive;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using Avalonia.Styling;
using MessageBox.Avalonia.DTO;
using MessageBox.Avalonia.Enums;
using BaoYuanSerial.Models;
using System;
using Avalonia.Markup.Xaml.MarkupExtensions;
using BaoYuanSerial.Util;
namespace BaoYuanSerial.Views
{
public partial class MainWindow :Window
{
private readonly List<Window> _windows = new List<Window>();
MainWindowViewModel _thisViewModel;
CheckBox _chbLoop;
public MainWindow()
{
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
//Instance = this;
var AboutMenu = this.FindControl<MenuItem>("AboutMenu");
AboutMenu.Command = ReactiveCommand.Create(AboutMenuClicked);
var DonateMenu = this.FindControl<MenuItem>("DonateMenu");
DonateMenu.Command = ReactiveCommand.Create(DonateMenuClicked);
var OptionsMenu = this.FindControl<MenuItem>("OptionsMenu");
OptionsMenu.Command = ReactiveCommand.Create(OptionsMenuClicked);
var tlbtnOptions = this.FindControl<Button>("tlbtnOptions");
tlbtnOptions.Command = ReactiveCommand.Create(OptionsMenuClicked);
var ToolBoxMenu = this.FindControl<MenuItem>("ToolBoxMenu");
ToolBoxMenu.Command = ReactiveCommand.Create(ToolBoxMenuClicked);
var AsciiCodeMenu = this.FindControl<MenuItem>("AsciiCodeMenu");
AsciiCodeMenu.Command = ReactiveCommand.Create(AsciiCodeMenuClicked);
var ChineseMenu = this.FindControl<MenuItem>("ChineseMenu");
ChineseMenu.Command = ReactiveCommand.Create(ChineseMenuClicked);
var EnglishMenu = this.FindControl<MenuItem>("EnglishMenu");
EnglishMenu.Command = ReactiveCommand.Create(EnglishMenuClicked);
Button btnHideLeft = this.FindControl<Button>("btnHideLeft");
btnHideLeft.Click += btnHideLeft_Click;
ComboBox CbbHistory = this.FindControl<ComboBox>("CbbHistory");
CbbHistory.SelectionChanged += SendHistoryComb_Changed;
_chbLoop = this.FindControl<CheckBox>("chbLoop");
_chbLoop.Checked += LoopChbox_Checked; //当checkbox未选中转为选中时触发。
_chbLoop.Unchecked += LoopChbox_UnChecked; //当checkbox选中转为未选中时触发
GlobalPara.GetLocSet();
Localizer.Instance.LoadLanguage(GlobalPara.LocSet.Language);
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
public void LoopChbox_Checked(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
_thisViewModel = (MainWindowViewModel)this.DataContext;
if (_thisViewModel != null)
{
if (_thisViewModel._serialPort == null || _thisViewModel.SendTxt.Trim() == "")
{
var msBoxStandardWindow = MessageBox.Avalonia.MessageBoxManager
.GetMessageBoxStandardWindow(new MessageBoxStandardParams
{
ButtonDefinitions = ButtonEnum.Ok,
ContentTitle = "Tips",
ContentMessage = "Please Open ComPort First Or SendText is not Empty",
Icon = MessageBox.Avalonia.Enums.Icon.Info,
FontFamily = "Microsoft YaHei,Simsun",
WindowStartupLocation = Avalonia.Controls.WindowStartupLocation.CenterScreen,
#if Ubuntu
Style =MessageBox.Avalonia.Enums.Style.UbuntuLinux
#elif MSWindow
Style = MessageBox.Avalonia.Enums.Style.Windows
#endif
});
msBoxStandardWindow.Show();
_chbLoop.IsChecked = false;
return;
}
_thisViewModel.SendCmdIsEnable = false;
_thisViewModel.SendPara.IsLoop = true;
Task.Factory.StartNew(async() => {
while(_thisViewModel.SendPara.IsLoop)
{
await _thisViewModel.SendCmdLoop();
}
});
}
}
public void LoopChbox_UnChecked(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
_thisViewModel = (MainWindowViewModel)this.DataContext;
if (_thisViewModel != null)
{
_thisViewModel.SendCmdIsEnable = true;
_thisViewModel.SendPara.IsLoop = false;
}
}
private void btnHideLeft_Click(object obj, Avalonia.Interactivity.RoutedEventArgs e)
{
SplitView splitView = this.FindControl<SplitView>("viewSplit");
splitView.IsPaneOpen = !splitView.IsPaneOpen;
}
private void SendHistoryComb_Changed(object obj, SelectionChangedEventArgs e)
{
_thisViewModel = (MainWindowViewModel)this.DataContext;
if(_thisViewModel != null)
{
_thisViewModel.SendTxt= _thisViewModel.SendTxtHistory[_thisViewModel.SendTxtHisSelIndex];
}
}
protected override void OnClosing(CancelEventArgs e)
{
foreach (var window in _windows)
{
window.Close();
}
}
private void AboutMenuClicked()
{
var window = new AboutWindow
{
DataContext = new AboutViewModel(),
Topmost = true,
CanResize = false
};
window.ShowDialog(this);
window.Activate();
_windows.Add(window);
}
private void DonateMenuClicked()
{
var window = new DonateWindow
{
Topmost = true,
CanResize = false
};
window.ShowDialog(this);
window.Activate();
_windows.Add(window);
}
private void OptionsMenuClicked()
{
var window = new OptionsWindow
{
DataContext = new OptionsViewModel(),
Topmost = true,
CanResize = false
};
window.Show();
window.Activate();
_windows.Add(window);
}
private void ToolBoxMenuClicked()
{
var window = new ToolBoxWindow
{
DataContext=new ToolBoxViewModel(),
Topmost = true,
CanResize = false
};
window.ShowDialog(this);
window.Activate();
_windows.Add(window);
}
private void AsciiCodeMenuClicked()
{
var window = new AsciiCodeWindow
{
Topmost = true,
CanResize = false
};
window.ShowDialog(this);
window.Activate();
_windows.Add(window);
}
private void ChineseMenuClicked()
{
Localizer.Instance.LoadLanguage("zh-CN");
try
{
GlobalPara.SaveCurLanguage("zh-CN");
}
catch
{
}
}
private void EnglishMenuClicked()
{
Localizer.Instance.LoadLanguage("en-US");
try
{
GlobalPara.SaveCurLanguage("en-US");
}
catch
{
}
}
private void OnLanguageChanged(object sender, SelectionChangedEventArgs args)
{
//var cb = sender as ComboBox;
//var language = cb.SelectedIndex == 0 ? "en-US" : "zh-CN";
//Localizer.Instance.LoadLanguage(language);
}
}
}
以上Linux系统部署串口通讯就完成,快去试试吧。
Linux系统安装SQL Server数据库
.NET6接口WebApi部署到Linux系统上
C# VOL.NET6项目使用宝塔部署到Linux系统完整篇
C# AvaloniaUI实现跨平台多语言串口通讯
C# WinForm实现跨平台串口通讯
C#WPF实现串口通讯
Visual Studio 2022安装Avalonia
C#Avalonia串口通讯Linux部署测试 (qq.com)
© 版权声明
文章版权归作者所有,未经允许请勿转载。如内容涉嫌侵权,请在本页底部进入<联系我们>进行举报投诉!
THE END















暂无评论内容