C#通信精讲系列——C# 通讯编程基础(含代码实例)

一、通讯基础理论

1.1 基本概念

  • 通讯发生在两端或多端之间,分为发送方和接收方

  • C# 中通讯主要分为两大块:

    • 串口通讯:有距离限制,速度较慢

    • 网络通讯:传输距离远,速度快,重要且难度较大

1.2 通讯协议

通讯双方必须遵循约定的数据格式(数据报文 / 数据帧),这些约定的规则称为通讯协议

通讯类型 常见协议
串口通讯 RS232、RS485、Modbus(通用)、西门子 S7 协议等
网络通讯 TCP、UDP、HTTP、HTTPS、STMP 等

在网络通讯中:

  • 一端称为服务器(Server / 主机 Host)

  • 另一端称为客户端(Client / 从机 Slave)

  • 一个服务器可以连接多个客户端

二、串口通讯详解

2.1 串口基本概念

  • 英文:serial port,也称串行通信接口或 COM 接口

  • 用于在两个设备之间通过专门设计的线路传输数据

  • 实现计算机与外部设备的可靠点对点(P2P/E2E)连接

  • 常见设备:打印机、调制解调器、传感器等

2.2 串行通讯原理

  • 串行数据传输:通过单个线路按顺序发送比特信息

  • 并行数据传输:使用多个信道同时传输

  • 单位换算:8bit = 1 字节,1024 位 = 128 字节

2.3 通信模式

  • 单工模式:只能单向传输

  • 半双工模式:可以双向传输,但不能同时进行

  • 全双工模式:可以同时双向传输(串口通讯属于此类)

2.4 串口通讯数据格式(重点)

一个完整的串口数据格式包括:

复制代码
起始位(1bit)+ 数据位(8bit)+ 奇偶校验位(1bit)+ 停止位(1bit)
关键参数:
  1. 波特率

    • 传输速度,单位 bps(每秒比特数)

    • 常用值:600、1200、2400、4800、9600、19200、38400bps

  2. 数据位数

    • 接收和发送的数据字节数

    • 常用 7 位或 8 位,默认使用 8 位

  3. 校验位

    • 保证数据准确性的校验机制

    • 类型:

      • 奇校验(Odd):使总位数为奇数

      • 偶校验(Even):使总位数为偶数

      • 无校验(None):不进行校验

      • 标记校验(Mark):校验位固定为 1

      • 空格校验(Space):校验位固定为 0

  4. 停止位

    • 数据传输完成的标志位

    • 通常为 1 位

三、C# 串口通讯编程实例

3.1 串口操作类(SerialPort)常用成员

属性

  • PortName:端口名称(如 "COM1")

  • BaudRate:波特率

  • DataBits:数据位

  • StopBits:停止位

  • Parity:校验位

  • IsOpen:串口是否已打开

方法

  • Open ():打开串口

  • Close ():关闭串口

  • Write ()/WriteLine ():发送数据

  • Read ()/ReadLine ()/ReadExisting ():读取数据

事件

  • DataReceived:数据接收事件

3.2 基本串口通讯示例

cs 复制代码
using System;
using System.IO.Ports;
using System.Windows.Forms;
​
namespace SerialCommunicationDemo
{
    public partial class MainForm : Form
    {
        // 创建串口对象
        private SerialPort _serialPort = new SerialPort();
        
        public MainForm()
        {
            InitializeComponent();
            InitializeSerialPort();
            LoadPortNames();
        }
        
        // 初始化串口参数
        private void InitializeSerialPort()
        {
            // 默认参数设置
            _serialPort.BaudRate = 9600;       // 波特率
            _serialPort.DataBits = 8;          // 数据位
            _serialPort.StopBits = StopBits.One; // 停止位
            _serialPort.Parity = Parity.None;  // 校验位
            _serialPort.ReadTimeout = 500;     // 读取超时
            _serialPort.WriteTimeout = 500;    // 写入超时
            
            // 绑定数据接收事件
            _serialPort.DataReceived += SerialPort_DataReceived;
        }
        
        // 加载可用串口列表
        private void LoadPortNames()
        {
            string[] portNames = SerialPort.GetPortNames();
            cmbPort.Items.AddRange(portNames);
            
            if (portNames.Length > 0)
                cmbPort.SelectedIndex = 0;
        }
        
