作者: Jowen
查看: 12925|回复: 25

[源码] 【串口操作类源码(原创)】如转载,请保留作者信息

[复制链接]
Jowen 发表于 2015-8-21 10:17:32 | 显示全部楼层 |阅读模式
查看: 12925|回复: 25
说明:
  • 串口操作类,相当于底层驱动哦,通过事件形式广播串口接收数据,接收的数据是原始数据没有做处理的。
  • 事件中数据包含,byte[],字符串(支持中文),十六进制。具体协议你可以在数据接受事件中根据自己的协议作相应处理。
  • 你要做的就是实例化,绑定事件,处理事件过来的数据就可以了,具体自测吧,由于每个人串口初始化数据不一样。
  • 该类我构造方法没有写public XXX(string name="xxx",...),而是一个一个写的,具体自己根据需要更改吧,如果觉得好,请点赞支持,谢谢!

下面是自定义事件部分:
[C#] 纯文本查看 复制代码
 /// <summary>
    /// 当前版本:   1.1
    /// 作者:    孙建伟
    /// 创建日期:   2015-08-12 
    /// 最后修改日期: 2015-08-21
    /// 当串口接收到数据时,会产生一个事件。
    /// SerialDataArgs就是该事件的参数,参数中的RecvData包含接收到的数据。
    /// 修改记录:
    /// 2015-08-21
    /// 新增字符串与字节之间的互相转化
    /// 使用方法:
    ///SerialPortEx.OnDataReceived+=***即可
    /// </summary>
    public class ReceivedDataArgs : EventArgs
    {

        static System.Text.UTF8Encoding _converter = new System.Text.UTF8Encoding();//支持中文

        /// <summary>
        /// 接收到的数据组成的字节数组
        /// </summary>
        private byte[] recvData;

        /// <summary>
        /// 构造函数,需要一个包含数据的byte[]作为初始化参数来实例化 SerialDataArgs
        /// </summary>
        /// <param name="_recvData">接收到的数据</param>
        public ReceivedDataArgs(byte[] _recvData)
        {
            if (_recvData == null)
            {
                throw (new ArgumentNullException("recvData数据为null"));
            }
            this.recvData = _recvData;
        }

        /// <summary>
        /// 返回接收到的数据内容btye[]形式
        /// </summary>
        public byte[] RecvData
        {
            get
            {
                return recvData;
            }
        }
        /// <summary>
        /// 返回操作系统当前ANSI代码页的编码形式接收数据
        /// </summary>
        public string EncodingDefaultData
        {
            get
            {
                string strtemp = Encoding.Default.GetString(recvData);
                if (strtemp.Length > 2)
                {
                    if (strtemp.Substring(strtemp.Length - 2).IndexOf("\r\n") != -1)
                    {
                        strtemp = strtemp.Substring(0, strtemp.Length - 2);
                    }
                }
                return strtemp;
            }
        }

        /// <summary>
        /// 返回十六进制形式接收数据
        /// </summary>
        public string HexData
        {
            get { return ByteToHexString(recvData); }
        }
        /// <summary>
        /// 返回字符串接收数据,支持中文,该字符串如果末尾有\r\n换行符,已自动去除
        /// </summary>
        public string UTF8Data
        {
            get
            {
                string strtemp = _converter.GetString(recvData);
                if (strtemp.Length > 2)
                {
                    if (strtemp.Substring(strtemp.Length - 2).IndexOf("\r\n") != -1)
                    {
                        strtemp = strtemp.Substring(0, strtemp.Length - 2);
                    }
                }
                return strtemp;
            }
        }

        #region 字节数组转化为十六进制
        /// <summary>
        /// 字节数组转化为十六进制
        /// </summary>
        /// <param name="InBytes">字节数组</param>
        /// <returns></returns>
        public static string ByteToHexString(byte[] InBytes)
        {
            StringBuilder sb = new StringBuilder();
            foreach (byte InByte in InBytes)
            {
                sb.Append(String.Format("{0:X2} ", InByte));
            }
            return sb.ToString();
        }
        #endregion

        #region 字节数组转化为十六进制(指定长度)
        /// <summary>
        /// 字节数组转化为十六进制(指定长度)
        /// </summary>
        /// <param name="InBytes">字节数组</param>
        /// <param name="len"></param>
        /// <returns></returns>
        public static string ByteToHexString(byte[] InBytes, int len)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < len; i++)
            {
                sb.Append(String.Format("{0:X2} ", InBytes));
            }
            return sb.ToString();
        }
        #endregion

        #region 十六进制字符串转换成字节型
        /// <summary>
        /// 十六进制字符串转换成字节型  
        /// </summary>
        /// <param name="InHexString">十六进制字符串</param>
        /// <returns></returns>
        public static byte[] HexStringToByte(string InHexString) {
            string[] ByteStrings;
            ByteStrings = InHexString.Split(" ".ToCharArray());
            byte[] ByteOut;
            ByteOut = new byte[ByteStrings.Length - 1];
            for (int i = 0; i == ByteStrings.Length - 1; i++) {
                ByteOut[i] = Convert.ToByte(("0x" + ByteStrings));
            }
            return ByteOut;
        }
        #endregion


        #region 字符串转换成字节型
        /// <summary>
        /// 字符串(支持中文)转换成字节型
        /// </summary>
        /// <param name="InString">字符串</param>
        /// <returns></returns>
        public static byte[] StringToByte(string InString)
        {
            return _converter.GetBytes(InString);
        }
        #endregion

        #region 字节数组转化为字符串
        /// <summary>
        /// 字节数组转化为字符串(支持中文)
        /// </summary>
        /// <param name="InBytes">字节数组</param>
        /// <returns></returns>
        public static string ByteToString(byte[] InBytes)
        {
            return _converter.GetString(InBytes);
        }
        #endregion
    }
    }


