-
2020-06-20 14:12:48
c#串口程序接收数据并打印
In this C# program – we are going to print size of various data types, to print size of a type, we use sizeof() operator.
在此C#程序中–我们将打印各种数据类型的大小,并使用typeof()运算符打印类型的大小。
It accepts a data type and returns its size in the memory.
它接受数据类型并在内存中返回其大小。
Example:
例:
// C# program to C# program to print // size of various data types using System; using System.IO; using System.Text; namespace IncludeHelp { class Test { // Main Method static void Main(string[] args) { Console.WriteLine("sizeof(int): {0}", sizeof(int)); Console.WriteLine("sizeof(float): {0}", sizeof(float)); Console.WriteLine("sizeof(char): {0}", sizeof(char)); Console.WriteLine("sizeof(double): {0}", sizeof(double)); Console.WriteLine("sizeof(bool): {0}", sizeof(bool)); //hit ENTER to exit the program Console.ReadLine(); } } }
Output
输出量
sizeof(int): 4 sizeof(float): 4 sizeof(char): 2 sizeof(double): 8 sizeof(bool): 1
翻译自: https://www.includehelp.com/dot-net/print-size-of-various-data-types-in-c-sharp.aspx
c#串口程序接收数据并打印
更多相关内容 -
C#串口程序.rar
2019-08-24 20:30:31C#串口程序,例程演示串口的发送与接收。 简单的C#串口通讯例子(附源文件) -
[002]C#串口程序.zip上位机开发VC串口学习资料源码下载
2022-05-03 23:47:04[002]C#串口程序.zip上位机开发VC串口学习资料源码下载[002]C#串口程序.zip上位机开发VC串口学习资料源码下载[002]C#串口程序.zip上位机开发VC串口学习资料源码下载[002]C#串口程序.zip上位机开发VC串口学习资料源码... -
C#串口程序
2013-04-16 17:27:17C# 串口程序C#中串口通信编程 收藏 本文将介绍如何在.NET平台下使用C#创建串口通信程序,.NET 2.0提供了串口通信的功能,其命名 空间是System.IO.Ports。这个新的框架不但可以访问计算机上的串口,还可以和串口... -
vs c#串口程序
2017-09-30 13:37:04用c#写的串口程序,vs2015上运行没问题 using System.IO.Ports; -
C# 串口程序
2013-03-26 20:45:21自己写的,适合刚开始学习串口的同学!基本上没有问题,蛮实用的! -
SerialPort.rar_C# 串口ASCII_C#串口发送ASCII_串口通信程序_用C
2022-07-14 09:00:13用C#编写的用ASCII码发送的串口通信程序 -
C#串口数据接收储存程序
2021-11-21 21:55:05C#编写,正常使用过没问题 -
C# 串口程序源码
2013-11-21 11:00:051、源代码,简单界面设置,详细的备注,看后大家对串口调试有个基本了解,可根据自己项目的需要进行创新; 2、可单机调试,将RS232用导线连接2、3脚连接即可; -
为什么C#串口程序在关闭串口时候会死锁
2015-07-30 10:48:12为什么C#串口程序在关闭串口时候会死锁_老文章_赛迪网 http://www.ccidnet.com/2010/0524/2067861.shtml 【赛迪网讯】用过微软SerialPort类的人,都遇到过这个尴尬,关闭串口的时候会让软件死锁。天哪,我可...为什么C#串口程序在关闭串口时候会死锁_老文章_赛迪网 http://www.ccidnet.com/2010/0524/2067861.shtml
【赛迪网讯】用过微软SerialPort类的人,都遇到过这个尴尬,关闭串口的时候会让软件死锁。天哪,我可不是武断,算了。不要太绝对了。99.9%的人吧,都遇到过这个问题。我想只有一半的人真的解决了。另外一半的人就睁只眼闭只眼阿弥佗佛希望不要在客户那里出现这问题了。
view plaincopy to clipboardprint? void comm_DataReceived(object sender, SerialDataReceivedEventArgs e) { //先记录下来,避免某种原因,人为的原因, 操作几次之间时间长,缓存不一致 int n = comm.BytesToRead; //声明一个临时数组存储当前来的串口数据 byte[] buf = new byte[n]; //增加接收计数 received_count += n; //读取缓冲数据 comm.Read(buf, 0, n); //清除字符串构造器的内容 builder.Clear(); //因为要访问ui资源,所以需要使用invoke方式同步ui。 this.Invoke((EventHandler)(delegate{...界面更新,略})); } private void buttonOpenClose_Click(object sender, EventArgs e) { //根据当前串口对象,来判断操作 if (comm.IsOpen) { //打开时点击,则关闭串口 comm.Close();//这里就是可能导致软件死掉的地方 } else {...} } void comm_DataReceived(object sender, SerialDataReceivedEventArgs e) { //先记录下来,避免某种原因,人为的原因, 操作几次之间时间长,缓存不一致 int n = comm.BytesToRead; //声明一个临时数组存储当前来的串口数据 byte[] buf = new byte[n]; //增加接收计数 received_count += n; //读取缓冲数据 comm.Read(buf, 0, n); //清除字符串构造器的内容 builder.Clear(); //因为要访问ui资源,所以需要使用invoke方式同步ui。 this.Invoke((EventHandler)(delegate{...界面更新,略})); } private void buttonOpenClose_Click(object sender, EventArgs e) { //根据当前串口对象,来判断操作 if (comm.IsOpen) { //打开时点击,则关闭串口 comm.Close();//这里就是可能导致软件死掉的地方 } else {...} }
为什么会死锁呢,并发冲突。 我们要了解一下SerialPort的实现和串口通讯机制,在你打开串口的时候,SerialPort会创建一个监听线程ListenThread,在这个线程中,等待注册的串口中断,当收到中断后,会调用DataReceived事件。调用完成后,继续进入循环等待,直到串口被关闭退出线程。 我们的UI主线程如何做的呢,首先创建一个窗体,然后执行了Application.Run(窗体实例)。是这样把,这里的Application.Run就是创建了一个消息循环,循环的处理相关的消息。 这里我们就有了2个线程,UI主线程、串口监听线程。那么你在DataReceived处理数据的时候,就需要线程同步,避免并发冲突,什么是并发冲突?并发冲突就是2个或多个并行(至少看上去像)的线程运行的时候,多个线程共同的操作某一线程的资源,在时序上同时或没有按我们的预计顺序操作,这样就可能导致数据混乱无序或是彼此等待完成死锁软件。 而串口程序大多是后者。为什么呢,看看我们的例子中DataReceived做了什么?首先读取数据,然后就是调用this.Invoke方法更新UI了。这里Invoke的时候,监听线程将等待UI线程的标志,等到后,开始操作UI的资源,当操作完成之前,监听线程也就停在DataReceived方法的调用这里,如果这个时候。并发了关闭串口的操作会如何呢?SerialPort的Close方法,会首先尝试等待和监听线程一样的一个互斥体、临界区、或是事件(不确定.net用的哪种)。那这个同步对象什么时候释放呢?每次循环结束就释放,哦。循环为什么不结束呢?因为这一次的循环操作执行到DataReceived之后,执行了Invoke去更新界面了,那Invoke怎么又没有执行完成呢?看上去很简单的几行代码。虽然我没仔细研读过.net的Invoke原理,但我猜测是通过消息的方式来同步的,这也是为什么这么多的类,只有控件(窗体也是控件的一种,.net在概念上,颠覆了微软自己的概念,传统的win32编程,是说所有的控件都是个window,只是父窗体不同,表现形式不同,但都是基于系统消息队列的,.net出于更高的抽象,正好反过来了。呵呵)才有Invoke方法了。(委托自己的Invoke和这个不同) 我猜测控件/窗体的Invoke是SendMessage方式实现的,那么发送消息后就会等待消息循环来处理消息了。如果你直接去关闭串口了。你点击按钮本身也会被转换成消息WM_CLICK,消息循环在处理按钮的WM_CLICK时候,调用你按钮的OnClick方法,进而触发调用你的ButtonClose_Click事件,这都是同步调用的,你的主线程,处理消息的过程,停在了这个Click事件,而你的Click事件又去调用了SerialPort的Close方法,Close方法又因为和串口监听线程的同步信号量关联在一起需要等待一次的while结束,而这个while循环中调用了DataReceived方法,这个方法中调用了Invoke,也就是发送了消息到消息队列等待结果,但消息循环正在处理你的关闭按钮事件等待退出。 实在太复杂了,这个情况下,你想要真的关闭串口成功,就需要while中的DataReceived方法调用结束释放同步信号,就需要执行完Invoke,就需要执行消息循环,幸运的是,我们真的有办法执行消息循环来打破僵局。Application.DoEvents()。还好,不幸中的万幸。可是问题又来了,你能让Invoke结束,但你无法确定是否在你调用消息循环后,你的某一时刻不会再次并发,可能由于单cpu的串行操作模拟并行中,又把时间片先分给了优先级高的串口监听线程呢?是有可能的。所以,我们就需要一点方法来避免再次invoke窗体。优化后不会司机的例子如下,我们修改DataReceived方法,关闭方法,并定义2个标记Listening和Closing。
view plaincopy to clipboardprint? 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; using System.Text.RegularExpressions; namespace SerialportSample { public partial class SerialportSampleForm : Form { private SerialPort comm = new SerialPort(); private StringBuilder builder = new StringBuilder(); //避免在事件处理方法中反复的创建,定义到外面。 private long received_count = 0;//接收计数 private long send_count = 0;//发送计数 private bool Listening = false; //是否没有执行完invoke相关操作 private bool Closing = false; //是否正在关闭串口,执行Application.DoEvents, 并阻止再次invoke public SerialportSampleForm() { InitializeComponent(); } //窗体初始化 private void Form1_Load(object sender, EventArgs e) { //初始化下拉串口名称列表框 string[] ports = SerialPort.GetPortNames(); Array.Sort(ports); comboPortName.Items.AddRange(ports); comboPortName.SelectedIndex = comboPortName.Items.Count > 0 ? 0 : -1; comboBaudrate.SelectedIndex = comboBaudrate.Items.IndexOf("9600"); //初始化SerialPort对象 comm.NewLine = "\r\n"; comm.RtsEnable = true;//根据实际情况吧。 //添加事件注册 comm.DataReceived += comm_DataReceived; } void comm_DataReceived (object sender, SerialDataReceivedEventArgs e) { if (Closing) return; //如果正在关闭,忽略操作,直接返回, 尽快的完成串口监听线程的一次循环 try { Listening = true; //设置标记,说明我已经开始处理数据, 一会儿要使用系统UI的。 int n = comm.BytesToRead; //先记录下来,避免某种原因,人为的原因, 操作几次之间时间长,缓存不一致 byte[] buf = new byte[n]; //声明一个临时数组存储当前来的串口数据 received_count += n;//增加接收计数 comm.Read(buf, 0, n);//读取缓冲数据 builder.Clear();//清除字符串构造器的内容 //因为要访问ui资源,所以需要使用invoke方式同步ui。 this.Invoke((EventHandler)(delegate { //判断是否是显示为16禁止 if (checkBoxHexView.Checked) { //依次的拼接出16进制字符串 foreach (byte b in buf) { builder.Append(b.ToString("X2") + " "); } } else { //直接按ASCII规则转换成字符串 builder.Append(Encoding.ASCII.GetString(buf)); } //追加的形式添加到文本框末端,并滚动到最后。 this.txGet.AppendText(builder.ToString()); //修改接收计数 labelGetCount.Text = "Get:" + received_count.ToString(); })); } finally { Listening = false;//我用完了,ui可以关闭串口了。 } } private void buttonOpenClose_Click(object sender, EventArgs e) { //根据当前串口对象,来判断操作 if (comm.IsOpen) { Closing = true; while (Listening) Application.DoEvents(); //打开时点击,则关闭串口 comm.Close(); } else { //关闭时点击,则设置好端口,波特率后打开 comm.PortName = comboPortName.Text; comm.BaudRate = int.Parse(comboBaudrate.Text); try { comm.Open(); } catch(Exception ex) { //捕获到异常信息,创建一个新的comm对象, 之前的不能用了。 comm = new SerialPort(); //现实异常信息给客户。 MessageBox.Show(ex.Message); } } //设置按钮的状态 buttonOpenClose.Text = comm.IsOpen ? "Close" : "Open"; buttonSend.Enabled = comm.IsOpen; } //动态的修改获取文本框是否支持自动换行。 private void checkBoxNewlineGet_CheckedChanged (object sender, EventArgs e) { txGet.WordWrap = checkBoxNewlineGet.Checked; } private void buttonSend_Click(object sender, EventArgs e) { //定义一个变量,记录发送了几个字节 int n = 0; //16进制发送 if (checkBoxHexSend.Checked) { //我们不管规则了。如果写错了一些,我们允许的, 只用正则得到有效的十六进制数 MatchCollection mc = Regex.Matches(txSend.Text, @"(?i)[\da-f]{2}"); List<byte> buf = new List<byte>(); //填充到这个临时列表中 //依次添加到列表中 foreach (Match m in mc) { buf.Add(byte.Parse(m.Value)); } //转换列表为数组后发送 comm.Write(buf.ToArray(), 0, buf.Count); //记录发送的字节数 n = buf.Count; } else//ascii编码直接发送 { //包含换行符 if (checkBoxNewlineSend.Checked) { comm.WriteLine(txSend.Text); n = txSend.Text.Length + 2; } else//不包含换行符 { comm.Write(txSend.Text); n = txSend.Text.Length; } } send_count += n;//累加发送字节数 labelSendCount.Text = "Send:" + send_count.ToString(); //更新界面 } private void buttonReset_Click(object sender, EventArgs e) { //复位接受和发送的字节数计数器并更新界面。 send_count = received_count = 0; labelGetCount.Text = "Get:0"; labelSendCount.Text = "Send:0"; } } }
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; using System.Text.RegularExpressions; namespace SerialportSample { public partial class SerialportSampleForm : Form { private SerialPort comm = new SerialPort(); private StringBuilder builder = new StringBuilder(); //避免在事件处理方法中反复的创建,定义到外面。 private long received_count = 0; //接收计数 private long send_count = 0; //发送计数 private bool Listening = false; //是否没有执行完invoke相关操作 private bool Closing = false; //是否正在关闭串口,执行Application.DoEvents, 并阻止再次invoke public SerialportSampleForm() { InitializeComponent(); } //窗体初始化 private void Form1_Load(object sender, EventArgs e) { //初始化下拉串口名称列表框 string[] ports = SerialPort.GetPortNames(); Array.Sort(ports); comboPortName.Items.AddRange(ports); comboPortName.SelectedIndex = comboPortName.Items.Count > 0 ? 0 : -1; comboBaudrate.SelectedIndex = comboBaudrate.Items.IndexOf("9600"); //初始化SerialPort对象 comm.NewLine = "\r\n"; comm.RtsEnable = true; //根据实际情况吧。 //添加事件注册 comm.DataReceived += comm_DataReceived; } void comm_DataReceived (object sender, SerialDataReceivedEventArgs e) { if (Closing) return; //如果正在关闭,忽略操作,直接返回, 尽快的完成串口监听线程的一次循环 try { Listening = true; //设置标记,说明我已经开始处理数据, 一会儿要使用系统UI的。 int n = comm.BytesToRead; //先记录下来,避免某种原因,人为的原因, 操作几次之间时间长,缓存不一致 byte[] buf = new byte[n]; //声明一个临时数组存储当前来的串口数据 received_count += n; //增加接收计数 comm.Read(buf, 0, n); //读取缓冲数据 builder.Clear(); //清除字符串构造器的内容 //因为要访问ui资源,所以需要使用invoke方式同步ui。 this.Invoke((EventHandler)(delegate { //判断是否是显示为16禁止 if (checkBoxHexView.Checked) { //依次的拼接出16进制字符串 foreach (byte b in buf) { builder.Append(b.ToString("X2") + " "); } } else { //直接按ASCII规则转换成字符串 builder.Append(Encoding.ASCII.GetString(buf)); } //追加的形式添加到文本框末端,并滚动到最后。 this.txGet.AppendText(builder.ToString()); //修改接收计数 labelGetCount.Text = "Get:" + received_count.ToString(); })); } finally { Listening = false;//我用完了,ui可以关闭串口了。 } } private void buttonOpenClose_Click(object sender, EventArgs e) { //根据当前串口对象,来判断操作 if (comm.IsOpen) { Closing = true; while (Listening) Application.DoEvents(); //打开时点击,则关闭串口 comm.Close(); } else { //关闭时点击,则设置好端口,波特率后打开 comm.PortName = comboPortName.Text; comm.BaudRate = int.Parse(comboBaudrate.Text); try { comm.Open(); } catch(Exception ex) { //捕获到异常信息,创建一个新的comm对象, 之前的不能用了。 comm = new SerialPort(); //现实异常信息给客户。 MessageBox.Show(ex.Message); } } //设置按钮的状态 buttonOpenClose.Text = comm.IsOpen ? "Close" : "Open"; buttonSend.Enabled = comm.IsOpen; } //动态的修改获取文本框是否支持自动换行。 private void checkBoxNewlineGet_CheckedChanged (object sender, EventArgs e) { txGet.WordWrap = checkBoxNewlineGet.Checked; } private void buttonSend_Click(object sender, EventArgs e) { //定义一个变量,记录发送了几个字节 int n = 0; //16进制发送 if (checkBoxHexSend.Checked) { //我们不管规则了。如果写错了一些, //我们允许的,只用正则得到有效的十六进制数 MatchCollection mc = Regex.Matches(txSend.Text, @"(?i)[\da-f]{2}"); List<byte> buf = new List<byte>();//填充到这个临时列表中 //依次添加到列表中 foreach (Match m in mc) { buf.Add(byte.Parse(m.Value)); } //转换列表为数组后发送 comm.Write(buf.ToArray(), 0, buf.Count); //记录发送的字节数 n = buf.Count; } else//ascii编码直接发送 { //包含换行符 if (checkBoxNewlineSend.Checked) { comm.WriteLine(txSend.Text); n = txSend.Text.Length + 2; } else//不包含换行符 { comm.Write(txSend.Text); n = txSend.Text.Length; } } send_count += n; //累加发送字节数 labelSendCount.Text = "Send:" + send_count.ToString(); //更新界面 } private void buttonReset_Click(object sender, EventArgs e) { //复位接受和发送的字节数计数器并更新界面。 send_count = received_count = 0; labelGetCount.Text = "Get:0"; labelSendCount.Text = "Send:0"; } } }
至此,不会再出现关闭死锁问题了。 希望这篇文章能解你的燃眉之急,非常高兴能与读者分享我层遇到,大多数人都遇到的这个问题。如果说的不明白,欢迎讨论。 后续的有关通讯程序底层设计的文章会讲述一个具有丰富扩展性,但有设计简介的万能通讯库,支持网络、蓝牙、串口通讯、并口通讯。但不要指望我都实现出来了,我只是设计出这个框架。
-
c#串口程序c#串口程序
2010-01-13 10:43:08简单的实现收发数据!c#串口程序c#串口程序 -
C#串口收发数据,很简单!
2021-07-06 16:51:54实现串口收发,详细注释,通俗易懂,,看了代码就发现,就这?就这么简单?是的!不会亏! -
C#编写串口程序(详细教程) 中文PDF版.rar
2020-02-06 03:35:23C#编写串口程序(详细教程) 中文PDF版,侧可以正常使用。C#编写串口程序(详细教程) 中文PDF版 -
C#串口编程实例代码
2020-09-01 20:09:08主要为大家详细介绍了C#串口编程实例代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 -
C# 串口通信 最基础程序(附带注释)
2020-10-13 18:53:56C#要实现串口通信一定要创建一个Form,添加一个serialPort控件 源码及说明 这是一个连接COM3串口,通过键盘摁键发出信息的基础程序(摁键对应小键盘的1,2,3) using System; using System.Collections.Generic; ...前提
C#要实现串口通信一定要创建一个Form源码及说明
这是一个连接COM3串口,通过键盘摁键发出信息的基础程序(摁键对应小键盘的1,2,3)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.IO.Ports; using System.Text.RegularExpressions; namespace 上位机串口程序 { public partial class Form1 : Form { SerialPort sp1 = new SerialPort(); public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { Control.CheckForIllegalCrossThreadCalls = false; //这个类中我们不检查跨线程的调用是否合法(因为.net 2.0以后加强了安全机制,,不允许在winform中直接跨线程访问控件的属性) sp1.DataReceived += new SerialDataReceivedEventHandler(sp1_DataReceived);//接收到数据时的委托事件 //sp1.ReceivedBytesThreshold = 1; //准备就绪 sp1.DtrEnable = true; sp1.RtsEnable = true; //设置数据读取超时为1秒 sp1.ReadTimeout = 1000; sp1.Close(); if (!sp1.IsOpen) { sp1.PortName = "COM3"; sp1.BaudRate = 4800; //波特率 sp1.DataBits = 8; //数据位 sp1.StopBits = StopBits.One; sp1.Parity = Parity.None; if (sp1.IsOpen == true)//如果打开状态,则先关闭一下 { sp1.Close(); } sp1.Open(); //打开串口 judge.Text = "串口连接成功"; } } //委托方法 void sp1_DataReceived(object sender, SerialDataReceivedEventArgs e) { byte[] byteRead = new byte[sp1.BytesToRead]; //BytesToRead:sp1接收的字符个数 Byte[] receivedData = new Byte[sp1.BytesToRead]; //创建接收字节数组 sp1.Read(receivedData, 0, receivedData.Length); //读取数据 sp1.DiscardInBuffer(); //清空SerialPort控件的Buffer string strRcv = null; for (int i = 0; i < receivedData.Length; i++) //窗体显示 { strRcv += receivedData[i].ToString("X2"); //16进制显示 } receive.Text += strRcv + "\r\n"; } void text_send(string send_str) { String strSend = send_str; string sendBuf = strSend; string sendnoNull = sendBuf.Trim(); string sendNOComma = sendnoNull.Replace(',', ' '); string sendNOComma1 = sendNOComma.Replace(',', ' '); string strSendNoComma2 = sendNOComma1.Replace("0x", ""); strSendNoComma2.Replace("0X", ""); string[] strArray = strSendNoComma2.Split(' '); int byteBufferLength = strArray.Length; for (int i = 0; i < strArray.Length; i++) { if (strArray[i] == "") { byteBufferLength--; } } byte[] byteBuffer = new byte[byteBufferLength]; int ii = 0; for (int i = 0; i < strArray.Length; i++) { Byte[] bytesOfStr = Encoding.Default.GetBytes(strArray[i]); int decNum = 0; if (strArray[i] == "") { continue; } else { decNum = Convert.ToInt32(strArray[i], 16); } byteBuffer[ii] = Convert.ToByte(decNum); ii++; } sp1.Write(byteBuffer, 0, byteBuffer.Length); } private void Form1_KeyUp(object sender, KeyEventArgs e) { switch(e.KeyValue) { case 97: text_send("01"); break; case 98: text_send("02"); break; case 99: text_send("03"); break; default:text_send("04");break; } } } }
-
C#串口介绍及串口通信程序设计实现(附程序分享)
2021-06-13 11:00:51串行接口简称串口(Serial Interface),也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口。串行接口是指数据一位一位地顺序传送。其特点是通信线路简单,只要一对传输线就可以实现...一、简介
串行接口简称串口(Serial Interface),也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口。串行接口 是指数据一位一位地顺序传送。其特点是通信线路简单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成本,特别适用于远距离通信,但传送速度较慢。
9位针脚功能对应如下:
- 载波检测(DCD)
- 接受数据(RXD)
- 发出数据(TXD)
- 数据终端准备好(DTR)
- 信号地线(SG)
- 数据准备好(DSR)
- 请求发送(RTS)
- 清除发送(CTS)
- 振铃指示(RI)
二、串口应用
工业领域使用较多,比如:数据采集,设备控制等等,好多都是用串口通信来实现!比如国家电表的通信接口就是串口通信。上述9针脚接口中,我们一般只接出RXD TXD两针,外加GND,即可实现两台设备之间的串口通信。
三、串口通信协议
空闲位:
UART协议规定,当总线处于空闲状态时信号线的状态为‘1’即高电平,表示当前线路上没有数据传输。
起始位:
每开始一次通信时发送方先发出一个逻辑”0”的信号(低电平),表示传输字符的开始。因为总线空闲时为高电平所以开始一次通信时先发送一个明显区别于空闲状态的信号即低电平。
数据位:
起始位之后就是我们所要传输的数据,数据位可以是5、6、7、8,9位等,构成一个字符(一般都是8位)。如ASCII码(7位),扩展BCD码(8位)。先发送最低位,最后发送最高位,使用低电平表示‘0’高电平表示‘1’完成数据位的传输。
奇偶校验位:
数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性。校验位其实是调整个数,串口校验分几种方式:
- 1、无校验(no parity)。
- 2、奇校验(odd parity):如果数据位中“1”的数目是偶数,则校验位为“1”,如果“1”的数目是奇数,校验位为“0”。
- 3、偶校验(even parity):如果数据为中“1”的数目是偶数,则校验位为“0”,如果为奇数,校验位为“1”。
- 4、mark parity:校验位始终为1(不常用)。
- 5、parity:校验位始终为0(不常用)。
停止位:
它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。 由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备之间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟的机会。停止位个数越多,数据传输越稳定,但是数据传输速度也越慢。
波特率:
数据传送速率用波特率来表示,单位bps(bits per second),即每秒钟传送的二进制位数。例如数据传送速率为120字符/秒,而每一个字符为10位(1个起始位,7个数据位,1个校验位,1个结束位),则其传送的波特率为10×120=1200字符/秒=1200波特。常见的波特率9600bps、115200bps等等,其他标准的波特率是1200,2400,4800,19200,38400,57600。举个例子,如果串口波特率设置为9600bps,那么传输一个比特需要的时间是1/9600≈104.2us。
四、C#程序设计
- 首先在VS中建立Windows窗口程序;
- 串口通信程序中首先设置串口相关必要信息,包括:串口号,波特率,数据位,停止位,校验位等,以及接受与发送的数据量Rx与Tx。基本逻辑是:打开软件后,首先获取现在存在的串口号,添加至串口号选择栏的下拉项目中:
rivate void comboBox_Port_Update() { RegistryKey keyCom = Registry.LocalMachine.OpenSubKey("Hardware\\DeviceMap\\SerialComm"); //需要调用Win32 if(keyCom != null) { string[] sSubKeys = keyCom.GetValueNames(); foreach(string sName in sSubKeys ) { string sValue = (string)keyCom.GetValue(sName); comboBox1.Items.Add(sValue ); } } }
3. 添加发送和接收项目,并且设置发送按钮与清除接收消息框的清除按钮:
4. 测试各项功能,以及调试bug。需要考虑这些情况:
(1)串口还没打开就发送数据,需要弹出警告框提示串口还未打开:
(2)发送栏的参数还没设置完整,就点击发送按钮:
还有一些设计交互逻辑,在慢慢测试中就会发现,在此不再一一列举。有需要程序源代码的同学私信我,或者不介意的话可以加微信estorm22交流。
程序源码见我的github:https://github.com/chengoes/SerialPort
硬件之家,技术向前。
-
C#开发的串口程序(源代码)
2011-03-06 14:44:23串口程序功能说明: 1.可根据计算机配置选择串口号 2.要通过串口发送的指令可以进行编辑保存,调用时只需按“发送”按钮,操作方便 3.通过串口发送的指令可以按单个字符方式发送,适于不同场合需要 4.串口数据可以... -
C#串口通信程序
2018-03-13 11:08:11C#编写的串口通信程序 。 -
C#串口介绍以及简单串口通信程序设计和实现
2018-11-24 01:12:01C#串口介绍以及简单串口通信程序设计实现 周末,没事干,写个简单的串口通信工具,也算是本周末曾来过,废话不多,直接到主题 串口介绍 串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是... -
C# 串口调试助手源代码
2020-12-21 18:30:38C#开发的串口调试助手。 功能相对简单,权当参考,大家可以根据自行需求开发相关功能。 C#开发的串口调试助手。 功能相对简单,权当参考,大家可以根据自行需求开发相关功能。 -
C#串口小程序
2017-08-22 08:17:20C#串口小程序 -
C# 串口程序采集串口数据
2010-01-12 16:00:14发送命令采集串口数据C# 串口程序采集串口数据 -
C# 串口通信源码
2018-12-02 19:19:56基于C#的串口小助手,串口源码。对于初学C#开发、串口助手开发的同学非常用帮助,注释很详细,有C语言基础的就能看懂。 -
C#上位机串口助手源码.zip
2021-11-19 17:35:58C#上位机串口助手源码 -
C# 串口通信Winfrom 程序,检测串口 发送和接收消息 亲测可用
2019-05-29 19:01:54C# 串口通信Winfrom 程序,检测串口 发送和接收消息 亲测可用 -
c#串口升级程序
2018-07-19 10:47:58c#程序,每次串口上传,每次上传128字节,按着自己定义的校验,主要目的是自己校验比较快,虽然出错概率会增加,但是校验不会给mcu带来太多压力。程序第一个指令是知道程序在app还是api,然后进入api。