龙空技术网

串口通讯——C#

讲讲01 3758

前言:

现在各位老铁们对“串口通信程序c语言代码”可能比较关怀,大家都想要学习一些“串口通信程序c语言代码”的相关知识。那么小编在网络上搜集了一些对于“串口通信程序c语言代码””的相关知识,希望我们能喜欢,我们快快来学习一下吧!

一、串口简述

串口通讯是指外设和计算机间通过数据信号线,地线,控制线等,按位进行传输数据的一种通讯方式。这种通讯方式使用的数据线少,在远距离通信中可以节约成本,但其传输速度比并行通讯慢。

串行接口是一种可以将接受来自CPU的并行数据字符转换为连续的串行数据流发送出去,同时也可将接受的串行数据流转换为并行的数据字符供给CPU的器件。

串口通讯的速度与波特率有关,波特率就是发送二进制数据位的速率, 习惯上用 baud 表示, 即我们发送一位二进制数据的持续时间=1/baud。

一个字节是 8 位,当要发送数据之前,先发一位 0 表示起始位,然后发送 8 位数据位,数据位是先低后高的顺序,数据位发完后再发一位 1 表示停止位。这样本来要发送一个字节的 8 位数据,而实际上我们一共发送了 10 位。

以波特率9600为例,发送一位的时间为1/9600,那么发送一个字节的时间为10x1/9600,大约为1.042ms,我们可以利用这个通讯时间来处理数据分包和黏包的问题。

二、C#中的串口通讯

C#中提供了System.IO.Ports.SerialPort类,根据SerialPort类提供的简单操作步骤,可以很容易的完成串口的信息收发程序,从特定的串口中接收到数据也可以进行数据的发送。

1、开发环境和工具

①WIN10系统

