广告位联系
返回顶部
分享到

c#模拟串口通信SerialPort的实现

C#教程 来源:互联网 作者:秩名 发布时间:2022-05-11 23:20:54 人浏览
摘要

一、前导知识 串行口是计算机的标准接口,现在的PC机(个人电脑)一般至少有两个串行口COM1和COM2。串行口应用广泛,在数据通信、计算机网络以及分布式工业控制系统中,经常采用

一、前导知识

串行口是计算机的标准接口,现在的PC机(个人电脑)一般至少有两个串行口COM1和COM2。串行口应用广泛,在数据通信、计算机网络以及分布式工业控制系统中,经常采用串行通信来交换数据和信息

电气标准及协议来分包括RS-232-C、RS-422、RS485、USB(Universal Serial Bus)等

实现串口通信的必要设置

串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。

对于两个进行通行的端口,这些参数必须匹配:

波特率

这是一个衡量通信速度的参数。它表示**每秒钟传送的bit的个数**。例如300波特表示每秒钟发送300个bit,波特率和距离成反比。高波特率常常用于放置的很近的仪器间的通信,典型的例子就是GPIB设备的通信

数据位

这是衡量通信中实际数据位的参数。当计算机发送一个信息包,实际的数据不会是8位的,标准的值是5、7和8位,如何设置取决于你想传送的信息。比如,标准的ASCII码是0~127(7位)。扩展的ASCII码是0~255(8位)。如果数据使用简单的文本(标准 ASCII码),那么每个数据包使用7位数据。每个包是指一个字节,包括开始/停止位,数据位和奇偶校验位。由于实际数据位取决于通信协议的选取,术语“包”指任何通信的情况。

停止位

用于表示单个包的最后一位。典型的值为1,1.5和2位。由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢

奇偶校验位

 在串口通信中一种简单的检错方式。有四种检错方式:偶、奇、高和低。当然没有校验位也是可以的。对于偶和奇校验的情况,串口会设置校验位(数据位后面的一位),用一个值确保传输的数据有偶个或者奇个逻辑高位。例如,如果数据是011,那么对于偶校验,校验位为0,保证逻辑高的位数是偶数个。如果是奇校验,校验位位1,这样就有3个逻辑高位。高位和低位不真正的检查数据,简单置位逻辑高或者逻辑低校验。这样使得接收设备能够知道一个位的状态,有机会判断是否有噪声干扰了通信或者是否传输和接收数据是否不同步

二、实验

我们将通过模拟串口通信,在pc机上进行两个串口(COM1、COM2)的交互

需要用到的软件:

Launch Virtual Serial Port Driver Pro:虚拟串口。使用它来模拟两个串口的连接

绘制窗口

 代码实现

1.使用SerialPort控制串口

1

private SerialPort sp1 = new SerialPort();

2.打开串口

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

private void button2_Click(object sender, EventArgs e)

{

    if (!sp1.IsOpen)

    {

        try

        {

            //串口号

            sp1.PortName = "COM1";

            //波特率

            sp1.BaudRate = 115200;

            //数据位

            sp1.DataBits = 8;

            //停止位

            sp1.StopBits = StopBits.One;

            //奇偶校验位

            sp1.Parity = Parity.Even;

            //DataReceived事件发送前,内部缓冲区里的字符数

            sp1.ReceivedBytesThreshold = 1;

            sp1.RtsEnable = true; sp1.DtrEnable = true; sp1.ReadTimeout = 3000;

           // Control.CheckForIllegalCrossThreadCalls = false;

            //表示将处理 System.IO.Ports.SerialPort 对象的数据接收事件的方法。

            sp1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(sp1_DataReceived_1);

            //打开串口

            sp1.Open();

            MessageBox.Show("COM1打开成功!");

        }

        catch (Exception ex)

        {

            MessageBox.Show("COM1打开失败!");

        }

    }

    else

    {

        MessageBox.Show("COM1打开成功!");

    }

}

3.关闭串口

1

2

3

4

5

6

7

8

private void button3_Click(object sender, EventArgs e)

{

    if (sp1.IsOpen)

    {

        sp1.Close();

        MessageBox.Show("COM1关闭成功!");

    }

}

串口2的打开和关闭同理串口1实现

4.发送

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

private void button1_Click(object sender, EventArgs e)

{

    if (sp1.IsOpen)

    {

        if (!string.IsNullOrEmpty(this.textBox1.Text))

        {

            sp1.WriteLine(this.textBox1.Text+"\r\n");

 

        }

        else

        {

            MessageBox.Show("发送数据为空");

        }

    }

    else

    {

        MessageBox.Show("COM1未打开!");

    }

 

 

}

