C#实现简单串口通信

串口通信(Serial Communications)是指外设和计算机间通过数据信号线、地线等按位(bit)进行传输数据的一种通信方式,属于串行通信方式,能够实现远距离通信,长度可达1200米。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通信的端口,这些参数必须匹配。

串口通信的接口标准有很多,有 RS-232C、RS-232、RS-422A、RS-485 等。常用的就是 RS-232 和 RS-485。串口通信使用的大多都是 DB9 接口,如下图。

1 载波检测(DCD) 2 接受数据(RXD) 3 发出数据(TXD) 4 数据终端准备好(DTR) 5 信号地线(SG) 6 数据准备好(DSR) 7 请求发送(RTS) 8 清除发送(CTS) 9 振铃指示(RI)

这里我们以 RS-232 接口进行演示。

1、数据包格式定为(10bytes):

帧头(0xAA,0x55),命令字(1byte),地址位(2bytes),数据位(2bytes),校验位(1byte,和校验),帧尾(0xFE,0xFE)

地址位和数据位都是高位在前。

数据封装方法:

//数据打包
private byte[] DataPackage(byte cmd, int addr, int data)
        {
            byte[] package = new byte[10];
            package[0] = 0xAA;//帧头
            package[1] = 0x55;
            package[2] = cmd;//命令字    
            byte[] dataaddr = IntToByteArray(addr);
            package[3] = dataaddr[0];//地址高字节
            package[4] = dataaddr[1];//地址低字节
            byte[] value = IntToByteArray(data);
            package[5] = value[0];//数据高字节
            package[6] = value[1];//数据低字节
            package[7] = CheckSum(package);//校验位
            package[8] = 0xFE;//帧尾
            package[9] = 0xFE;
            return package;
        }
 
        //将int转换成2位数组
        private static byte[] IntToByteArray(int value)
        {
            int hvalue = (value >> 8) & 0xFF;
            int lValue = value & 0xFF;
            byte[] arr = new byte[] { (byte)hvalue, (byte)lValue };
            return arr;
        }
 
        //得到和校验码
        private byte CheckSum(byte[] package)
        {
            byte checksum = 0;
            for (int i = 0; i < package.Length; i++)
            {
                checksum += package[i];
            }
            return checksum;
        }

2、串口调用封装类CommHelper.cs

internal class CommHelper
    {
        //委托
        public delegate void EventHandle(byte[] readBuffer);
        public event EventHandle DataReceived;
 
        public SerialPort serialPort;
        private Thread thread;
        volatile bool _keepReading;
 
        public CommHelper()
        {
            serialPort = new SerialPort();
            
            thread = null;
            _keepReading = false;
 
            serialPort.ReadTimeout = -1;
            serialPort.WriteTimeout = 1000;
        }
 
        //获取串口打开状态
        public bool IsOpen
        {
            get
            {
                return serialPort.IsOpen;
            }
        }
 
        //开始读取
        private void StartReading()
        {
            if (!_keepReading)
            {
                _keepReading = true;
                thread = new Thread(new ThreadStart(ReadPort));
                thread.Start();
            }
        }
 
        //停止读取
        private void StopReading()
        {
            if (_keepReading)
            {
                _keepReading = false;
                thread.Join();
                thread = null;
            }
        }
 
        //读数据
        private void ReadPort()
        {
            while (_keepReading)
            {
                if (serialPort.IsOpen)
                {
                    int count = serialPort.BytesToRead;
                    if (count > 0)
                    {
                        byte[] readBuffer = new byte[count];
                        try
                        {
                            Application.DoEvents();
                            serialPort.Read(readBuffer, 0, count);
                            DataReceived?.Invoke(readBuffer);
                            Thread.Sleep(100);
                        }
                        catch (TimeoutException)
                        {
                        }
                    }
                }
            }
        }
 
        //写数据
        public void WritePort(byte[] send, int offSet, int count)
        {
            if (IsOpen)
            {
                serialPort.Write(send, offSet, count);
            }
        }
 
        //打开
        public void Open()
        {
            Close();
            try
            {
                serialPort.Open();
                serialPort.RtsEnable = true;
                if (serialPort.IsOpen)
                {
                    StartReading();
                }
                else
                {
                    MessageBox.Show("串口打开失败!");
                }
            }
            catch
            {
 
            }
        }
 
        //关闭
        public void Close()
        {
            StopReading();
            serialPort.Close();            
        }
    }

