A:通讯工程设计的基础部分
串行通信接口标准
一、RS-232C接口
RS-232C是EIA(美国电子工业协会)1969年修订RS-
232C标准。RS-232C定义了数据终端设备(DTE)与数据
通信设备(DCE)之间的物理接口标准。
1、机械特性
RS-232C接口规定使用25针连接器,连接器的尺寸及每个插
针的排列位置都有明确的定义。(阳头)
2、功能特性
4、过程特性
过程特性规定了信号之间的时序关系,以便正
确地接收和发送数据 。
远程通信连接
近程通信连接
5、RS-232C电平与TTL电平转换驱动电路
6、采用RS-232C接口存在的问题
1、传输距离短,传输速率低
RS-232C总线标准受电容允许值的约束,使用时传输距离一
般不要超过15米(线路条件好时也不超过几十米)。最高传送
速率为20Kbps。
2、有电平偏移
RS-232C总线标准要求收发双方共地。通信距离较大时,
收发双方的地电位差别较大,在信号地上将有比较大的地电流
并产生压降。
3、抗干扰能力差
RS-232C在电平转换时采用单端输入输出,在传输过程中
当干扰和噪声混在正常的信号中。为了提高信噪比,RS-232C
总线标准不得不采用比较大的电压摆幅。
二、RS-422A接口
RS-422A输出驱动器为双端平衡驱动器。如果其中一条
线为逻辑“1”状态,另一条线就为逻辑“0”,比采用单端
不平衡驱动对电压的放大倍数大一倍。差分电路能从地线干
扰中拾取有效信号,差分接收器可以分辨200mV以上电位差。
若传输过程中混入了干扰和噪声,由于差分放大器的作用,
可使干扰和噪声相互抵消。因此可以避免或大大减弱地线干
扰和电磁干扰的影响。RS-422A传输速率(90Kbps)时,
传输距离可达1200米。
三、RS-485接口
RS-485是RS-422A的变型:RS-422A用于全双工,而RS
-485则用于半双工。RS-485是一种多发送器标准,在通信线
路上最多可以使用32 对差分驱动器/接收器。如果在一个网
络中连接的设备超过32个,还可以使用中继器。
RS-485的信号传输采用两线间的电压来表示逻辑1和逻辑
0。由于发送方需要两根传输线,接收方也需要两根传输线。
传输线采用差动信道,所以它的干扰抑制性极好,又因为它
的阻抗低,无接地问题,所以传输距离可达1200米,传输速
率可达1Mbps。
RS-485是一点对多点的通信接口,一般
采用双绞线的结构。普通的PC机一般不带
RS485接口,因此要使用RS-232C/RS-485转
换器。对于单片机可以通过芯片MAX485来完
成TTL/RS-485的电平转换。在计算机和单片
机组成的RS-485通信系统中,下位机由单片
机系统组成,上位机为普通的PC机,负责监
视下位机的运行状态,并对其状态信息进行
集中处理,以图文方式显示下位机的工作状
态以及工业现场被控设备的工作状况。系统
中各节点(包括上位机)的识别是通过设置
不同的站地址来实现的。
RS-232的引脚功能和信号流动的方向,常和调制解调器传输有
关.以下是9支引脚的相关说明:
DCD(1):此引脚是由调制解调器控制,当电话接同之后,
发送的信号载在载波信号上面,调制解调器利用此引脚通知计
算机有载波被检测到,即表示现在处于联机状态;而当载波被检
测到时才可保证此时是处于联机状态.一般若计算机未收到此
信号,均会响应信息,并将调制解调器挂断.
RXD(2):此引脚会将远程所发送过来的数据接收近来.在
接收的过程中,由于数据是以数字类型发送,读者可以在调制解
调器的RXD信号灯上看到明灭交错,此即为0与1交替所产生的
现象,也就是电位高低变化所产生的现象.
TXD(3):此引脚将计算机所要发送出去的数据发送出去.
在发送的过程中,由于数据以数字类型发送,读者可以在调制解
调器的TXD信号灯上看到明灭交错,此即为0与1交替所产生的
现象,也就是电位高低所产生的现象.
DTR(4):此引脚由计算机控制,用以通知调制解调器可以
进行传输.高电位时表示计算机已经准备就绪,随时可以接收数
据.
GND(5):此引脚为接地端,作为计算机与调制解调器之间的标
准电位参考.两端设备的接地端标准电位必须一样,否则会产生地
回路(Ground Loop),使得信号因标准电位的不同而产生偏移,也
会导致结果失常.RS-232数据采用单接点(Single Ended)式的信
号发送方式,其特点是信号电压的标准电位不同而造成数据的错
误.
DSR(6):此引脚由调制解调器控制,调制解调器用这支引脚
的高电位通知计算机一切均准备就绪,可以发送数据过来.
RTS(7):此引脚由计算机控制,用以通知调制解调器马上发
送数据至计算机.而当调制解调器收到此信号后,便会将它由电话
在线收到的数据发给计算机;在此之前若有数据发送至调制解调
器则会暂时存在缓冲区中.
CTS(8):此引脚由调制解调器控制,用以通知计算机将欲发送
是数据送至调制解调器.当计算机收到此引脚的信号,即将准备送
出的数据送至调制解调器,而调制解调器则将计算机送过来的数
据由电话线送出.
RI(9):调制解调器通知有电话进来.
由于串行通信的简单易用,在工业领域也大量使用串行通信作为数据交换
的手段,可是工业环境通常会有噪声干扰传输路线,在用RS-232串行通信进
行传输时经常会受到外界的电气干扰而使信号发生错误。为了解决上述问题,
RS-485串行通信方式就应运而生了。
为了了解信号的干扰情况,首先我们来看图所示的RS-232信号传输方
式。
由图中可知,RS-232串行通信的信号标准电位是参考接
地端而看来的。发送端参考接地端1来发送数据;接受端
则参考接地端2来还原出发送的端的信号;在两个接地端
同电位的前提下,发送端与接受端的信号会呈现出相同的
结果。如果数据传输的过程中有噪声进入到传输线路中,
可能会产生干扰,如图所示。
干扰信号在接地端和信号上均会产生影响,原始信号在加上干
扰信号后依然发送到接受端。因此,信号便发生了扭曲,当然
整个信号就都不对了。
RS-485信号传输方式如图所示。RS-485的信号在
发送出去前会先分解成正负的两条线路,当到达接收端以后,
再将信号相减还原成原来的信号。
如果将原始的信号标注为(DT),而被分解
后的信号分别标注为(D+)和(D-),则原
始信号与分解后的信号在由发送端发出去时的
运算关系如下:
( DT)=(D+)-(D-)
• 同样,接受端在接受到信号后,也按上式的关
系将信号还原成原来的样子。
• 而如果此线路受到干扰,其情况可能如图
所示了.
这时候在两条传输线上的信号会分别成为
(D+)+Noise和(D-)+Noise 。如果接收端
接收此信号,它必须按照一定的方式将其合成,
合成的方程式如下:
[(D+)+Noise]-[(D-)+Noise]=(D+)-(D-)=DT
所以,使用RS-485网络可以有效的防止噪
声干扰。也正因为这种特性,工业上比较适合
使用这种串行传输方式。
RS-485虽然可防止噪声,但也并非无懈
可击。若噪声电压很大(例如闪电),一样也
会造成错误。
当计算机要发送的数据给调制解调器时,在计算机上RS-232
硬件线路的引脚位图图所示.
在图中,计算机与调制解调器的通信步骤如下:
(1)调制解调器将计算机通信端口上的DSR引脚电位升高,表
示调制解调器已经准备好接收由计算机串行通信端口传过
来的数据.
(2)计算机将DTR引脚电位升高,表示计算机也已将数
据准备妥当.
(3)计算机将RST引脚电位升高,告诉调制解调器计算
机即将开始发送数据.
(4)调制解调器将RST引脚电位升高,通知计算机可以
开始发送数据.
(5)接着计算机就开始将数据发送到调制解调器,当调
制解调器收到数据后,便会将收到的数据利用电话线路发
送出去.
在经过DSR DTR RST和CTS 4支引脚标准
电位确认后,计算机与调制解调器的握手程
序完成.计算机正式将数据由RS-232通信端
口发送至调制解调器,而调制解调器也就在
接收数据后,随即将数据发送至电话在线,
而通过电话线发送到远方的调制解调器,再
转送至该台远程计算机.
当数据由远程进来,而计算机要经过调
制解调器接收时,计算机与调制解调器两者
之间也需进行握手的操作,计算机上的RS-
232硬件线路的引脚电位图如图所示.
在图中,计算机与调制解调器间的通信步骤如下
:
(1)调制解调器将计算机串行通信断口上的
DSR引脚电位升高,表示调制解调器已经准备好了.
(2)此时有电话自电话线中传来,RI引脚发生
变化.
(3)计算机将DTR电位升高,告诉调制解调器
计算机可以发送数据,此信号标准电位会一直维持
至断线为止.
(4)调制解调器握手完成后,调制解调器会检
测到载波信号.
(5)调制解调器开始将由在线收到的数据发送
到计算机上去.
DSR会一直维持在高电位的状态,一旦电话
进来至调制解调器时,RI引脚会发生变化,一检测
到此引脚的变化以后,DTR引脚就进入升高的状态,
至于是一直维持在高电位至断线或是只有接通电
话之前为高电位则视通信软件的设计而定.接着
调制解调器检测到载波信号后即进行数据的传输,
并将受到的数据发送给计算机.
由于RS-232最早的用途即是与调制解调器
进行远程传输用,因此以上的所有说明也都以调
制解调器为对象,这些基本的概念具备后,对于往
后各章在系统控制上的说明应用也就较为得心应
手了.
通信参数
就串行通信来看,交换数据的双方利用传输
在线的电压改变来达到数据交换的目的,但是如何
从不断改变的电压状态中解析出其中的信息,就需
要双方共同决定才行.
如上所述,既然是通信,双方当然需要说明到
底是如何发送数据或命令的,否则如果双方没有一
套共同的译码方式,恐怕都无法了解对方所发送过
来的数据的意义.因此,双方为了可以进行通信,必
须要遵守一定的通信规则,这个共同的规则就是通
信端口的初始化.
通讯中的流量控制-硬件握手
硬件握手使用DSR(第六引脚),CTS(第八引脚)、DTR(第四引脚)
和RST(第7引脚)四条硬件线路。
例如计算机正在发送数据给设备C,设备C的处理速度不够快,因此其
接收缓冲区中的数据量已达到一定的程度,在发送下去将会造成缓冲区溢满,
这时就必须暂停数据的发送。而计算机与设备C之间在此种发送问题时的握手
步骤如图所示。
图的步骤说明如下:
(1)设备C必须将相对于计算机上的DSR引脚降为低
电压。
(2)计算机检测到DSR引脚为低电压后,暂停数据
的传输;同时设备C也会继续处理位于缓冲区的数据。
(3)待设备C的接收缓冲区数据下降到一定程度后,
设备C将DSR引脚的标准电位升高。
(4)计算机一检测到DSR引脚为高电位后,就继续
发送数据给设备C。
在上面的例子中。仅仅使用一个DSR引脚的标准电位
信号即可达到双方流量控制通知的作用。在部分设备上,
发送操作继续之前,DSR与CTS两个线路的标准电位都升
高才行,如调制解调器既是如此。
同样,以上面的例子来说,数据、由设备C发送至计
算机时,若计算机处理速度不够快,计算机就必须告诉设
备C这一情况,使其暂停数据的发送,其握手步骤如图
所示。
图的步骤说明如下:
(1)计算机将DTR信号降为低电压。
(2)设备C检测到DTR引脚为低电压后,暂停数据的
传输,同时计算机亦会继续处理位于缓冲区的数据。
(3)待计算机的接收缓冲区数据量下降至一定程度后,
计算机DTR引脚的标准电位升高。
(4) 设备C一检测到DTR引脚为高电位后,就继续给
计算机发送数据。
部分情况必须是DTR与RST两条硬件线路均回到高
电位后,设备C才会继续发送数据,这必须视两者间实际
协议情况而定。
流量控制-软件握手
另一种传输流量控制的方法则是使用软件握手,
以下数据在线的数据信号来代替实际的硬件线路。软件
握手中最常见的就是XON/XOFF协议。
在XON/XOFF协议中,若接收端想使发送端暂停数
据的发送时,它便向发送端送出一个ASCII码第19个字
符(十六进制是3);而若恢复发送时,便向发送端送
出ASCII码第17个字符(十六进制11),两个字符的交
互使用,便可以控制发送端发送操作。其操作流程与硬
件握手类似,例如,计算机与设备C进行数据的传输,
计算机不断地将数据发送到设备C,此时的设备C来不
及处理,则两者可以进行如图的软件握手步骤。
图的步骤说明如下:
(1)设备C在本身输入缓冲区快满时,送出
ASCII码第19个字符通知计算机暂停数据的传输。
(2)计算机受到该字符后,暂停数据的传
输;同时设备C也会继续处理位于缓冲区的数据。
(3)待设备C的接收缓冲区数据良下降到
一定程度后,设备C将发送ASCII码第17个字符计
算机,告诉计算机可以继续发送数据 。
(4)计算机接到该字符后,继续发送数据
至设备C。
以相反的方向来说,若计算机的速度比较慢
时,就会进行如图的握手。
图的步骤说明如下:
(1)计算机在本身输入缓冲区快满时,送出ASCII码的第19个字
符通知设备C暂停数据的传输。
(2)设备C收到该字符后,暂停数据的传输,同时计算机也会继续处
理位于缓冲区的数据。
(3)待计算机的接收缓冲区数据量下降至一定程度后,计算机将发送
ASCII码第17个字符至C,告诉设备C可以继续发送数据。
(4)设备C 收到该字符后,继续发送数据至计算机。
• 在PC机上进行串行通信通常有如下方法:
• 1、利用Bios和Dos功能调用实现串口通讯(PC机
主板上有8250芯片)。
• 2、利用8251实现串口通信(需要做接口板)。
• 3、利用Visual Basic 或Visual C++或
Delphi7企业版提供的通讯控件MSCOMM实现串
行通讯。
• 4、利用visual studio 2005(.NET)以上版本提供
的 SerialPort控件实现串行通信。
• Visual 的版本分为普及版,专业版及
企业版,每一个版本都为了适应不同的用户。普
及版特别适合刚刚学习可视化设计系统的初学者,
而专业版及企业版适合专业的系统设计人员。串
行通信的控件包含在专业版信企业版中。本节主
要介绍Visual 中的MSCOMM通讯控件。
• MSComm控件的应用步骤
• ( 1 )单击[工程]菜单。
• ( 2 )在工程菜单中选择[部件]命令,如图所
示。
• ( 3 )打开[部件]对话框,选中Microsoft Comm
Control 复选框。
• ( 4 )单击[应用]或[确定]按钮,即可在工具箱
中见到“电话盒(MSComm)”的图标,我们可
以将MSComm控件加载,进行串行通信。
• 如果打开的是以前的工程,工程中就含有
MSComm控件的引用记录,则工程会自动去搜索
MSComm控件,并将它加载,不需要以上的步骤。
• Windows 的操作系统与DOS是迥然不同的,
Windows采用了全新的对象化观念,把所有的程
序都对象化,在对象化之后,Visual Basic的串行
通信是将RS-232的低级操作予以封装,我们用
Visual Baisc的程序设计串行通信的相关工程时,
要遵循以下4主要步骤:
• ( 1 )对象:首先了解所要操作的对象是什么。
• ( 2 )属性:设置该对象所具备的特性。
• ( 3 )事件:该对象在系统执行的行程上会因其
他对象而发生什么样的事情。
• ( 4 )方法:当该对象被引发了某个事件之后,
系统(或程序)应该采用的相应步骤是什么。
• 1 。对象
• 首先我们要使用MSComm控件对外进行通信,
因此在工具箱中选择了MSComm控件的图标后,
便可在窗体上安置一个MSComm控件,如同在画
面上安装一个和串行端口通信的渠道。
• 2 。属性
• 接下来就是属性的设置。每一个控件的属性
都相当多,通过属性值的设置,我们可以指定硬
件以一定的方法工作。当用户在窗体上安置一个
MSComm控件后,可以按下F4键调出其相应的属
性表,其中列出了所有可在设计阶段更改的属性。
属性栏将各个属性都列出来,用户可以选择相应
的项目后,进行属性的设置。
• MSComm控件的属性众多;其重要属性说明如下:
• 1、CommPort属性
• CommPort属性用于设置或返回通信连接端口号码。
程序必须指定所要使用的串行端口的号码,Windows系统
会使用所设置的通信端口与外界进行通信。程序可借助此
属性返回所使用的连接端口号码。在此所设置的通信端口
号由1开始往上递增,MSComm控件的最大值是16,当
使用的通信端口号码超过16时,此控件会生成错误信息。
• 虽然Windows操作系统可以容纳最多256个串行通信端口,
不过Visual Basic的MSComm控件则仅限于16个端口。
• 例如:=1 ‘指定使用COM1进行通
信传输。
• 注意:要使用超过16个的串行通信端口时,除了方法不一
样之外,也必须配合硬件的升级,以多端口卡达到实际上
的串行端口扩充目的。
• 2、Settings属性
• Settings属性用于设置初始化参数。以字符
的形式设置或返回波特率、奇偶校验、数据位、
停止位等4个参数。其格式为为“BBBB,P,D
,S”,其中BBBB表示波特率,P表示奇偶校验
位检查方式,D表示数据位数,S表示停止位数。
默认值是“9600,N,8,1”,它表示所使用的
通信端口是以每秒9600位的速率进行传输,不
进行奇偶校验的检查,每个数据单元是8个位,
而停止位是1个位,而这4项必须是按照顺序,
不可前后对调;其中的字母N可以是大写或小写。
• 例如:=”9600,n,8,1”
• 3 .PortOpen
• PortOpen属性用于设置或返回通信连接端口的
状态。使用串行端口之前必须先将要使用的串
行端口打开,而在使用完毕之后,也必须执行
关闭操作。
• 打开串行口:COMM1. PortOpen=True;关闭
串行口:COMM1. PortOpen= False。
• 4 .Input属性
• Input属性用于从输入缓冲区返回并删除字符。
程序靠这个命令将对方传到输入缓冲区中的数
据读进程序中,并清除缓冲区中已被除数读取
的数据。
• 5 .Output属性
• Output属性用于将要发送的数据输入传输
缓冲区。当程序需要传输字符串到对方时,
可将字符串使用此命令输入输出缓冲区,
一般的数据均是在送达输出缓冲区后随即
被送出,当MSComm控件设置有发送阈值
属性时,则会生成事件(SThreshold,请看
随后的说明)。
• 例如:=”ABCDE”,此即
将ABCDE这5个字符通过RS-232串行通信
端口发送出去。
• 6 .InputLen属性
• InputLen属性用于指定由串行端口读入的字符
串长度或字节数。Visual Basic程序可使用
Input命令将存放在输入缓冲区的字符读入,
但要指定所读入的字符长度则需要设置本属性。
若指定读取的单位是字节,则是读入的字节的
个数。
• 7 .HandShaking属性
• HandShaking属性用于指定通信双方的握手协
议。所谓的“握手协议”也就是流量管制。
• 握
• 8 . RThreshold属性
• RThreshold属性用于设置或返回引发接收
事件的字节数,即属性页上的“最小接收
字符数”。当接收缓冲区达到所设置的字
节数旱,将会引发OnComm事件上的接收
事件(请看后面章节的说明)。
• 例如:=20,当接收
缓冲区达到20个字符时,引发接收事件。
• 9 .STHreshold属性
• 若设置STHreshold属性为(默认值),则数据传输
事件不会生成OnComm事件中的发送事件。若设
置STHreshold属性为1,将使得MSComm控件在
传输缓冲区完全空时,生成OnComm事件。如果
在传输缓冲区中的字符数少于所设置的数值,则
CommEvent属性会被设置为comEvSend,并生成
OnComm事件。
• 例如:=20,当发送缓冲
区字符少于20个字符时,引发发送事件。
• 10 .CommEvent属性
• CommEvent属性在通信错误或事件发生时都会生
成OnComm事件,CommEvent属性存有该错误
或事件的数值码。
• 11 .DTREnable属性
• DTREnable属性用于判断在通信时是否启用
Data Terminal Ready (DTR)线路。通常Data
Terminal Ready是由计算机发送到调制解调
器的信号,表示计算机在等待接受传输,即
属性选项卡上的“启用Data Terminal Ready
线路”。当DTREnable设置为True,Data
Terminal Ready 线会在连接端口打开时设置
为高电位,在连接端口关闭时被设置为低电
位。
• 例如:=True,将DTR
引脚升为高电位。
• 12 .RTSEnable属性
• RTSEnable属性用于决定是否使Request
To Send(RTS)线有效。一般情况下,由计
算机发送Request To Send信号到调制解调
器,以请示准许发送数据。RTSEnable属
性允许用户以手动方式轮询检测Request
To Send线以判断其状态。
• 例如:=True,将
RTS引脚升为高电位。
• 13 .InBufferCount属性
• InBufferCount属性用于返回在接收缓冲区
中的字符数。该属性在设计阶段无法使用。
InBufferCount是指已接收,并在接收缓冲
区中等待读取的字符数。用户可以把
InBufferCount属性设置为0,以清除接收缓
冲区。
• 例如:Count%=,
返回已接收到的字符数。
• 14 .InputMode属性
• InputMode属性用于设置或返回Input属
性取回的数据类型。InputMode属性决定
Input属性如何取回数据,数据可能会以字
符串的形式接收或是作为字节数组中的二
进制数据来接收,完全要由属性的设置来
决定。
• 例如:=1,以二进制
方式取得数据。
• =0,以字符
串的形式接收。
• B:通讯工程设计初步!!!
• 1、通信控件的引用及属性设置。
• 结合实例编写简单收发程序
• 2 、自动接收程序
• MSComm只有一个OnComm事件。
• 在这个事件中根据CommEvent属性值的不同,将各
别的程序代码写入相关的子程序中。
• 在此例中,只要RThresold中的设置字符数到达时
• 便会使得CommEvent属性值变成comEvReceive,
• 因此,接收的子程序便被执行。
• 硬件:把串口232接口的第2和3脚短接构成自收自
发回路。
• (1)人机界面设计如下图所示
• (2)软件设计:
• ‘使用命令按钮控件,’关闭通信端口,'结束系统
• Private Sub CmdExit_Click()
• = False
• End
• End Sub
• ‘使用命令按钮控件,’使用Input属性读取串行端口的传入值,
• '并将结果显示在Label控制的Caption属性里
• Private Sub CmdReceive_Click()
• Dim buf$
• buf = Trim()
• If Len(buf) = 0 Then
• = "Empty"
• Else
• = buf
• End If
• End Sub
• Private Sub Command1_Click()
• = ""
• End Sub
• ‘窗体的加载事件,'打开串行通信端口,
参数亦可在打开之前先行指定,
• '指定完后,再打开该通信端口
• Private Sub Form_Load()
• = True
• End Sub
• '使用命令按钮控件
• '使用Output属性将用户欲发送的字符串送
出
• Private Sub CmdSend_Click()
• = Trim()
• End Sub
• Private Sub Comm1_OnComm()
• Select Case
• ' 借着取代底下每一个 case 语句来处理每个事件与错误
• ' 事件
• Case comEvCD ' CD 线的状态发生变化.
• Case comEvCTS ' CTS 线的状态发生变化.
• Case comEvDSR ' DSR 线的状态发生变化.
• Case comEvRing ' Ring Indicator 变化.
• Case comEvReceive ' 收到 RThreshold # of
• = +
Trim()
• Case comEvSend ' 传输缓冲区有 Sthreshold 个字符
• End Select
• End Sub
• '使用命令按钮控件
• '将接收区的显示范围清空
• Private Sub Command1_Click()
• = ""
• End Sub
• '窗体的加载事件
• ‘打开串行通信端口
• Private Sub Form_Load()
• = True
• End Sub
• 3、自收自发通信程序测试2
• 发送和接收都用命令按钮来完成。
• 人机界面设计如下:
• ‘使用命令按钮控件,关闭通信端口,结束系统
• Private Sub CmdExit_Click()
• = False
• End
• End Sub
• '使用命令按钮控件
• '接收由通信端口发送过来的字符串,并判断之
• Private Sub CmdReceive_Click()
• Dim buf$
• buf = Trim() '将缓冲区内的数据收进buf变量
中
• If Len(buf) = 0 Then '判断其中是否存在数据
• = "Empty"
• Else
• = buf
• End If
• End Sub
• '使用命令按钮控件
• '将数据由通信端口发送出去
• Private Sub CmdSend_Click()
• = Trim()
• End Sub
• '窗体的加载事件
• '打开通信端口,通信端口的设置参数也可以
• '在打开前作设置
• Private Sub Form_Load()
• = True
• End Sub
• 5、硬件线路测试
• 在此例中,针对几条硬件线路的电压状态
作检测,一旦检测到发生变化,则以信号
灯予以表示。人机界面设计如下图:
• 软件设计:
• ‘使用命令按钮控件,结束系统
• Private Sub Command1_Click()
• End
• End Sub
• ‘窗体的加载事件,打开串行通信端
• Private Sub Form_Load()
• = True
• End Sub
• 'MSComm的OnComm事件程序
• '由CommEvent属性值的不同,将各别的程序代
码写入相关的子程序中。
• Private Sub MSComm1_OnComm()
• Select Case
• ' 借着取代底下每一个 case 语句来处理每个事件与错误
• Case comEvCD ' CD 线的状态发生变化.
• If Then '检测DCD引脚电位
• = RGB(255, 0, 0) '改变信号灯为红灯
• Else
• = RGB(255, 255, 255) '信号灯灭掉
• End If
• Case comEvCTS ' CTS 线的状态发生变化.
• If Then '检测CTS引脚电位
• = RGB(255, 0, 0) '改变信号灯为红灯
• Else
• = RGB(255, 255, 255) '信号灯灭掉
• End If
• Case comEvDSR ' DSR 线的状态发生变化.
• If Then '检测DSR引脚电位
• = RGB(255, 0, 0) '改变信号灯为红灯
• Else
• = RGB(255, 255, 255) '信号灯灭掉
• End If
• Case comEvRing ' Ring Indicator 变化.
• If = RGB(255, 0, 0) Then '改变信号灯为红灯
• = RGB(255, 255, 255) '信号灯灭掉
• Else
• = RGB(255, 0, 0) '信号灯灭掉
• End If
• Case comEvReceive ' 收到 RThreshold # of
• Case comEvSend ' 传输缓冲区有 Sthreshold 个字符
• End Select
• End Sub
• 线路测试数据输入例2
• 本工程的特点是在定时器的Timer事件中,用
查询的方法检查 这4条线路的(CD、CTS、
DSR、RI)状态,并以此改变4个Shape控件的
背景色。另外,通过本例学会使用文本框的
• MouseMove方法。
• 软件设计:
• Private Sub cmdEnd_Click()
• = False
• End
• End Sub
• Private Sub cmdEnd_MouseMove(Button As
Integer, Shift As Integer, X As Single, Y As
Single)
• = "单击此按钮可结束本系统!"
• End Sub
• Private Sub cmdStart_Click()
• = Not
• End Sub
• '定时器控件的Timer事件
• Private Sub Timer1_Timer()
• If Then '检测DCD引脚电位
• = RGB(255, 0, 0) '改变信号灯为红灯
• Else
• = RGB(255, 255, 255) '信号灯灭掉
• End If
• If Then '检测CTS引脚电位
• = RGB(255, 0, 0) '改变信号灯为红灯
• Else
• = RGB(255, 255, 255) '信号灯灭掉
• End If
•
• If Then '检测DSR引脚电位
• = RGB(255, 0, 0) '改变信号灯为红灯
• Else
• = RGB(255, 255, 255) '信号灯灭掉
• End If
• If = comEvRing Then
• = RGB(255, 0, 0) '改变信号灯为红灯
• Else
• = RGB(255, 255, 255) '信号灯灭掉
• End If
• End Sub
• 6、字节测试
• 在自动控制系统中,发送的命令及接收的
数据多以字节(8位2进制数)来表示。本
例就是定义两个字节型动态数组来完成数
据的发送和接收。人机界面如下图:
• Option Explicit
• '声明两个字节类型的变量数组
• '一个用于存储输出数据
• '一个用于存储输入数据
• Dim OutByte() As Byte
• Dim InByte() As Byte
• Private Sub CmdExit_Click()
• End
• End Sub
• Private Sub CmdReceive_Click()
• Dim i%, Buf$
• Buf = ""
• InByte =
• For i = LBound(InByte) To UBound(InByte)
• Buf = Buf + Hex(InByte(i)) + Chr(32)
• Next i
• = Buf
• End Sub
• Private Sub CmdSend_Click()
• Dim Buf$, i%
• Dim S3(1 To 1) As Byte
• Buf = Trim()
• OutByte = StrConv(Buf, vbFromUnicode) '转
换字符串
• Buf = '清空输入缓冲区
• = OutByte '送出数据
• End Sub
• Private Sub Form_Load()
• = True
• End Sub
• 7 线路测试数字输出
• 数据终端准备好DTR和请求发送RTS是由
计算机端输出的,使用这两根线可对开关
量进行控制。硬件设计如图所示:
• 软件设计:
• '按不同的状况更改Shape对象的填满颜色
• '并更改线路的电压状态
• Private Sub cmdDTR_Click()
• = Not
• If Then
• = RGB(255, 0, 0)
• Else
• = RGB(0, 0, 0)
• End If
• End Sub
• Private Sub cmdEND_Click()
• = False
• End
• End Sub
• '按不同的状况更改Shape对象的填满颜色
• '并更改线路的电压状态
• Private Sub cmdRTS_Click()
• = Not
• If Then
• = RGB(255, 0, 0) '更改颜色为红色
• Else
• = RGB(0, 0, 0) '更改颜色为黑色
• End If
• End Sub
• Private Sub Form_Load()
• = True
• End Sub
• 8、字节测试2
• 在自动控制系统中,发送的命令及接收的
数据多以字节(8位2进制数)来表示。本
例就是定义两个字节型动态数组来完成数
据的发送和接收。人机界面如下图:
• 软件设计:
• Option Explicit
• '声明两个字节类型的变量数组
• ‘一个用于存储输出数据,一个用于存储输入数据
• Dim OutByte() As Byte
• Dim InByte() As Byte
• Private Sub CmdExit_Click()
• End
• End Sub
• '将字节数据以十六进制表示并存入Buf变量
• '将Buf变量内容显示到接收的文本框中
• Private Sub CmdReceive_Click()
• Dim i%, Buf$
• Buf = ""
• InByte =
• For i = LBound(InByte) To UBound(InByte)
• Buf = Buf + Hex(InByte(i)) + Chr(32)
• Next i
• = Buf
• End Sub
• '将用户的输入字符串先存入Buf变量中
• '使用StrConv将Buf变量作类型转换
• '再将转换完的数组利用Output指令送出
• Private Sub CmdSend_Click()
• Dim Buf$, i%
• Dim S3(1 To 1) As Byte
• Buf = Trim()
• OutByte = StrConv(Buf, vbFromUnicode) '转换字符串
• Buf = '清空输入缓冲区
• = OutByte '送出数据
• End Sub
• ‘窗体的加载事件,在此作打开通信端口
• Private Sub Form_Load()
• = True
• End Sub
• 9、利用文本框的KeyPress事件
• 根据文本框的keyPress事件的返回值决定
是否发送。
• 人机界面设计如下:
• Private Sub CmdExit_Click()
• = False
• End
• End Sub
• Private Sub CmdReceive_Click()
• Dim buf$
• buf = Trim()
• If Len(buf) = 0 Then
• = "Empty"
• Else
• = buf
• End If
• End Sub
• '使用Output属性发送字符串出去
• ''''''''''''''''''''''''''''''''''''''
• Private Sub CmdSend_Click()
• = Trim()
• End Sub
• Private Sub Comm1_OnComm()
• Select Case
• Case comEvReceive ' 收到 RThreshold # of
• = +
Trim()
• Case comEvSend
• End Select
• End Sub
• Private Sub Command1_Click()
• = ""
• End Sub
• Private Sub Form_Load()
• = True
• End Sub
• Private Sub optCom_Click(Index As Integer)
• = True
• End Sub
• '检查用户输入的数据是否为Chr(13)
• Private Sub txtSend_KeyPress(KeyAscii As Integer)
• If KeyAscii = 13 Then
• = Trim()
• End If
• End Sub
• 10、用定时器自动读取
• 用2台计算机或用有2个串口的计算机,亦
可采用自收自发的方式来实现。
• 人机界面设计:
• 软件设计
• '使用命令按钮控件
• '关闭通信端口
• '结束系统
• Private Sub cmdEnd_Click()
• = False
• End
• End Sub
• '使用命令按钮控件
• '将定时器控件的启动/关闭状态作切换
• Private Sub cmdStart_Click()
• = Not
• End Sub
• '窗体窗体的加载事件
• '打开通信端口,Private Sub Form_Load()
• = True
• End Sub
• '定时器的Timer事件程序
• '此事件会在每一个Interval属性值的间隔内被调用
一次
• '程序检查输入缓冲区中是否有数据,若有数据
• '则将此数据读取后,指定给文本框的Text属性
• Private Sub Timer1_Timer()
• If > 0 Then
• = +
• End If
• End Sub
• 11、中文转换成字节发送
• 使用字节方式发送与接收数据时,必须使
用byte类型变量声明,MSCOMM的默认声
明是Text而不是Binary,使用Text模式将无
法接收与发送ASCII码128以上的单个字节,
VB认为它是双字字符的一部分,并等待下
一个字节的到达后再合成一个文字。
• StrConv(S,返回值)转换函数能把双字节
字符转换成2个单字节。其中常用的返回值
为:VBunicode和VBFronUnicode.
• 软件设计:
• Option Explicit
• ''''''''''''''''''''''''''''''''''''''
• '声明两个字节类型的变量数组
• '一个用于存储输出数据
• '一个用于存储输入数据
• ''''''''''''''''''''''''''''''''''''''
• Dim OutByte() As Byte
• Dim InByte() As Byte
• Private Sub CmdExit_Click()
• End
• End Sub
• Private Sub CmdReceive_Click()
• Dim i%, Buf$
• Buf = ""
• InByte =
• For i = LBound(InByte) To
UBound(InByte)
• Buf = Buf + Hex(InByte(i)) + Chr(32)
• Next i
• = Buf
• End Sub
• Private Sub CmdSend_Click()
• Dim Buf$, i%
• Dim S3(1 To 1) As Byte
• Buf = Trim()
• OutByte = StrConv(Buf, vbFromUnicode) '转
换字符串
• Buf = '清空输入缓冲区
• = OutByte '送出数据
• End Sub
• Private Sub Form_Load()
• = True
• End Sub
• 12、单双字节测试
• Private Sub CmdEnd_Click()
• = False
• End
• End Sub
• Private Sub cmdSend_Click()
• =
• End Sub
• '窗体的加载事件
• '将通信端口打开,通信参数也可以在打开前先设置
• '设置引发接收事件的接收阈值
• Private Sub Form_Load()
• = True
• = Val()
• End Sub
• '通信控件的OnComm事件
• Private Sub MSComm1_OnComm()
• Select Case
• ' 借着取代底下每一个 case 语句来处理每个事件与错误 事件
• Case comEvCD ' CD 线的状态发生变化.
• Case comEvCTS ' CTS 线的状态发生变化.
• Case comEvDSR ' DSR 线的状态发生变化.
• Case comEvRing ' Ring Indicator 变化.
• Case comEvReceive ' 收到 RThreshold # of
• = + Trim()
& vbCrLf
• Case comEvSend ' 传输缓冲区有 Sthreshold 个字符 '
• End Select
• End Sub
• '阈值设置文本框的Change事件
• '当设置的阈值发生变化时(用户输入)
• '实时地改变通信对象的属性
• Private Sub txtThreshold_Change()
• =
Val()
• End Sub
• 13、智能接收终端
• 指能够接收服务器端发送来的命令或数据,能对解析出
不同的命令并执行相应的操作的智能节点。接受的命令和
数据来自主机。
• 人机界面如下图所示:
• (1)接收命令
• Private Sub CmdExit_Click()
• End
• End Sub
• Private Sub Comm1_OnComm()
• Dim t&, Buf$, StrPos%
• Select Case
• ' 借着取代底下每一个 case 语句来处理每个事件与错误事件
• Case comEvCD ' CD 线的状态发生变化.
• Case comEvCTS ' CTS 线的状态发生变化.
• Case comEvDSR ' DSR 线的状态发生变化.
• Case comEvRing ' Ring Indicator 变化.
• Case comEvReceive ' 收到 RThreshold # of Data
• t = GetTickCount() ‘库函数调用
• Do
• DoEvents
• Loop Until GetTickCount - t > 100
•
• Buf = Trim() '从输入缓冲区读取数据
• If Len(Buf) < 2 Then Exit Sub
• = + Buf
• StrPos = InStr(1, Buf, "%%")
• If StrPos < 1 Then
• = "未收到正常命令!"
• Else
• = "执行" & Right(Buf, Len(Buf) -
(StrPos + 1)) &
• "命令成功…" '我们自己的控制子程序
• End If
• Case comEvSend ' 传输缓冲区有 Sthreshold 个
字符 '
• End Select
• End Sub
• Private Sub Command1_Click()
• = ""
• End Sub
• Private Sub Form_Load()
• = True
• End Sub
• 在标准模块声明:
• Option Explicit
• Declare Function GetTickCount Lib
"kernel32" () As Long
• 14、数据服务器(数据以!号结束)
• 根据客户端的数据请求,给客户提供数
据(21个),最后发送“!”表示数据发送
结束。另外,通过本例学会使用API函数的调
用。
• Private Sub CmdExit_Click()
• End
• End Sub
• Private Sub Comm1_OnComm()
• Dim t&, Buf$, StrPos%, CmdStr$
• Dim i%
• Select Case
• Case comEvCD ' CD 线的状态发生变化.
• Case comEvCTS ' CTS 线的状态发生变化.
• Case comEvDSR ' DSR 线的状态发生变化.
• Case comEvRing ' Ring Indicator 变化.
• Case comEvReceive ' 收到 RThreshold # of
Data
• t = GetTickCount()
• Do
• DoEvents
• Loop Until GetTickCount - t > 100Buf =
Trim() '从输入缓冲区读取数据
• If Len(Buf) < 2 Then Exit Sub
• = + Buf
• StrPos = InStr(1, Buf, "%%")
• If StrPos < 1 Then
• = "未收到正常命令!"
• Else
• CmdStr = Right(Buf, Len(Buf) - (StrPos + 1))
• = "执行" & CmdStr & "命令中…"
• '我们自己的子程序
• If UCase(Trim(CmdStr)) <> "DATA" Then
• = "命令不正确!"
• Exit Sub
• End If
• = + "数据发送中…"
• For i = 0 To 20
• = Trim(Str(GetData())) & ","
• Next i
• = "!"
• = + "发送完成。"
• End If
• Case comEvSend ‘ 传输缓冲区有 Sthreshold 个字符
• End Select
• End Sub
• Private Sub Command1_Click()
• = ""
• End Sub
• Private Sub Form_Load()
• = True
• End Sub
• 在标准模块中声明和定义函数:
• Option Explicit
• ‘声明使用GettickCount的API函数
• Declare Function GetTickCount Lib "kernel32" () As Long
• Function GetData()
• Randomize
• GetData = 10 * Rnd()
• End Function
• 15、数据服务器模拟2
• 提供数据服务。若收到数据请求端发来的
字符串中有前导码“%%”和命令”DATA”,
就给请求端发送数据。*标准模块函数的调用。
• 人机界面:
• Option Explicit
• Private Sub CmdExit_Click()
• End
• End Sub
• Private Sub Comm1_OnComm()
• Dim t&, Buf$, ByteBuf() As Byte, StrPos%, CmdStr$
• Dim i%
• Select Case
• Case comEvCD ' CD 线的状态发生变化.
• Case comEvCTS ' CTS 线的状态发生变化.
• Case comEvDSR ' DSR 线的状态发生变化.
• Case comEvRing ' Ring Indicator 变化.
• Case comEvReceive ' 收到 RThreshold # of Data
• t = GetTickCount()
• Do
• DoEvents
• Loop Until GetTickCount - t > 100
• Buf = Trim() 'Read Data from input buffer
• If Len(Buf) < 2 Then Exit Sub
• = + Buf
• StrPos = InStr(1, Buf, "%%")
• If StrPos < 1 Then
• = "未收到正常命令!"
• Else
• CmdStr = Right(Buf, Len(Buf) - (StrPos + 1))
• ' = "执行" & CmdStr & "命令中…"
• '我们自已的子程序
• If InStr(1, UCase(Trim(CmdStr)), "DATA") = 0 Then
• = "命令不正确!"
• Exit Sub
• End If
• = + "数据发送中…"
• ReDim ByteBuf(0 To 20)
• GetData ByteBuf()
• = ByteBuf
• = + "发送完成。"
• End If
• Case comEvSend ' 传输缓冲区有 Sthreshold 个字符 '
• End Select
• End Sub
• Private Sub Command1_Click()
• = ""
• End Sub
• Private Sub Form_Load()
• = True
• End Sub
• 在标准模块中:
• Option Explicit
• '声明使用GettickCount的API函数
• Declare Function GetTickCount Lib "kernel32" () As Long
• Function GetData(Data() As Byte)
• Dim i%
• Randomize
• '以下产生0~255之间的数字
• For i = LBound(Data) To UBound(Data)
• Data(i) = CByte(255! * Rnd())
• Next i
• End Function
• 16、数据请求端
• 起作用是向数据服务器提出数据请求,本例
的数据请求命令串中应包含“%%Data”字样。
• 人机界面:
• 软件设计:
• '声明一个字符串变量作为接收字符串的存储区
• Dim ReceiveStr$
• '使用命令按钮
• '结束系统
• Private Sub CmdExit_Click()
• End
• End Sub
• '将发送字符串利用Output指令发送出去
• Private Sub CmdSend_Click()
• = Trim()
• End Sub
• Private Sub Comm1_OnComm()
• Dim buf$, StrPos%
• Select Case
• Case comEvCD ' CD 线的状态发生变化.
• Case comEvCTS ' CTS 线的状态发生变化.
• Case comEvDSR ' DSR 线的状态发生变化.
• Case comEvRing ' Ring Indicator 变化.
• Case comEvReceive ' 收到 RThreshold # of
• buf = Trim()
• ReceiveStr = ReceiveStr + buf
• If InStr(1, buf, "!") < 1 Then
• Exit Sub
• Else
•
• Do
• StrPos = InStr(1, ReceiveStr, ",")
• If StrPos = 0 Then Exit Do
• = +
Left(ReceiveStr, StrPos - 1) & Chr(13) & Chr(10)
• ReceiveStr = Right(ReceiveStr, Len(ReceiveStr) -
InStr(1, ReceiveStr, ","))
• Loop
• ReceiveStr = ""
• End If
• Case comEvSend ' 传输缓存区有 Sthreshold 个字符
'
• End Select
• End Sub
• '清空接收区的显示内容
• Private Sub Command1_Click()
• = ""
• End Sub
• Private Sub Form_Load()
• = True
• End Sub
• 17、图形显示
• 把接收的数据以图形的方式显示出来,本例是
在图片框中划线的方法绘制图形。运行时要和
数据服务器端配合。亦即,向数据服务器请求
数据,收到数据后绘成曲线。
• Dim ReceiveStr$, ReceiveData!(21)
• '使用命令按钮
• '结束系统
• Private Sub CmdExit_Click()
• End
• End Sub
• '将发送字符串利用Output指令发送出去
• ''''''''''''''''''''''''''''''''''''''
• Private Sub CmdSend_Click()
• = Trim()
• End Sub
• Private Sub Comm1_OnComm()
• Dim buf$, StrPos%, i%, j%, TempSng!
• Dim X!(20), Y!(20)
• Select Case
• Case comEvCD ' CD 线的状态发生变化.
• Case comEvCTS ' CTS 线的状态发生变化.
• Case comEvDSR ' DSR 线的状态发生变化.
• Case comEvRing ' Ring Indicator 变化.
• Case comEvReceive ' 收到 RThreshold # of
• buf = Trim()
• ReceiveStr = ReceiveStr + buf
• If InStr(1, ReceiveStr, "!") < 1 Then
• Exit Sub
• Else
• i = 0
•
•
• Do
• StrPos = InStr(1, ReceiveStr, ",")
• If StrPos = 0 Then Exit Do
• ReceiveData(i) = Val(Left(ReceiveStr, StrPos - 1))
• ReceiveStr = Right(ReceiveStr, Len(ReceiveStr) - InStr(1, ReceiveStr,
","))
• X(i) = i
• Y(i) = ReceiveData(i)
• If i = 0 Then
• (X(i), Y(i))
• Else
• -(X(i), Y(i))
• End If
• i = i + 1
• Loop
• ReceiveStr = ""
• End If
• Case comEvSend ‘ 传输缓冲区有 Sthreshold 个字符
• End Select
• End Sub
• Private Sub Command1_Click()
•
• End Sub
• Private Sub Command2_Click()
• Dim StrPos%
• StrPos = InStr(1, , "%%")
• If StrPos < 1 Then Exit Sub
• If UCase(Right(, Len() - StrPos - 1)) <> "DATA" Then
Exit Sub
• = 1000
• = True
• End Sub
• Private Sub Form_Load()
• = True
• (0, 10)-(20, 0)
• = RGB(0, 0, 255)
• End Sub
• Private Sub Timer1_Timer()
• CmdSend_Click
• End Sub
• 18、图形显示处理方法2
• 本节与上例主要体现在小数处理部分的技
巧、方法等。
• 人机界面同上例.
• Option Explicit
• ''''''''''''''''''''''''''''''''''''''
• Dim ReceiveStr$, ReceiveData!(21)
• Private Sub CmdExit_Click()
• End
• End Sub
• '使用命令按钮控件
• '将传送字符串利用Output指令传送出去
• '并处理由服务器所返回来的字节数据
• Private Sub CmdSend_Click()
• Dim buf() As Byte, i%
• Dim X!(), Y!(), TempStr$
• Dim TT As Long
• = 0 '清除输入缓冲区
• = Trim() '传送指令
• TT = GetTickCount
• ' TimeDelay 1500
•
• Do
• DoEvents
• = False
• Loop Until >= 21 Or GetTickCount - TT > 2000
• = True
• If < 20 Then Exit Sub
• buf = '将缓冲区内的数据读入
• ReDim X(LBound(buf) To UBound(buf)) '重订数组范围
• ReDim Y(LBound(buf) To UBound(buf))
• (LBound(buf), 2)-(UBound(buf), 0)
• '清除图片
• For i = LBound(buf) To UBound(buf)
• X(i) = i
• '组合实际数值
• TempStr = CStr(IIf(buf(i) And &H80, 1, 0)) & "." & CStr((buf(i) And &H7F))
• Y(i) = Val(TempStr) '转换为数值
• If i = 0 Then
• (X(i), Y(i)) '绘原点
• Else
• -(X(i), Y(i)) '绘线
• End If
• Next i
• End Sub
• Private Sub Command1_Click()
•
• End Sub
• Private Sub Command2_Click()
• Dim StrPos%
• StrPos = InStr(1, , "%%")
• If StrPos < 1 Then Exit Sub
• If UCase(Right(, Len() - StrPos - 1)) <> "DATA" Then Exit Sub
• = 1000
• = True
• End Sub
• Private Sub Form_Load()
• = True
• = RGB(0, 0, 255)
• End Sub
• Private Sub Timer1_Timer()
• CmdSend_Click
• End Sub
• 要在标准模块中写:
• Option Explicit
• Public Declare Function GetTickCount Lib "kernel32" ()
As Long
• ''''''''''''''''''''''''''''''''''''''''''''''''''
''''''''''''''''''''''''''''''''''''''''''''''''''
''''
• '时间延迟子程序,单位是毫秒
• ''''''''''''''''''''''''''''''''''''''''''''''''''
''''''''''''''''''''''''''''''''''''''''''''''''''
''''
• Sub TimeDelay(DT As Long)
• Dim TT As Long
• TT = GetTickCount
• Do
• DoEvents
• Loop Until GetTickCount - TT >= DT
• End Sub
• 19、信号灯显示
• 信号灯可反映设备运行的状态,例如,电
动机的启、停。来自现场某种物理量的大小
(数据的大小),也可用面向对象的颜色参数
来表示,例如RGB(a,b,c)或QBcolor(n)等。
• 本节就是把来自数据服务器的数据作为RGB
()函数的参数,也就是以此来改变shape控
件的背景色即信号灯的颜色。
• 人机界面设计:
• 软件设计:
• ''''''''''''''''''''''''''''''''''''''
• '声明一个字符串变量及单精度变量数组
• '字符串变量用以存储接收到的字符串
• '数组则用以存储处理后的数值数据
• ''''''''''''''''''''''''''''''''''''''
• Dim ReceiveStr$, ReceiveData!(21)
• Private Sub CmdExit_Click()
• End
• End Sub
• Private Sub CmdSend_Click()
• = Trim()
• End Sub
• Private Sub Comm1_OnComm()
• Dim buf$, StrPos%, i%, j%, TempSng!
• Select Case
• Case comEvCD ' CD 线的状态发生变化.
• Case comEvCTS ' CTS 线的状态发生变化.
• Case comEvDSR ' DSR 线的状态发生变化.
• Case comEvRing ' Ring Indicator 变化.
• Case comEvReceive ' 收到 RThreshold # of
• buf = Trim()
• If InStr(1, buf, "!") < 1 Then
• ReceiveStr = ReceiveStr + buf
• Else
• i = 0
• Do
• StrPos = InStr(1, ReceiveStr, ",")
• If StrPos = 0 Then Exit Do
• ReceiveData(i) = Val(Left(ReceiveStr, StrPos - 1))
• ReceiveStr = Right(ReceiveStr, Len(ReceiveStr) -
InStr(1, ReceiveStr, ","))
• i = i + 1
• Loop
• ReceiveStr = ""
• End If
• j = 0
•
• For i = 0 To 15 Step 3
• TempSng = ReceiveData(i) + ReceiveData(i + 1) +
ReceiveData(i + 2)
• If TempSng > 15# Then
• Shape1(j).FillColor = RGB(255, 0, 0)
• ElseIf TempSng > 10! Then
• Shape1(j).FillColor = RGB(128, 128, 128)
• Else
• Shape1(j).FillColor = RGB(0, 255, 0)
• End If
• j = j + 1
• Next i
• Case comEvSend ' 传输缓冲区有 Sthreshold 个字符
• End Select
• End Sub
• Private Sub Command1_Click()
• Dim i%
• For i = 0 To 5
• Shape1(i).FillColor = RGB(0, 0, 0)
• Next i
• End Sub
• Private Sub Command2_Click()
• Dim StrPos%
• StrPos = InStr(1, , "%%")
• If StrPos < 1 Then Exit Sub
• If UCase(Right(, Len() - StrPos -
1)) <> "DATA" Then Exit Sub
• = 1000
• = True
• End Sub
• Private Sub Form_Load()
• = True
• End Sub
• Private Sub Timer1_Timer()
• CmdSend_Click
• End Sub
• C:通讯工程应用
• 1、单个单片机与PC串口通信(c1)
• PC通过串行口将数字(00,01,02,03...
,FF,十六进制)发送给单片机,单片机
收到后回传这个数字,PC接收到回传数据
后显示出来,若发送的数据和接收到的数
据相等,则串行通信正确,否则有错误。
启始符是数字00,结束符是数字FF。
• PC端程序设计
• 人机界面设计如下图
• 软件:
• '将数字(0,1,2,3...255,转换为16进制)传给单片机,单
片机收到后回传这个数字,PC机接收到回传数据后显示出来,
• '若发送和接收的数据相同,显示通信正常,否则通信不正常
• '发送以00开始,以FF结束
• '定义变量
• Dim data, data1 As Variant '串口初始化
• '在窗体的Load事件中加入下列代码对串口进行初始化:
• Private Sub Form_Load()
• = 1
• = 1
• = 1
• = 1
• = "9600,n,8,1"
• = True
• = "00"
• End Sub
• '单击清空文本框
• Private Sub senddata_Click()
• = ""
• = True
• End Sub
• Private Sub senddata_Change()
• = UCase()
• End Sub
• Private Sub senddata_KeyPress(KeyAscii As Integer)
• If (KeyAscii >= Asc("a") And KeyAscii <= Asc("f"))
Then
• KeyAscii = KeyAscii - 32
• End If
• End Sub
• '向单片机发送数据
• Private Sub Cmdsend_Click()
• If Len() <> 2 Then
• MsgBox ("请输入2位16进制数!")
• Exit Sub
• End If
• c =
• If (c = "FF") Then
• data1 = "&H" & c
• data = Chr(data1)
• Else
• a = Left(c, 1) '截取senddata左边字符
• b = Right(c, 1) '截取senddata右边字符
• data1 = "&H" & 'data1没有将senddata中的字符拆开
• data = Chr("&H" & a) & Chr("&H" & b) '将senddata中的字符拆开存入data
中,这样就会解决例如A1接收不正确的问题
• End If
• = data
• = False
• End Sub
• '获取温度测量值并显示
• '每发送一次指令,触发下面事件,返回数据串
• Private Sub MSComm1_OnComm()
• Dim Inbyte() As Byte
• Dim buffer As Variant
• '读取仪表返回数据串
• Select Case
• Case comEvReceive
• Inbyte =
• For i = LBound(Inbyte) To UBound(Inbyte)
• buffer = buffer + Hex(Inbyte(i))
• Next i
• Case comEvSend
• End Select
• If Len(Trim(buffer)) = 1 Then
• = Str("0") & buffer
• Else
• = buffer
• End If
•
• If "&H" & buffer = data1 Then
• = QBColor(13)
• = "通信正常!"
• End If
• If "&H" & buffer <> data1 Then
• = QBColor(12)
• = "通信不正常!"
• = "未接收到数据"
• End If
• If Trim(buffer) = "FF" Then
• = QBColor(12)
• = "输入00重新开始!"
• End If
• End Sub
• '当退出程序时,关闭串行口
• Private Sub Cmdquit_Click()
• Unload Me
• End Sub
• Private Sub Form_QueryUnload(Cancel As
Integer, UnloadMode As Integer)
• = False '关闭串口
• End Sub
• PC端的设计方案2(c1-2)
• 人机界面如下:
• 软件:
• Dim data As Variant '串口初始化
• '在窗体的Load事件中加入下列代码对串口进行初始化:
• Private Sub Form_Load()
• = 1
• = 1
• = 1
• = 1
• = "9600,n,8,1"
• = True
• End Sub
• '单击清空文本框
• Private Sub numText_Click()
• = ""
• = True
• End Sub
• '向单片机发送数据
• Private Sub Cmdsend_Click()
• data = "&H" & Hex(Val())
• = Chr(data)
• = False
• End Sub
• '获取温度测量值并显示
• '每发送一次指令,触发下面事件,返回数据串
• Private Sub MSComm1_OnComm()
• Dim Inbyte() As Byte
• Dim buffer As Variant
• '读取仪表返回数据串
• Select Case
• Case comEvReceive
• Inbyte =
• For i = LBound(Inbyte) To UBound(Inbyte)
• buffer = buffer + Hex(Inbyte(i))
• Next i
•
• Case comEvSend
• End Select
• If Len(Trim(buffer)) = 1 Then
• = Str("0") & buffer
• Else
• = buffer
• End If
• If "&H" & buffer = data Then
• = QBColor(13)
• = "通信正常!"
• End If
• If "&H" & buffer <> data Then
• = QBColor(12)
• = "通信不正常!"
• End If
•
• If Trim(buffer) = "FF" Then
• = QBColor(12)
• = "输入0重新开始!"
• End If
• End Sub
• '当退出程序时,关闭串行口
• Private Sub Cmdquit_Click()
• Unload Me
• End Sub
• Private Sub Form_QueryUnload(Cancel As
Integer, UnloadMode As Integer)
• = False '关闭串口
• End Sub
• 单片机端(c1单片机)
• # include<>
• # define uchar unsigned char
• void rece(void);
• void init(void);
• uchar re[17];
• /*主程序*/
• void main(void)
• {
• uchar temp;
• init();
• do{
• while(RI==0);
• temp=SBUF;
• if(temp==0x00)
• {rece();}
• else break;
• }while(1);
• }
• /*串口初始化*/
• void init(void)
• {
• TMOD=0x20; //定时器1--方式2
• PCON=0x80; //电源控制
• SCON=0x50; //方式1
• TL1=0xFa;
• TH1=0xFa; //晶振,波特率为
4800 0xf3 9600 0xfa 19200 0xfd
• TR1=1; //启动定时
• }
• /*接收返回数据*/
• void rece(void)
• {
• char i;
• i=0;
• do{while(RI==0);
• re[i]=SBUF;
• RI=0;
• SBUF=re[i];
• while(TI==0);
• TI=0;
• i++;
• }while(re[i-1]!=255);
• }
• 2、单个单片机与PC串口通信项目(c2)
• 1)测试通信状态
• 先在文本框中输入字符串“Hello”,单击“测试”按钮,
将字符串“Hello”发送到单片机,若PC与单片机通信正常,
在PC程序的文本框中显示字符串“OK!”,否则显示字符串
“ERROR!”。
• 2)循环计数
• 单击“开始”按钮,文本框中数字从0开始累加,0、1、
2、3…,并将此数发送到单片机的显示器上显示;当累加到
10时,回到0重新开始累加,依次循环;任何时候,单击“停
止”按钮,PC程序中和单片机显示器都停止累加,再单击“
开始”按钮,接着停下的数继续累加。
• 3)控制指示灯
• 在单片机继电器接线端子的2个通道上分别接上2个指示
灯,在PC程序画面上选择指示灯号,如1号灯,单击画面“
打开”按钮,单片机上1号灯亮,同时蜂鸣器响;单击画面“
关闭”按钮,1号灯灭,蜂鸣器停止响;同样控制2号灯的亮
灭(蜂鸣器同时动作)。
• PC 端发送 MCU端接收并完成
• H OK
• R 开始记数
• S 停止记数
• A 1号灯亮,同时蜂鸣器响
• B 1号灯灭,蜂鸣器停止响
• C 2号灯亮,同时蜂鸣器响
• D 2号灯灭,蜂鸣器停止响
• 注:MCU端是自动化专业学生研发的单片机开发
装置
• 单片机硬件电路
• 单片机程序(c2-单片机)
• #include <>
• /****************************数码显示 键盘接口定义
• sbit PS0=P0^0;//数码管个位
• sbit PS1=P0^1;//数码管十位
• sbit PS2=P0^2;//数码管百位
• sbit PS3=P0^3;//数码管千位
• sfr P_data=0xa0;//P2口为显示数据输出口
• unsigned char
tab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//字段转换表
• sbit P_1=P1^1;
• sbit P_3=P1^3;
• sbit P_7=P1^7;
• sbit LIGHT1=P1^4;//灯1
• sbit LIGHT2=P1^5;//灯2
• sbit BUZZER=P0^4;//蜂鸣器
• unsigned char COUNTER;//循环计数器
• bit count;//循环计数器 启停标志位 1启动记数 0停止记数
• void delay(unsigned int delay_time) //短延时子程序
• {for(;delay_time>0;delay_time--)
• {}
• }
• unsigned char htd(unsigned char a)
• {
• unsigned char b,c; //16进制转换成10进制
• b=a%10;
• c=b;
• a=a/10;
• b=a%10;
• c=c|b<<4;
• return c;
• }
• void uart(void) interrupt 4 //把接收到的数据写入ucReceiveData
()
• {
• TI=0;
• RI=0;
• if(SBUF=='H')//接收到'H'字符 发送'OK'
• {
• SBUF='O';
• while(TI==0) ;
• TI=0;
• SBUF='K';
• while(TI==0) ;
• TI=0;
• }
•
• else if(SBUF=='R')
• {
• count=1;
• }
• else if(SBUF=='S')
• {
• count=0;
• }
• else if(SBUF=='A')
• {
• LIGHT1=0;//1号灯亮
• BUZZER=0;//蜂鸣器响
• }
•
• else if(SBUF=='B')
• {
• LIGHT1=1;//1号灯灭
• BUZZER=1;//蜂鸣器停
• }
• else if(SBUF=='C')
• {
• LIGHT2=0;//2号灯亮
• BUZZER=0;//蜂鸣器响
• }
• else if(SBUF=='D')
• {
• LIGHT2=1;//2号灯灭
• BUZZER=1;//蜂鸣器停
• }
• }
• void display(unsigned int temp)
• {
•
• P_data=tab[temp&0x0f];//显示个位
• PS0=0;
• PS1=1;
• PS2=1;
• PS3=1;
• delay(200);
•
• P_data=tab[(temp>>4)&0x0f]; //显示十位
• PS0=1;
• PS1=0;
• PS2=1;
• PS3=1;
• delay(200);
•
•
• P_data=tab[(temp>>8)&0x0f];//显示百位
• PS0=1;
• PS1=1;
• PS2=0;
• PS3=1;
• delay(200);
•
• P_data=tab[(temp>>12)&0x0f]; //显示千位
• PS0=1;
• PS1=1;
• PS2=1;
• PS3=0;
• delay(200);
• PS3=1;
• P_data=0xff;//恢复数据口
• }
• void main(void)
• {
• TMOD=0x20; //定时器1--方式2
• IE=0x12; //中断控制设置,串口、T2开中断
• EA=0,禁能中断服务。*/
• PCON=0x80; //电源控制
• SCON=0x50; //方式1
• TL1=0xFa;//0xF4;
• TH1=0xFa;//0xF4;
• TR1=1;
• ES=1;
• EA=1;
• LIGHT1=1;
• LIGHT2=1;
• COUNTER=0;
•
• PCON=0x80; //电源控制
• SCON=0x50; //方式1
• TL1=0xFa;//0xF4;
• TH1=0xFa;//0xF4;
• TR1=1; //启动定时
• ES=1;
• EA=1;
• LIGHT1=1;
• LIGHT2=1;
• COUNTER=0;
•
• while(1)
• {
• unsigned char i;
• for(i=0;i<50;i++)
• display(htd(COUNTER));
• if(count)
• COUNTER++;
• if(COUNTER>10)
• COUNTER=0;
• }
• }
• PC机端(c2)
• 人机界面设计如下图
• 软件设计
• '定义变量
• Dim choise As Integer '选择指示灯号
• Dim cnum As Integer '循环计数标志
• '串口初始化
• Private Sub Form_Load()
• = 1 '设置通信端口号为COM1
• = "9600,n,8,1" '设置串口通信参数
• = 0 '接收文本型数据
• = True '打开通信端口1
• = False
• = False
• choise = 1
• End Sub
• '把字符"H"通过串口发送出去
• '如果通信正常,单片机返回字符串"OK"
• Private Sub CmdTest_Click()
• Dim buffer As String
• = Trim()
• Call delay
• buffer =
• If buffer = "OK" Then
• = "OK!"
• = False
• = True
• = True
• Else
• = "ERROR!"
• = False
• End If
• End Sub
• '延时
• Sub delay()
• For i = 0 To 2000000
• n = n + 1
• Next i
• End Sub
• '开始计数
• Private Sub CmdStart_Click()
• = "R"
• = True
• End Sub
• '停止计数
• Private Sub CmdStop_Click()
• = "S"
• End Sub
• '选择1号灯
• Private Sub Option1_Click()
• choise = 1
• End Sub
• '选择2号灯
• Private Sub Option2_Click()
• choise = 2
• End Sub
• '打开指示灯
• Private Sub CmdOpen_Click()
• If choise = 1 Then
• = "A"
• Else
• = "C"
• End If
• End Sub
• '关闭指示灯
• Private Sub CmdClose_Click()
• If choise = 1 Then
• = "B"
• Else
• = "D"
• End If
• End Sub
• '停止程序运行
• Private Sub Cmdquit_Click()
• Unload Me
• End Sub
• '关闭通信端口,
• Private Sub Form_Unload(Cancel As Integer)
• = False
• End Sub
• Private Sub Timer1_Timer()
• cnum = cnum + 1
• If cnum > 200 Then
• cnum = 0
• End If
• = cnum
• End Sub
• 2、PC与多个单片机串口通信设计任务(c3)
• PC通过串行口(RS485)将十六进制数发送给多个单片
机,驱动地址吻合的单片机继电器动作,并在数码管显示接收
的数。单片机接收到数据后,返回原数据给PC。
• 单片机程序(c3)
• #include< (c3)
• #include<>
• #define addr 01
• #define uint unsigned int
• #define uchar unsigned char
• sbit jdq1=P1^0;//继电器1
• sbit jdq2=P1^1;//继电器2
• /****************************数码显示 键盘接口定义
****************************************/
• sbit PS0=P0^0;//数码管个位
• sbit PS1=P0^1;//数码管十位
• sbit PS2=P0^2;//数码管百位
• sbit PS3=P0^3;//数码管千位
• sfr P_data=0xA0;//P2口为显示数据输出口
• uchar tab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
• uchar data_buf[2];
• void init_serial(void);
• void display(uchar a,uchar c);
• void sw_out(unsigned char b);//开关量输出
• void delay(unsigned int delay_time);
• void main(void)
• { uint a;
• init_serial();
• RI=0;
• while(1)
• { for(a=0;a<200;a++)//显示,兼有延时的作用
• display(data_buf[1],addr);
•
• }
• }
• /**************************串口初始化
函数void init_serial(void)
• { TMOD=0X20;//定时器1方式2
• TH1=0XFA;
• TL1=0XFA;
• PCON=0X80;
• SCON=0X50;//串口方式1,允许接收,
波特率9600bit/s
• TR1=1; //开始计时
• ES=1;
• EA=1;
• }
• //串口中断处理函数
• void serial_int() interrupt 4
• { uchar c0,i;
• if(RI==1)
• { data_buf[i]=SBUF;
• RI=0;
• i++;
• c0++;
• if(data_buf[0]!=addr)
• { data_buf[0]=0;
• data_buf[1]=0;
• c0=0;
• i=0;
• return;
• }
• if( c0==2)
• { c0=0;
• sw_out(data_buf[1]);
• TI=0;
• SBUF=data_buf[0];
• while(!TI);
• TI=0;
• TI=0;
• SBUF=data_buf[1];
• while(!TI);
• TI=0;
• i=0;
• }
• }
• }
• /**************************数码管显示函数
**************************/
• void display(uchar a,uchar c)
• {
• P_data=tab[a&0x0f];//显示数据1位
• PS0=0;
• PS1=1;
• PS2=1;
• PS3=1;
• delay(200);
• P_data=tab[(a>>4)&0x0f]; //显示数据十位
• PS0=1;
• PS1=0;
• delay(200);
•
• P_data=tab[c];//显示地址1位
• PS1=1;
• PS2=0;
• delay(200);
• P_data=tab[0];//显示地址十位
• PS2=1;
• PS3=0;
• delay(200);
• PS3=1;
• P_data=0xff;//恢复数据口
• }
• /**************************数据输出函数
• void sw_out(unsigned char b)
• {
• if(b==0x00)
• {
• jdq1=1; //接收到发来的数据00,关闭继电器1和2
• jdq2=1;
• }
• else if(b==0x01)
• {
• jdq1=1; //接收到发来的数据01,继电器1关闭,继电
器2打开
• jdq2=0;
• }
•
• else if(b==0x10)
• {
• jdq1=0; //接收到发来的数据10,继电器1打开,继电器2
关闭
• jdq2=1;
• }
• else if(b==0x11)
• {
• jdq1=0; //接收到发来的数据11,打开继电器1和2
• jdq2=0;
• }
• }
• void delay(unsigned int delay_time) //延时子程序
• {for(;delay_time>0;delay_time--)
• {}
• }
• PC机端(c3)
• 1、人机界面设计如下
• 'PC发送数据01 11,表示01号单片机板继电器1和2打开
• 'PC发送数据01 00,表示01号单片机板继电器1和2关闭
• 'PC发送数据02 01,表示02号单片机板继电器1关闭,继电器
2打开
• 'PC发送数据02 10,表示02号单片机板继电器1打开,继电器
2关闭
• '初始化串口
• Private Sub Form_Load()
• = 1
• = "9600,n,8,1"
• = 1
• = 1
• = 1
• = True
• End Sub
• '状态输出
• Private Sub Cmdout_Click()
• Dim uout1 As Variant '单片机地址号
• Dim uout2 As Variant '单片机继电器状态值
• uout1 = "&H" & Val()
• uout2 = "&H" & Val()
• = Chr(uout1) & Chr(uout2)
'将16进制数据值发送给单片机
• End Sub
• '返回数据
• Private Sub MSComm1_OnComm()
• Dim Inbyte() As Byte
• Dim buffer As String
• Dim strdata(10) As String
• Dim datanum As String
• Select Case
• Case comEvReceive
• Inbyte =
'读取单片机返回的数据串
•
• For i = LBound(Inbyte) To UBound(Inbyte)
• buffer = buffer + Hex(Inbyte(i)) + Chr(32)
• Next i
• Case comEvSend
• End Select
• For jj = 1 To 6
• strdata(jj) = Mid(Trim(buffer), jj, 1) '从数
据串中逐个取位
• Next jj
• If Len(Trim(buffer)) = 3 Then
• datanum = "0" & strdata(1) & strdata(2) & "0" &
strdata(3)
• End If
•
• If Len(Trim(buffer)) = 4 Then
• datanum = "0" & strdata(1) & strdata(2) &
strdata(3) & strdata(4)
• End If
• = datanum '显示单片
机返回的数据串
• End Sub
• '关闭程序
• Private Sub Cmdexit_Click()
• = False
• Unload Me
• End Sub