C# 串口通信

Posted Zjl-NanKe

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# 串口通信相关的知识,希望对你有一定的参考价值。

这里浅说一下蓝牙与串口的区别:

        蓝牙:连接以mac地址为主,显示名称可以更改,低功耗蓝牙还需要配置服务与特征(服务有读,写,可读可写区别)

特点:不同设备连接同一台蓝牙设备,mac地址与显示名称都是唯一的

        串口:连接以端口名称为主,例如com1,com2,连接时需要配置参数较多

特点:不同设备接入同一个串口模块,显示的名称可能不一样

串口:SerialPort      继承于System.IO.Ports

        不同串口模块所需要的驱动不同,使用之前都需要安装对应模块驱动,因为电脑安装的驱动数量不同,就会造成同一个串口驱动在不同电脑中占得位置不同。

        举个例子:电脑相当于菜市场,串口相当于摊位,默认是没有摊位的,插入串口之后会声明一个摊位(端口com),摊位区分是以数字标识区分的例如com1,com2,com3(这是比较烦人的),插入串口之后,想要确定这个串口模块声明的摊位(端口)名称就需要在设备管理器中查看

  这里的silicon labs cp210x就是我插入的串口模块,他声明了端口名称为com4,连接时就需要选择com4,配置对应参数(串口模块的参数发布之后都是固定的,对于用户操作可以后台做成配置文件写死)。

 

  连接一个串口需要配置以下参数:

            _serialPortObject.PortName =串口名称
            _serialPortObject.BaudRate = 波特率
            _serialPortObject.DataBits = 数据位
            _serialPortObject.Parity = 校验位
            _serialPortObject.StopBits = 停止位

        以上任意一个串口参数配置与硬件串口模块参数不匹配,都会造成连接参数错误, 还有一些可配置项如输入与输出缓冲区大小,超时配置等等

 

 串口接收数据是订阅DataReceived方法,属于观察者模式

  _serialPortObject.DataReceived += PushMessage;

  private void PushMessage(object sender, SerialDataReceivedEventArgs e)
       
                lock (_objLock)
               
                    if (_serialPortObject.IsOpen == false) return;
                    int length = _serialPortObject.BytesToRead; 获取接收缓冲区的字节数
                    byte[] buffer = new byte[length];  //接收数据则字节数组
                    if (length <= 0) return;
                    _serialPortObject.Read(buffer, 0, length);                //从缓冲区获取读取指定字节数据
               
       

关于串口遇到的问题记录:

        串口因为是外接模块所以需要安装对应驱动,最好从串口官网下载指定兼容驱动,不然容易造成蓝屏死机等等问题

51单片机上位机编写与串口通信-深入了解串口

采用环境

VS,keil:

简单介绍

简单的利用VS写上位机 ,和51单片机进行一个通信

单片机通信原理这里不多说直接放链接CSDN有很多很详细的博客

51单片机串口通信原理讲解

C#网上很多教程这里推荐一篇更加详细的博客

C#串口编程

对于串口不理解的可以看这一篇

C#中串口通信SerialPort类

此项目下载地址

https://download.csdn.net/download/chen_taifu/19827747


代码

C51

/*
	开发者邮箱
	@m.t-chen@foxmail.com
	串口发送数据和接收
*/
#include <reg52.h>
#include <stdio.h>
#include "ccom.h"      

//串口寄存器配置
void init()

	TMOD=0x20;	  		//定时器工作方式,选择了定时器1,工作方式2 八位初值自动重装的8位定时器。		 
	TH1=0xfd;	  			//定时器1初值	,设置波特率为9600 晶振11.0529MHZ?
	TL1=0xfd;
	TR1=1;		 				//打开计数器	 TCON
	SCON=0X50;				//设置为工作方式1 (10位/8位数据)允许串口接收位
	EA=1;	      			//允许中断(总闸)
	ES=1;		 		 			//允许串口中断