3、调用(模拟测试读写硬件版本号)

//地址存储信息定义
private static int HARD_VERSION = 0;            //硬件版本号
       
//命令定义
private static byte RD_HV = 0;                //读硬件版本
private static byte WR_HV = 1;                //写硬件版本
 
private CommHelper comm = new CommHelper();
private bool GetCorrect = false; //用来标识是否已经接收到返回值
 
private List<byte> buffer = new List<byte>(1024);//默认分配1M内存,限制不能超过
private byte[] binary_data = new byte[10];//指定格式的某个完整数据
 
//串口初始化
private void InitComm()
        {
            comm.serialPort.PortName = "COM1";
            comm.serialPort.BaudRate = 19200;
            try
            {
                comm.Open();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            if (comm.IsOpen)
            {
                comm.DataReceived += new CommHelper.EventHandle(comm_DataReceived);
            }
        }
 
        //数据接收后处理
        private void comm_DataReceived(byte[] readBuffer)
        {
            try
            {
                buffer.AddRange(readBuffer);//将数据放到缓存中
                //完整性判断
                while (buffer.Count >= 10)
                {
                    //查找数据头
                    if (buffer[0] == 0xAA && buffer[1] == 0x55)
                    {
                        //和校验
                        byte checksum = 0;
                        for (int i = 0; i < 7; i++)
                        {
                            checksum += buffer[i];
                        }
                        if (checksum != buffer[7])
                        {
                            buffer.RemoveRange(0, 10);//如果校验失败,从缓存中删除这一包数据
                            continue;
                        }
                        buffer.CopyTo(0, binary_data, 0, 10);//复制一条完整的数据到具体的数据缓存
 
                        //读取硬件版本号
                        if (binary_data[2] == RD_HV && ByteArrayToInt(binary_data[3], binary_data[4]) == HARD_VERSION)//命令字为读RD_HV,地址HARD_VERSION
                        {
                            GetCorrect = true;
                            string data = ByteArrayToString(binary_data[5], binary_data[6]);
                            //这里可以处理数据更新界面展示
                        }
 
                        buffer.RemoveRange(0, 10);
                    }
                    else
                    {
                        GetCorrect = false;
                        buffer.RemoveAt(0);//如果数据开始不是头,则删除数据
                    }
                }
            }
            catch
            {
 
            }
        }
 
        //将2位数组转换成字符串
        private static string ByteArrayToString(byte arr1, byte arr2)
        {
            int value = ByteArrayToInt(arr1, arr2);
            string str = Convert.ToString(value, 10);
            return str;
        }
 
        //将2位数组转换成10进制数
        private static int ByteArrayToInt(byte arr1, byte arr2)
        {
            byte[] arr = new byte[] { arr1, arr2 };
            int value = (int)((arr[0] & 0xFF) << 8)
                      | (arr[1] & 0xFF);
            return value;
        }
 
        //读取硬件版本号
        private void ReadHV()
        {
            GetCorrect = false;
            try
            {
                comm.WritePort(DataPackage(RD_HV, HARD_VERSION, 0), 0, 10);//发送RD_E2P命令,地址HARD_VERSION
                Delay(100);
                if (GetCorrect == true)
                {
                    MessageBox.Show("硬件版本号读取成功!");
                }
                else
                {
                    MessageBox.Show("硬件版本号读取失败!");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
 
        //写入硬件版本号
        private void WriteHV()
        {
            if (tbVersion.Text.Length == 4 && isLegal(tbVersion.Text))//限定只能写入4个字符且输入合法
            {
                try
                {
                    int buf = Convert.ToInt32(tbVersion.Text);
                    GetCorrect = false;
                    comm.WritePort(DataPackage(WR_HV, HARD_VERSION, buf), 0, 10);//发送WR_HV命令,地址HARD_VERSION
                    Delay(100);
                    if (GetCorrect == true)
                    {
                        MessageBox.Show("硬件版本号写入成功!");
                    }
                    else
                    {
                        MessageBox.Show("硬件版本号写入失败!");
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            else
            {
                MessageBox.Show("硬件版本号数据格式错误!请重新写入!");
            }
        }
 
        //判断输入是否合法,必须是数字
        private const string PATTERN = @"^[0-9]*$";
        private bool isLegal(string hex)
        {
            return System.Text.RegularExpressions.Regex.IsMatch(hex, PATTERN);
        }
 
        //延时函数
        [DllImport("kernel32.dll")]
        static extern uint GetTickCount();
        static void Delay(uint ms)
        {
            uint start = GetTickCount();
            while (GetTickCount() - start < ms)
            {
                Application.DoEvents();
            }
        }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 基于C#实现串口通信

    本文实例为大家分享了C#实现串口通信的具体代码,供大家参考,具体内容如下 1.基本概念 2.前端winForm布局如下(仅仅为了实现功能,布局略丑) 3.代码实现如下 namespace SerialPortTest   {       public partial class Form1 : Form       {           SerialPort sp1 = new SerialPort();           public Form1()           {        

  • C#串口通信程序实例详解

    创建C#串口通信程序之命名空间 System.IO.Ports命名空间中最重用的是SerialPort 类. 创建C#串口通信程序之创建SerialPort 对象 通过创建SerialPort 对象,我们可以在程序中控制串口通信的全过程. 我们将要用到的SerialPort 类的方法: ReadLine():从输入缓冲区读一新行的值,如果没有,会返回NULLWriteLine(string):写入输出缓冲Open():打开一个新的串口连接Close():关闭 复制代码 代码如下: SerialP

  • C#串口通信实现方法

    本文实例讲述了C#串口通信实现方法.分享给大家供大家参考.具体方法如下: 通过COM1发送数据,COM2接收数据.当COM2接收完本次发送的数据后,向COM1发送信息通知COM1本次数据已发完,COM1接到通知后,再发下一段数据.这样可以确保每次发送的数据都可以被正确接收. 代码如下: 复制代码 代码如下: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data;

  • C#串口通信模块使用方法示例

    C#串口模块的使用.使用VS .net框架下WinForm程序应用开发. C#开发的串口通信小工具. 相比于QT添加的串口类,WinForm是通过组件的形式将串口加入到程序中.. 在创建完windows窗体之后,添加组件类,就可以将串口加入到其中. 然后就需要写数据成员,初始化和方法,实现串口的读写功能. 串口类数据成员 SerialPort SComm; // 使用构造函数取串口控件 TextBox MsgRc; // 接收数据成员 //构造函数初始化 public SerialComm(Se

  • C#串口通信工具类的封装

    本文实例为大家分享了C#串口通信工具类的封装代码,供大家参考,具体内容如下  1.SerialPortHelper串口工具类封装 using System; using System.Collections.Generic; using System.IO.Ports; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Timers;   namespace public.Util {

  • C#中的串口通信SerialPort详解

    今天这篇文章带大家学习下C#中的串口通讯.在日常的开发工作中,如果工作内容是CS方向的同学应该很容易接触到串口通讯方面的业务需求.那么也就很容易想到C#中SerialPort类,它就是专门来处理串口通讯相关的. 了解什么是串口通讯 串口通讯是指外设和计算机间通过数据信号线,地线,控制线等,按位进行传输数据的一种通讯方式. 这种通讯方式使用的数据线少,在远距离通信中可以节约成本,但其传输速度比并行通讯慢. 串口是计算机上一种非常通用的设备通讯协议.大多数计算机包含两个基于RS-232的串口. 串口

  • 使用Java实现简单串口通信

    本博文参考自https://www.jb51.net/article/100269.htm www.jb51.net/article/100269.htm 没想到挺多人需要这个的,很高兴这篇文章能对大家有帮助,主要的工具类博文里已经有了,当然,要小工具源码的留言邮箱即可. 2019.09.05 最近接触到了串口及其读写,在此记录java进行串口读写的过程. 1.导入支持java串口通信的jar包: 在maven项目的pom.xml中添加RXTXcomm的依赖 或者 下载RXTXcomm.jar并

  • C#实现简单串口通信

    串口通信(Serial Communications)是指外设和计算机间通过数据信号线.地线等按位(bit)进行传输数据的一种通信方式,属于串行通信方式,能够实现远距离通信,长度可达1200米.尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据.串口通信最重要的参数是波特率.数据位.停止位和奇偶校验.对于两个进行通信的端口,这些参数必须匹配. 串口通信的接口标准有很多,有 RS-232C.RS-232.RS-422A.RS-485 等.常用的就是 RS

  • 基于Java编写串口通信工具

    最近一门课要求编写一个上位机串口通信工具,我基于Java编写了一个带有图形界面的简单串口通信工具,下面详述一下过程,供大家参考 ^_^ 一: 首先,你需要下载一个额外的支持Java串口通信操作的jar包,由于java.comm比较老了,而且不支持64位系统,这里推荐Rxtx这个jar包(32位/64位均支持). 官方下载地址:http://fizzed.com/oss/rxtx-for-java (注:可能需要FQ才能下载) 不能FQ的童鞋,可以在这里下载: http://xiazai.jb51

  • java 串口通信详细及简单实例

    java 实现串口通信 最近做了一个与硬件相关的项目,刚开始听说用java和硬件打交道,着实下了一大跳.java也可以操作硬件? 后来接触到是用java通过串口通信控制硬件感觉使用起来还不错,也很方便. 特拿出来和大家一起分享一下. 准备工作: 首先到SUN官网下载一个zip包:javacomm20-win32.zip 其中重要的有这几个文件: win32com.dll comm.jar javax.comm.properties 按照说明配置好环境,如下: 将win32com.dll复制到<J

  • Python3简单实现串口通信的方法

    如下所示: import serial import sys import os import time import re def wait_for_cmd_OK():     while True:         line = ser.readline()         try:             print(line.decode('utf-8'),end='')         except:             pass         if ( re.search(b'

  • Android 串口通信编程及串口协议分析

    Android 串口通信编程:嵌入式编程和可穿戴设备及智能设备都会用到串口,这里就带大家分析下, 一,android串口通信 串口通信采用一个第三方开源项目,实现串口数据收发. 1. 使用了http://code.google.com/p/android-serialport-api/的项目的serialport api和jni: 2. 支持4串口同时收发,有定时自动发送功能,收发模式可选Txt或Hex模式: 3.  n,8,1,没得选: 4. 为减轻界面卡顿的情况,接收区的刷新采用单独的线程进

  • 对Python 简单串口收发GUI界面的实例详解

    忙活了三个多小时,连学带做,总算是搞出来了一个具有基本功能的串口通信PC机的GUI界面,Tkinter在python中确实很好用,而且代码量确实也很少,不足的是Tkinter不自带combox,但是幸运的是我下载的2.7版本自带了包含有combox的ttk模块,于是乎问题就顺利解决了. 下面是源代码,一些错误提示功能还没有做,目前只是简单地实现了下位机与PC的通信界面,下位机还是用的STM32F103 #encoding=utf-8 __author__ = 'freedom' from Tki

  • Android串口开发之使用JNI实现ANDROID和串口通信详解

    一:串口通信简介 前段时间因为工作需要研究了一下android的串口通信,网上有很多讲串口通信的文章,我在做的时候也参考了很多文章,现在就将我学习过程中的一些心得分享给大家,由于串口开发涉及到jni,所以开发环境需要支持ndk开发,如果未配置ndk配置的朋友,或者对jni不熟悉的朋友,请查看上一篇文章,android 串口开发第一篇:搭建ndk开发环境以及第一个jni调用程序 ,串口通信和java操作io类似,先打开串口,然后向串口发送或者读取数据,最后关闭串口,所以基本思路就是: 1.对串口文

  • Java实现的串口通信功能示例

    本文实例讲述了Java实现的串口通信功能.分享给大家供大家参考,具体如下: 用Java实现串口通信(windows系统下),需要用到sun提供的串口包 javacomm20-win32.zip.其中要用到三个文件,配置如下: 1.comm.jar放置到 JAVA_HOME/jre/lib/ext; 2.win32com.dll放置到 JAVA_HOME/bin; 3.javax.comm.properties 两个地方都要放     jre/lib(也就是在JAVA文件夹下的jre)    JA

随机推荐