xmal 文件
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Management;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace Read串口读取速度Ports
{
///
/// MainWindow.xaml 的交互逻辑
///
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
//一些变量的声明
SerialPort ComPortL = new SerialPort();
SerialPort ComPortR = new SerialPort();
DispatcherTimer autoSendTickL = new DispatcherTimer();
DispatcherTimer autoSendTickR = new DispatcherTimer();
private bool Listening = false;//用于检测是否没有执行完invoke相关操作,仅在单线程收发使用,但是在公共代码区有相关设置,所以未用#define隔离
private bool WaitClose = false;//invoke里判断是否正在关闭串口是否正在关闭串口,执行Application.DoEvents,并阻止再次invoke ,解决关闭串口时,程序假死,具体参见http://news.ccidnet.com/art/32859/20100524/2067861_4.html 仅在单线程收发使用,但是在公共代码区有相关设置,所以未用#define隔离
private bool recStaus = true;//接收状态字
Queue recQueue = new Queue();//接收数据过程中,接收数据线程与数据处理线程直接传递的队列,先进先出
private static bool Sending = false;//正在发送数据状态字
private static Thread _ComSend;//发送数据线程
private SendSetStr SendSet = new SendSetStr();//发送数据线程传递参数的结构体
private struct SendSetStr//发送数据线程传递参数的结构体格式
{
public string SendSetData;//发送的数据
public bool? SendSetMode;//发送模式
}
public string[] port_Collect = new string[2]; //端口名字存储
private void Window_Loaded(object sender, RoutedEventArgs e)
{
///串口获取方式一:
List Portstr = new List();
port_Collect = new string[2];
bool kb = MulGetHardwareInfo(HardwareEnum.Win32_PnPEntity, "Name", ref Portstr);
#region
///串口
//foreach (var item in Portstr)
//{
// Console.WriteLine(item);
//}
///串口获取方式二
//string[] Ports = SerialPort.GetPortNames();
//foreach (var item in Ports)
//{
// Console.WriteLine(item);
//}
#endregion
if (port_Collect == null)
{
port_Collect = new string[2];
}
if (kb == true)
{
for (int i = 0; i < Portstr.Count; i++)
{
port_Collect[i] = Portstr[i];
}
}
else
{
if( Portstr.Count<0)
{
MessageBox.Show("没找到串口,请重新检测");
return;
}
}
if (port_Collect[0] == null || port_Collect[0].Length < 1)
{
MessageBox.Show("请重新连接左端口");
}
else
{
ComPortL.PortName = port_Collect[0];
ComPortL.BaudRate = 192000;
ComPortL.DataBits = 8;
ComPortL.Parity = Parity.None;
ComPortL.StopBits = StopBits.One;
ComPortL.ReceivedBytesThreshold = 1;
//ComPortL.DtrEnable = true;
//ComPortL.RtsEnable = true;
//找到之后,进行初始化
ComPortL.ReadTimeout = 8000;
ComPortL.WriteTimeout = 8000;
ComPortL.ReadBufferSize = 15360;
ComPortL.WriteBufferSize = 15360;
ComPortL.DataReceived += new SerialDataReceivedEventHandler(ComReceiveL);//串口接受中断
autoSendTickL.Tick += new EventHandler(autoSendL);//定时发送中断
Thread _ComRec = new Thread(new ThreadStart(ComRec)); //查询串口接收数据线程声明
_ComRec.Start();//启动线程
}
if (port_Collect[1] == null || port_Collect[1].Length < 1 )
{
MessageBox.Show("请重新连接右端口");
}
else
{
ComPortR.PortName = port_Collect[1];
//初始化右端口
}
}
public bool recModeCheck = false;
void ComRec()//接收线程,窗口初始化中就开始启动运行
{
while (true)//一直查询串口接收线程中是否有新数据
{
if (recQueue.Count > 0)//当串口接收线程中有新的数据时候,队列中有新进的成员recQueue.Count > 0
{
string recData;//接收数据转码后缓存
byte[] recBuffer = (byte[])recQueue.Dequeue();//出列Dequeue(全局)
recData = System.Text.Encoding.Default.GetString(recBuffer);//转码
UIAction(() =>
{
if (recModeCheck == false)//接收模式为ASCII文本模式
{
LrecTBox.Text += recData;//加显到接收区
}
else
{
StringBuilder recBuffer16 = new StringBuilder();//定义16进制接收缓存
for (int i = 0; i < recBuffer.Length; i++)
{
recBuffer16.AppendFormat("{0:X2}" + " ", recBuffer[i]);//X2表示十六进制格式(大写),域宽2位,不足的左边填0。
}
LrecTBox.Text += recBuffer16.ToString();//加显到接收区
if(LrecTBox.Text.Length>1000)
{
LrecTBox.Clear();
Console.WriteLine("Clear");
}
}
//SerialL.Text = (Convert.ToInt32(SerialL.Text) + recBuffer.Length).ToString();//接收数据字节数
SerialL.Text = recBuffer.Length.ToString();
LrecScrol.ScrollToBottom();//接收文本框滚动至底部
});
}
else
{
Thread.Sleep(100);//如果不延时,一直查询,将占用CPU过高
}
}
}
void autoSendL(object sender, EventArgs e)//自动发送
{
Send();//调用发送方法
}
void Send()//发送数据,分为多线程方式和单线程方式
{
try
{
if (Sending == true) return;//如果当前正在发送,则取消本次发送,本句注释后,可能阻塞在ComSend的lock处
_ComSend = new Thread(new ParameterizedThreadStart(ComSend)); //new发送线程
SendSet.SendSetData = @"t";//发送数据线程传递参数的结构体--发送的数据
SendSet.SendSetMode = false;//发送数据线程传递参数的结构体--发送方式
_ComSend.Start(SendSet);//发送线程启动
}
catch
{
return;
}
}
private void ComSend(Object obj)//发送数据 独立线程方法 发送数据时UI可以响应
{
lock (this)//由于send()中的if (Sending == true) return,所以这里不会产生阻塞,如果没有那句,多次启动该线程,会在此处排队
{
Sending = true;//正在发生状态字
byte[] sendBuffer = null;//发送数据缓冲区
string sendData = SendSet.SendSetData;//复制发送数据,以免发送过程中数据被手动改变
if (SendSet.SendSetMode == true)//16进制发送
{
try //尝试将发送的数据转为16进制Hex
{
sendData = sendData.Replace(" ", "");//去除16进制数据中所有空格
sendData = sendData.Replace("\r", "");//去除16进制数据中所有换行
sendData = sendData.Replace("\n", "");//去除16进制数据中所有换行
if (sendData.Length == 1)//数据长度为1的时候,在数据前补0
{
sendData = "0" + sendData;
}
else if (sendData.Length % 2 != 0)//数据长度为奇数位时,去除最后一位数据
{
sendData = sendData.Remove(sendData.Length - 1, 1);
}
List sendData16 = new List();//将发送的数据,2个合为1个,然后放在该缓存里 如:123456→12,34,56
for (int i = 0; i < sendData.Length; i += 2)
{
sendData16.Add(sendData.Substring(i, 2));
}
sendBuffer = new byte[sendData16.Count];//sendBuffer的长度设置为:发送的数据2合1后的字节数
for (int i = 0; i < sendData16.Count; i++)
{
sendBuffer[i] = (byte)(Convert.ToInt32(sendData16[i], 16));//发送数据改为16进制
}
}
catch //无法转为16进制时,出现异常
{
UIAction(() =>
{
autoSendTickL.Stop();//关闭自动发送
MessageBox.Show("请输入正确的16进制数据");
});
Sending = false;//关闭正在发送状态
_ComSend.Abort();//终止本线程
return;//输入的16进制数据错误,无法发送,提示后返回
}
}
else //ASCII码文本发送
{
if(sendData == null)
{
return;
}
sendBuffer = System.Text.Encoding.Default.GetBytes(sendData);//转码
}
try//尝试发送数据
{//如果发送字节数大于1000,则每1000字节发送一次
int sendTimes = (sendBuffer.Length / 1000);//发送次数
for (int i = 0; i < sendTimes; i++)//每次发生1000Bytes
{
ComPortL.Write(sendBuffer, i * 1000, 1000);//发送sendBuffer中从第i * 1000字节开始的1000Bytes
UIAction(() =>//激活UI
{
// sendCount.Text = (Convert.ToInt32(sendCount.Text) + 1000).ToString();//刷新发送字节数
});
}
if (sendBuffer.Length % 1000 != 0)//发送字节小于1000Bytes或上面发送剩余的数据
{
ComPortL.Write(sendBuffer, sendTimes * 1000, sendBuffer.Length % 1000);
UIAction(() =>
{
// sendCount.Text = (Convert.ToInt32(sendCount.Text) + sendBuffer.Length % 1000).ToString();//刷新发送字节数
});
}
}
catch//如果无法发送,产生异常
{
UIAction(() =>//激活UI
{
if (ComPortL.IsOpen == false)//如果ComPort.IsOpen == false,说明串口已丢失
{
SetComLose();//串口丢失后的设置
}
else
{
MessageBox.Show("无法发送数据,原因未知!");
}
});
}
//sendScrol.ScrollToBottom();//发送数据区滚动到底部
Sending = false;//关闭正在发送状态
_ComSend.Abort();//终止本线程
}
}
//接收数据 中断只标志有数据需要读取,读取操作在中断外进行
private void ComReceiveL(object sender, SerialDataReceivedEventArgs e)
{
if (WaitClose) return;//如果正在关闭串口,则直接返回
//发送和接收均为文本时,接收中为加入判断是否为文字的算法,发送你(C4E3),接收可能识别为C4,E3,可用在这里加延时解决
Thread.Sleep(5);
if (recStaus)//如果已经开启接收
{
byte[] recBuffer;//接收缓冲区
try
{
recBuffer = new byte[ComPortL.BytesToRead];//接收数据缓存大小
ComPortL.Read(recBuffer, 0, recBuffer.Length);//读取数据
recQueue.Enqueue(recBuffer);//读取数据入列Enqueue(全局)
}
catch
{
UIAction(() =>
{
if (ComPortL.IsOpen == false)//如果ComPort.IsOpen == false,说明串口已丢失
{
SetComLose();//串口丢失后相关设置
}
else
{
MessageBox.Show("无法接收数据,原因未知!");
}
});
}
}
else//暂停接收
{
ComPortL.DiscardInBuffer();//清接收缓存
}
}
void UIAction(Action action)//在主线程外激活线程方法
{
System.Threading.SynchronizationContext.SetSynchronizationContext(new System.Windows.Threading.DispatcherSynchronizationContext(App.Current.Dispatcher));
System.Threading.SynchronizationContext.Current.Post(_ => action(), null);
}
private void SetComLose()//成功关闭串口或串口丢失后的设置
{
autoSendTickL.Stop();//串口丢失后要关闭自动发送
//autoSendCheck.IsChecked = false;//自动发送改为未选中
WaitClose = true;//;//激活正在关闭状态字,用于在串口接收方法的invoke里判断是否正在关闭串口
while (Listening)//判断invoke是否结束
{
DispatcherHelper.DoEvents(); //循环时,仍进行等待事件中的进程,该方法为winform中的方法,WPF里面没有,这里在后面自己实现
}
MessageBox.Show("串口已丢失");
WaitClose = false;//关闭正在关闭状态字,用于在串口接收方法的invoke里判断是否正在关闭串口
}
//模拟 Winfrom 中 Application.DoEvents() 详见 http://www.silverlightchina.net/html/study/WPF/2010/1216/4186.html?1292685167
public static class DispatcherHelper
{
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static void DoEvents()
{
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(ExitFrames), frame);
try { Dispatcher.PushFrame(frame); }
catch (InvalidOperationException) { }
}
private static object ExitFrames(object frame)
{
((DispatcherFrame)frame).Continue = false;
return null;
}
}
//获取串口端口号,依据Guid获取
///
/// 枚举win32 api
///
public enum HardwareEnum
{
// 硬件
Win32_Processor, // CPU 处理器
Win32_PhysicalMemory, // 物理内存条
Win32_Keyboard, // 键盘
Win32_PointingDevice, // 点输入设备,包括鼠标。
Win32_FloppyDrive, // 软盘驱动器
Win32_DiskDrive, // 硬盘驱动器
Win32_CDROMDrive, // 光盘驱动器
Win32_BaseBoard, // 主板
Win32_BIOS, // BIOS 芯片
Win32_ParallelPort, // 并口
Win32_SerialPort, // 串口
Win32_SerialPortConfiguration, // 串口配置
Win32_SoundDevice, // 多媒体设置,一般指声卡。
Win32_SystemSlot, // 主板插槽 (ISA & PCI & AGP)
Win32_USBController, // USB 控制器
Win32_NetworkAdapter, // 网络适配器
Win32_NetworkAdapterConfiguration, // 网络适配器设置
Win32_Printer, // 打印机
Win32_PrinterConfiguration, // 打印机设置
Win32_PrintJob, // 打印机任务
Win32_TCPIPPrinterPort, // 打印机端口
Win32_POTSModem, // MODEM
Win32_POTSModemToSerialPort, // MODEM 端口
Win32_DesktopMonitor, // 显示器
Win32_DisplayConfiguration, // 显卡
Win32_DisplayControllerConfiguration, // 显卡设置
Win32_VideoController, // 显卡细节。
Win32_VideoSettings, // 显卡支持的显示模式。
// 操作系统
Win32_TimeZone, // 时区
Win32_SystemDriver, // 驱动程序
Win32_DiskPartition, // 磁盘分区
Win32_LogicalDisk, // 逻辑磁盘
Win32_LogicalDiskToPartition, // 逻辑磁盘所在分区及始末位置。
Win32_LogicalMemoryConfiguration, // 逻辑内存配置
Win32_PageFile, // 系统页文件信息
Win32_PageFileSetting, // 页文件设置
Win32_BootConfiguration, // 系统启动配置
Win32_ComputerSystem, // 计算机信息简要
Win32_OperatingSystem, // 操作系统信息
Win32_StartupCommand, // 系统自动启动程序
Win32_Service, // 系统安装的服务
Win32_Group, // 系统管理组
Win32_GroupUser, // 系统组帐号
Win32_UserAccount, // 用户帐号
Win32_Process, // 系统进程
Win32_Thread, // 系统线程
Win32_Share, // 共享
Win32_NetworkClient, // 已安装的网络客户端
Win32_NetworkProtocol, // 已安装的网络协议
Win32_PnPEntity,//all device
}
///
/// WMI取硬件信息
///
///
///
///
public static bool MulGetHardwareInfo(HardwareEnum hardType, string propKey, ref List strs)
{
try
{
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from " + hardType))
{
var hardInfos = searcher.Get();
foreach (var hardInfo in hardInfos)
{
//Console.WriteLine(hardInfo.Properties[propKey].Value.ToString()); 将来限制的时候,在这里进行判断处理,
if (hardInfo.Properties[propKey].Value.ToString().ToUpper().Contains("COM") &&
hardInfo.Properties[propKey].Value.ToString().ToUpper().Contains("USB-SERIAL CH340"))
{
strs.Add(cutSerStr(hardInfo.Properties[propKey].Value.ToString()));
}
}
searcher.Dispose();
}
return false;
}
catch
{
return true;
}
}
///
/// 获取串口号
///
///
public static string cutSerStr(string str)
{
int i = str.IndexOf("(");
int j = str.LastIndexOf(")");
return str.Substring(i + 1, j - i - 1);
}
//串口的开关闭合
private void OpenPortBtn_Click(object sender, RoutedEventArgs e)
{
if(ComPortL.PortName.Length<0)
{
MessageBox.Show("端口不存在");
return;
}
if(ComPortL.IsOpen == false)
{
try //尝试打开串口
{
ComPortL.PortName = port_Collect[0];
ComPortL.BaudRate = 192000;
ComPortL.DataBits = 8;
ComPortL.Parity = Parity.None;
ComPortL.StopBits = StopBits.One;
ComPortL.ReceivedBytesThreshold = 1;
}
catch
{
MessageBox.Show("无法打开串口,请检测此串口是否有效或被其他占用!");
return;//无法打开串口,提示后直接返回
}
}
ComPortL.Open();
WaitClose = false;//等待关闭串口状态改为false
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
MessageBoxResult result = MessageBox.Show("确认是否要退出?", "退出", MessageBoxButton.YesNo);//显示确认窗口
if (result == MessageBoxResult.No)
{
e.Cancel = true;//取消操作
}
}
private void Window_Closed(object sender, EventArgs e)
{
Application.Current.Shutdown();//先停止线程,然后终止进程.
Environment.Exit(0);//直接终止进程.
}
private void ClosePortBtn_Click(object sender, RoutedEventArgs e)
{
ComPortL.Close();
ComPortL.Dispose();
}
private void SendPortBtn_Click(object sender, RoutedEventArgs e)
{
//Send();
this.Dispatcher.Invoke(new Action(delegate
{
LrecTBox.Clear();
}));
}
private void check_Yes(object sender, RoutedEventArgs e)
{
if((bool)check.IsChecked == true)
{
autoSendTickL.Interval = TimeSpan.FromMilliseconds(0);//设置自动发送间隔
autoSendTickL.Start();//开始自动发送定时器
}
else
{
autoSendTickL.Stop();
}
}
}
}
以上基本包含了全部的功能,一些细节也指出了