5.接收

1

2

3

4

5

6

7

8

9

10

11

12

13

14

StringBuilder builder1 = new StringBuilder();

//在接收到了ReceivedBytesThreshold设置的字符个数或接收到了文件结束字符并将其放入了输入缓冲区时被触发

public void sp1_DataReceived_1(object sender, SerialDataReceivedEventArgs e)

{

    Console.WriteLine("接收中...");

    int n = sp1.BytesToRead;      //先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致

    byte[] buf = new byte[n];   //声明一个临时数组存储当前来的串口数据

    sp1.Read(buf, 0, n);      //读取缓冲数据

    builder1.Remove(0, builder1.Length); //清除字符串构造器的内容

    builder1.Append(Encoding.ASCII.GetString(buf));

    string comdata = builder1.ToString();

    Console.WriteLine("data: + " + comdata);

    this.Invoke(settextevent,comdata);

}

这里仅仅实现了一般的接收方式,并不严谨和健壮

测试

使用软件模拟串口连接

 打开两个程序

 在一程序中打开串口1,在二程序中打开串口2,发送消息

在一程序中输入字符"hello,HanHanCheng!",发现在二程序中接收到,同样,在二程序中输入,在一中也能收到

 三、总结

1.由于是异步线程接收,在接收中需要使用委托来跨线程调用组件

1

2

3

4

5

6

7

8

public delegate void settext(string text);

public event settext settextevent;

public void set(string text)

{

    this.textBox2.Text = text;

}

//再注册

settextevent += set;

2.DataReceived事件触发条件需要注意,可能在实现时,无法触发导致无法接收。

触发条件是:在接收到了ReceivedBytesThreshold设置的字符个数或接收到了文件结束字符并将其放入了输入缓冲区时被触发

四、附件完整代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using System.IO.Ports;

  