        // 打开/关闭串口按钮
        private void btnOpenClose_Click(object sender, EventArgs e)
        {
            if (!_serialPort.IsOpen)
            {
                try
                {
                    // 设置端口名称
                    _serialPort.PortName = cmbPort.SelectedItem.ToString();
                    
                    // 打开串口
                    _serialPort.Open();
                    
                    // 更新UI状态
                    btnOpenClose.Text = "关闭串口";
                    cmbPort.Enabled = false;
                    txtLog.AppendText("串口已打开" + Environment.NewLine);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("打开串口失败:" + ex.Message);
                }
            }
            else
            {
                // 关闭串口
                _serialPort.Close();
                
                // 更新UI状态
                btnOpenClose.Text = "打开串口";
                cmbPort.Enabled = true;
                txtLog.AppendText("串口已关闭" + Environment.NewLine);
            }
        }
        
        // 发送数据按钮
        private void btnSend_Click(object sender, EventArgs e)
        {
            if (!_serialPort.IsOpen)
            {
                MessageBox.Show("请先打开串口");
                return;
            }
            
            try
            {
                string dataToSend = txtSendData.Text;
                if (!string.IsNullOrEmpty(dataToSend))
                {
                    // 发送数据
                    _serialPort.WriteLine(dataToSend);
                    txtLog.AppendText("发送:" + dataToSend + Environment.NewLine);
                    txtSendData.Clear();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("发送数据失败:" + ex.Message);
            }
        }
        
        // 数据接收事件处理
        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                // 读取接收到的数据
                string receivedData = _serialPort.ReadLine();
                
                // 跨线程更新UI
                this.Invoke(new Action(() =>
                {
                    txtLog.AppendText("接收:" + receivedData + Environment.NewLine);
                }));
            }
            catch (Exception ex)
            {
                this.Invoke(new Action(() =>
                {
                    txtLog.AppendText("接收数据错误:" + ex.Message + Environment.NewLine);
                }));
            }
        }
        
        // 窗体关闭时确保串口已关闭
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (_serialPort.IsOpen)
                _serialPort.Close();
        }
    }
}
​
  1. 串口初始化

    • 设置了常用的串口参数(波特率 9600、数据位 8 等)

    • 绑定了数据接收事件,用于处理异步接收的数据

  2. 核心功能

    • 打开 / 关闭串口

    • 发送数据到串口设备

    • 接收来自串口设备的数据

    • 显示通讯日志

  3. 注意事项

    • 操作串口前必须确保端口已正确打开

    • 数据接收事件在非 UI 线程触发,更新 UI 时需要使用 Invoke

    • 程序退出前应关闭串口,释放资源

四、开发与调试工具

  1. 虚拟串口工具

    • Virtual Serial Port Driver:创建虚拟串口对,用于调试
  2. 串口调试助手

    • XCOM V2.0:常用的串口调试工具

    • 其他可选:SSCOM、友善串口调试助手等

  3. 使用技巧

    • 先用虚拟串口和调试助手测试通讯逻辑

    • 确保通讯双方参数(波特率、校验位等)完全一致

    • 遇到问题时,先检查硬件连接和参数设置

五、常见问题与解决

  1. 无法打开串口

    • 检查端口是否被其他程序占用

    • 确认端口名称是否正确

    • 检查设备驱动是否安装

  2. 数据传输错误

    • 确认双方波特率、校验位等参数一致

    • 检查物理连接是否稳定

    • 尝试降低波特率测试

  3. 接收数据不完整

    • 可能是缓冲区设置问题

    • 考虑增加接收超时时间

    • 实现数据帧校验机制

通过以上内容,你可以掌握 C# 串口通讯的基本理论和编程实现方法。在实际应用中,还需要根据具体的硬件设备和通讯协议进行适当调整。

一、通讯基础理论

1.1 基本概念

  • 通讯发生在两端或多端之间,分为发送方和接收方

  • C# 中通讯主要分为两大块:

    • 串口通讯:有距离限制,速度较慢

    • 网络通讯:传输距离远,速度快,重要且难度较大

1.2 通讯协议

通讯双方必须遵循约定的数据格式(数据报文 / 数据帧),这些约定的规则称为通讯协议