void main()

	init();								//初始化
	while(1)

	  if(bzf_cz==1)				//接收到数据运行
	
		if(bzf_hh!=0)		    //是否需要换行检测
		
			bzf_hh=0;					//重置
			TI=1;						
			printf("\\n");			//换行
			while(!TI);
			TI=0;
		
			for(i=0;i<50;i++)
		
			SBUF=s[i];
			while(!TI);
			TI=0;
		
		bzf_cz=0;
	


 
void ser() interrupt 4

		if(RI)		 								//接收数据,手动将RI清0
		    
		RI=0;
		
		if(bzf_cz==0&&j!=0)  			//第二次输入后将数组a还原
		
			for(j=0;j<50;j++)				//最大50个字符
			s[j]='\\0';
			j=0;
			bzf_hh=1;								//换行标识符
		
		s[j]=SBUF;								//读取数据到s
		bzf_cz=1;						      //接收标识符
		j++;	
	 

上位机项目建立流程

新建项目/Visual C# 选择窗体应用

控件有label1 ,comboBox,textBox,button,

容器panel

组件serialPort

代码

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.Text.RegularExpressions;

namespace _51串口机

    public partial class Form1 : Form
    
        private StringBuilder sb = new StringBuilder();     //为了避免在接收处理函数中反复调用,依然声明为一个全局变量
        public Form1()
        
            InitializeComponent();

        

        private void Form1_Load(object sender, EventArgs e)
        

            int i;
            for (i = 300; i <= 38400; i = i * 2)
            
                comboBox2.Items.Add(i.ToString());  //添加波特率列表
            
            //获取电脑当前可用串口并添加到选项列表中
            comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());
            //批量添加波特率列表
            string[] comboxD =  "43000", "56000", "57600", "115200", "128000", "230400", "256000", "460800" ;
            comboBox2.Items.AddRange(comboxD);

            //添加数据位列表
            string[] comboxA =  "6", "7", "8" ;
            comboBox3.Items.AddRange(comboxA);

            //添加校验位列表
            string[] comboxC =  "0", "1" ;
            comboBox4.Items.AddRange(comboxC);

            //添加停止位位列表
            string[] comboxB =  "1.5", "2" ;
            comboBox5.Items.AddRange(comboxB);

            //设置默认值
            comboBox1.Text = "COM1";
            comboBox2.Text = "9600";
            comboBox3.Text = "8";
            comboBox4.Text = "None";
            comboBox5.Text = "1";
        
        private void button1_Click(object sender, EventArgs e)
        
            try
            
                //将可能产生异常的代码放置在try块中
                //根据当前串口属性来判断是否打开
                if (serialPort1.IsOpen)
                
                    //串口已经处于打开状态
                    serialPort1.Close();    //关闭串口
                    button1.Text = "打开串口";
                    button1.BackColor = Color.ForestGreen;
                    comboBox1.Enabled = true;
                    comboBox2.Enabled = true;
                    comboBox3.Enabled = true;
                    comboBox4.Enabled = true;
                    comboBox5.Enabled = true;
                    textBox1.Text = "";     //清空接收区
                    textBox2.Text = "";     //清空发送区
                
                else
                
                    //串口已经处于关闭状态,则设置好串口属性后打开
                    comboBox1.Enabled = false;
                    comboBox2.Enabled = false;
                    comboBox3.Enabled = false;
                    comboBox4.Enabled = false;
                    comboBox5.Enabled = false;
                    serialPort1.PortName = comboBox1.Text;
                    serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);
                    serialPort1.DataBits = Convert.ToInt16(comboBox3.Text);

                    if (comboBox4.Text.Equals("None"))
                        serialPort1.Parity = System.IO.Ports.Parity.None;
                    else if (comboBox4.Text.Equals("Odd"))
                        serialPort1.Parity = System.IO.Ports.Parity.Odd;
                    else if (comboBox4.Text.Equals("Even"))
                        serialPort1.Parity = System.IO.Ports.Parity.Even;
                    else if (comboBox4.Text.Equals("Mark"))
                        serialPort1.Parity = System.IO.Ports.Parity.Mark;
                    else if (comboBox4.Text.Equals("Space"))
                        serialPort1.Parity = System.IO.Ports.Parity.Space;

                    if (comboBox5.Text.Equals("1"))
                        serialPort1.StopBits = System.IO.Ports.StopBits.One;
                    else if (comboBox5.Text.Equals("1.5"))
                        serialPort1.StopBits = System.IO.Ports.StopBits.OnePointFive;
                    else if (comboBox5.Text.Equals("2"))
                        serialPort1.StopBits = System.IO.Ports.StopBits.Two;

                    serialPort1.Open();     //打开串口
                    button1.Text = "关闭串口";
                    button1.BackColor = Color.Firebrick;
                
            
            catch (Exception ex)
            
                //捕获可能发生的异常并进行处理

                //捕获到异常,创建一个新的对象,之前的不可以再用
                serialPort1 = new System.IO.Ports.SerialPort();
                //刷新COM口选项
                comboBox1.Items.Clear();
                comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());
                //响铃并显示异常给用户
                System.Media.SystemSounds.Beep.Play();
                button1.Text = "打开串口";
                button1.BackColor = Color.ForestGreen;
                MessageBox.Show(ex.Message);
                comboBox1.Enabled = true;
                comboBox2.Enabled = true;
                comboBox3.Enabled = true;
                comboBox4.Enabled = true;
                comboBox5.Enabled = true;
            
        

        private void SerialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        
            sb.Clear();                              //防止出错,首先清空字符串构造器
            int num = serialPort1.BytesToRead;      //获取接收缓冲区中的字节数
            byte[] received_buf = new byte[num];    //声明一个大小为num的字节数据用于存放读出的byte型数据

            serialPort1.Read(received_buf, 0, num);   //读取接收缓冲区中num个字节到byte8位类型 received数组中

            sb.Append(Encoding.ASCII.GetString(received_buf));  //将整个数组解码为ASCII数组
            foreach (byte b in received_buf) //遍历数组进行字符串转化及拼接
            
                sb.Append(b.ToString());
            

            try
            
                //因为要访问UI资源,所以需要使用invoke方式同步ui
                Invoke((EventHandler)(delegate
                
                    textBox1.AppendText(sb.ToString());
                
                ));

            
            catch (Exception ex)
            
                //响铃并显示异常给用户
                System.Media.SystemSounds.Beep.Play();
                MessageBox.Show(ex.Message);

            

        

        private void label6_Click(object sender, EventArgs e)
        

        

        private void button2_Click(object sender, EventArgs e)
         
            try
            

                //首先判断串口是否开启
                if (serialPort1.IsOpen)
                
                    serialPort1.Write(textBox2.Text);

                
            
            catch (Exception ex)
            
                serialPort1.Close();
                //捕获到异常,创建一个新的对象,之前的不可以再用
                serialPort1 = new System.IO.Ports.SerialPort();
                //刷新COM口选项
                comboBox1.Items.Clear();
                comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());
                //响铃并显示异常给用户
                System.Media.SystemSounds.Beep.Play();
                button1.Text = "打开串口";
                button1.BackColor = Color.ForestGreen;
                MessageBox.Show(ex.Message);
                comboBox1.Enabled = true;
                comboBox2.Enabled = true;
                comboBox3.Enabled = true;
                comboBox4.Enabled = true;
                comboBox5.Enabled = true;
            
        

        private void button3_Click(object sender, EventArgs e)
        
            textBox2.Text = "";  //清空接收文本框
            textBox1.Text = "";     //清空发送文本框
        
    

以上是关于C# 串口通信的主要内容,如果未能解决你的问题,请参考以下文章

Unity串口通信接受和发送数据C#

C#串口介绍及串口通信程序设计实现(附程序分享)

C#串口通信中的await事件和超时

c#如何实现串口通信读取数据

C#中的串口通信SerialPort

C# 串口通信