C# 编程实现串口通信

流过昼夜 提交于 2020-01-02 00:48:39

http://blog.sina.com.cn/s/blog_6c67dab30101p3vn.html

-------------------------------------------------------------------------------

public partial class Form1 : Form
    {
        int k = 0;
        int[] crc_data1 = { 0, 0 };
        int[] crc_data2 = { 0, 0, 0, 0, 0 };
        int[] crc_data3 = { 0, 0, 0, 0, 0 };
        int x = 0;
        short qtemp;
        byte[] new_byte1 = { 0, 0, 0, 0, 0, 0, 0 };
        SolidBrush bush1 = new SolidBrush(Color.Red);
        SolidBrush bush2 = new SolidBrush(Color.Green);
        public Form1()
        {
            InitializeComponent();
        }

        //串口初始化
        private void Form1_Load(object sender, EventArgs e)
        {
            serialPort1.PortName = "COM3";
            serialPort1.BaudRate = 9600;
            serialPort1.DataBits = 8;
            serialPort1.StopBits = System.IO.Ports.StopBits.One;
            serialPort1.Parity = System.IO.Ports.Parity.None;
            serialPort1.Open();
        }
 
        //向水浸传感器发送读指令
        private void timer1_Tick(object sender, EventArgs e)
        {
            byte[] boutdata1 = { 0x01, 0x04, 0x01, 0xE3 };
            serialPort1.Write(boutdata1, 0, 4);
        }

        //触发事件,读取温度传感器返回数据
        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            System.Threading.Thread.Sleep(100);
            int byte_num1 = serialPort1.Read(new_byte1, 0, 7);
            this.Invoke(new EventHandler(DisplayText));
        }

        private void DisplayText(object sender, EventArgs e)
        {
            if (new_byte1[0] == 1) //水浸传感器
            {
                for (int i = 0; i < 2; i++)
                    crc_data1[i] = (int)new_byte1[i];
                int[] crc1 = crc16(crc_data1);
                if (crc1[0] == new_byte1[2] && crc1[1] == new_byte1[3]) //校验CRC
                     alarm1(); //显示,红灯报警,绿灯正常
                else
                    MessageBox.Show("校验码错误,数据无效!", "");
                byte[] boutdata2 = { 0x02, 0x03, 0x00, 0x01, 0x00, 0x01, 0xD5, 0xF9 }; //发送温度传感器数据
                serialPort1.Write(boutdata2, 0, 8);
            }
            if (new_byte1[0] == 2 && new_byte1[1] == 3) //温度传感器
            {
                for (int i = 0; i < 5; i++)
                    crc_data2[i] = (int)new_byte1[i];
                int[] crc2 = crc16(crc_data2);
                if (crc2[0] == new_byte1[5] && crc2[1] == new_byte1[6])
                    DisplayText2(); //显示温度并画出温度曲线
                else
                    MessageBox.Show("校验码错误,数据无效!", "");
                byte[] boutdata3 = { 0x50, 0x03, 0x00, 0x03, 0x00, 0x01, 0x79, 0x8B }; //发送烟感传感器数据
                serialPort1.Write(boutdata3, 0, 8);
            }
            if (new_byte1[0] == 80 && new_byte1[1] == 3) //烟感传感器
            {
                for (int i = 0; i < 5; i++)
                    crc_data3[i] = (int)new_byte1[i];
                int[] crc3 = crc16(crc_data3);
                if (crc3[0] == new_byte1[5] && crc3[1] == new_byte1[6])
                    alarm3(); //显示,红灯报警,绿灯正常
                else
                    MessageBox.Show("校验码错误,数据无效!", "");
            }
        }

        //关闭串口,退出程序
        private void button1_Click(object sender, EventArgs e)
        {
            serialPort1.Close();
            Close();
        }
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (serialPort1.IsOpen) serialPort1.Close();
        }  
    }

 

