路由器接路由器怎么设置-屏幕分辨率改不了

mscomm
2023年4月4日发(作者:骁龙821)

vc串口通讯控件MSComm编程详解

在mfc中进行串口通讯最简单的方法莫过于在对话框中使用MSCOMM控件了,MSComm通信控件提供了

一系列标准通信命令的接口,它允许建立串口连接,可以连接到其他通信设备(如Modem).

还可以发送命令、进行数据交换以及监视和响应在通信过程中可能发生的各种错误和事件,从而可以用它

创建全双工、事件驱动的、高效实用的通信程序。

一、用MSComm控件通信

1.串口通信基础知识

一般悦来,计算机都有一个或多个串行端口,它们依次为com1、Com2、…,这些串口还提供了外部

设备与pC进行数据传输和皿信的通道。这些串口在CPU和外设之间充当解释器的角色。当字符数据从CPU

发送给外设时,这些字符数据将被转换成串行比特流数据;当接收数据时,比特流数据被转换为字符数据

传递给CPU,再进一步说,在操作系统方面,Windows用通信驱动程序()调用API函数发

送和接收数据,当用通信控件或声明调用API函数时,它门由解释并传递给设备驱动程序,

作为一个vB程序员,要编写通信程序.只需知道通信控件提供给Windows通信AP1函数的接口即可.换

句话说,只需设定和监视通信控件的属性和事件即可。

2.使用Mscomm控件

在开始使用MSComm控件之前。需要先了解其属性、事件或错误

属性描述

CommPort设置或返回通信端口号

Settings以字符串的形式设置或返回波特率、奇偶校验、数据位和停止位

PortOpen设置或返回通信端口的状态。也可以打开和关闭端口

Input返回和删除接收缓冲区中的字符

Output将字符串写入发送缓冲区

CommEvent属性为通信事件或错误返回下列值之一。在该控件的对象库中也可以找到这些常量。

常量值描述

ComEventBreak1001收到了断开信号

ComEventCTSTO1002ClearToSendTimeout。在发送字符时,在系统指定的事1件内,CTS(Clear

ToSend)线是低电平

ComEventDSRTO1003DataSetReadyTimeout。在发送字符时,在系统指定的事件内,DSR(DataSet

Ready)线是低电平

ComEventFrame1004数据帧错误。硬件检测到一个数据帧错误

ComEventOverrun1006端口溢出。硬件中的字符尚未读,下一个字符又到达,并且丢失

ComEventCDTO1007CarrierDetectTime。在发送字符时,在系统指定的事件内,CD(CarrierDetect)

线是低电平。CD也称为RLSD(ReceiveLineSingalDetect,接收线信号检测)

ComEventRxOver1008接收缓冲区溢出。在接收缓冲区中没有空间

ComEventRxParity1009奇偶校验错。硬件检测到奇偶校验错误7

ComEventTxFull1010发送缓冲区满。在对发送字符排队时,发送缓冲区满

ComEventDCB1011检取端口DCB(DeviceControlBlick)时发生了没有预料到的错误

通信事件包含了下面的设置:

常量值描述

ComEvSend1发送缓冲区中的字符数比Sthreshold值低

ComEvReceive2接收到了Rthreshold个字符。持续产生该事件,直到使用了Input属性删除了接收

缓冲区中的数据

ComEvCTS3CTS(ClearToSend)线改变

ComEvDSR4DSR(DataSetReady)线改变。当DSR从1到0改变时,该事件发生

ComEvCD5CD(CarrierDetect)线改变ComEvRing6检测到响铃信号。一些URAT(Universal

AsynchronousReciver--Transmitters,通用异步收发器)不支持该事件

ComEvEOF7收到了EOF字符(ASCII字符26)

Error消息(MSComm控件)下表列出了MSComm控件可捕获的错误消息:

常量值描述

ComInvalidPropertyValue380无效的属性值

ComSetNotSupported383属性只读

ComGetNotSupported394属性只读

ComPortOpen8000端口打开时该存在无效

8001超时设置必须比0值大

ComPortInvalid8002无效的端口号

8003属性只在运行时有效

8004属性在运行时是只读的

ComPortAleadyOpen8005端口已经打开

8006设备标识符无效或不支持

8007不支持设备的波特率

8008指定的字节大小无效

8009缺省参数错误

8010硬件不可用(被其他设备锁住)

8011函数不能分配队列

ComNoOpen8012设备没有打开

8013设备已经打开

8014不能使用通信通知

ComSetCommStateFailed8015不能设置通信状态

8016不能设置通信事件屏蔽

ComPortNotOpen8018该存在只在端口打开是有效

8019设备忙

ComReadError8020通信设备读错误

ComDCBError8021检取端口设备控制块时出现内部错误

注意在使用的时候一定要保证两个通讯串口的设置是相同的,否则受到的信息将会产生错误!

由于取值位数的不同,有可能发送的信息要读很多次才能组合成需要的信息!

1。建立mfc工程,都会撒。

将控件加进来:打开“Project->AddToProject->ComponentsandControls->RegisteredActivexControls”,然

后选择控件:MicrosoftCommunicationControl,version6.0插入到当前的工程中。这样就将类CMSComm的

相关文件和mscomm.h一并加入到了工程中。编程时只需将控件对话中的MSComm控件

拖至你的应用对话框中就OK了

2。定义串口对象:

CMSCommm_MSComm;

3。串口初始化:

DWORDstyle=WS_VISIBLE;

m_(NULL,style,CRect(0,0,0,0),this,IDC_MSCOMM);

if(m_tOpen())//如果串口是打开的,则行关闭串口

{

m_tOpen(FALSE);

}

m_mPort(1);//选择COM1

m_ufferSize(1024);//接收缓冲区

m_BufferSize(1024);//发送缓冲区

m_utLen(0);//设置当前接收区数据长度为0,表示全部读取

m_utMode(1);//以二进制方式读写数据

m_reshold(1);//接收缓冲区有1个及1个以上字符时,将引发接收数据的OnComm事件

m_tings("9600,n,8,1");//波特率9600无检验位,8个数据位,1个停止位

if(!m_tOpen())//如果串口没有打开则打开

m_tOpen(TRUE);//打开串口

else

