串行通信学习笔记

基础知识参考MSDN:https://msdn.microsoft.com/zh-cn/library/system.io.ports.serialport(v=vs.110).aspx

串行通信的一些基础知识包括:比特率、起始位、奇偶位、校验位、16进制显示数据等。目前用两种方法写:一是用Visual Studio 自带的SerialPort类https://www.cnblogs.com/Zed-H/p/8651882.html,二是自制SerialPort 控件。自制控件参考了https://blog.csdn.net/baidu_26678247/article/details/78252606?locationNum=3&fps=1

 

目录

1.对比两种写串口程序的方法:直接使用SerialPort类和自制控件。

​​

2. 对范例代码的解读、一些知识点

1.发送数据

2.显示数据:传输数据是在串口接收,显示是在界面,要避免线程出错,需要用委托。

3.其他

3. 总结

1.收获

2.问题

3.心得

4.书籍


首先,简要对这两种方法做一个对比吧。

1.对比两种写串口程序的方法:直接使用SerialPort类和自制控件。

自制控件更有层次感,体现了面向对象封装的特点。当然,两种方法殊途同归,无论如何都是要使用 using System.IO.Ports和

using System.IO,实例化串口对象。软件实现的功能主要是:1.连接串口 2.发送数据 3.接收数据  也就是三个功能模块,与之相对应的三个事件分别由“打开“按钮触发;“发送”按钮触发;接收到数据,自行触发。比如在数据接收事件中加上一行代码MessageBox.Show(sender.ToString()+'\r'+e.ToString() ); 就可以得到如下图:

 触发它的是我在发送文本框输入的字符,也就是sender, e是System.IO.Ports.SerialDataReceivedEventArgs,这是一个data class,里面存储了需要传递的参数。自制控件窗口的数据接收事件需要与Serial Port控件的Event绑定。之前我出现了收不到数据的情况,就是因为没有绑定自定义的事件,如下图:同样的自制控件定义的事件也要与主窗口的Event(右栏属性那个闪电形状⚡的图标)绑定。

2. 对范例代码的解读、一些知识点

因为我是纯C#小白,因此看范例代码时候很多语句都看不懂,但也没必要全部搞懂,毕竟那是人家的代码,只要提取出主要的功能模块、了解核心的Method,知道怎么去实现功能,就可以了。老看别人的终究是瘸的,拿开拐杖还是不会走。下面很多英文定义来自MSDN,比中文更好理解。当然,不用过于纠结某个定义,(比如handle没有精确的定义,非常抽象,我只知道它是一个source),可以”不求甚解“,意会了,拿来用,也是一种”封装“和”抽象“的思想吧。

1.发送数据

位:数据储存的最小单位
字节:数据处理的最小单位
1 byte = 8 bits
字是可变字长的,比如64位计算机,字长是64位,它的一个字是8个字节。计算机每个单元存储一个字,数据运算也是以字为单位,因此字长越长,计算机性能越优越。
串行通信是一位一位的进行传送,有固定时间间隔,异步通信起始位+数据位+停止位为一帧,一般数据位是8个,即一个字节。1个字节可以存入一个ASCII码,2个字节可以存放一个汉字国标码。

文本传输方式:

AA,十六进制字符,换算成二进制为1010 1010。一个十六进制数最大是4位-F,两个就是8位一个字节。所以按十六进制显示的字符就是两个两个传输。

AA, ASCII码字符,对应的十进制数是65,那么二进制就是0100 0001 0100 0001,因此传输按ASCII显示的数据都是一个字符一个字符的传输。

总的来说就是数据都是转化成2进制传输的,只是在终端上的显示方式不同,根据需求选择它是以字ASCII还是十六进制显示,因为同一个字符,选择错了显示方式,传输的数据就错了。

数据发送接收步骤

(这里方法的具体使用并不固定)

 

GetBytes()方法:将指定字符串中的所有字符编码为一个字节序列

Serial.Write() 将字节写入串口

Serial.BytesToRead()属性接收缓冲区中数据的字节数

Serial.Read()读取数据

GetString()方法将字节转化为字符

Serial是串口对象

 

如何判断数据包完整发送

1.根据起始位+数据位+校验位+停止位来判断。

2.创建定时器,用时长判断。

timeout用来维护超时值,超时了就放弃已有数据包。

Sender, e

sender就是触发这个事件的控件,它是一个对象,比如button1的click事件则sender就是button1,将sender转换成button类型,即可直接操控sender。

在自制控件主窗口的接收事件中直接同委托调用textBox1.Text = sender.ToString();

2.显示数据:数据传输是在串口接收,数据显示是在界面,要避免线程出错,需要用委托。

方法一:直接使用SerialPort类

