前几天做毕业设计,其中要用到串口和下位机进行通信,于是自己捣鼓了一个简单的串口通信程序。

在做通信之前要先弄一个SerialPort组件出来,当然也可以通过程序来创建。本次设计中采用的是拖的winform中提供的组件,效果是一样的。不过要使程序正确的运行起来,电脑上要安装一个pl232的驱动,安装完成后,还必须要插入一根串口线才行,或者是USB转串口的线也可以。

SerialPort有很多的属性和方法,但是在我做的这个简单的串口通信中用到的属性和方法很少,可以讲VS调出来看看有哪些属性和方法,有很多的属性已经帮我们设置好了,利用默认的设置就行

1、设置COM口

串口通信是需要利用计算机的COM接口,而很多的接口是被其它程序使用的,故首先要获得计算机当前我们程序中能够使用的COM接口,首先要添加一个引用:Microsoft.VisualBasic

<span style="font-size:18px;">	private string LoadSerial ()
{
Microsoft.VisualBasic.Devices.Computer pc;
pc = new Microsoft.VisualBasic.Devices.Computer();
//判断能够使用的COM口数量
if (pc.Ports.SerialPortNames.Count > 0)
{
//当有COM口可以使用的时候,将第一个COM口赋值给属性PortName
//也可以直接:serial.PortName = "COM2"; 指明了要使用COM2接口
serial.PortName = pc.Ports.SerialPortNames[0];
serial.BaudRate = 115200; //设置通信的波特率,默认的是9600,所以也可以不用设置
serial.StopBits = System.IO.Ports.StopBits.One; //停止位的位数,一般的串口通信都有停止位
serial.DateBit = 8; //数据位数,每一帧有效数据的位数,默认的为8,这个根据需要设置
}
else
{
return "系统没有可用串口,请检查和下位机连线是否正常";
}
return "OK";
}</span>

我设置的属性也基本上都是这些,其他的什么读缓存大小写缓存大小以及什么读取超时和写超时等等都使用默认的就OK,主要还是COM端口的设置

2、发送数据

串口通信,对方是下位机,故在通信中采用的是ASCII码,所以要先将数据转换成二进制然后进行发送,由于系统会自动的添加什么启示结束位等,我们也就不需要关系,直接将要发送的数据丢给他就行,当然也可以手动的进行判断。发送数据前需要先打开串口。

<span style="font-size:18px;">		try
{
if (!serial.IsOpen) //判断串口是否打开,会返回一个布尔值
{
serial.Open(); //如果串口没有打开就打开串口
}
byte[] by = ASCIIEncoding.ASCII.GetBytes("b"); //将要发送的数据转换成二进制
serial.Write(by, 0, by.Length); //发送
}
catch (Exception ex)
{
return "请求结束出错:" + ex.Message;
}</span>

因为要打开串口,串口是硬件资源,打开的时候很可能会失败抛异常,故用一个try...catch...语句包起来。发送数据的方法还有一个WriteLine,但个人觉得用Wrte更好。其实严格的讲,在发送之前应该先判断是否能够进行发送,这可以通过属性来完成,在这里就没有判断了,直接发送。

3、创建一个接收数据的后台线程

本次用串口来进行通信主要是用来接收数据,就收数据中没有采用系统提供的事件机制,而是创建了一个后台的线程来进行不断的监视读取缓存中有没有数据。先创建后台线程:

<span style="font-size:18px;">	private string LoadThread()
{
try
{ Thread thread = new Thread(ReceiveDate); //传递的是接收数据的方法,这个方法中用来接收数据
thread.Name = "serialThread";
thread.IsBackground = true;//设置线程为后台线程,前台关闭,此线程也就关闭
thread.Start();
}
catch (Exception ex)
{
return "出错了!" + ex.Message;
}
return "OK";
}</span>

4、数据的接收和处理

设计中事先约定好的通信协议就是:总共七位数据,第一位是ABCDE五个字符中任意一个,第二位是数字,第三位是小数点,第4~6位是数字,最后一位是字符V。