通讯类型 常见协议
串口通讯 RS232、RS485、Modbus(通用)、西门子 S7 协议等
网络通讯 TCP、UDP、HTTP、HTTPS、STMP 等

在网络通讯中:

  • 一端称为服务器(Server / 主机 Host)

  • 另一端称为客户端(Client / 从机 Slave)

  • 一个服务器可以连接多个客户端

二、串口通讯详解

2.1 串口基本概念

  • 英文:serial port,也称串行通信接口或 COM 接口

  • 用于在两个设备之间通过专门设计的线路传输数据

  • 实现计算机与外部设备的可靠点对点(P2P/E2E)连接

  • 常见设备:打印机、调制解调器、传感器等

2.2 串行通讯原理

  • 串行数据传输:通过单个线路按顺序发送比特信息

  • 并行数据传输:使用多个信道同时传输

  • 单位换算:8bit = 1 字节,1024 位 = 128 字节

2.3 通信模式

  • 单工模式:只能单向传输

  • 半双工模式:可以双向传输,但不能同时进行

  • 全双工模式:可以同时双向传输(串口通讯属于此类)

2.4 串口通讯数据格式(重点)

一个完整的串口数据格式包括:

复制代码
起始位(1bit)+ 数据位(8bit)+ 奇偶校验位(1bit)+ 停止位(1bit)
关键参数:
  1. 波特率

    • 传输速度,单位 bps(每秒比特数)

    • 常用值:600、1200、2400、4800、9600、19200、38400bps

  2. 数据位数

    • 接收和发送的数据字节数

    • 常用 7 位或 8 位,默认使用 8 位

  3. 校验位

    • 保证数据准确性的校验机制

    • 类型:

      • 奇校验(Odd):使总位数为奇数

      • 偶校验(Even):使总位数为偶数

      • 无校验(None):不进行校验

      • 标记校验(Mark):校验位固定为 1

      • 空格校验(Space):校验位固定为 0

  4. 停止位

    • 数据传输完成的标志位

    • 通常为 1 位

三、C# 串口通讯编程实例

3.1 串口操作类(SerialPort)常用成员

属性

  • PortName:端口名称(如 "COM1")

  • BaudRate:波特率

  • DataBits:数据位

  • StopBits:停止位

  • Parity:校验位

  • IsOpen:串口是否已打开

方法

  • Open ():打开串口

  • Close ():关闭串口

  • Write ()/WriteLine ():发送数据

  • Read ()/ReadLine ()/ReadExisting ():读取数据

事件

  • DataReceived:数据接收事件

3.2 基本串口通讯示例

cs 复制代码
using System;
using System.IO.Ports;
using System.Windows.Forms;
​
namespace SerialCommunicationDemo
{
    public partial class MainForm : Form
    {
        // 创建串口对象
        private SerialPort _serialPort = new SerialPort();
        
        public MainForm()
        {
            InitializeComponent();
            InitializeSerialPort();
            LoadPortNames();
        }
        
        // 初始化串口参数
        private void InitializeSerialPort()
        {
            // 默认参数设置
            _serialPort.BaudRate = 9600;       // 波特率
            _serialPort.DataBits = 8;          // 数据位
            _serialPort.StopBits = StopBits.One; // 停止位
            _serialPort.Parity = Parity.None;  // 校验位
            _serialPort.ReadTimeout = 500;     // 读取超时
            _serialPort.WriteTimeout = 500;    // 写入超时
            
            // 绑定数据接收事件
            _serialPort.DataReceived += SerialPort_DataReceived;
        }
        
        // 加载可用串口列表
        private void LoadPortNames()
        {
            string[] portNames = SerialPort.GetPortNames();
            cmbPort.Items.AddRange(portNames);
            
            if (portNames.Length > 0)
                cmbPort.SelectedIndex = 0;
        }
        