串口操作部分:
[C#] 纯文本查看 复制代码
/// <summary>
///相当于串口底层驱动,初始化必要调用SerialPortInstace(*,*,...)方法初始化。通过绑定自定义事件OnDataReceived获取串口数据
/// </summary>
public static class SerialPortEx
{
/// <summary>
/// 接收数据统一事件绑定,注意:如果获取该数据需要对界面控件更新,绑定的方法中请使用委托,否则会报跨线程访问控件错误
/// </summary>
public static Action<ReceivedDataArgs> OnDataReceived;
 
/// <summary>
/// 串口操作类,可对该类设置需要的参数,如果需要重载接收数据,只需绑定事件OnDataReceived即可,如果需要协议,在重载事件中处理
/// </summary>
public static SerialPort SerialPort;
 
/// <summary>
/// 事件是否初始化
/// </summary>
static bool _bini = false;
 
/// <summary>
/// 打开串口,如果串口没有打开则会打开,串口已打开,则不处理
/// </summary>
public static void Open()
{
if (!SerialPort.IsOpen)
{
SerialPort.Open();
}
}
 
/// <summary>
/// 关闭串口,如果串口打开,则会关闭
/// </summary>
public static void Close()
{
if (_bini)
{
if (SerialPort.IsOpen)
{
SerialPort.Close();
}
}
}
/// <summary>
/// 设置串口号
/// </summary>
/// <param name="portname"></param>
public static void SetPort(string portname)
{
if (_bini)
{
bool bopen = SerialPort.IsOpen;//设置串口号要保持串口号的状态一致
if (bopen)
{
SerialPort.Close();
}
SerialPort.PortName = portname;
if (bopen)
{
SerialPort.Open();
}
}
}
 
/// <summary>
/// 返回当前电脑可用串口数
/// </summary>
/// <returns></returns>
public static string[] Ports()
{
return SerialPort.GetPortNames();
}
 
#region 初始化串口参数
/// <summary>
/// 串口初始化(如果调用过该方法后,在再调用该方法或重载方法都无效,如一定要重新初始化,请先调用Clear()清除方法后再调用)
/// </summary>
public static void SerialPortInstace()
{
if (!_bini)
{
SerialPort = new SerialPort();
SerialPort.DataReceived += SerialPort_DataReceived;
_bini = true;
}
}
/// <summary>
/// 串口初始化(如果调用过该方法后,在再调用该方法或重载方法都无效,如一定要重新初始化,请先调用Clear()清除方法后再调用)
/// </summary>
/// <param name="portname">串口号</param>
public static void SerialPortInstace(string portname)
{
if (!_bini)
{
SerialPort = new SerialPort(portname);
SerialPort.DataReceived += SerialPort_DataReceived;
_bini = true;
}
}
 
/// <summary>
/// 串口初始化(如果调用过该方法后,在再调用该方法或重载方法都无效,如一定要重新初始化,请先调用Clear()清除方法后再调用)
/// </summary>
/// <param name="portname">串口号</param>
/// <param name="baudrate">波特率</param>
public static void SerialPortInstace(string portname, int baudrate)
{
if (!_bini)
{
SerialPort = new SerialPort(portname, baudrate);
SerialPort.DataReceived += SerialPort_DataReceived;
_bini = true;
}
}
 
/// <summary>
/// 串口初始化(如果调用过该方法后,在再调用该方法或重载方法都无效,如一定要重新初始化,请先调用Clear()清除方法后再调用)
/// </summary>
/// <param name="portname">串口号</param>
/// <param name="baudrate">波特率</param>
/// <param name="parity">奇偶校验位</param>
public static void SerialPortInstace(string portname, int baudrate, Parity parity)
{
if (!_bini)
{
SerialPort = new SerialPort(portname, baudrate, parity);
SerialPort.DataReceived += SerialPort_DataReceived;
_bini = true;
}
}
 
/// <summary>
/// 串口初始化(如果调用过该方法后,在再调用该方法或重载方法都无效,如一定要重新初始化,请先调用Clear()清除方法后再调用)
/// </summary>
/// <param name="portname"串口号></param>
/// <param name="baudrate">波特率</param>
/// <param name="parity">奇偶校验位</param>
/// <param name="databits">数据位</param>
public static void SerialPortInstace(string portname, int baudrate, Parity parity, int databits)
{
if (!_bini)
{
SerialPort = new SerialPort(portname, baudrate, parity, databits);
SerialPort.DataReceived += SerialPort_DataReceived;
_bini = true;
}
}
/// <summary>
/// 串口初始化(如果调用过该方法后,在再调用该方法或重载方法都无效,如一定要重新初始化,请先调用Clear()清除方法后再调用)
/// </summary>
/// <param name="portname">串口号</param>
/// <param name="baudrate">波特率</param>
/// <param name="parity">奇偶校验位</param>
/// <param name="databits">数据位</param>
/// <param name="stopbits">停止位</param>
public static void SerialPortInstace(string portname, int baudrate, Parity parity, int databits, StopBits stopbits)
{
if (!_bini)
{
SerialPort = new SerialPort(portname, baudrate, parity, databits, stopbits);
SerialPort.DataReceived += SerialPort_DataReceived;
_bini = true;
}
}
/// <summary>
/// 清除串口配置参数同时并关闭串口
/// </summary>
public static void Clear()
{
if (_bini)
{
if (OnDataReceived != null)
{
OnDataReceived(new ReceivedDataArgs(ReceivedDataArgs.StringToByte("##****$$")));//特殊指令,接到该指令,关闭串口,控制只能有一个地方使用串口
}
Close();
SerialPort.DataReceived -= SerialPort_DataReceived;
OnDataReceived = null;
_bini = false;
}
}
#endregion
 
/// <summary>
/// 时间缓存
/// </summary>
static int _timebuf = 100;
public static int TimeReadBuf
{
get { return _timebuf; }
set { _timebuf = value > 100 ? value : 100; }
}
// 串口数据接收
private static void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(TimeReadBuf);//不是在主线程,这里多少时间都没有关系,主要是缓存数据,读完缓冲区后会自动清除
int iLen = SerialPort.BytesToRead;//获取缓存大小
byte[] byRead = new byte[iLen];
int iBarCodeLen = SerialPort.Read(byRead, 0, iLen);
Close();//为了安全,关闭串口
if (OnDataReceived != null)
{
OnDataReceived(new ReceivedDataArgs(byRead));
}
Open();//重新打开串口
}

评分

参与人数 1金钱 +5 收起 理由
乔克斯 + 5 感谢LZ对论坛做出的贡献~

查看全部评分

回复 论坛版权

使用道具 举报

乔克斯 发表于 2015-8-21 11:03:40 | 显示全部楼层
感谢分享,帖子已重新整理排版。并合并超出部分的源码。
 楼主| Jowen 发表于 2015-8-21 11:08:52 | 显示全部楼层
乔克斯 发表于 2015-8-21 11:03
感谢分享,帖子已重新整理排版。并合并超出部分的源码。

谢谢!Joks!
Ghost 发表于 2015-8-21 11:24:11 | 显示全部楼层
不错 挺好  赞赞赞
Blue_Pen 发表于 2015-8-21 12:41:07 | 显示全部楼层
只是来围观的
Ghost 发表于 2015-8-21 15:33:54 | 显示全部楼层
#region 十六进制字符串转换成字节型
            /// <summary>
            /// 十六进制字符串转换成字节型  
            /// </summary>
            /// <param name="InHexString">十六进制字符串</param>
            /// <returns></returns>
            public static byte[] HexStringToByte(string InHexString)
            {
                string[] ByteStrings;
                ByteStrings = InHexString.Split(" ".ToCharArray());
                byte[] ByteOut;
                ByteOut = new byte[ByteStrings.Length - 1];
                for (int i = 0; i == ByteStrings.Length - 1; i++)
                {
                    ByteOut[i] = Convert.ToByte(("0x" + ByteStrings));
                }
                return ByteOut;
            }
            #endregion

源方法有问题  ByteOut[i] = Convert.ToByte(("0x" + ByteStrings)); 少了数组下标
 楼主| Jowen 发表于 2015-8-22 11:09:28 | 显示全部楼层
Ghost 发表于 2015-8-21 15:33
#region 十六进制字符串转换成字节型
            ///
            /// 十六进制字符串转换成字节型  

谢谢你的细心,这个我还真没有注意到,我程序里面没有用到这个方法,所以...
乔克斯 发表于 2015-8-22 15:14:48 | 显示全部楼层
Ghost 发表于 2015-8-21 15:33
#region 十六进制字符串转换成字节型
            ///
            /// 十六进制字符串转换成字节型  

原帖已修改
 楼主| Jowen 发表于 2015-8-22 20:57:40 | 显示全部楼层
Jowen 发表于 2015-8-22 11:09
谢谢你的细心,这个我还真没有注意到,我程序里面没有用到这个方法,所以... ...

我代码里面是有的,可能帖子被修改的时候出去了吧!
Wushao 发表于 2015-8-27 13:08:26 | 显示全部楼层
mark一下,mark一下,mark一下,mark一下,mark一下,mark一下
您需要登录后才可以回帖 登录 | 加入CSkin博客

本版积分规则

QQ|申请友链|小黑屋|手机版|Archiver|CSkin ( 粤ICP备13070794号

Powered by Discuz! X3.2  © 2001-2013 Comsenz Inc.  Designed by ARTERY.cn
GMT+8, 2024-3-29 18:53, Processed in 0.588337 second(s), 32 queries , Gzip On.

快速回复 返回顶部 返回列表