由于ASCII中得到的空格和换行符是用"\0"和“\n”来表示的利用string.trim()方法是不能够将这个给移除的,所以每次都只是读取一位数据,当然这样肯定会影响通信的效率。读取一位数据后先判断是不是空格和换行,是就将数据丢弃,一般空格和换行都是出现在上一组数据发送完成后才有的,没有考虑数据出错后变为"\0"和"\n"的问题,这也算是一个漏洞。七位数据接收完成后,通过正则表达式来进行验证,验证通过后将数据存入到事先准备好的字典中,字典的关键字是七位数据中的第一位子字符串,值是一个字符串集合,用来将小数点去掉后四位数字组成的字符串存储下来。

代码如下:

<span style="font-size:18px;">	//声明一个字典,存放数据
Dictionary<string, List<string>> receiveDate = null;
private void ReceiveDate ()
{
string date = ""; //保存接收的数据
//实例化这个字典
receiveDate = new Dictionary<string, List<string>>();
string datePath = "";//用来存放,当前是那一路的信号
int index = 0; //七位数据,用来标识接收的是第几位数据
DateTime time1=DateTime.Now;
while (true)
{
try
{
if (serial.IsOpen) //如果串口打开就进行数据的读取
{
if (serial.BytesToRead > 0) //先判断读缓存中有没有数据
{
byte[] byteDate = new byte[1]; //设置每一次读取的字节数为1
serial.Read(byteDate, 0, byteDate.Length);
string strDate = ASCIIEncoding.ASCII.GetString(byteDate);
if (strDate == "\0" || strDate == "\n")
{
index = 0;
date = "";
continue;
}
else
{
index++; //接收的是多少位数
date += strDate;
}
if (index == 7) //七位数据接收完成
{
//利用正则表达式来进行匹配和数据的提取
Regex reg = new Regex(@"^([ABCDE]{1})(\d{1})\.(\d{3})V$");
Match match = reg.Match(date, 0, date.Length);
if (match.Success)
{
datePath = match.Groups[1].Value;
string numStr = match.Groups[2].Value + match.Groups[3].Value;
int num = -1;
//将接收到的数据进行一个转换,转换成功后保存
if (int.TryParse(numStr, out num))
{
//经过正则表达式验证后,datePath一定是ABCDE中的一个数据,先判断是否包含这个关键字,如果不包含就添加
if (!receiveDate.ContainsKey(datePath))
{
receiveDate[datePath] = new List<int>();//添加关键字就需要声明一个集合赋值给它
}
receiveDate[datePath].Add(num);//将数据存储起来
time = DateTime.Now; //记录正确接收数据的时间
}
}
//清空,进入下一轮的数据接收
date = "";
datePath = "";
index = 0;
}
}
else
{
<span style="white-space: pre;"> </span>//这个else中做的事情是如果长时间接收不到数据就添加0,代码就不附加了
}
}
}
catch (Exception ex)
{ }
}
}</span>

到此,一个简单的串口通信程序就搞定了。

