串口通信与NJH框架

NJH框架

  1     public class BaseSerialPort {
  2 
  3         #region 字段
  4         private const int msgMaxLength = 512;//通信协议中最长的指令的字节数目,制定的通信协议最长指令不得超过msgMaxLength
  5         private object locker = new object();//在串口接收数据的线程中使用,保证数据接收正确
  6         
  7         private byte[] byteMsgRecv;//使用字节协议时,用于接收数据
  8         private string strMsgRecv;//使用字符协议时,用于接收数据
  9 
 10         private AutoResetEvent waiterForRsp = new AutoResetEvent(false);//用于同步用户的Logic线程和串口的DataReceived线程
 11         private int usingSource = 0;//保证一条指令的交互完整性,或多条指令组成的模块的交互完整性
 12 
 13         public SerialPort _device {
 14             get; private set;
 15         }
 16         private Encoding encoding;//字符编码
 17         #endregion
 18 
 19         #region 构造函数
 20         /// <summary>
 21         /// 使用字节型通信协议调用此构造函数
 22         /// </summary>
 23         /// <param name="portName">串口名</param>
 24         /// <param name="baudRate">波特率</param>
 25         /// <param name="dataBits">数据位</param>
 26         /// <param name="stopBits">停止位</param>
 27         /// <param name="parity">奇偶校验</param>
 28         public BaseSerialPort(string portName, int baudRate, int dataBits, StopBits stopBits, Parity parity) {
 29             this._device = new SerialPort();
 30             this._device.PortName = portName;
 31             this._device.BaudRate = baudRate;
 32             this._device.DataBits = dataBits;
 33             this._device.StopBits = stopBits;
 34             this._device.Parity = parity;
 35             this._device.DataReceived += Device_DataReceived;
 36             this.encoding = null;
 37         }
 38         /// <summary>
 39         /// 使用字符串型通信协议调用此构造函数
 40         /// </summary>
 41         /// <param name="portName">串口名</param>
 42         /// <param name="baudRate">波特率</param>
 43         /// <param name="dataBits">数据位</param>
 44         /// <param name="stopBits">停止位</param>
 45         /// <param name="parity">奇偶校验</param>
 46         public BaseSerialPort(string portName, int baudRate, int dataBits, StopBits stopBits, Parity parity, Encoding encoding) {
 47             this._device = new SerialPort();
 48             this._device.PortName = portName;
 49             this._device.BaudRate = baudRate;
 50             this._device.DataBits = dataBits;
 51             this._device.StopBits = stopBits;
 52             this._device.Parity = parity;
 53             this._device.DataReceived += Device_DataReceived;
 54             this.encoding = encoding;
 55         }
 56         #endregion
 57 
 58         #region 连接设备
 59         public void Connect() {
 60             try {
 61                 if (!this._device.IsOpen) {
 62                     this._device.Open();
 63                 }
 64             }
 65             catch {
 66                 throw new Exception(string.Format("端口{0}已被占用或被拒绝访问",this._device.PortName));
 67             }
 68         }
 69         #endregion
 70 
 71         #region 关闭连接
 72         public void Close() {
 73             if (this._device.IsOpen) {
 74                 this._device.Close();
 75             }
 76         }
 77         #endregion
 78 
 79         #region 接收数据
 80         public void Device_DataReceived(object sender, SerialDataReceivedEventArgs e) {
 81             lock (locker) {
 82                 if (_device.BytesToRead > 0) {
 83                     byte[] buff = new byte[msgMaxLength];
 84                     int startIndex = 0;
 85                     while (_device.BytesToRead > 0) {
 86                         int count = _device.Read(buff, startIndex, _device.BytesToRead);
 87                         startIndex += count;
 88                         Thread.Sleep(10);
 89                     }
 90 
 91                     byte[] msg = new byte[startIndex];
 92                     Array.Copy(buff, msg, startIndex);
 93 
 94                     if (this.encoding == null) {
 95                         this.byteMsgRecv = msg;
 96                     }
 97                     else {
 98                         string strMsg = this.encoding.GetString(msg);
 99                         this.strMsgRecv = strMsg;
100                     }
101                     waiterForRsp.Set();
102                 }
103             }
104         }
105         #endregion
106 
107         #region 发送消息
108         public void SendMsg(byte[] msg) {
109             this.Connect();
110             this._device.Write(msg, 0, msg.Length);
111         }
112 
113         public void SendMsg(string msg) {
114             this.Connect();
115             byte[] msgToByte = this.encoding.GetBytes(msg);
116             this._device.Write(msgToByte, 0, msgToByte.Length);
117         }
118         #endregion
119 
120         #region 原子操作
121         /// <summary>
122         /// 接收设备的响应消息(字节型通信协议)
123         /// </summary>
124         /// <param name="timeOut">等待设备回复的最大时长</param>
125         /// <param name="msg">收到的设备的回复</param>
126         /// <returns></returns>
127         public bool RecvRsp(int timeOut, out byte[] msg) {
128             bool isInTime = waiterForRsp.WaitOne(timeOut);
129             byte[] buff = new byte[byteMsgRecv.Length];
130             Array.Copy(byteMsgRecv, buff, byteMsgRecv.Length);
131             msg = buff;
132             return isInTime;
133         }
134         /// <summary>
135         /// 接收设备的响应消息(字符型通信协议)
136         /// </summary>
137         /// <param name="timeOut">等待设备回复的最大时长</param>
138         /// <param name="msg">收到的设备的回复</param>
139         /// <returns></returns>
140         public bool RecvRsp(int timeOut, out string msg) {
141             bool isInTime = waiterForRsp.WaitOne(timeOut);
142             msg = strMsgRecv;
143             return isInTime;
144         }
145 
146         public void OccupyRoute() {
147             while (Interlocked.Exchange(ref usingSource, 1) == 1)
148                 ;
149         }
150 
151         public void AbandonRoute() {
152             Interlocked.Exchange(ref usingSource, 0);
153         }
154         #endregion
155     }
View Code

