-
二、代码
#region 字段
SerialPort serialPortTool;
System.Windows.Forms.Timer timer;
private bool IsConnected = false;
private string portName = "COM1";
private int baudRate = 9600;
private Parity parity = Parity.None;
private int dataBits = 8;
private StopBits stopBits = StopBits.One;
public int[] _BaudRateArray = { 9600, 14400, 19200, 38400, 57600, 115200};
public int[] _DataBitArray = { 8, 7, 6, 5 };
States runState = States.None;
#endregion
-
(二)窗体初始化、加载
#region 窗体初始化、加载
public FrmSerialPort()
{
InitializeComponent();
this.CenterToParent();
}
private void FrmSerialPort_Load(object sender, EventArgs e)
{
Initialize();
}
private void Initialize()
{
cbx_SerialPort.DataSource = GetPortArray();
cbx_BaudRate.DataSource = GetBaudRateArray();
cbx_Parity.DataSource = GetParityArray();
cbx_DataBits.DataSource = GetDataBitArray();
cbx_StopBits.DataSource = GetStopBitArray();
cbx_StopBits.SelectedIndex = 1;
cbx_BaudRate.SelectedIndex = 0;
serialPortTool = new SerialPort();
if (timer == null) timer = new System.Windows.Forms.Timer();
timer.Tick += Timer_Tick;
timer.Interval = 200;
}
#endregion
-
(三)通讯状态、数据接收、消息更新、控件状态更新
#region 通讯状态、数据接收、消息更新
private void Timer_Tick(object sender, EventArgs e)
{
if (!IsConnected) return;
rsc_RunState.Invoke(new Action(() => {
if (runState == States.Running)
{
rsc_RunState.State = rsc_RunState.State == States.None ? States.Running : States.None;
Task.Delay(200);
}
else if (runState == States.Stop)
{
rsc_RunState.State = rsc_RunState.State == States.None ? States.Stop : States.None;
Task.Delay(200);
}
else
{
rsc_RunState.State = States.None;
}
}));
}
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
if (radioBtn_ReceiveEncodingASCII.Checked)
{
HexToString(((SerialPort)sender).ReadExisting() , out string data);
MessageUpdate($"{data}", Color.Blue, "# RECV ASCII>");
}
else if (radioBtn_ReceiveEncodingHEX.Checked)
{
string hexString = StringToHex(((SerialPort)sender).ReadExisting());
MessageUpdate($"{hexString}", Color.Blue, "# RECV HEX>");
}
}
private void MessageUpdate(string data, Color color, string appendText = null,bool isAppendTime = true)
{
rtbx_Message.BeginInvoke(new Action(() => {
if (isAppendTime)
{
rtbx_Message.AppendText($"[{DateTime.Now.ToString()}]");
}
if (appendText!=null)
{
rtbx_Message.AppendText($"{appendText}{Environment.NewLine}");
}
int startIndex = rtbx_Message.Text.Length;
rtbx_Message.AppendText($"{data}{Environment.NewLine}");
SetTextColor(rtbx_Message, startIndex, data.Length, color);
}));
}
private void SetTextColor(RichTextBox rtb, int startIndex, int length, Color color)
{
rtb.Invoke(new Action(() => {
int originalStart = rtb.SelectionStart;
int originalLength = rtb.SelectionLength;
rtb.Select(startIndex, length);
rtb.SelectionColor = color;
rtb.Select(originalStart, originalLength);
}));
}
private void ControlStateUpdate()
{
cbx_SerialPort.Enabled = !IsConnected;
cbx_BaudRate.Enabled = !IsConnected;
cbx_Parity.Enabled = !IsConnected;
cbx_DataBits.Enabled = !IsConnected;
cbx_StopBits.Enabled = !IsConnected;
}
#endregion
-
(四)按钮事件:打开串口、发送数据
#region 按钮事件
private void btn_Open_Click(object sender, EventArgs e)
{
try
{
if (!IsConnected)
{
serialPortTool.Close();
timer.Stop();
serialPortTool = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
serialPortTool.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
serialPortTool.Open();
IsConnected = true;
timer.Start();
btn_Open.Text = "关闭";
runState = States.Running;
}
else
{
serialPortTool.Close();
timer.Stop();
runState = States.Stop;
btn_Open.Text = "打开";
IsConnected = false;
}
}
catch (Exception)
{
serialPortTool.Close();
runState = States.Stop;
IsConnected = false;
btn_Open.Text = "打开";
}
rsc_RunState.State = runState;
ControlStateUpdate();
}
private void btn_SendData_Click(object sender, EventArgs e)
{
if (serialPortTool == null || !serialPortTool.IsOpen) return;
string data = rtbx_SendData.Text;
if(radioBtn_SendEncodingASCII.Checked)
{
MessageUpdate($"{data}", Color.Green, "# SEND ASCII>");
serialPortTool.Write(data);
}
else if (radioBtn_SendEncodingHEX.Checked)
{
MessageUpdate($"{data}", Color.Green, "# SEND HEX>");
SendHex(data);
}
}
private void btn_ClearMessage_Click(object sender, EventArgs e)
{
rtbx_Message.Clear();
}
private void btn_ClearSendData_Click(object sender, EventArgs e)
{
rtbx_SendData.Clear();
}
#endregion
-
(五)串口参数变更
#region 串口参数变更
private void cbx_SerialPort_SelectedIndexChanged(object sender, EventArgs e)
{
portName = cbx_SerialPort.SelectedItem.ToString();
}
private void cbx_BaudRate_SelectedIndexChanged(object sender, EventArgs e)
{
if (int.TryParse(cbx_BaudRate.SelectedItem.ToString(), out int result))
{
baudRate = result;
}
else
{
cbx_BaudRate.SelectedText = baudRate.ToString();
}
}
private void cbx_Parity_SelectedIndexChanged(object sender, EventArgs e)
{
if (Enum.TryParse(cbx_Parity.SelectedItem.ToString(),out Parity result))
{
parity = result;
}
else
{
cbx_Parity.SelectedText = parity.ToString();
}
}
private void cbx_DataBits_SelectedIndexChanged(object sender, EventArgs e)
{
if (int.TryParse(cbx_DataBits.SelectedItem.ToString(), out int result))
{
dataBits = result;
}
else
{
cbx_DataBits.SelectedText = dataBits.ToString();
}
}
private void cbx_StopBits_SelectedIndexChanged(object sender, EventArgs e)
{
if (Enum.TryParse(cbx_StopBits.SelectedItem.ToString(), out StopBits result))
{
stopBits = result;
if (result == StopBits.None)
{
stopBits = StopBits.One;
cbx_StopBits.SelectedIndex =1;
}
}
else
{
cbx_StopBits.SelectedText = dataBits.ToString();
}
}
#endregion
-
(六)获取串口参数数据源
#region 获取串口参数数据源
public Array GetPortArray()
{
return SerialPort.GetPortNames();
}
public Array GetBaudRateArray()
{
return _BaudRateArray;
}
public Array GetDataBitArray()
{
return _DataBitArray;
}
public Array GetParityArray()
{
return Enum.GetValues(typeof(Parity));
}
public Array GetStopBitArray()
{
return Enum.GetValues(typeof(StopBits));
}
#endregion
-
(六)设置变更:发送ASCII、发送HEX
#region 设置变更事件
private void radioBtn_SendEncodingASCII_CheckedChanged(object sender, EventArgs e)
{
if (radioBtn_SendEncodingASCII.Checked)
{
HexToString(rtbx_SendData.Text, out string data);
rtbx_SendData.Clear();
rtbx_SendData.Text = data;
}
}
private void radioBtn_SendEncodingHEX_CheckedChanged(object sender, EventArgs e)
{
if (radioBtn_SendEncodingHEX.Checked)
{
rtbx_SendData.Text = StringToHex(rtbx_SendData.Text);
}
}
#endregion
-
(七)数据发送HEX、数据转换
#region 数据发送
public void SendHex(string hexData)
{
if (serialPortTool != null && serialPortTool.IsOpen)
{
try
{
hexData = hexData.Replace(" ", "");
if (hexData.Length % 2 != 0)
{
Debug.WriteLine("HEX数据长度必须为偶数");
return;
}
byte[] buffer = new byte[hexData.Length / 2];
for (int i = 0; i < hexData.Length; i += 2)
{
buffer[i / 2] = Convert.ToByte(hexData.Substring(i, 2), 16);
}
serialPortTool.Write(buffer, 0, buffer.Length);
Debug.WriteLine($"已发送HEX数据: {BitConverter.ToString(buffer).Replace("-", " ")}");
}
catch (Exception ex)
{
Debug.WriteLine($"发送HEX数据失败: {ex.Message}");
}
}
}
public string StringToHex(string text)
{
byte[] bytes = Encoding.ASCII.GetBytes(text);
return BitConverter.ToString(bytes).Replace("-", " ");
}
public void HexToString(string hexInput,out string data)
{
bool isPureHex = IsPureHexString(hexInput.Replace(" ", "").Replace("-", ""));
if (isPureHex)
{
hexInput = hexInput.Replace(" ", "").Replace("-", "");
if (hexInput.Length % 2 != 0)
{
data = hexInput;
return;
}
byte[] bytes = new byte[hexInput.Length / 2];
for (int i = 0; i < hexInput.Length; i += 2)
{
string hexByte = hexInput.Substring(i, 2);
bytes[i / 2] = Convert.ToByte(hexByte, 16);
}
data = Encoding.ASCII.GetString(bytes);
}
else
{
data = hexInput;
}
}
private bool IsPureHexString(string input)
{
if (string.IsNullOrEmpty(input)) return false;
foreach (char c in input)
{
if (!((c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'F') ||
(c >= 'a' && c <= 'f')))
{
return false;
}
}
return true;
}
#endregion
-
(八)自定义控件:状态显示
public class RunStateControl : Control
{
private int radius =30;
private States state = States.None;
private Color fillColor = Color.Gray;
[Category("UserProperty")]
[Description("轮廓半径")]
public int Radius
{
get => radius;
set
{
if (radius != value)
{
radius = value;
Size = new Size(value - 3, value - 3);
this.Invalidate();
}
}
}
[Category("UserProperty")]
[Description("状态")]
public States State {
get => state;
set
{
if (state != value)
{
state = value;
switch (value)
{
case States.None:
this.FillColor = Color.Gray;
break;
case States.Running:
this.FillColor = Color.LightSeaGreen;
break;
case States.Stop:
this.FillColor = Color.Red;
break;
default:
this.FillColor = Color.Gray;
break;
}
this.Invalidate();
}
}
}
public Color FillColor {
get => fillColor;
set => fillColor = value;
}
public RunStateControl()
{
this.DoubleBuffered = true;
this.State = States.None;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
int diameter = Math.Min(this.Width, this.Height) - 4;
Rectangle circleRect = new Rectangle(
(this.Width - diameter) / 2,
(this.Height - diameter) / 2,
diameter, diameter);
using (Pen pen = new Pen(FillColor, 2))
{
g.DrawEllipse(pen, circleRect);
}
using (Brush brush = new SolidBrush(FillColor))
{
g.FillPie(brush, circleRect, -90, 360f);
}
}
}
public enum States
{
None,
Running,
Stop,
}