110,571
社区成员
发帖
与我相关
我的任务
分享
/// <summary>
/// 获取串口参数,该结果返回Json格式的字符串
/// </summary>
/// <param name="portname">获取的串口名</param>
/// <returns>返回string类型结果</returns>
public string GetPortParam(string portname)
{
//返回Json,结果为:"{串口名":{"BaudRate":"波特率","StopBits":"停止位","Parity":"校验位","DataBits":"数据位"}}
return "{\"" + spList[portname].PortName +
"\":{\"BaudRate\":\"" + spList[portname].BaudRate +
"\",\"StopBits\":\"" + spList[portname].StopBits.ToString() +
"\",\"Parity\":\"" + spList[portname].Parity.ToString() +
"\",\"DataBits\":\"" + spList[portname].DataBits + "\"}}";
}
/// <summary>
/// 根据提供的串口名设置该串口参数
/// </summary>
/// <param name="portname">串口名</param>
/// <param name="BaudRate">波特率</param>
/// <param name="StopBits">停止位</param>
/// <param name="Parity">校验位</param>
/// <param name="DataBits">数据位</param>
/// <returns></returns>
public string SetPortParam(string portname, int BaudRate, string StopBits, string Parity, int DataBits)
{
//把相应的数值赋值到对应的接口中,其中,枚举值则进行解析
//枚举解析方法:(强转需要解析成的枚举)Enum.parse(typeof(解析成的枚举),该枚举的指定字符串【可以为该枚举的数字值,也可以是该枚举的表示字符串】);
spList[portname].BaudRate = BaudRate;
spList[portname].StopBits = (StopBits)Enum.Parse(typeof(StopBits), StopBits);
spList[portname].Parity = (Parity)Enum.Parse(typeof(Parity), Parity);
spList[portname].DataBits = DataBits;
//返回提示字符串,并把修改后的参数罗列出来以便确认修改完成
return string.Format(
"修改完成!\n串口名:{0}\n波特率:{1}\n停止位:{2}\n校验位:{3}\n数据位:{4}"
, spList[portname].PortName, spList[portname].BaudRate
, spList[portname].StopBits, spList[portname].Parity
, spList[portname].DataBits);
}
/// <summary>
/// 返回已有的串口名
/// </summary>
/// <returns>返回已有的串口名</returns>
public string getAllPortParam()
{
string result = "{\"PortNames\":[";
foreach (string item in spList.Keys)
{
result += "\"" + item + "\",";
}
result = result.Substring(0,result.Length-1)+"]}";
return result;
}
using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using System.Runtime.InteropServices;
namespace SerialPortActiveX
{
public class SPActiveX
{
//定义字典集合装取需要到的数据
/// <summary>
/// 该集合装有所有系统检测到的串口,实例化并以串口名为key值存储,实例化过程在无参构造函数中
/// </summary>
public Dictionary<string, SerialPort> spList = new Dictionary<string, SerialPort>();
/// <summary>
/// 该集合装取所有读取出来的数据根据sp_DataReceived(sender,e)方法进行逻辑处理
/// key值代表该value的值属于哪个串口,key值为该串口名
/// </summary>
public Dictionary<string, string> read_string = new Dictionary<string, string>();
/// <summary>
/// 该集合装取读取出来的数据经过逻辑处理后的最终结果,处理过程在sp_DataReceived(sender,e)方法
/// key值为串口名
/// </summary>
public Dictionary<string, string> read_result = new Dictionary<string, string>();
/// <summary>
/// 该集合装取经过处理过后再处理出一串根据既定位置截取的数字字符串,属于计数(根据取出的数据截取想要的那部分,以闭合次数为基准的逻辑处理)
/// key值为串口名
/// </summary>
public Dictionary<string, string> read_count = new Dictionary<string, string>();
/// <summary>
/// 初始化方法,方法中与实例化所有系统检测到的串口,并绑定方法和打开
/// 绑定的事件为DataReceived(接受到数据时触发),绑定的方法为sp_DataReceived(sender,e)
/// 打开串口后,以串口名为key值储存到spList集合中
/// </summary>
public SPActiveX()
{
//SerialPort中的GetPortName可以获取当前系统所能检测到的所有串口的名字,通过foreach一个一个取出来用
foreach (string portname in SerialPort.GetPortNames())
{
//**创建一个临时SerialPort类,进行初始化操作并存到集合**\\
//以串口名实例化一个临时SerialPort
SerialPort sp_emp = new SerialPort(portname);
//绑定事件,事件触发时执行方法,事件触发条件为接收到数据,触发时执行的方法为sp_DataReceived
sp_emp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
//打开该串口
sp_emp.Open();
//经过上面的处理后,以串口名为key值添加到spList集合中
spList.Add(sp_emp.PortName, sp_emp);
}
}
/// <summary>
/// 该方法将会绑定到DataReceived事件中,接受数据时触发,所以该方法在时对数据进行处理的。
/// 把完整的数据根据串口名无处理存储到read_string中
/// 把read_string根据逻辑处理成一句目前所接受的结果中可以分辨出来的有用的一串字符
/// 根据串口名存储到read_result中
/// 把read_result中处理过的数据处理成一个结果根据串口名存储到read_count,逻辑基准为闭合计数
/// 注:该方法名非固定,但是参数是固定的
/// </summary>
/// <param name="sender">该属性未发送者(即触发该事件的本体,在该方法为,触发事件执行方法的那个串口,理解为他就是接受到数据的串口)</param>
/// <param name="e">事件数据类,该方法中没有用到</param>
public void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//把发送者转为SerialPort并使用,sender为触发事件的串口
SerialPort sp = (SerialPort)sender;
//根据SerialPort提供的方法Read(byte[],int,int)的需求,首先根据接收缓冲区的字节数作为长度实例化一个byte数据
byte[] data = new byte[sp.BytesToRead];
//调用Read方法,第一个参数为byte[]类型,会把数据传到该byte[]里面,第二参数为数据偏移量,第三参数为获取的数据的长度
//第二和第三的参数可以理解为截取
sp.Read(data, 0, data.Length);
//第一个逻辑处理start\\
//接受到数据后,无处理存储到read_string中,此处注意的是,read方法返回的字符是实时返回的,
//也就是说数据时不确定完整性的,这里我会无差别全部拼接,read_string为字典集合,首先要判断该集合是否已存
//在该数据,如果有则覆盖,没有则新添加,字典集合提供了ContainsKey方法,该方法通过提供key值判断该key值
//是否已经存在返回bool值,如果存在则为true,不存在反之
if (read_string.ContainsKey(sp.PortName))
//如果存在的话,直接拼接数据,System.Text.Encoding.ASCII.GetString(byte[])方法作用是
//把对应的byte数据根据ascii码转为相应的字符串
read_string[sp.PortName] += System.Text.Encoding.ASCII.GetString(data);
else
//如果没有则以串口名新添加
read_string.Add(sp.PortName, System.Text.Encoding.ASCII.GetString(data));
//第一个逻辑处理end\\
//第二个逻辑处理start\\
//该逻辑是根据取出来的数据编辑的,完整的返回数据为@开头,*结尾(事实上是以\r\n结尾),如果IndexOf查找
//不到这两个字符,则可以判断为,数据不完整,数据不完整的时候则全部存入read_result,如果完整则要通过处理
//多余的数据并把需要的数据正确截取出来
//注:IndexOf(string)方法作用为:在指定字符串中查找提供的字符并返回其下标,如果没找到则返回-1
if (read_string[sp.PortName].IndexOf("@") >= 0 && read_string[sp.PortName].IndexOf("*") >= 0)
{
//这部分处理处计数字符串,根据返回的规律截取数据的从@字符开始的后19位开始,截取8位
string sp_stringemp = read_string[sp.PortName].Substring(read_string[sp.PortName].IndexOf("@") + 19, 8);
//声明一个int变量存储该字符串有几个零
int i = 0;
//foreach循环计数该数字字符串前面的零有几个,从最大位开始,遇到非零跳出循环
foreach (char c in sp_stringemp)
{
if (c == '0')
{
i++;
}
else
{
break;
}
}
//这里的if和存储read_string时的判断一样,判断是否存在
if (read_count.ContainsKey(sp.PortName))
//这里的?字符是简写的if,变量 = 条件?如果ture时赋值:如果false赋值;,这里的使用逻辑是
//入股前面的零个数与字符长度相等了(00000000),则赋值0(字符串),否则剪掉前面的0,赋值对应
//的数字字符串(比如00011200会处理为11200)
read_count[sp.PortName] = i == sp_stringemp.Length ? "0" : sp_stringemp.Substring(i > 0 ? i : 0, sp_stringemp.Length - i);
else
//不存在则新建
read_count.Add(sp.PortName, i == sp_stringemp.Length ? "0" : sp_stringemp.Substring(i > 0 ? i : 0, sp_stringemp.Length - i));
//第二个逻辑处理end\\
//第三个逻辑处理start\\
//判断同上
if (read_count.ContainsKey(sp.PortName))
//把read_string处理,使用Substring(开始下标,截取长度)方法进行截取,开始下标为@字符所在的位置,,长度为结束字符*减去@字符的位置
read_result[sp.PortName] = read_string[sp.PortName].Substring(read_string[sp.PortName].IndexOf("@"), read_string[sp.PortName].IndexOf("*") - read_string[sp.PortName].IndexOf("@") + 1);
else
//无则新建
read_result.Add(sp.PortName, read_string[sp.PortName].Substring(read_string[sp.PortName].IndexOf("@"), read_string[sp.PortName].IndexOf("*") - read_string[sp.PortName].IndexOf("@") + 1));
//第三个逻辑处理end\\
//经过上面的处理之后,read_string要清空,否则会影响正确结果
//如:第一次取出数据为@123*,第二次为@abc*,如果不清空根据拼接原理结果为@123*@abc*,
//上面处理出来的结果就一直为@123*,而不是后面最新读取出来的正确结果
read_string[sp.PortName] = "";
}
else
{
//数据不完整,数据不完整的时候则全部存入read_result
read_result[sp.PortName] = read_string[sp.PortName];
}
}
/// <summary>
/// 发送数据方法,需要指定发送到哪个串口
/// </summary>
/// <param name="portname">需要发送的串口名</param>
/// <param name="SendData">需要发送的内容</param>
/// <returns></returns>
public string SendData(string portname, string SendData)
{
//trycatch捕捉异常
try
{
//对指定指令进行约定的校验位处理
//初始化校验数
int checkcode = 0;
//拆分字符串为一个一个字符
foreach (char c in SendData)
{
//把拆分的字符转为ascii码并与校验数进行异或运算,并把结果返回给校验位本身
//异或:
//异或时指把数字转为二进制,进行异或位运算后,把结果从二进制转为十进制并返回
//如:62和78进行异或
//62的二进制:0111110
//78的二进制:1001110
//----------------------
//结果为: 1110000
//相同为1,不同为零
//1110000的十进制为112
//则结果为112
checkcode = (int)c ^ checkcode;
}
//把校验数转为16进制的字符串,并全转为大写(16进制或许有字母)
string checodestr = checkcode.ToString("x").ToUpper();
//检验数如果只有一位数(长度为1)时,则补充一个零,如果多于一位则完全赋值
string checkResult = checodestr.Length == 1 ? "0" + checodestr : checodestr;
//把结果转为ascii码的byte数组,拼接规律为:SendData(需要传输的数据)+checkReSult(校验数)+“*\r\n”(固定形式)
byte[] WriteBuffer = Encoding.ASCII.GetBytes(SendData + checkResult + "*\r\n");
//写入方法Write(byte[]写入数据,偏移量,写入长度)
spList[portname].Write(WriteBuffer, 0, WriteBuffer.Length);
//返回结果
return "写入成功!";
}
catch (Exception ex)
{
//如果捕捉到异常则返回写入失败并显示错误信息
return "写入失败!\n" + ex.Message;
}
}
/// <summary>
/// sp_DataReceived方法已经处理过数据了,需要数据时则根据需要取得串口获取数据
/// </summary>
/// <param name="portname">获取的串口名</param>
/// <returns>返回string类型结果</returns>
public string GetResult(string portname)
{
return read_result[portname];
}
/// <summary>
/// sp_DataReceived方法已经处理过数据了,需要数据时则根据需要取得串口获取数据
/// </summary>
/// <param name="portname">获取的串口名</param>
/// <returns>返回string类型结果</returns>
public string GetCount(string portname)
{
return read_count[portname];
}
}
}