②Visual Studio社区版 2022(C#)

2、创建一个类,命名为SerialBase

添加一个自定义控件,右键解决方案,点击添加,点击新建项

②添加类,并命名为SerialBase,然后点击添加

③在SerialBase这个cs文件里面添加以下程序

using System;using System.Collections.Generic;using System.IO.Ports;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;namespace Serial{        public class SerialBase : IDisposable        {            /// <summary>            /// 实例化一个无参的构造方法            /// </summary>            public SerialBase()            {                serialPort = new SerialPort();            }            /// <summary>            /// 初始化串口信息,9600波特率,8位数据位,1位停止位,无奇偶校验            /// </summary>            /// <param name="portName">端口号信息</param>            public void SerialPortInit(string portName)            {                SerialPortInit(portName, 9600);            }            /// <summary>            /// 初始化串口信息,波特率,8位数据位,1位停止位,无奇偶校验            /// </summary>            /// <param name="portName">端口号信息,例如"COM3"</param>            /// <param name="baudRate">波特率</param>            public void SerialPortInit(string portName, int baudRate)            {                SerialPortInit(portName, baudRate, 8, StopBits.One, Parity.None);            }            /// <summary>            /// 初始化串口信息,波特率,数据位,停止位,奇偶校验            /// </summary>            /// <param name="portName">端口号信息,例如"COM3"</param>            /// <param name="baudRate">波特率</param>            /// <param name="dataBits">数据位</param>            /// <param name="stopBits">停止位</param>            /// <param name="parity">奇偶校验</param>            public void SerialPortInit(string portName, int baudRate, int dataBits, StopBits stopBits, Parity parity)            {                if (serialPort.IsOpen)                {                    return;                }                serialPort.PortName = portName;    // 串口                serialPort.BaudRate = baudRate;    // 波特率                serialPort.DataBits = dataBits;    // 数据位                serialPort.StopBits = stopBits;    // 停止位                serialPort.Parity = parity;      // 奇偶校验                PortName = serialPort.PortName;                BaudRate = serialPort.BaudRate;            }            /// <summary>            /// 根据自定义初始化方法进行初始化串口信息            /// </summary>            /// <param name="init">初始化的委托方法</param>            public void SerialPortInit(Action<SerialPort> init)            {                if (serialPort.IsOpen)                {                    return;                }                serialPort.PortName = "COM10";                serialPort.BaudRate = 9600;                serialPort.DataBits = 8;                serialPort.StopBits = StopBits.One;                serialPort.Parity = Parity.None;                init.Invoke(serialPort);                PortName = serialPort.PortName;                BaudRate = serialPort.BaudRate;            }            /// <summary>            /// 打开串行端口            /// </summary>            public void Open()            {                if (!serialPort.IsOpen)                {                    serialPort.Open();                }            }            /// <summary>            /// 指示串口是否处打开            /// </summary>            /// <returns>是或否</returns>            public bool IsOpen()            {                return serialPort.IsOpen;            }            /// <summary>            /// 关闭端口连接            /// </summary>            public void Close()            {                if (serialPort.IsOpen)                {                    serialPort.Close();                }            }            public void write(string buf)            {                serialPort.Write(buf);            }            /// <summary>            /// 读取串口的数据            /// </summary>            /// <param name="send">发送的原始字节数据</param>            /// <returns>带接收字节的结果对象</returns>            public byte[] ReadBase(byte[] send)            {                if(IsClearCacheBeforeRead) ClearSerialCache();                int sendResult = SendByte(send);                if(sendResult != 0)                {                }                byte[] receiveResult = ReceivedByte(serialPort, true);                return receiveResult;            }            /// <summary>            /// 发送数据到串口里去            /// </summary>            /// <param name="serialPort">串口对象</param>            /// <param name="data">字节数据</param>            /// <returns>是否发送成功,0发送成功,1发送报错,2发送内容为空</returns>            public int SendByte(byte[] data)            {                if (data != null && data.Length > 0)                {                    try                   {                        serialPort.Write(data, 0, data.Length);                       return 0;                   }                   catch                   {                       return 1;                   }                 }                else                {                    return 2;                }            /// <summary>            /// 从串口接收一串数据信息,可以指定是否一定要接收到数据            /// </summary>            /// <param name="serialPort">串口对象</param>            /// <param name="awaitData">是否必须要等待数据返回</param>            /// <returns>结果数据对象</returns>            public byte[] ReceivedByte(SerialPort serialPort, bool awaitData)            {                byte[] buffer = new byte[1024];                System.IO.MemoryStream ms = new System.IO.MemoryStream();                DateTime start = DateTime.Now;// 开始时间,用于确认是否超时的信息                while (true)                {                    Thread.Sleep(sleepTime);                    try                    {                        if (serialPort.BytesToRead < 1) //没有数据进来,进行判断                        {                           //超时                           if ((DateTime.Now start).TotalMilliseconds >receiveTimeout&& receiveTimeout!=0)                            {                                ms.Dispose();                                 break;                            }                            else if (ms.Length > 0)   //数据接收完成                            {                                break;                            }                            else if (awaitData)    //等待数据传入                            {                                continue;                            }                            else                            {                                break;                            }                        }                        //有数据进来,继续接收数据                                                int receive = serialPort.Read(buffer, 0, buffer.Length);                        ms.Write(buffer, 0, receive);                    }                    catch                    {                        ms.Dispose();                    }                }                byte[] result = ms.ToArray();                ms.Dispose();                return result;            }            /// <summary>            /// 是否在发送数据前清空缓冲数据,默认是false            /// </summary>            public bool IsClearCacheBeforeRead            {                get { return isClearCacheBeforeRead; }                set { isClearCacheBeforeRead = value; }            }            /// <summary>            /// 清除串口缓冲区的数据,并返回该数据,如果缓冲区没有数据,返回的字节数组长度为0            /// </summary>            /// <returns>是否操作成功的方法</returns>            public byte[] ClearSerialCache()            {                return ReceivedByte(serialPort, false);            }            /// <summary>            /// 返回表示当前对象的字符串            /// </summary>            /// <returns>字符串</returns>            public override string ToString()            {                return "SerialBase";            }            /// <summary>            /// 接收数据的超时时间,默认5000ms,设为0则表示无超时报警             /// </summary>            public int ReceiveTimeout            {                get { return receiveTimeout; }                set { receiveTimeout = value; }            }            /// <summary>            /// 连续串口缓冲数据检测的间隔时间,默认20ms            /// </summary>            public int SleepTime            {                get { return sleepTime; }                set { if (value > 0) sleepTime = value; }            }            /// <summary>            /// 本连接对象的端口号名称            /// </summary>            public string PortName { get; private set; }            /// <summary>            /// 本连接对象的波特率            /// </summary>            public int BaudRate { get; private set; }            private bool disposedValue;            protected virtual void Dispose(bool disposing)            {                if (!disposedValue)                {                    if (disposing)                    {                        // TODO: 释放托管状态(托管对象)                        serialPort?.Dispose();                    }                    // TODO: 释放未托管的资源(未托管的对象)并替代终结器                    // TODO: 将大型字段设置为 null                    disposedValue = true;                }            }            //// TODO: 仅当“Dispose(bool disposing)”拥有用于释放未托管资源的代码时才替代终结器            // ~SerialBase()            // {            //     // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中            //     Dispose(disposing: false);            // }            public void Dispose()            {                // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中                Dispose(disposing: true);                GC.SuppressFinalize(this);            }            private SerialPort serialPort = null;               // 串口交互            private int receiveTimeout = 5000;                  // 接收数据的超时时间            private int sleepTime = 20;                         // 睡眠的时间            private bool isClearCacheBeforeRead = false;        // 是否在发送前清除缓冲        }}

3、在Winform中调用SerialBase

从左侧工具箱拖曳控件并布局,如下图所示

②实现程序

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;using System.IO.Ports;using System.Data.SqlTypes;using System.Xml.Linq;namespace Serial{    public partial class Form1 : Form    {        public Form1()        {            InitializeComponent();        }        SerialBase serial = new SerialBase();//定义一个串口        private void SerialInit(SerialPort Init)        {            Init.PortName = cboxPort.Text;                       //串口号            Init.BaudRate = Convert.ToInt16(cboxBaudRate.Text);  //波特率            Init.DataBits = 8;            Init.StopBits = StopBits.One;            Init.Parity = Parity.None;        }        private void btnFlesh_Click(object sender, EventArgs e)        {            string[] names=SerialPort.GetPortNames();//查找可用串口            cboxPort.Items.Clear();                                 for(int i=0;i<names.Length;i++)            {                cboxPort.Items.Add(names[i]);        //串口号下拉菜单,增加一个条目            }        }        private void btnOpenPort_Click(object sender, EventArgs e)        {            serial.SerialPortInit(SerialInit);      //初始化串口               serial.Open();                          //打开串口        }        private void btnSend_Click(object sender, EventArgs e)        {            byte[] rece = new byte[1024];            //发送数据            rece = serial.ReadBase(new byte[] { 0x00,0x01,0x02,0x03,0x04,0x05}) ;                        txtBoxRece.Text += rece.Length > 0 ? DataTrans.ByteToHexString(rece)+ "\r\n" : "接收数据超时" + "\r\n";        }

4、效果演果

视频加载中...

标签: #串口通信程序c语言代码