{

m_BufferCount(0);

AfxMessageBox("OpenTheSerialPort1Failurre!");

}

4。串口数据读写:

MSComm类的读写函数比较简单:GetInput()和SetOutput()。函数原形分别为VARIANTGetInput()和

voidSetOutput(constVARIANTnewValue),均使用VARIANT类型。但PC机发送和接收数据时习惯用字

符串形式。MSDN中查阅VARIANT类型,可以用BSTR表示字符串,但所有的BSTR都包含宽字符,而

只有WindowsNT支持宽字符,Windows9X并不支持。所以要完成一个适应各平台的串口应用程序必须解

决这个问题。这里使用CbyteArray即可解决之。

发数据:在对话框对加入按钮控件并给你添加消息

voidCTest_mscommDlg::OnSend()

{

//TODO:Addyourcontrolnotificationhandlercodehere

inti,Count;

CStringm_SendData;

m_SendData="Hello!";

Count=m_gth();

CByteArraym_Array;

m_All();

m_e(Count);

for(i=0;im_(i,m_SendData[i]);

m_put(COleVariant(m_Array));

}

收数据:给串口控件添加消息

voidCTest_mscommDlg::OnOnCommMscomm()

{

VARIANTm_input;

char*str,*str1;

intk,nEvent,i;

CStringstr2,m_RcvData;

nEvent=m_mEvent();

switch(nEvent)

{

case2:

k=m_ufferCount();//接收缓冲区的字符数目

if(k>0)

{

m_input=m_ut();

str=(char*)(unsignedchar*)m_->pvData;

}

i=0;

str1=str;

while(i)

{

i++;

str1++;

}

*str1='{t}';

str2=(constchar*)str;//清除字符串中的不必要字符

m_RcvData=(constchar*)str;

}

//数据显示处理

m_disp+=m_RcvData;

UpdateData(false);

}

目次

控件两种处理通讯的方式">MSComm控件两种处理通讯的方式

CommPort属性

RThreshold属性

CTSHolding属性

SThreshold属性

CDHolding属性

DSRHolding属性

Settings属性

InputLen属性

EOFEnable属性

Handshake常数

OnComm常数

InputMode常数

错误消息

MSComm控件通过串行端口传输和接收数据,为应用程序提供串行通讯功能。MSComm控件在串口编

程时非常方便,程序员不必去花时间去了解较为复杂的API函数,而且在VC、VB、Delphi等语言中均可

使用。MicrosoftCommunicationsControl(以下简称MSComm)是Microsoft公司提供的简化Windows下

串行通信编程的ActiveX控件,它为应用程序提供了通过串行接口收发数据的简便方法。具体的来说,它

提供了两种处理通信问题的方法:一是事件驱动(Event-driven)方法,一是查询法。

控件两种处理通讯的方式">控件两种处理通讯的方式

MSComm控件提供下列两种处理通讯的方式:事件驱动方式和查询方式。

1.1事件驱动方式

事件驱动通讯是处理串行端口交互作用的一种非常有效的方法。在许多情况下,在事件发生时需要得到通

知,例如,在串口接收缓冲区中有字符,或者CarrierDetect(CD)或RequestToSend(RTS)线上一个

字符到达或一个变化发生时。在这些情况下,可以利用MSComm控件的OnComm事件捕获并处理这些

通讯事件。OnComm事件还可以检查和处理通讯错误。所有通讯事件和通讯错误的列表,参阅CommEve

nt属性。在编程过程中,就可以在OnComm事件处理函数中加入自己的处理代码。这种方法的优点是程

序响应及时,可靠性高。每个MSComm控件对应着一个串行端口。如果应用程序需要访问多个串行端口,

必须使用多个MSComm控件。

1.2查询方式

查询方式实质上还是事件驱动,但在有些情况下,这种方式显得更为便捷。在程序的每个关键功能之后,

可以通过检查CommEvent属性的值来查询事件和错误。如果应用程序较小,并且是自保持的,这种方法

可能是更可取的。例如,如果写一个简单的电话拨号程序,则没有必要对每接收一个字符都产生事件,因

为唯一等待接收的字符是调制解调器的“确定”响应。

控件的常用属性

MSComm控件有很多重要的属性,但首先必须熟悉几个属性。

CommPort设置并返回通讯端口号。

Settings以字符串的形式设置并返回波特率、奇偶校验、数据位、停止位。

PortOpen设置并返回通讯端口的状态。也可以打开和关闭端口。

Input从接收缓冲区返回和删除字符。

Output向传输缓冲区写一个字符串。

下面分别描述:

CommPort属性设置并返回通讯端口号。

语法rt[value](value一整型值,说明端口号。)

说明在设计时,value可以设置成从1到16的任何数(缺省值为1)。但是如果用PortOpen属性打开

一个并不存在的端口时,MSComm控件会产生错误68(设备无效)。

注意:必须在打开端口之前设置CommPort属性。

RThreshold属性:在MSComm控件设置CommEvent属性为comEvReceive并产生OnComm之前,

设置并返回的要接收的字符数。

语法hold[=value](value整型表达式,说明在产生OnComm事件之前要接收的字符数。)

说明当接收字符后,若Rthreshold属性设置为0(缺省值)则不产生OnComm事件。例如,设置Rthr

eshold为1,接收缓冲区收到每一个字符都会使MSComm控件产生OnComm事件。

CTSHolding属性:确定是否可通过查询ClearToSend(CTS)线的状态发送数据。ClearToSend是调

制解调器发送到相联计算机的信号,指示传输可以进行。该属性在设计时无效,在运行时为只读。

语法:ding(Boolean)

Mscomm控件的CTSHolding属性设置值:

TrueClearToSend线为高电平。

FalseClearToSend线为低电平。

说明:如果ClearToSend线为低电平(CTSHolding=False)并且超时时,MSComm控件设置CommE

vent属性为comEventCTSTO(ClearToSendTimeout)并产生OnComm事件。

ClearToSend线用于RTS/CTS(RequestToSend/ClearToSend)硬件握手。如果需要确定ClearToS

end线的状态,CTSHolding属性给出一种手工查询的方法。

详细信息有关握手协议,请参阅Handshaking属性。

SThreshold属性:MSComm控件设置CommEvent属性为comEvSend并产生OnComm事件之前,设

置并返回传输缓冲区中允许的最小字符数。

语法hold[=value]

value整形表达式,代表在OnComm事件产生之前在传输缓冲区中的最小字符数。

说明:若设置Sthreshold属性为0(缺省值),数据传输事件不会产生OnComm事件。若设置Sthresho

ld属性为1,当传输缓冲区完全空时,MSComm控件产生OnComm事件。如果在传输缓冲区中的字符

数小于value,CommEvent属性设置为comEvSend,并产生OnComm事件。comEvSend事件仅当字符

数与Sthreshold交叉时被激活一次。例如,如果Sthreshold等于5,仅当在输出队列中字符数从5降到

4时,comEvSend才发生。如果在输出队列中从没有比Sthreshold多的字符,comEvSend事件将绝不会

发生。

Handshake常数

常数值描述

comNone0无握手。

comXonXoff1XOn/Xoff握手。

comRTS2Request-to-send/clear-to-send握手。

comRTSXOnXOff3Request-to-send和clear-to-send握手皆可。

OnComm常数

常数值描述

comEvSend1发送事件。

comEvReceive2接收事件。

comEvCTS3clear-to-send线变化。

comEvDSR4data-setready线变化。

comEvCD5carrierdetect线变化。

comEvRing6振铃检测。

comEvEOF7文件结束。

Error常数

常数值描述

comEventBreak1001接收到中断信号

comEventCTSTO1002Clear-to-send超时

comEventDSRTO1003Data-setready超时

comEventFrame1004帧错误

comEventOverrun1006端口超速

comEventCDTO1007Carrierdetect超时

comEventRxOver1008接收缓冲区溢出

comEventRxParity1009Parity错误

comEventTxFull1010传输缓冲区满

comEventDCB1011检索端口设备控制块(DCB)时的意外错误

InputMode常数

常数值描述

comInputModeText0(缺省)通过Input属性以文本方式取回数据。

comInputModeBinary1通过Input属性以二进制方式检取回数据。

CDHolding属性:通过查询CarrierDetect(CD)线的状态确定当前是否有传输。CarrierDetect是从调制

解调器发送到相联计算机的一个信号,指示调制解调器正在联机。该属性在设计时无效,在运行时为只读。

语法ing

设置值:CDHolding属性的设置值为:

设置描述

TrueCarrierDetect线为高电平

FalseCarrierDetect线为低电平

说明:注意当CarrierDetect线为高电平(CDHolding=True)且超时时,MSComm控件设置CommEve

nt属性为comEventCDTO(CarrierDetect超时错误),并产生OnComm事件。

注意在主机应用程序中捕获一个丢失的传输是特别重要的,例如一个公告板,因为呼叫者可以随时挂起(放

弃传输)。

CarrierDetect也被称为ReceiveLineSignalDetect(RLSD)。

数据类型Boolean

DSRHolding属性:确定DataSetReady(DSR)线的状态。DataSetReady信号由调制解调器发送到相

连计算机,指示作好操作准备。该属性在设计时无效,在运行时为只读。

语法:ding

object所在处表示对象表达式,其值是“应用于”列表中的对象。

DSRHolding属性返回以下值:

值描述

TrueDataSetReady线高

FalseDataSetReady线低

说明:当DataSetReady线为高电平(DSRHolding=True)且超时时,MSComm控件设置CommEvent

属性为comEventDSRTO(数据准备超时)并产生OnComm事件。当为DataTerminalEquipment(DT

E)机器写DataSetReady/DataTerminalReady握手例程时该属性是十分有用的。数据类型:Boolean

Settings属性:设置并返回波特率、奇偶校验、数据位、停止位参数。

语法:gs[=value]

说明:当端口打开时,如果value非法,则MSComm控件产生错误380(非法属性值)。

Value由四个设置值组成,有如下的格式:

"BBBB,P,D,S"BBBB为波特率,P为奇偶校验,D为数据位数,S为停止位数。value的缺省值是:

"9600,N,8,1"

InputLen属性:设置并返回Input属性从接收缓冲区读取的字符数。

语法en[=value]

InputLen属性语法包括下列部分:

value整型表达式,说明Input属性从接收缓冲区中读取的字符数。

说明:InputLen属性的缺省值是0。设置InputLen为0时,使用Input将使MSComm控件读取接收缓

冲区中全部的内容。

若接收缓冲区中InputLen字符无效,Input属性返回一个零长度字符串("")。在使用Input前,用户可以

选择检查InBufferCount属性来确定缓冲区中是否已有需要数目的字符。该属性在从输出格式为定长数据

的机器读取数据时非常有用。

EOFEnable属性:确定在输入过程中MSComm控件是否寻找文件结尾(EOF)字符。如果找到EOF字

符,将停止输入并激活OnComm事件,此时CommEvent属性设置为comEvEOF,

语法:ble[=value]

EOFEnable属性语法包括下列部分:

value布尔表达式,确定当找到EOF字符时,OnComm事件是否被激活,如“设置值”中所描述。

value的设置值:

True当EOF字符找到时OnComm事件被激活。

False(缺省)当EOF字符找到时OnComm事件不被激活。

说明:当EOFEnable属性设置为False,OnComm控件将不在输入流中寻找EOF字符。

错误消息(MSComm控件)

下表列出MSComm控件可以捕获的错误:

值描述

380无效属性值comInvalidPropertyValue

383属性为只读comSetNotSupported

394属性为只读comGetNotSupported

8000端口打开时操作不合法comPortOpen

8001超时值必须大于0

8002无效端口号comPortInvalid

8003属性只在运行时有效

8004属性在运行时为只读

8005端口已经打开comPortAlreadyOpen

8006设备标识符无效或不支持该标识符

8007不支持设备的波特率

8008指定的字节大小无效

8009缺省参数错误

8010硬件不可用(被其它设备锁定)

8011函数不能分配队列

8012设备没有打开comNoOpen

8013设备已经打开

8014不能使用comm通知

8015不能设置comm状态comSetCommStateFailed

8016不能设置comm事件屏蔽

8018仅当端口打开时操作才有效comPortNotOpen

8019设备忙

8020读comm设备错误comReadError

8021为该端口检索设备控制块时的内部错误comDCBError

1引言

近年来,随着微处理器、计算机和数字通信技术的迅猛发展,计算机控制已扩展到了几乎所

有的工业领域。它不仅以其良好的性能满足了工业生产的广泛需要,而且将通信技术与信息

处理技术融为一体,成为具有逻辑控制功能、过程控制功能、运动控制功能、数据处理功能、

联网通信功能的多功能控制器。在PLC组成的控制系统中,一般由PLC作为下位机,完成

数据采集、状态判别、输出控制等,上位机(微型计算机、工业控制机)完成采集数据信息的

存储、分析处理、人机界面的交互以及打印输出,以实现对系统的实时监控。这种监控系统

充分利用了微型机和PLC各自的特点,实现了优势互补。其中的技术关键是实现PLC与计

算机的互联通信。

2通信方式和通信协议

2.1通信方式

目前PLC和PC机的互联通信方式有以下几种:

(1)通过PLC开发商提供的系统协议和网络适配器,构成特定公司产品的内部网络,其通

信协议不公开。互联通信必须使用开发商提供的上位机组态软件,并采用支持相应协议的外

设。这种方式其显示画面和功能往往难以满足用户的具体需要;

(2)购买目前通用的上位机组态软件。这种方式除了要增加系统投资以外,其运用的灵活性

也受到一定限制;

(3)利用PLC厂商所提供的标准通信端口和由用户自定义的自由端口通信方式。这种方式

不需要增加投资,具备较好的灵活性,特别适合小规模控制系统。

S7-200系列PLC的通信接口是与RS-485兼容的9针D型连接器,符合EN50170。附表

给出了通信口的引脚分配。

PC机的标准串口为RS-232,西门子公司提供的PC/PPI电缆带有RS232/RS485电平转换

器,因此在不增加任何硬件的情况下,可以很方便地将PLC和PC机互联。

2.2通信协议

S7-200支持多种通信协议,主要有:

(1)点对点接口协议(PPI)

PPI是主/从协议,网络上的S7-200CPU均为从站,其他CPU、SIMATIC编程器或TD2

00为主站;

(2)多点接口协议(MPI)

MPI是集成在西门子公司的可编程序控制器、操作员界面和编程器上的集成通信接口,用于

建立小型的通信网络。最多可接32个节点,典型数据长度为64字节,最大距离100m;

(3)Profibus协议

Profibus协议用于分布式I/O设备(远程I/O)的高速通信。许多厂家生产类型众多的PROFI

BUS设备,如简单的输入/输出模块、电机控制器和可编程序控制器;

(4)用户定义协议(自由端口模式)

通过使用接收中断、发送中断、字符中断、发送指令(XMT)和接收指令(RCV),自由端口通

信可以控制S7-200CPU通信口。通过SMB30,允许在CPU处于RUN模式时通信口采

用自由端口模式。CPU处于STOP模式时,停止自由端口通信,通信口强制转换为PPI协

议模式。

自由端口模式为计算机与S7-200CPU之间的通信提供了一种廉价与灵活的方法。计算机

与PLC通信时,为了避免各方争用信道,一般采用主从方式,即计算机为主机,PLC为从

机,只有主机才有权主动发送请求报文,从机收到后返回响应报文。

3PLC端通信编程

PLC的通信编程首先是对串口初始化。对S7-200的初始化是通过对特殊标志位SMB30写

入通信控制字,设置端口0通信的波特率,奇偶校验位、停止位和字符长度。SMB130用

于端口1的设置。显然,这些设定必须与PC机设定相一致。S7-200系列有专用的发送指

令XMT(Transmit),通过指定的通信端口(PORT),发送存储在数据缓冲区(TBL)中的信息。

接收指令RCV(Receive)初始化或终止接收信息的服务,通过指定的通信端口(PORT),接

收信息并存储在数据缓冲区(TBL)中。为提高通信可靠性可以采用异或校验(或求和校验)。

使用字符中断方式接收数据,以起始字符作为接收报文的开始,部分程序如下:

//主程序

LDSM0.0

MOVB16#05,SMB30

//19200bps,8位数据,无奇偶校验,1位停止位

ATCHINT_0,8//出现接收字符中断时执行INT_0

ENI//允许中断

//中断程序

LDSM0.0

DTCH10//关闭定时中断10

XMTVB100,0//回送接收到的数据

ATCHINT_0,8//准备接收下一帧报文

需要注意的是,如果使用PC/PPI电缆,在S7-200CPU的用户程序中应考虑电缆的切换

时间。从接收到请求报文后到发送响应报文的延迟时间和再次发出请求报文的延迟时间都必

须大于等于电缆的切换时间。通信波特率为9600bps和19200bps时,切换时间分别为2

ms和1ms。

4上位机通信编程

在Windows环境下开发与工业PLC通信的软件,利用VisualC++6.0的通信控件MSCom

m控件编写软件程序。该通信控件提供了使用RS232开发串行通信软件的细则,使用事件

驱动或查询方式来解决开发通信软件中遇到的问题。

在当前工程中插入Mscomm控件时,如果是基于对话框或视图类是基于CformView的应用

程序,加入方法十分简单。如果不是,就需要创建一个Mscomm控件。方法与普通的Acti

veX控件的创建类似。首先在MainFrm.h中添加声明语句:

protected:CMSCommm_myCom;

然后在::OnCreate()函数中添加下列创建控件的语句:

DWORDstyle=WS_VISIBLE|WS_CHILD;

If(!m_(NULL,style,CRect(0,0,0,0),this,ID_COMMCTRL))

{

TRACE0("FailedtocreateOLECommunicationsControl");

Return-1;

}

开发通信程序部分代码如下:

//首先初始化通信端口

m_mPort(1);//选择COM1

m_ufferSize(1024);//设置输入缓冲

//区的大小

m_BufferSize(512);//设置输出缓

//冲区的大小

m_utMode(1);//设置数据获取方式

m_tings("19200,N,8,1");//设置通

//信参数

m_utLen(0);//设置读取方式

if(!m_tOpen());

m_tOpen(TRUE);//打开串口

收发数据时我们一般习惯于使用字符串形式(数组形式),而读写函数GetInput()和SetOutp

ut()都要使用VARIANT类型(查阅MSDN可知,IDispatch::Invoke()的参数和返回值作为V

ARIANT对象处理),可以用BSTR表示字符串(包含宽字符),为了解决系统不支持宽字符

的问题,使用了CByteArray,部分程序如下:

//接收事件

voidCCommDlg::OnComm()

{

intiCount;

if(m_mEvent()==2)

//接收事件,在缓冲区内数据被移走前持续产生

iCount=m_ufferCount();

//接收到字符数目

m_utLen(iCount);

if(iCount>0){

COleVariantvRec=m_ut();

//读取字符

Type(VT_BSTR);

m_response=l;

//把接收到的变量赋给应答帧文本框变量

UpdateData(FALSE);

…}//数据处理

}

//发送事件

voidCCommDlg::OnSend()

{

//…准备需要发送的命令,放在SendData[>中

CByteArrayarray;

All();

e(iCount);

for(inti=0;i

(i,SendData[i>);

m_put(COleVariant(array);

)

5结束语

西门子S7-200型PLC有很强的通信功能,在硬件配置与安装上,建议系统交流电源使用

双层隔离,输入信号光电隔离,提高信噪比,远离强电布线,模拟量信号和数字信号采用屏

蔽线传送,采用可靠接地等措施,能有效地消除或减弱外界信号干扰。在软件设计与编程上,

加入抗干扰模块,如采用软件滤波技术,对一些重要模拟量参数进行延时判定,并进一步确

认报警;在通讯软件设计中采用多种校验措施等都能大大提高系统的抗干扰性能。采用本方

法设计的通讯程序简单实用、维护和扩充方便,对同类系统的设计与实现有一定的启发。

1.建立项目

2.在项目中插入MSComm控件

3.利用ClassWizard定义CMSComm类控制变量

4.在对话框中添加控件

5.添加串口事件消息处理函数OnComm()

6.打开和设置串口参数

7.发送数据

8.发送十六进制字符

9.在接收框中以十六进制显示

10.如何设置自动发送

11.什么是VARIANT数据类型?如何使用VARIANT数据类型?

这是串口调试助手源程序及编程详细过程(一)的续篇,首先谢谢朋友们的支持与鼓励。

8.发送十六进制字符

在主对话框中加入一个复选接钮,ID为IDC_CHECK_HEXSENDCaption:十六进制发送,再利用

ClassWizard为其添加控制变量:m_ctrlHexSend;

在ClassView中为SCommTestDlg类添加以下两个PUBLIC成员函数,并输入相应代码;

//由于这个转换函数的格式限制,在发送框中的十六制字符应该每两个字符之间插入一个空隔

//如:A123450B0029

//CByteArray是一个动态字节数组,可参看MSDN帮助

intCSCommTestDlg::String2Hex(CStringstr,CByteArray&senddata)

{

inthexdata,lowhexdata;

inthexdatalen=0;

intlen=gth();

e(len/2);

for(inti=0;i

{

charlstr,hstr=str[i];

if(hstr=='')

{

i++;

continue;

}

i++;

if(i>=len)

break;

lstr=str[i];

hexdata=ConvertHexChar(hstr);

lowhexdata=ConvertHexChar(lstr);

if((hexdata==16)||(lowhexdata==16))

break;

else

hexdata=hexdata*16+lowhexdata;

i++;

senddata[hexdatalen]=(char)hexdata;

hexdatalen++;

}

e(hexdatalen);

returnhexdatalen;

}

//这是一个将字符转换为相应的十六进制值的函数

//好多C语言书上都可以找到

//功能:若是在0-F之间的字符,则转换为相应的十六进制字符,否则返回-1

charCSCommTestDlg::ConvertHexChar(charch)

{

if((ch>='0')&&(ch<='9'))

returnch-0x30;

elseif((ch>='A')&&(ch<='F'))

returnch-'A'+10;

elseif((ch>='a')&&(ch<='f'))

returnch-'a'+10;

elsereturn(-1);

}

再将CSCommTestDlg::OnButtonManualsend()修改成以下形式:

voidCSCommTestDlg::OnButtonManualsend()

{

//TODO:Addyourcontrolnotificationhandlercodehere

UpdateData(TRUE);//读取编辑框内容

if(m_ck())

{

CByteArrayhexdata;

intlen=String2Hex(m_strTXData,hexdata);//此处返回的len可以用于计算发送了多少个十六进制数

m_put(COleVariant(hexdata));//发送十六进制数据

}

else

m_put(COleVariant(m_strTXData));//发送ASCII字符数据

}

现在,你先将串口线接好并打开串口调试助手V2.1,选上以十六制显示,设置好相应串口,然后运行我们

这个程序,在发送框中输入00010203A1CC等十六进制字符,并选上以十六进制发送,单击手动发送,

在串口调试助手的接收框中应该可以看到00010203A1CC了。

9.在接收框中以十六进制显示

这就容易多了:在主对话框中加入一个复选接钮,IDC_CHECK_HEXDISPLAYCaption:十六进制显示,

再利用ClassWizard为其添加控制变量:m_ctrlHexDiaplay。然后修改CSCommTestDlg::OnComm()函数:

voidCSCommTestDlg::OnComm()

{

//TODO:Addyourcontrolnotificationhandlercodehere

VARIANTvariant_inp;

COleSafeArraysafearray_inp;

LONGlen,k;

BYTErxdata[2048];//设置BYTE数组An8-bitintegerthatisnotsigned.

CStringstrtemp;

if(m_mEvent()==2)//事件值为2表示接收缓冲区内有字符

{

variant_inp=m_ut();//读缓冲区

safearray_inp=variant_inp;//VARIANT型变量转换为ColeSafeArray型变量

len=safearray_DimSize();//得到有效数据长度

for(k=0;k

safearray_ment(&k,rxdata+k);//转换为BYTE型数组

for(k=0;k

{

BYTEbt=*(char*)(rxdata+k);//字符型

if(m_ck())

("%02X",bt);//将字符以十六进制方式送入临时变量strtemp存放,注意这里加入一个

空隔

else

("%c",bt);//将字符送入临时变量strtemp存放

m_strRXData+=strtemp;//加入接收编辑框对应字符串

}

}

UpdateData(FALSE);//更新编辑框内容

}

测试:在串口调试助手发送框中输入00010203A1CC等十六进制字符,并选上以十六进制发送,单击

手动发送,在本程序运行后选上以十六进制显示,在串口调试助手中单击手动发送或自动发送,则在本程

序的接收框中应该可以看到00010203A1CC了。

10.如何设置自动发送

最简单的设定自动发送周期是用SetTimer()函数,这在数据采集中很有用,在控制中指令的传送也

可能用到定时发送。

方法是:在ClassWizard中选上MessageMap卡,然后在ObjectsIDs选中CSCommTestDlg类,再在

Messages框中选上WM_TIMER消息,单击ADD_FUNCTION加入voidCSCommTestDlg::OnTimer(UINTnIDEvent)

函数,这个函数是放入“时间到”后要处理的代码:

voidCSCommTestDlg::OnTimer(UINTnIDEvent)

{

//TODO:Addyourmessagehandlercodehereand/orcalldefault

OnButtonManualsend();

CDialog::OnTimer(nIDEvent);

}

再在在主对话框中加入一个复选接钮,ID为IDC_CHECK_AUTOSENDCaption:自动发送(周期1秒),再利

用ClassWizard为其添加BN_CLICK消息处理函数voidCSCommTestDlg::OnCheckAutosend():

voidCSCommTestDlg::OnCheckAutosend()

{

//TODO:Addyourcontrolnotificationhandlercodehere

m_bAutoSend=!m_bAutoSend;

if(m_bAutoSend)

{

SetTimer(1,1000,NULL);//时间为1000毫秒

}

else

{

KillTimer(1);//取消定时

}

}

其中:m_bAutoSend为BOOL型变量,在CLASSVIEW中为CSCommTestDlg类加入,并在构造函数中初始化:

m_bAutoSen=FALSE;

现在可以运行程序测试了。

11.什么是VARIANT数据类型?如何使用VARIANT数据类型?

不知如何使用VARIANT数据类型,有不少朋友对VARIANT这个新的数据类型大感头疼。SetOutput()

函数中需要的VARIANT参数还可以使用COleVariant类的构造函数简单生成,现在GetInput()函数的返

回值也成了VARIANT类型,那么如何从返回的值中提取有用的内容。VARIANT及由之而派生出的

COleVariant类主要用于在OLE自动化中传递数据。实际上VARIANT也只不过是一个新定义的结构罢了,

它的主要成员包括一个联合体及一个变量。该联合体由各种类型的数据成员构成,而该变量则用来指明联

合体中目前起作用的数据类型。我们所关心的接收到的数据就存储在该联合体的某个数据成员中。该联合

体中包含的数据类型很多,从一些简单的变量到非常复杂的数组和指针。由于通过串口接收到的内容常常

是一个字节串,我们将使用其中的某个数组或指针来访问接收到的数据。这里推荐给大家的是指向一个

SAFEARRAY(COleSafeArray)类型变量。新的数据类型SAFEARRAY正如其名字一样,是一个“安全数组”,

它能根据系统环境自动调整其16位或32位的定义,并且不会被OLE改变(某些类型如BSTR在16位或32

位应用程序间传递时会被OLE翻译从而破坏其中的二进制数据)。大家无须了解SAFEARRAY的具体定义,

只要知道它是另外一个结构,其中包含一个(void*)类型的指针pvData,其指向的内存就是存放有用数

据的地方。简而言之,从GetInput()函数返回的VARIANT类型变量中,找出parray指针,再从该指针指

向的SAFEARRAY变量中找出pvData指针,就可以向访问数组一样取得所接收到的数据了。具体应用请参见

voidCSCommTestDlg::OnComm()函数。

大概我现在也说不清这个问题,我自己从第一次接触这个东西,到现在还是给别人讲不清。

另:二进制收发设置请参考MSComm控件说明。

在VC++中用ActiveX控件实现与单片机的串行通信

在单片机应用系统中,经常需要通过RS-232串行口与微机进行通信。目前在各种操作系统中,

Microsoft的Windows较为常见,而且大多为Windows95/98等32位平台。以往在Windows平台上的串行

通信多使用其提供的API函数来实现,这种方法使用起来需要许多底层设置,因而较为繁琐,并且难以理

解。Microsoft推出的ActiveX技术提供了另外一种实现串行通信的方法。这种方法不仅相对较为简单,

而且非常实用。尤其是VisualC++这种可视化面向对象的编程环境中,可以真正把串口看作一个对象,编

程时只需简单的设置,理解起来也很容易。下面详细讨论Microsoft提供的串行通信ActiveX控件的使用

方法。该控件的相应文件是,以下简称为MSCOMM控件。

一、MSCOMM控件

MSCOMM控件,即MicrosoftCommunicationControl,是Microsoft为简化Windows下串行通信编程

而提供的ActiveX控件。它提供了一系列标准通信命令的使用接口,利用它可以建立与串口的连接,并可

以通过串口连接到其他通信

设备(如调制解调器),发出命令,交换数据以及监视和响应串行连接中发生的事件和错误。MSCOMM控件

可用于创建电话拨号程序、串口通信程序和功能完备的终端程序。

MSCOMM控件提供了两种处理通信的方式:

(1)事件驱动方式。当通信事件发生时,MSCOMM控件会触发OnComm事件,调用者可以捕获该事件,

通过检查其CommEvent属性便可确认发生的是哪种事件或错误,从而进行相应的处理。这种方法的优点是

响应及时、可靠性高。

(2)查询方式。在程序的每个关键功能之后,可以通过检查CommEvent属性的值来查询事件和错误。

如果应用程序较小,这种方法可能更可取。例如,如果写一个简单的电话拨号程序,则没有必要每接收1

个字符都产生事件,因为惟一等待接收的字符是调制解调器的"确定"响应。

在使用MSCOMM控件时,1个MSCOMM控件只能同时对应1个串口。如果应用程序需要访问和控件多个

串口,那么必须使用多个MSCOMM控件。

在VC++中,MSCOMM控件只对应着1个C++类--CMSComm。由于MSCOMM控件本身没有提供方法,所以

CMSComm类除了Create()成员函数外,其他的函数都是Get/Set函数对,用来获取或设置控件的属性。

MSCOMM控件也只有1个OnComm事件,用来向调用者通知有通信事件发生。

MSCOMM控件有许多很重要的属性,限于篇幅只给出几个较为重要和常用的属性,如表1所列。

表1MSCOMM控件的重要属性

二、编程实现

从表1可以看到,MSCOMM可以两种不同的形式接收数据,即以文本形式和以二进制形式。用MSCOMM

控件进行字符数据传输的文献和资料可以找到很多,在Microsoft的MSDN(MicrosoftDeveloperNetwork)

中就可以找到这样的例子,即VCTERM。可是几乎所有以单片机为核心的测量系统所得到的原始数据都是二

进制形式的,所以,以二进制形式传输数据将是最为直接而又简洁的办法。不仅如此,由于MSCOMM控件在

文本形式下,其传输的是宽字符格式的字符,要想得到有用信息,还要额外处理。因此本文主要讨论在二

进制形式下的使用方法。

在VC++6.0中,用APPWizard可以生成三种应用程序:单文档(SDI)、多文档(MDI)和基于对话框

的应用程序。为了说明问题和省去不必要的细节,下面以基于对话框的应用程序为例。

1.创建一个基于对话框的应用程序

打开VC++6.0集成开发环境,选择菜单项File/New,在出现的对话框中选中Projects标签中的MFC

AppWizard(exe),然后在ProjectName框中填入MyCOMM(可根据需要命名),之后点OK按钮。在接着出现

的对话框中选中DialogBased项,然后点NEXT按钮。以下的各对话框都按照缺省设置,这样即可生成一

个基于对话框的应用程序。在资源编程器中会出现其对话框模板。

2.插入MSCOMM控件

选择菜单项Project/Addtoproject/ComponentsandControls„,在弹出的对话框中选择Registered

ActiveXControls文件夹下的MicrosoftCommunicationsControl,version6.0,然后按下Insert按钮,

接着会弹出一个对话框,提示生成的类名及文件名,按OK按钮即可实现控件的插入。这时在对话框的控件

工具栏上会多出一个电话机模样的控件图标,Workspace的Classview中也多了一个类CMSComm。

此时即可将MSCOMM控件加入到对话框模板,加入方法与其他控件一样。然后还要在对话框类中相应加

入一个成员变量,此处我们将其命名为m_comm。加入方法为:首先,在对话框模板中,用鼠标右键点击该

控件,选择ClassWizard,在出现的对话框的MemberVariables标签的ControlIds项下,选中IDC_MSCOMM1。

然后,按AddVariable„按钮,在出现的对话框的MemberVariableName项中输入m_comm。最后,按OK

按钮即可。

3.设置属性

可以在两个地方对控件的属性进行设置:

(1)对话框资源编辑器中。在对话框模板上,用右键单击MSCOMM控件,然后选择Properties„菜单

项,最后便可设置各项属性。此处只对以下几处进行改动,其他接受缺省设置:Rthershold:1,InputLen:

1,DTREnable:不选,InputMode:1-Binary。

(2)对话框类的OnInitDialog()函数中。下面是以上设置的函数实现:

BOOLCMyCOMMDlg::OnlnitDialog()

{

CDialog::OnlnitDialog();

//此处为应用框架自动生成代码,不予列出

//TODO:Addextrainitializationhere

m_mPort(1);//使用串口1

m_tings("9600,N,8,1");

//波特率为9600,无奇偶校验,8位数据位,1位停止位

m_reshold(10);//每接收10个字符就触发1次接收事件

m_reshold(0);//不触发发送事件

m_utLen(10);//每次读操作从缓冲区中取10个字符

m_utMode(1);//二进制数据传输形式

m_tOpen(TRUE);//打开串口

returnTRUE;//returnTRUEunlessyousetthefocustoacontrol

}

4.发送二进制数据

如果需要发送二进制数据,可将数据作如下处理。具体代码如下:

CByteArraybytOutArr;

(0x0);//给数组赋值

(0x1);

(0x2);

(0x3);

(0x4);

COleVariantvarOut;

varOut=COleVariant(bytOutArr);//将数据转换为变体数据类型

m_put(varOut);//发送数据

5.接收二进制数据

当需要接收大量的数据时,最好采用事件驱动方式进行编程。具体步骤如下:

(1)响应OnComm事件。在对话框资源编程器中,双击对话框模板上的MSCOMM控件,在弹出的对话框

中填入您所希望的事件响应函数名,此处将其命名为OnCommMscomm1()。

(2)在事件响应函数中接收和处理数据。接收来的数据为变体数据,所以需要做一些处理,具体代码

如下:

voidCMyCOMMDlg::OnCommMscomm1()

{

COleVariantvarRcv;

CByteArraybyt;

inti;

longnum;

switch(m_mEvent())

{

cass1://数据发送事件

break;

case2://数据接收事件

varRcv=m_ut();

Type(VT_ARRAY|VT_UI1);

BYTEHUGEP*pbstr;

HRESULThr;

hr=SafeArrayAccessData(,(voidHUGEP*FAR*)&pbstr);//获取安全数组指针

if(FAILED(hr)){

AfxMessageBox("获取数组指针失败!");

break;}

num=0;

hr=SafeArrayGetUBound(,1amp;num);//获取数组上界

if(FAILED(hr)){

AfxMessageBox("获取数组上界失败!");

break;}

for(i=0;(pbstr[i]);

SafeArrayUnaccessData();

//此时数据已保存在二进制数组byt中,可根据需要进行相关处理

break;

default:

break;

}

}

以上代码中的处理部分可以做成一个单独的函数,在此处调用即可。经过以上代码的处理,接收来的

数据已存放在二进制数组byt中,可以根据自己的需要对其进行相关处理,如保存和显示等。

三、硬件接口

单片机与微机之间的硬件接口可以用1片MAX232或ICL232与几个电容即可实现,有许多文献讨论

过,此处不再多述。

以上方法经过笔者在实践中的应用,感到非常简洁、方便,具有很强的实用意义。

MSComm控件

VisualC++为我们提供了一种好用的ActiveX控件MicrosoftCommunicationsControl(即MSComm)

来支持应用程式对串口的访问,在应用程式中插入MSComm控件后就能较为方便地实现对通过计算机串

口收发数据。

要使用ActiveX控件MSComm,程式员必须将其添加入工程,其方法是:

(1)单击主菜单project的子菜单AddToproject的ComponentsandControls选项;

(2)在弹出的"ComponentsandControlsGallery"对话框中选择RegisteredActiveXControls目录中

的"MicrosoftCommunicationsControl,version6.0"选项,如下图:

单击其中的"Insert"按钮,MSComm控件就被增加到工程中了。和此同时,类CMSComm的相关文件mscomm.h

和也一并被加入Project的HeaderFiles和SourceFiles中。当然,程式员能自己修改文件名,

如下图:

直接分析mscomm.h头文件就能完备地获取这个控件的使用方法(主要是public类型的接口函数),下面我

们摘取了头文件的主要代码并对其关键部分给出了注释:

#if!defined(AFX_MSCOMM_H__)

#defineAFX_MSCOMM_H__

#if_MSC_VER>1000

#pragmaonce

#endif//_MSC_VER>1000

//MachinegeneratedIDispatchwrapperclass(es)createdbyMicrosoftVisualC++

//NOTE:classisregeneratedby

//MicrosoftVisualC++,yourmodificationswillbeoverwritten.

/////////////////////////////////////////////////////////////////////////////

//CMSCommwrapperclass

classCMSComm:publicCWnd

{

protected:

DECLARE_DYNCREATE(CMSComm)

public:

CLSIDconst&GetClsid()

{

staticCLSIDconstclsid={0x648a5600,0x2c6e,0x101b,{0x82,0xb6,0x0,0x0,0x0,0x0,0x0,

0x14}};

returnclsid;

}

virtualBOOLCreate(LPCTSTRlpszClassName,

LPCTSTRlpszWindowName,DWORDdwStyle,

constRECT&rect,

CWnd*pParentWnd,UINTnID,

CCreateContext*pContext=NULL)

{returnCreateControl(GetClsid(),lpszWindowName,dwStyle,rect,pParentWnd,nID);}

BOOLCreate(LPCTSTRlpszWindowName,DWORDdwStyle,

constRECT&rect,CWnd*pParentWnd,UINTnID,

CFile*pPersist=NULL,BOOLbStorage=FALSE,

BSTRbstrLicKey=NULL)

{returnCreateControl(GetClsid(),lpszWindowName,dwStyle,rect,pParentWnd,nID,

pPersist,bStorage,bstrLicKey);}

//Attributes

public:

//Operations

public:

voidSetCDHolding(BOOLbNewValue);

BOOLGetCDHolding();

voidSetCommID(longnNewValue);

longGetCommID();

voidSetCommPort(shortnNewValue);

//设置端口号,如nNewValue=1表示COM1

shortGetCommPort();

voidSetCTSHolding(BOOLbNewValue);

BOOLGetCTSHolding();

voidSetDSRHolding(BOOLbNewValue);

BOOLGetDSRHolding();

voidSetDTREnable(BOOLbNewValue);

BOOLGetDTREnable();

voidSetHandshaking(longnNewValue);

longGetHandshaking();

voidSetInBufferSize(shortnNewValue);

shortGetInBufferSize();

voidSetInBufferCount(shortnNewValue);

shortGetInBufferCount();

voidSetBreak(BOOLbNewValue);

BOOLGetBreak();

voidSetInputLen(shortnNewValue);

shortGetInputLen();

voidSetNullDiscard(BOOLbNewValue);

BOOLGetNullDiscard();

voidSetOutBufferSize(shortnNewValue);

shortGetOutBufferSize();

voidSetOutBufferCount(shortnNewValue);

shortGetOutBufferCount();

voidSetParityReplace(LPCTSTRlpszNewValue);

CStringGetParityReplace();

voidSetPortOpen(BOOLbNewValue);

//打开或关闭串口,TRUE:打开,FALSE:关闭

BOOLGetPortOpen();

//串口是否已打开,TRUE:打开,FALSE:关闭

voidSetRThreshold(shortnNewValue);

//如果设置为1,表示一接收到字符就发送2号事件

shortGetRThreshold();

voidSetRTSEnable(BOOLbNewValue);

//硬件握手使能?

BOOLGetRTSEnable();

voidSetSettings(LPCTSTRlpszNewValue);

//Settings由4部分组成,其格式为:"BBBB,P,D,S",即"波特率,是否奇偶校验,数据位//个数,停止

位",如设置为:"9600,n,8,1"

CStringGetSettings();

voidSetSThreshold(shortnNewValue);

//如果保持缺省值0不变,则表示发送数据的过程中串口上不发生事件

shortGetSThreshold();

voidSetOutput(constVARIANT&newValue);

//一个非常重要的函数,用于写串口,注意其接收的输入参数为VARIANT类型对象,

//我们需要将字符串转化为VARIANT类型对象

VARIANTGetOutput();

voidSetInput(constVARIANT&newValue);

VARIANTGetInput();

//一个非常重要的函数,用于读串口,注意其返回的是VARIANT类型对象,我们需要

//将其转化为字符串

voidSetCommEvent(shortnNewValue);

shortGetCommEvent();

//一个非常重要的函数,获得串口上刚发生的事件("事件"能理解为软件意义上的

//"消息"或硬件意义上的"中断"),事件的发送会导致OnComm消息的诞生!

voidSetEOFEnable(BOOLbNewValue);

BOOLGetEOFEnable();

voidSetInputMode(longnNewValue);

longGetInputMode();

};

//{{AFX_INSERT_LOCATION}}

//MicrosoftVisualC++willinsertadditionaldeclarationsimmediatelybeforethepreviousline.

#endif

分析上述原始码可知,基本上,MSComm的诸多接口能分为如下几类:

(1)打开和设置串口接口函数;

(2)获得串口设置和串口状态接口函数;

(3)设置串口发送数据方式、缓冲区接口及发送数据接口函数;

(4)设置串口接收数据方式、缓冲区接口及接收数据接口函数;

(5)设置和获取串口上发生的事件接口函数。

更多推荐

mscomm