namespace Training_USBCOM

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

            settextevent += set;

        }

  

        private SerialPort sp1 = new SerialPort();

        StringBuilder builder = new StringBuilder();

        private void button1_Click(object sender, EventArgs e)

        {

            if (sp1.IsOpen)

            {

                if (!string.IsNullOrEmpty(this.textBox1.Text))

                {

                    sp1.WriteLine(this.textBox1.Text+"\r\n");

  

                }

                else

                {

                    MessageBox.Show("发送数据为空");

                }

            }

            else

            {

                MessageBox.Show("COM1未打开!");

            }

  

  

        }

  

        public delegate void settext(string text);

        public event settext settextevent;

        public void set(string text)

        {

            this.textBox2.Text = text;

        }

         

  

        StringBuilder builder1 = new StringBuilder();

        //在接收到了ReceivedBytesThreshold设置的字符个数或接收到了文件结束字符并将其放入了输入缓冲区时被触发

        public void sp1_DataReceived_1(object sender, SerialDataReceivedEventArgs e)

        {

            Console.WriteLine("接收中...");

            int n = sp1.BytesToRead;      //先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致

            byte[] buf = new byte[n];   //声明一个临时数组存储当前来的串口数据

            sp1.Read(buf, 0, n);      //读取缓冲数据

            builder1.Remove(0, builder1.Length); //清除字符串构造器的内容

            builder1.Append(Encoding.ASCII.GetString(buf));

            string comdata = builder1.ToString();

            Console.WriteLine("data: + " + comdata);

            this.Invoke(settextevent,comdata);

        }

  

        private void button2_Click(object sender, EventArgs e)

        {

            if (!sp1.IsOpen)

            {

                try

                {

                    //串口号

                    sp1.PortName = "COM1";

                    //波特率

                    sp1.BaudRate = 115200;

                    //数据位

                    sp1.DataBits = 8;

                    //停止位

                    sp1.StopBits = StopBits.One;

                    //奇偶校验位

                    sp1.Parity = Parity.Even;

                    //DataReceived事件发送前,内部缓冲区里的字符数

                    sp1.ReceivedBytesThreshold = 1;

                    sp1.RtsEnable = true; sp1.DtrEnable = true; sp1.ReadTimeout = 3000;

                   // Control.CheckForIllegalCrossThreadCalls = false;

                    //表示将处理 System.IO.Ports.SerialPort 对象的数据接收事件的方法。

                    sp1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(sp1_DataReceived_1);

                    //打开串口

                    sp1.Open();

                    MessageBox.Show("COM1打开成功!");

                }

                catch (Exception ex)

                {

                    MessageBox.Show("COM1打开失败!");

                }

            }

            else

            {

                MessageBox.Show("COM1打开成功!");

            }

        }

  

        private void button3_Click(object sender, EventArgs e)

        {

            if (sp1.IsOpen)

            {

                sp1.Close();

                MessageBox.Show("COM1关闭成功!");

            }

        }

  

        private void button5_Click(object sender, EventArgs e)

        {

            if (!sp1.IsOpen)

            {

                try

                {

                    //串口号

                    sp1.PortName = "COM2";

                    //波特率

                    sp1.BaudRate = 115200;

                    //数据位

                    sp1.DataBits = 8;

                    //停止位

                    sp1.StopBits = StopBits.One;

                    //奇偶校验位

                    sp1.Parity = Parity.Even;

                    sp1.ReceivedBytesThreshold = 1;

                    sp1.RtsEnable = true; sp1.DtrEnable = true; sp1.ReadTimeout = 3000;

                    Control.CheckForIllegalCrossThreadCalls = false;

                    //表示将处理 System.IO.Ports.SerialPort 对象的数据接收事件的方法。

                    sp1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(sp1_DataReceived_1);

                    //打开串口

                    sp1.Open();

                    MessageBox.Show("COM2打开成功!");

                }

                catch (Exception ex)

                {

                    MessageBox.Show("COM2打开失败!");

                }

            }

            else

            {

                MessageBox.Show("COM2打开成功!");

            }

        }

  

        private void button4_Click(object sender, EventArgs e)

        {

            if (sp1.IsOpen)

            {

                sp1.Close();

                MessageBox.Show("COM2关闭成功!");

            }

        }

    }

}


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://blog.csdn.net/hey_lie/article/details/120194909
相关文章
  • WPF实现窗体亚克力效果的代码

    WPF实现窗体亚克力效果的代码
    WPF 窗体设置亚克力效果 框架使用大于等于.NET40。 Visual Studio 2022。 项目使用MIT开源许可协议。 WindowAcrylicBlur设置亚克力颜色。 Opacity设置透
  • C#非托管泄漏中HEAP_ENTRY的Size对不上解析

    C#非托管泄漏中HEAP_ENTRY的Size对不上解析
    一:背景 1. 讲故事 前段时间有位朋友在分析他的非托管泄漏时,发现NT堆的_HEAP_ENTRY的 Size 和!heap命令中的 Size 对不上,来咨询是怎么回事?
  • C#中ArrayList 类的使用介绍
    一:ArrayList 类简单说明 动态数组ArrayList类在System.Collecions的命名空间下,所以使用时要加入System.Collecions命名空间,而且ArrayList提供添加,
  • C#使用BinaryFormatter类、ISerializable接口、XmlSeriali

    C#使用BinaryFormatter类、ISerializable接口、XmlSeriali
    序列化是将对象转换成字节流的过程,反序列化是把字节流转换成对象的过程。对象一旦被序列化,就可以把对象状态保存到硬盘的某个位
  • C#序列化与反序列化集合对象并进行版本控制
    当涉及到跨进程甚至是跨域传输数据的时候,我们需要把对象序列化和反序列化。 首先可以使用Serializable特性。 1 2 3 4 5 6 7 8 9 10 11 12 13 14
  • C#事件中关于sender的用法解读

    C#事件中关于sender的用法解读
    C#事件sender的小用法 开WPF新坑了,看了WPF的炫酷界面,再看看winForm实在是有些惨不忍睹(逃)。后面会开始写一些短的学习笔记。 一、什么
  • 在C#程序中注入恶意DLL的方法

    在C#程序中注入恶意DLL的方法
    一、背景 前段时间在训练营上课的时候就有朋友提到一个问题,为什么 Windbg 附加到 C# 程序后,程序就处于中断状态了?它到底是如何实现
  • 基于C#实现一个简单的FTP操作工具
    实现功能 实现使用FTP上传、下载、重命名、刷新、删除功能 开发环境 开发工具: Visual Studio 2013 .NET Framework版本:4.5 实现代码 1 2 3 4 5 6 7
  • C#仿QQ实现简单的截图功能

    C#仿QQ实现简单的截图功能
    接上一篇写的截取电脑屏幕,我们在原来的基础上加一个选择区域的功能,实现自定义选择截图。 个人比较懒,上一篇的代码就不重新设计
  • C#实现线性查找算法的介绍
    线性查找,肯定是以线性的方式,在集合或数组中查找某个元素。 通过代码来理解线性查找 什么叫线性?还是在代码中体会吧。 首先需要一
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计