        // 打开/关闭串口按钮
        private void btnOpenClose_Click(object sender, EventArgs e)
        {
            if (!_serialPort.IsOpen)
            {
                try
                {
                    // 设置端口名称
                    _serialPort.PortName = cmbPort.SelectedItem.ToString();
                    
                    // 打开串口
                    _serialPort.Open();
                    
                    // 更新UI状态
                    btnOpenClose.Text = "关闭串口";
                    cmbPort.Enabled = false;
                    txtLog.AppendText("串口已打开" + Environment.NewLine);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("打开串口失败:" + ex.Message);
                }
            }
            else
            {
                // 关闭串口
                _serialPort.Close();
                
                // 更新UI状态
                btnOpenClose.Text = "打开串口";
                cmbPort.Enabled = true;
                txtLog.AppendText("串口已关闭" + Environment.NewLine);
            }
        }
        
        // 发送数据按钮
        private void btnSend_Click(object sender, EventArgs e)
        {
            if (!_serialPort.IsOpen)
            {
                MessageBox.Show("请先打开串口");
                return;
            }
            
            try
            {
                string dataToSend = txtSendData.Text;
                if (!string.IsNullOrEmpty(dataToSend))
                {
                    // 发送数据
                    _serialPort.WriteLine(dataToSend);
                    txtLog.AppendText("发送:" + dataToSend + Environment.NewLine);
                    txtSendData.Clear();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("发送数据失败:" + ex.Message);
            }
        }
        
        // 数据接收事件处理
        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                // 读取接收到的数据
                string receivedData = _serialPort.ReadLine();
                
                // 跨线程更新UI
                this.Invoke(new Action(() =>
                {
                    txtLog.AppendText("接收:" + receivedData + Environment.NewLine);
                }));
            }
            catch (Exception ex)
            {
                this.Invoke(new Action(() =>
                {
                    txtLog.AppendText("接收数据错误:" + ex.Message + Environment.NewLine);
                }));
            }
        }
        
        // 窗体关闭时确保串口已关闭
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (_serialPort.IsOpen)
                _serialPort.Close();
        }
    }
}
复制代码
  1. 串口初始化

    • 设置了常用的串口参数(波特率 9600、数据位 8 等)

    • 绑定了数据接收事件,用于处理异步接收的数据

  2. 核心功能

    • 打开 / 关闭串口

    • 发送数据到串口设备

    • 接收来自串口设备的数据

    • 显示通讯日志

  3. 注意事项

    • 操作串口前必须确保端口已正确打开

    • 数据接收事件在非 UI 线程触发,更新 UI 时需要使用 Invoke

    • 程序退出前应关闭串口,释放资源

四、开发与调试工具

  1. 虚拟串口工具

    • Virtual Serial Port Driver:创建虚拟串口对,用于调试
  2. 串口调试助手

    • XCOM V2.0:常用的串口调试工具

    • 其他可选:SSCOM、友善串口调试助手等

  3. 使用技巧

    • 先用虚拟串口和调试助手测试通讯逻辑

    • 确保通讯双方参数(波特率、校验位等)完全一致

    • 遇到问题时,先检查硬件连接和参数设置

五、常见问题与解决

  1. 无法打开串口

    • 检查端口是否被其他程序占用

    • 确认端口名称是否正确

    • 检查设备驱动是否安装

  2. 数据传输错误

    • 确认双方波特率、校验位等参数一致

    • 检查物理连接是否稳定

    • 尝试降低波特率测试

  3. 接收数据不完整

    • 可能是缓冲区设置问题

    • 考虑增加接收超时时间

    • 实现数据帧校验机制

通过以上内容,你可以掌握 C# 串口通讯的基本理论和编程实现方法。在实际应用中,还需要根据具体的硬件设备和通讯协议进行适当调整。

相关推荐
半桶水专家4 小时前
go语言中的结构体嵌入详解
开发语言·后端·golang
在屏幕前出油5 小时前
二、Python面向对象编程基础——理解self
开发语言·python
阿方索5 小时前
python文件与数据格式化
开发语言·python
cici158746 小时前
C#实现三菱PLC通信
java·网络·c#
weixin_440730507 小时前
java结构语句学习
java·开发语言·学习
JIngJaneIL7 小时前
基于java+ vue医院管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot
量子联盟7 小时前
功能完整的PHP站点导航管理系统php程序;开源免费下载
开发语言·php
仙俊红7 小时前
在 Java 中,`==` 和 `equals()` 的区别
java·开发语言·jvm
JIngJaneIL7 小时前
基于java + vue校园跑腿便利平台系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot
happybasic8 小时前
python字典中字段重复性的分析~~
开发语言·python