-----------------------------------------------------------------------------------

 

 

 

 

 

 

 

 

其实这是很简单的工作,只是我初次接触而已,做做笔记,方便以后使用时调用~

 
本来的背景是之前的B/S架构的网站,基于ASP.NET做的,但怎么都查不到直接用asp.net做串口通信,有的方法又太高级,我一时半会儿也学不会,所以还是转战最容易的serialPort控件了。
 
进行串口通讯时,需要设置一些相关参数,可以通过设置SerialPort 类的属性来进行。串口属性主要包括:
.PortName 串口名称,COM1, COM2等。
.BaudRate 波特率,也就是串口通讯的速度,进行串口通讯的双方其波特率需要相同,如果用PC连接其他非PC系统,一般地,波特率由非PC系统决定。
.Parity 奇偶校验。可以选取枚举Parity中的值
.DataBits 数据位
.StopBits 停止位,可以选取枚举StopBits中的值
.Handshake 握手方式,也就是数据流控制方式,可以选取枚举Handshake中的值。
这些可以赋值,也可以由窗口设置确定~
 
同一台电脑做测试时,可以使用VSPD软件进行虚拟串口,很好用哦!!
 
设置打开串口:
private void Com_Start_Click(object sender, EventArgs e)
        {
            serialPort1.Open();
            if (serialPort1.IsOpen)
                portstate.Text = "串口已经成功打开!";
            else
                portstate.Text = "串口打开失败!";
        }
引用:
在创建一个SerialPort 对象,设置串口属性后,可以通过 Open()方法打开串口。数据读写完成后,可以通过Close()方法关闭串口。根据经验,对于有些系统,在打开串口后,还需要将RtsEnable设置为True,这样才能读写数据,否则不能正常读写数据。
 
 
设置关闭串口:
 private void Com_Stop_Click(object sender, EventArgs e)
        {
            serialPort1.Close();
            portstate.Text = "串口已经关闭!";
        }
数据接收:
先选择控件,然后在 事件 中,选datareceived,于是就定义了一个函数,在函数中添加:
 string datareceive = serialPort1.ReadLine();
           Recive_Text.Invoke(new MethodInvoker(delegate
          {
              try
              {
                  Recive_Text.Text = datareceive;
              }
              catch (Exception ex)
              {
                  //MessageBox.Show(ex.ToString(), "1", MessageBoxButtons.OKCancel, MessageBoxIcon.Error);
              }
 
          }));
 
z注意: readline() 是一直读取到输入缓冲区中的 NewLine 值,即输入需要换行才响应。
其它的相关函数是:

Close

关闭端口连接,将 IsOpen 属性设置为False,并释放内部 Stream 对象

Open

打开一个新的串行端口连接

Read

从 SerialPort 输入缓冲区中读取数据字节数

ReadByte

从 SerialPort 输入缓冲区中同步读取一个字节

ReadChar

从 SerialPort 输入缓冲区中同步读取一个字符

ReadLine

一直读取到输入缓冲区中的 NewLine 值

ReadTo

一直读取到输入缓冲区中指定 value 的字符串

Write

已重载。将数据写入串行端口输出缓冲区

WriteLine

将指定的字符串和 NewLine 值写入输出缓冲区

DiscardInBuffer

DiscardOutBuffer

清空接收缓冲区数据

清空输出缓冲去数据

还有一些属性说明:

属性说明

名  称

说  明

BaseStream

获取 SerialPort 对象的基础 Stream 对象

BaudRate

获取或设置串行波特率

BreakState

获取或设置中断信号状态

BytesToRead

获取接收缓冲区中数据的字节数

BytesToWrite

获取发送缓冲区中数据的字节数

CDHolding

获取端口的载波检测行的状态

CtsHolding

获取“可以发送”行的状态

DataBits

获取或设置每个字节的标准数据位长度

DiscardNull

