zoukankan      html  css  js  c++  java
  • 串口通信与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()传出的接收到的数据。

  • 相关阅读:
    em,pt和px之间的换算
    css中 中文字体(fontfamily)的标准英文名称
    HTML css面试题
    css实现的透明三角形
    JavaScript经典面试题系列
    C++ template 学习笔记(第二章)
    C++ template 学习笔记 (第五章)
    20120906
    C++ template 学习笔记(第十六章) 16.1 命名模版参数
    C++ template 学习笔记(第三,四章)
  • 原文地址:https://www.cnblogs.com/riversouth/p/10255804.html
Copyright © 2011-2022 走看看