This.BeginInvoke(new MethodInvoker(delegate{textbox.AppendText(content);}))

因为要访问UI资源,所以需要使用invoke方式同步UI。UI:User Interface

MethodInvoker:Represents a delegate that can execute any method in managed code that is declared void and takes no parameters.

方法二:自制控件

Invoke((Action)delegate{textbox.text=sender.ToString();})

直接与委托绑定也是可以的:

Serial.DataReceived += new SerialDataReceivedEventHandler(Serial_DataReceived);

+=

sp1.DataReceived += Sp1_DataReceived; += 注册方法(将方法和事件绑定),有多少方法执行多少,在方法有返回值的情况下,只返回最后一个方法的值。

 

线程问题

Control.CheckForIllegalCrossThreadCalls = false的意思是禁止编译器对跨线程访问作检查,可以实现跨线程访问控件。.net 原则上禁止跨线程访问控件,因为这样可能造成错误的发生。

参考:多线程时访问UI资源方法https://www.cnblogs.com/mazhenyu/p/7986551.html

3.其他

字段、变量和属性类里面定义的variable就是field。之前我一直不清楚什么是字段什么是变量,它们的图标都是小方块,看起来应该是一码事。而属性通过set和get方法封装字段,使其不可随意访问,更安全。
Encoding类

Encoding 是抽象类,不能直接实例化,可以调用它的静态属性或者实例化一个子类。

字节和字符的互相转换:GetBytes()和GetChars()

UTF-8是包含中文的编码,如果传送的信息有这个,可以考虑使用。

StringBuilder 

Represents a mutable string of characters. String声明之后在内存中大小是不可修改的,而StringBuilder可以自由扩展大小(String分配在栈区,StringBuilder分配在堆区).

参考:https://www.cnblogs.com/cang12138/p/7323709.html

Get 

Defines an accessor method in a property or indexer that returns the property value or the indexer element.

Get:相当于读  Set:相当于写

修改控件设计

rebuild即可同步修改。

 

3. 总结

1.收获

1.对委托有了感性和理性的认识。关于委托的优秀博文分享:http://www.tracefact.net/tech/009.html 

  • 委托规定了所调用方法的参数类型和返回值类型。比如我附的链接那个例子里面,参数类型是string,返回值类型是void。
  • 委托的就像方法的代言人、经纪人,有了它出头和证明,即可调用方法。
  • 为了更好的封装性,引入了事件的概念,如同属性封装字段那样声明事件就如同声明一个封装好的委托。
  • 本质上委托的意义如上,不过在NET框架中声明有所不同,有sender:它是类型是object对象。它是source,触发事件的源头;e是需要传递的数据,EventArgs是data class。

2.知道在事件声明中常被人忽略的sender和e都有妙用,可以看到稍微底层一点的东西。比如委托博文链接的例子中,为了访问Heater类中的公共字段temperature(热水器类的热水器温度),有两种方法:

(a) Heater heater = (Heater)sender; 访问sender的公共字段,输出heater.area;

(b)实例化HeaterHeater heater = new Heater(),这样看来,Class Heater 实例化后的对象就是Heatersender。

  (c) 声明某方法时,如public static void ShowMsg(Object sender, Heater.BoiledEventArgs e),应用Heater类中的创建的data class(BoiledEventArgs),即可在方法中通过e.temperature访问公共字段temperature。

3.了解了GOF,Design Patterns,这是高度概括的面向对象设计策略。

4.先从MSDN上了解需要用到的类的框架,找思路,自己动手写。

2.问题

1.如何用线程接收数据?了解线程概念、应用。

2.关于数据接收涉及的时间问题研究的还不够透彻,比如定时器、延时接收(System.Threading.Thread.Sleep(100))、间隔接收(PerformClick参见MSDN:PerformClick)

3. 什么时候将方法声明为静态?私有还是公有还是其他?

4.学编程需要自己把语句从头写到尾还是知道怎么实现去搭积木?

3.心得

多和老工程师交流交流,他们一句话就能打通任督二脉。

多练习,面对任务,要学会给自己建立反馈。吃饭能知道自己吃了几分饱,在编程能力上也要知道自己几斤几两,预估自己完成一个任务的时间并预设一个deadline。这个时间就是一个重要指标,这样就能形成反馈。

第一篇博客写完了,希望看到的朋友们不吝赐教!

4.书籍

接下来阅读:

实操:《C#经典编程220例》、《Programming C# 5.0》

编程思想:《The Pragmatic Programmer: From Journeyman to Master》

公开课:学堂在线清华《软件设计》、《算法数据结构》

截至:2018年底,到时候上来分享

https://www.jianshu.com/p/963973835545

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值