获取或设置一个值,该值指示 Null 字节在端口和接收缓冲区之间传输时是否被忽略

DsrHolding

获取数据设置就绪 (DSR) 信号的状态

DtrEnable

获取或设置一个值,该值在串行通信过程中启用数据终端就绪 (DTR) 信号

Encoding

获取或设置传输前后文本转换的字节编码

Handshake

获取或设置串行端口数据传输的握手协议

IsOpen

获取一个值,该值指示 SerialPort 对象的打开或关闭状态

NewLine

获取或设置用于解释 ReadLine( )和WriteLine( )方法调用结束的值

Parity

获取或设置奇偶校验检查协议

ParityReplace

获取或设置一个字节,该字节在发生奇偶校验错误时替换数据流中的无效字节

PortName

获取或设置通信端口,包括但不限于所有可用的 COM 端口

ReadBufferSize

获取或设置 SerialPort 输入缓冲区的大小

ReadTimeout

获取或设置读取操作未完成时发生超时之前的毫秒数

ReceivedBytesThreshold

获取或设置 DataReceived 事件发生前内部输入缓冲区中的字节数

RtsEnable

获取或设置一个值,该值指示在串行通信中是否启用请求发送 (RTS) 信号

StopBits

获取或设置每个字节的标准停止位数

WriteBufferSize

获取或设置串行端口输出缓冲区的大小

WriteTimeout

获取或设置写入操作未完成时发生超时之前的毫秒数

 
 
 
读写行数据

双方通讯时,一般都需要定义通讯协议,即使最简单的通过串口发送文本聊天的程序。

通常是在当一方按下回车时,将其所数据的文本连同换行符发给另一方。在这个通讯事例中,协议桢是通过换行符界定的,每一桢数据都被换行符隔开,这样就很容易识别出通讯双发发送的信息。

在以上的例子中,可以用WriteLine()来发送数据,用ReadLine()来读取数据。WriteLine发送完数据后,会将换行符作为数据也发送给对方。ReadLine()读取数据时,直至遇到一个换行符,然后返回一个字符串代表一行信息。换行符可以通过SerialPort 的属性NewLine来设置。一般地,Windows将CrLn作为换行符,而在Linux下,换行符则只用一个Ln表示。

ReadLine()方法是阻塞的,直至遇到一个换行符后返回。在读取数据时,如果一直没有遇到换行符,那么在等待ReadTimeout时间后,抛出一个TimeoutException。默认情况下,ReadTimeout为InfiniteTimeout。这样,ReadLine一直处于阻塞状态,直至有新一行数据到达。

WriteLine()方法也是阻塞的,如果另一方不能及时接收数据,就会引起TimeoutException异常。

由于ReadLine()和WriteLine()方法都是阻塞式的,在程序使用SerialPort 进行串口通讯时,一般应该把读写操作交由其他线程处理,避免因为阻塞而导致程序不响应。

读写字节或字符数据

对于字节或字符数据,用Read()方法来读数据,该方法需要一个字节或字符数组作为参数来保存读取的数据,结果返回实际读取的字节或字符数。写数据使用Write()方法,该方法可以将字节数组、字符数据或字符串发送给另一方。

如果通讯双方交换的数据位字节流数据,要构建一个使用的串口通讯程序,那么双方应该定义数据桢格式。通常数据桢由桢头和桢尾来界定。

发送数据比较简单,只需要将构造好的数据用Write()方法发送出去即可。

接收数据则比较复杂,通讯是以字节流的形式到达的,通过调用一次Read()方法并不能确保所读取的数据就是完整一桢。因此需要将每次读取的数据整合在一起,对整合后的数据进行分析,按照定义的桢格式,通过桢头和桢尾,将桢信息从字节流中抽取出来,这样才能获取有意义的信息。

除了利用Read()方法来读数据,还可以使用ReadExisting()方法来读取数据。该方法读取当前所能读到的数据,以字符串的形式返回。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!