C# 串口通信总结

简介: 在C#串口通信开发过程中有的产家只提供通信协议,这时候开发人员要自己根据协议来封装方法,有的产家比较人性化提供了封装好的通信协议方法供开发人员调用。 1、只提供通信协议(例如,今年早些时候开发的出钞机): 如: ///    /// 出钞 DISPENSE(0x45)   ///   ...

在C#串口通信开发过程中有的产家只提供通信协议,这时候开发人员要自己根据协议来封装方法,有的产家比较人性化提供了封装好的通信协议方法供开发人员调用。

1、只提供通信协议(例如,今年早些时候开发的出钞机):

QQ截图20141113095538

QQ截图20141113095519

如:

/// <summary>
   /// 出钞 DISPENSE(0x45)
   /// </summary>
   public void Chuchao()
   {
       log("出钞设备出钞");
       if (!sp.IsOpen)
       {
           sp.Open();
       }
       try
       {

           var send = new byte[] { Eot, Id, Stx, Dipsense, 48, 51, Etx, 0x01 };
           int bcc = 0;
           for (int i = 0; i < send.Length - 1; i++)
               bcc ^= send[i];
           send[send.Length - 1] = (byte)bcc;
           sp.Write(send, 0, send.Length);
           log("操作命令:" + GetBytesString(send, 0, send.Length, " "));
           for (int i = 0; i < 3; i++)
           {
               var r = sp.ReadByte();
               log("发送命令,收到的反馈。" + r);
               if (r != Ack)
               {
                   sp.Write(send, 0, send.Length);
               }
               else
               {
                   break;
               }
           }

           byte[] recive = new byte[14];

           for (int i = 0; i < 3; i++)
           {
               bcc = 0;
               recive = GetData(recive.Length);
               for (int j = 0; j < recive.Length - 1; j++)
               {
                   bcc ^= recive[j];
               }
               if (bcc != recive[recive.Length - 1])
               {
                   sp.Write(new byte[] { Nck }, 0, 1);
                   log("收到信息:" + GetBytesString(recive, 0, recive.Length, " ") + ",接收标识:NCK:失败");
               }
               else
               {
                   sp.Write(new byte[] { Ack }, 0, 1);
                   log("收到信息:" + GetBytesString(recive, 0, recive.Length, " ") + ",接收标识:ACK:成功");
                   break;
               }
           }
           Error errorCode = new Error();
           errorCode.Code = recive[9];
           log("接收到的命令:" + recive[3] + ",接收到的错误码:" + errorCode.Code + "--" + errorCode.ErrorMsg);
           if (recive[3] != Dipsense || errorCode.Code > 0x31)
           {
               throw new Exception("出钞出错");
           }
       }
       catch (Exception e)
       {
           log(e.ToString());
           //throw;
       }
       finally
       {
           if (sp.IsOpen)
           {
               sp.Close();
           }
       }
   }

 

2、产家提供通信协议方法(例如,今年早些时候开发的银行卡支付机):