C#--简单的串口通信程序的更多相关文章

  1. Qt编写串口通信程序全程图文解说

    (说明:我们的编程环境是windows xp下,在Qt Creator中进行,假设在Linux下或直接用源代码编写,程序稍有不同,请自己修改.) 在Qt中并没有特定的串口控制类,如今大部分人使用的是第 ...

  2. 转:Qt编写串口通信程序全程图文讲解

    转载:http://blog.csdn.net/yafeilinux/article/details/4717706  作者:yafeilinux (说明:我们的编程环境是windows xp下,在Q ...

  3. Qt编写串口通信程序全程图文讲解 .

    在Qt中并没有特定的串口控制类,现在大部分人使用的是第三方写的qextserialport类,我们这里也是使用的该类.我们可以去 http://sourceforge.net/projects/qex ...

  4. 【转】Qt编写串口通信程序全程图文讲解

    本文章原创于www.yafeilinux.com 转载请注明出处. (说明:我们的编程环境是windows xp下,在Qt Creator中进行,如果在Linux下或直接用源码编写,程序稍有不同,请自 ...

  5. C#中缓存的使用 ajax请求基于restFul的WebApi(post、get、delete、put) 让 .NET 更方便的导入导出 Excel .net core api +swagger(一个简单的入门demo 使用codefirst+mysql) C# 位运算详解 c# 交错数组 c# 数组协变 C# 添加Excel表单控件(Form Controls) C#串口通信程序

    C#中缓存的使用   缓存的概念及优缺点在这里就不多做介绍,主要介绍一下使用的方法. 1.在ASP.NET中页面缓存的使用方法简单,只需要在aspx页的顶部加上一句声明即可:  <%@ Outp ...

  6. 创建C#串口通信程序详解

    在.NET平台下创建C#串口通信程序,.NET 2.0提供了串口通信的功能,其命名空间是System.IO.Ports.这个新的框架不但可以访问计算机上的串口,还可以和串口设备进行通信.我们将使用标准 ...

  7. C#串口通信程序详解

    C#串口通信程序详解 摘要:创建C#串口通信程序需要注意什么呢?创建C#串口通信程序的步骤是什么?那么本文就向你详细介绍创建C#串口通信程序集体的内容. 在.NET平台下创建C#串口通信程序,.NET ...

  8. C语言PIC16 serial bootloader和C#语言bootloader PC端串口通信程序

    了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). 新PIC16 Boot ...

  9. C#实现简单的串口通信

    前言 本着学习研究的态度,用c#语言实现简单的串口通信工具. 一.串口通信原理 串口通信 串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节.尽管比 ...

随机推荐

  1. DataGridView取消默认选中行

    DataGridView在添加数据后会默认选中第 一个单元格或者第一行,我就想取消它的默认选中行.在DataGridView绑定数据之后加上了ClearSelection().这样一来,不论是启动窗体 ...

  2. 获取屏幕分辨率(C#)

    C#获取屏幕分辨率的方法 static void Main(string[] args) { // 控制台程序,需要添加程序集: // using System.Drawing; // using S ...

  3. 取消双向绑定、输出html代码

    1.取消双向绑定,在绑定的值前加*号. 如: <div id="app"> <p>{{*message}}</p> </div> 2 ...

  4. js日期格式化方法 dateFormatFn

    var dateFormatFn=function(val,fmt){ var _this = new Date(val); console.log(_this,_this.getFullYear() ...

  5. redis 配置文件解读

    # Redis 配置文件 # 当配置中需要配置内存大小时,可以使用 1k, 5GB, 4M 等类似的格式,其转换方式如下(不区分大小写) # # 1k => 1000 bytes # 1kb = ...

  6. 如何解决加载动态链接库DLL失败,返回0,GetLastError返回错误码126

    通常情况下使用LoadLibrary加载DLL都可以成功,但是当被加载的DLL内部依赖其他DLL无法被找到时,该函数会返回126(ERROR_MOD_NOT_FOUND)错误. 解决办法有2种: 1) ...

  7. python中列表和元组的使用方法和区别

    一.二者区别 列表: 1.可以增加列表内容     append 2.可以统计某个列表段在整个列表中出现的次数 count 3.可以插入一个字符串,并把整个字符串的每个字母拆分当作一个列表段追加到列表 ...

  8. 深入理解Java String#intern() 内存模型

    原文出处: codelog.me 大家知道,Java中string.intern()方法调用会先去字符串常量池中查找相应的字符串,如果字符串不存在,就会在字符串常量池中创建该字符串然后再返回. 字符串 ...

  9. Python学习教程(learning Python)--3.3.2 Python的关系运算

    如果if的condition不用布尔表达式来做条件判断而采用关系表达式,实际上关系表达式运算的结果要么是True要么是False.下面我们先了解一些有关关系运算符的基础知识,如下表所示. 做个小程序测 ...

  10. ping通IP,telnet 3306不通

    一个同事装的MySQL数据库,无法连接.​​1.查看权限​​2.查看防火墙​​检查用户权限,防火墙都没问题,就是无法连接,能ping通,但是telnet 3306 端口无法成功.​​检查了下数据库配置 ...