C#中的WinFrom技術實現串口通訊助手(附源碼)
實現的功能:
1、實現自動加載可用串口。
2、打開串口,並且使用C#狀態欄顯示串口的狀態。
3、實現了串口的接收數據和發送數據功能。
4、串口使用定時器進行定時發送數據。
5、可以打開文件夾,選擇文件進行發送,並且將發送文件的內容顯示在發送文本框中。
6、可以清空發送和接收文本框中的內容。
7、可以實時計算發送和接收的字節數。
8、實現打開文件夾保存發送和接收的文件內容(目前只支持.txt文件)。
9、實時顯示當前時間。
功能演示
1、界面功能介紹:
2、打開串口演示:
3、發送數據演示:
動態演示
4、定時發送數據演示:
動態演示
5、發送文件內容演示:
動態演示
6、接收數據演示:
動態演示
7、保存數據演示:
動態演示
主要使用的技術:
1、數據保存和讀取。
2、定時器的操作。
3、串口模塊的使用。
4、委托和事件解決線程沖突問題。
工程源代碼:
using System;
using System.Drawing;
using System.IO; // 導入輸入輸出文件框
using System.IO.Ports; // 串口模塊
using System.Text;
using System.Windows.Forms;
namespace MainSender
{
// 解決線程訪問問題
public delegate void SerialPortEventHandler(Object sender, SerialPortEventArgs e); // 定義委托
public partial class SerialDebug : Form
{
private string FilePath = null; // 打開文件路徑
private object thisLock = new object(); // 鎖住線程
public event SerialPortEventHandler comReceiveDataEvent = null; // 定義串口接收數據響應事件
// 數據狀態
private static int sendCount = 0; // 發送數據量
private static int receCount = 0; // 接收數據量
public SerialDebug()
{
InitializeComponent();
InitializeSerialSet(); // 初始化串口設置
}
/// <summary>
/// 串口初始化設置
/// </summary>
public void InitializeSerialSet()
{
InitializePorts(); // 初始化串口號
// 初始化波特率
comboBox_BandRate.Text = comboBox_BandRate.Items[6].ToString();
// 初始化校驗位
comboBox_Check.Text = comboBox_Check.Items[0].ToString();
// 初始化數據位
comboBox_Data.Text = comboBox_Data.Items[0].ToString();
// 初始化停止位
comboBox_Stop.Text = comboBox_Stop.Items[0].ToString();
}
/// <summary>
/// 可用串口掃描,並且顯示
/// </summary>
public void InitializePorts()
{
comboBox_Serial.Items.Clear(); // 清空原來的信息
// 返回可用串口號,形式:COM3
string[] arraysPostsNames = SerialPort.GetPortNames(); // 獲取所有可用的串口號
// 檢查串口號是否正確
if (arraysPostsNames.Length > 0)
{
Array.Sort(arraysPostsNames); // 使用默認進行排序,從小到大腎虛
for (int i = 0; i < arraysPostsNames.Length; i++)
{
comboBox_Serial.Items.Add(arraysPostsNames[i]); // 將所有可用串口加載到串口顯示框當中
}
comboBox_Serial.Text = arraysPostsNames[0]; // 默認選擇第一個串口
comboBox_Serial.Enabled = true; // 打開選擇框
// 設置狀態欄屬性
toolStripStatus_Port.Text = "串口號:" + comboBox_Serial.Text; // 設置狀態欄的情況
toolStripStatus_Port.ForeColor = Color.Black; // 設置為紅色
}
else
{
toolStripStatus_Port.Text = "沒有可用串口"; // 設置狀態欄的情況
toolStripStatus_Port.ForeColor = Color.Red; // 設置為紅色
comboBox_Serial.Text = "None"; // 提示沒有可用串口
comboBox_Serial.Enabled = false; // 禁止打開串口選擇框
}
}
/// <summary>
/// 串口讀取數據響應方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void serialPortMonitor_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
ReceiveData();
}
private void SerialDebug_Load(object sender, EventArgs e)
{
comReceiveDataEvent += new SerialPortEventHandler(ComReceiveDataEvent); // 訂閱事件
toolStripStatus_Time.Text = "時間:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"); // 顯示當前時間
}
public void ComReceiveDataEvent(Object sender, SerialPortEventArgs e)
{
if (this.InvokeRequired)
{
try
{
Invoke(new Action<Object, SerialPortEventArgs>(ComReceiveDataEvent), sender, e);
}
catch (Exception)
{
}
return;
}
if (richTextBox_Receive.Text.Length > 0)
{
richTextBox_Receive.AppendText(" "); // 中間使用 隔開,也可以使用-隔開
}
richTextBox_Receive.AppendText(System.Text.Encoding.Default.GetString(e.receivedBytes));
// 更新狀態顯示框
receCount += e.receivedBytes.Length;
toolStripStatus_recestatus.Text = "收到數據: " + receCount.ToString();
}
/// <summary>
/// 串口選擇框改變
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Select_Ports_Change(object sender, EventArgs e)
{
// 設置狀態欄屬性
toolStripStatus_Port.Text = "串口號:" + comboBox_Serial.Text; // 設置狀態欄的情況
toolStripStatus_Port.ForeColor = Color.Black; // 設置為黑色
}
/// <summary>
/// 更新狀態欄
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Update_StatusTime(object sender, EventArgs e)
{
toolStripStatus_Time.Text = "時間:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"); // 顯示當前時間
}
/// <summary>
/// 保存文件加載方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SaveData_Click(object sender, EventArgs e)
{
SaveFileDialog saveDataSend = new SaveFileDialog();
saveDataSend.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); // 獲取文件路徑
saveDataSend.Filter = "*.txt|txt file"; // 文本文件
saveDataSend.DefaultExt = ".txt"; // 默認文件的形式
saveDataSend.FileName = "SendData.txt"; // 文件默認名
if (saveDataSend.ShowDialog() == DialogResult.OK) // 顯示文件框,並且選擇文件
{
FilePath = saveDataSend.FileName; // 獲取文件名
// 參數1:寫入文件的文件名;參數2:寫入文件的內容
try
{
System.IO.File.WriteAllText(FilePath, richTextBox_Send.Text); // 向文件中寫入內容
}
catch
{
MessageBox.Show("保存文件失敗", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); ;
}
}
}
/// <summary>
/// 選擇發送文件響應函數
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void textBox_Filepath_Click(object sender, EventArgs e)
{
OpenFileDialog fileDialog = new OpenFileDialog();
fileDialog.Multiselect = false; // 是否可以選擇多個文件
fileDialog.Title = "請選擇文件"; // 標題
fileDialog.Filter = "所有文件(*.*)|*.*"; // 顯示所有文件
if (fileDialog.ShowDialog() == DialogResult.OK) // 打開文件選擇框
{
FilePath = fileDialog.FileName; // 絕對路徑
textBox_Filepath.Text = FilePath; // 在窗口中顯示文件路徑
}
checkBox_Sendfile.Checked = true; // 設置發送文件框選項狀態
ReadFile(FilePath); // 將文件內容顯示在發送框當中
}
/// <summary>
/// 將文件內容顯示在發送數據顯示框中
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void ReadFile(string filepath)
{
try
{
richTextBox_Send.Text = ""; // 清空顯示框
StreamReader sr = new StreamReader(filepath, Encoding.Default);
string content;
while ((content = sr.ReadLine()) != null) // 按行讀取顯示在發送數據框中
{
richTextBox_Send.Text += (content.ToString() + "\r\n"); // ReadLine默認不會讀取換行符
}
}
catch (Exception)
{
}
}
/// <summary>
/// 清除發送數據
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button_ClcSendData_Click(object sender, EventArgs e)
{
richTextBox_Send.Text = ""; // 清空顯示框
sendCount = 0;
toolStripStatus_sendstatus.Text = "發送數據:" + sendCount.ToString();
}
/// <summary>
/// 清除接收數據
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button_ClcReceData_Click(object sender, EventArgs e)
{
richTextBox_Receive.Text = ""; // 清空接收數據
receCount = 0;
toolStripStatus_recestatus.Text = "收到數據:" + receCount.ToString();
}
/// <summary>
/// 發送數據按鍵點擊響應函數
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button_SendData_Click(object sender, EventArgs e)
{
string senddata = richTextBox_Send.Text;
byte[] data = System.Text.Encoding.Default.GetBytes(senddata); // 將發送的數據轉化為字節數組
SendData(data); // 發送數據
sendCount += senddata.Length;
toolStripStatus_sendstatus.Text = "發送數據:" + sendCount.ToString();
}
/// <summary>
/// 保存發送數據,保存發送數據菜單響應函數
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MenuItem_ReceData_Click(object sender, EventArgs e)
{
SaveFileDialog saveDataSend = new SaveFileDialog();
saveDataSend.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); // 獲取文件路徑
saveDataSend.Filter = "*.txt|txt file"; // 文本文件
saveDataSend.DefaultExt = ".txt"; // 默認文件的形式
saveDataSend.FileName = "ReceData.txt"; // 文件默認名
if (saveDataSend.ShowDialog() == DialogResult.OK) // 顯示文件框,並且選擇文件
{
FilePath = saveDataSend.FileName; // 獲取文件名
// 參數1:寫入文件的文件名;參數2:寫入文件的內容
try
{
System.IO.File.WriteAllText(FilePath, richTextBox_Receive.Text); // 向文件中寫入內容
}
catch
{
MessageBox.Show("保存文件失敗", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); ;
}
}
}
/// <summary>
/// 串口狀態響應函數
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button_OK_Click(object sender, EventArgs e)
{
if (serialPort1 == null)
{
return;
}
if (serialPort1.IsOpen == false)
{
serialPort1.PortName = comboBox_Serial.Text;
serialPort1.BaudRate = Convert.ToInt32(comboBox_BandRate.Text);
serialPort1.Parity = (Parity)Enum.Parse(typeof(Parity), comboBox_Check.Text); // 強制類型轉換
serialPort1.DataBits = Convert.ToInt32(comboBox_Data.Text);
serialPort1.StopBits = (StopBits)Enum.Parse(typeof(StopBits), comboBox_Stop.Text);
try
{
serialPort1.Open();
// 設置按鍵的使用權限
comboBox_Serial.Enabled = false;
comboBox_BandRate.Enabled = false;
comboBox_Check.Enabled = false;
comboBox_Data.Enabled = false;
comboBox_Stop.Enabled = false;
button_Refresh.Enabled = false;
button_SendData.Enabled = true;
checkBox_SendData.Enabled = true;
textBox_selectTime.Enabled = true;
checkBox_Sendfile.Enabled = true;
textBox_Filepath.Enabled = true;
// 打開屬性變為關閉屬性
button_OK.Text = "關閉串口";
toolStripStatus_Port.Text = "連接串口:" + comboBox_Serial.Text;
toolStripStatus_Port.ForeColor = Color.Green; // 設置為綠色
}
catch (Exception)
{
toolStripStatus_Port.Text = "連接失敗:" + comboBox_Serial.Text;
toolStripStatus_Port.ForeColor = Color.Red; // 設置為紅色
MessageBox.Show("串口連接失敗!\r\n可能原因:串口被占用", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
else
{
serialPort1.Close(); // 關閉串口
// 設置按鍵的使用權限
comboBox_Serial.Enabled = true;
comboBox_BandRate.Enabled = true;
comboBox_Check.Enabled = true;
comboBox_Data.Enabled = true;
comboBox_Stop.Enabled = true;
button_Refresh.Enabled = true;
button_SendData.Enabled = false;
checkBox_SendData.Enabled = false;
textBox_selectTime.Enabled = false;
checkBox_Sendfile.Enabled = false;
textBox_Filepath.Enabled = false;
// 打開屬性變為關閉屬性
button_OK.Text = "打開串口";
toolStripStatus_Port.Text = "斷開連接:" + comboBox_Serial.Text;
toolStripStatus_Port.ForeColor = Color.Red; // 設置為紅色
}
}
/// <summary>
/// 向串口中發送數據
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public bool SendData(byte[] data)
{
if (serialPort1 == null)
{
return false;
}
if (serialPort1.IsOpen == false)
{
return false;
}
try
{
serialPort1.Write(data, 0, data.Length);
}
catch (Exception)
{
//提示信息
MessageBox.Show("數據發送失敗!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return false;
}
return true;
}
/// <summary>
/// 串口接收數據
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public bool ReceiveData()
{
if (serialPort1 == null)
{
return false;
}
if (serialPort1.IsOpen == false)
{
return false;
}
if (serialPort1.BytesToRead <= 0) // 串口中沒有數據
{
return false;
}
lock (thisLock) // 鎖住串口
{
int len = serialPort1.BytesToRead;
byte[] data = new Byte[len];
try
{
serialPort1.Read(data, 0, len); // 向串口中讀取數據
}
catch (Exception)
{
MessageBox.Show("數據接收失敗!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return false;
}
SerialPortEventArgs args = new SerialPortEventArgs();
args.receivedBytes = data;
if (comReceiveDataEvent != null)
{
comReceiveDataEvent.Invoke(this, args);
}
}
return true;
}
/// <summary>
/// 刷新串口參數
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button_Refresh_Click(object sender, EventArgs e)
{
InitializeSerialSet(); // 刷新串口設置
}
/// <summary>
/// 定時發送數據
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void timerSend_Tick(object sender, EventArgs e)
{
if (checkBox_SendData.Checked)
{
string datastr = richTextBox_Send.Text;
if (datastr == "")
{
return;
}
timerSend.Interval = int.Parse(textBox_selectTime.Text); // 將字符串轉化為整型數字
byte[] data = System.Text.Encoding.Default.GetBytes(datastr); // 字符串轉化為字節數組
SendData(data);
sendCount += datastr.Length;
toolStripStatus_sendstatus.Text = "發送數據:" + sendCount.ToString();
// 控件設置
button_SendData.Enabled = false;
}
else
{
button_SendData.Enabled = true;
}
}
/// <summary>
/// 退出菜單
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MenuItem_Quit_Click(object sender, EventArgs e)
{
this.Close(); // 關閉窗體,然后退出
}
/// <summary>
/// 關於菜單
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MenuItem_About_Click(object sender, EventArgs e)
{
About about = new About();
about.Show(); // 顯示關於窗體
}
}
public class SerialPortEventArgs : EventArgs
{
public byte[] receivedBytes = null; // 用來接收串口讀取的數據
}
}
如果你對本工程感興趣可以下載源代碼。