这时候你只要在你的项目bin/Debug下面添加产家提供的dll,然后,再这样:

         /// <summary>
        /// 打开串口
         /// </summary>
        /// <param name="port">串口号字符串</param>
        /// <returns>
        /// 串口文件句柄
        /// 备注:必须先调用此函数,获得指定串口的串口文件句柄,才可调用其他函数。
        /// 可以同时打开多个串口,获得多个串口文件句柄,但不能多次打开同一个串口。
        /// 使用完毕后,必须调用CommClose()关闭串口。
        /// </returns>
        [DllImport("CRT_310.dll", EntryPoint = "CommOpen", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr CommOpen(string port);

        /// <summary>
        /// 按指定的波特率打开串口 (该函数完成的功能= CommOpen 函数+ CommSetting 函数)
        /// </summary>
        /// <param name="port">串口号字符串</param>
        /// <param name="data">指定波特率
        /// 波特率=1200,2400,4800,9600,19200,38400。
        /// 例如:CommOpen("Com1",9600);
        /// </param>
        /// <returns>串口文件句柄
        /// 备注:必须先调用此函数,获得指定串口的串口文件句柄,才可调用其他函数。
        /// 可以同时打开多个串口,获得多个串口文件句柄,但不能多次打开同一个串口。
        /// 使用完毕后,必须调用CommClose()关闭串口。</returns>
        [DllImport("CRT_310.dll", EntryPoint = "CommOpenWithBaut", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr CommOpenWithBaut(string port, uint data);
 

然后就可以像这样调用了:

public string CardBoxPositionToRead()
        {
            var comHandle = new IntPtr();
            var cardStates = new byte[2];
            var recordInfo = new byte[200];
            int? data;
            try
            {
                comHandle = PackageK100Dll.M100A_CommOpenWithBaud(ComPort, BaudRate);
                if (comHandle.ToInt32() == 0)
                {
                    PackageK100Dll.M100A_CommClose(comHandle);
                    return "打开串口失败!";
                }
                data = PackageK100Dll.M100A_CheckCardPosition(comHandle, false, 0, cardStates, recordInfo);
                if (data != 0)
                {
                    PackageK100Dll.M100A_CommClose(comHandle);
                    return "读取卡片位置失败";
                }
                switch (cardStates[0])
                {
                    //通道无卡
                    case 48:
                        break;
                    case 49:
                    case 50:
                        data = PackageK100Dll.M100A_MoveCard(comHandle, false, 0, 0x34, recordInfo);
                        if (data != 0)
                        {
                            PackageK100Dll.M100A_CommClose(comHandle);
                            return "移动卡片位置失败";
                        }
                        break;
                    //通道有卡
                    default:
                        PackageK100Dll.M100A_CommClose(comHandle);
                        return "请取走卡片或者业务正在办理,请稍候!";
                }
                switch (cardStates[1])
                {
                    case 48:
                        PackageK100Dll.M100A_CommClose(comHandle);
                        return "卡箱无卡";
                    default:
                        //将卡槽卡片移动到读写卡位置
                        data = PackageK100Dll.M100A_MoveCard(comHandle, false, 0, 0x30, recordInfo);
                        if (data != 0)
                        {
                            PackageK100Dll.M100A_CommClose(comHandle);
                            return "移动卡片位置失败";
                        }
                        PackageK100Dll.M100A_CommClose(comHandle);
                        return "true";
                }

            }
            catch (Exception)
            {
                PackageK100Dll.M100A_CommClose(comHandle);
                return "发生异常";
            }
        }
目录
相关文章
|
9月前
|
数据处理 C# C++
如何使用C#和C++结构体实现Socket通信
如何使用C#和C++结构体实现Socket通信
389 0
|
14天前
|
物联网 数据处理 C#
C#实现上位机开发,串口通信,读写串口数据并处理16进制数据
C#实现上位机开发,串口通信,读写串口数据并处理16进制数据。在自动化、物联网以及工业控制行业中,上位机开发是一项重要的技能。本教程主要介绍使用C#进行上位机开发,重点在于串口通信和数据处理。
195 82
|
6月前
|
物联网 C# Windows
看看如何使用 C# 代码让 MQTT 进行完美通信
看看如何使用 C# 代码让 MQTT 进行完美通信
790 0
|
8月前
|
C# Windows
C# 串口关闭时主界面卡死原因分析
串口程序关闭导致界面卡死的原因是主线程与辅助线程间的死锁。问题出在`SerialPort.Close()`方法与`DataReceived`事件处理程序。`DataReceived`事件在`lock (stream)`块中执行,而`Close()`方法会关闭`SerialStream`并锁定自身。当辅助线程处理数据并尝试更新UI时,UI线程因调用`Close()`被阻塞,造成死锁。解决办法是让`DataReceived`事件处理程序使用`this.BeginInvoke()`异步更新界面,避免等待UI线程,从而防止死锁。
|
9月前
|
C#
C# | 极简代码实现串口通信,功能超丰富 (使用BytesIO通信库)
C# 极简代码实现串口通信,功能超丰富 安装NuGet库 程序截图 事件监听 设计及实现 界面 代码 源码下载
433 0
C# | 极简代码实现串口通信,功能超丰富 (使用BytesIO通信库)
|
9月前
|
传感器 监控 网络协议
C# | 上位机开发新手指南(二)上位机通信
在上位机开发中,串口通信和TCP通信是两种常见的通信方式。串口通信是指通过串口将数据发送和接收到控制器或其他外设中,TCP通信则是通过网络将数据传输到远程设备中。下面介绍一下为什么学习串口通信和TCP通信在上位机开发中是很重要的。
696 0
C# | 上位机开发新手指南(二)上位机通信
|
9月前
|
C#
C# | 使用AutoResetEvent和ManualResetEvent进行线程同步和通信
在多线程编程中,AutoResetEvent 和 ManualResetEvent 是两个常用的同步原语。它们用于线程间的通信和协调,以确保线程按照特定的顺序执行。本篇博客将介绍这两种同步原语的概念、用法和区别。
153 0
C# | 使用AutoResetEvent和ManualResetEvent进行线程同步和通信
|
C# 开发者
C# 开发者技术:进程间数据共享之管道(Pipes)-异步通信版
主要类 1.NamedPipeClientStream 2.NamedPipeServerStream 解释:命名管道是一种进程间通信的方式,它允许不同进程之间在同一台机器上进行通信
1094 2
C# 开发者技术:进程间数据共享之管道(Pipes)-异步通信版
|
前端开发 JavaScript C#
【C#编程最佳实践 十】控件使用及Ajax通信
【C#编程最佳实践 十】控件使用及Ajax通信
86 0