使用方法:

1,适用场景

上位机和设备通过协议发送和接收数据交互,从而达到上位机控制设备的目的。

2,使用方法

(1)示例

现在有个需求:上位机软件包括一个点胶机控制器,用来控制点胶机的开始吐胶,停止吐胶,真空压力值等行为。

/// <summary>
    /// 点胶机控制器
    /// </summary>
    class DispenserControler {
        //串口
        private BaseSerialPort port = new BaseSerialPort("COM1", 9600, 8, StopBits.One, Parity.None,Encoding.ASCII);

        public void Init() {
            port.Connect();
        }
        //吐胶
        public void TuJiao() {
            port.OccupyRoute();
            port.SendMsg("tu jiao");
            string msg;
            bool res = port.RecvRsp(20000, out msg);
            if (res == false) {
                Console.WriteLine("OVER TIME");
            }
            else {
                Console.WriteLine(msg);
            }
             port.AbandonRoute();
        }
        public void ShutDown() {
            port.Close();
        }
    }

 (2)首先创建一个“控制器”类。

(3)创建一个BaseSerialPort实例,作为控制器的通信工具。

(4)根据通信协议是字节型还是字符串型,选用不同的构造函数创建BaseSerialPort实例。

(5)public void OccupyRoute()     public void AbandonRoute() 两个函数极为重要;

一.保证一个由若干指令组合而成的交互过程的连贯性

OccupyRoute();

Send();//不需要回复的指令

Send();//需要回复的指令

RecvRsp();//处理回复

AbandonRoute();

二,每条指令的开头和结尾

OccupyRoute();

Send();//需要回复的指令

RecvRsp();//处理回复

AbandonRoute();

含义:发送完指令,处理设备的回复,然后让出 串口接收数据的唯一缓存,允许其他指令和设备交互。

三,RecvRsp()的使用方法

检查返回值,若false,表示规定时间内未收到设备的回复,Rsp超时。

检查返回值,若true,则使用RecvRsp()传出的接收到的数据。

原文地址:https://www.cnblogs.com/riversouth/p/10255804.html