上位机MODBUS通信
- 格式:doc
- 大小:27.00 KB
- 文档页数:5
摘要随着微电子技术和计算机术的进步,可编程控制器以其可靠性高、抗干扰强、开发周期短,已经成为一种较为普及的、适应多种应用环境的工业控制器。
现已从最初的简单顺序控制、逻辑控制发展到可进行模拟量控制、位置控制,特别是PLC与PLC、PLC与计算机通信功能的实现,可组成多级控制系统,形成工厂自动化网络。
PLC可以多种方式如直接采用现有的组态监控软件与上位监控机通信,但针对小规模的控制系统,找到一种高性价比的通信方法,具有积极的实际意义。
本文就是讨论如何利用Modbus通信协议来实现施耐德电器公司的NanoPLC与上位监控PC机的通信。
关键词 modbus;plc;自动化网络;pc1硬件描述及串口设置1.1 接口电路设计PLC与PC间实现通信,可使二者互补功能上的不足,PLC用于控制方面既方便又可靠,而PC机在图形显示、数据处理、打印报表以及中文显示等方面有很强的功能。
因此,各PLC制造厂家纷纷开发了适用于本公司的各种型号PLC机通信的接口模块,不同的通信方式,有着不同的成本价格和不同的适用范围。
NanoPLC的CPU单元本身带有1个RS-485扩展口,可不配备专用通讯模块,而通过此接口与上位机进行串行通信。
在此介绍一种通过PLC的RS485扩展口与PC机的RS-232串行口进行通信的方法。
由于NanoPLC的扩展口采用RS-485标准,RS485是RS422的变型。
RS422为全双工,可同时发送与接收;RS485则为半双工,在某一时刻,1个发送另1个接收。
RS485是一种多发送器的电路标准,允许双导线上1个发送器驱动32个负载设备,负载设备可以是被动发送器、接收器或收发器。
而计算机的串行口采用RS-232标准。
因此,作为实现PLC与计算机通信的接口电路,必须将RS-485标准转换成RS-232标准。
我们利用SC-485转换器实现RS485与RS232之间的转换。
转换电路如图1所示。
图1 RS485与RS232转换电路图1.2 PLC串行口设置施耐德的NanoPLC对通信参数的设置通过设置扩展口来实现,系统采用PC 机作为Modbus通信网络主站,NanoPLC作为从站。
MODBUS_RTU通讯规约(本协议采用主从问答方式)一、通讯数据的类型及格式:上位机为主机,LM311T为从机。
从机采用中断方式接收数据,查询方式发送。
异步串行通讯, RS-485接口,半双工,1位起始位,1位或2位停止位,8位数据位;1位校验位(奇或偶),波特率9600BPS或19200BPS。
采用MODBUS-RTU通信协议。
●通讯数据(信息帧)格式数据格式:地址码功能码数据区错误校检数据长度:1字节1字节N字节16位CRC码(2字节)1.1 地址码:地址码是每次通讯信息帧的第一字节(8位),从1到255。
每个从机都必须有唯一的地址码,并且只有符合地址码的从机才能响应回送信息。
当从机回送信息时,回送数据均以各自的地址码开始。
主机发送的地址码表明将发送到的从机地址,而从机返回的地址码表明回送的从机地址。
1.2 功能码:功能码是每次通讯信息帧传送的第二个字节。
ModBus通讯规约可定义的功能码为1到127。
继电保护设备仅用到其中的一部分功能码。
作为主机请求发送,通过功能码告诉从机应执行什么动作。
作为从机响应,从机返回的功能码与从主机发送来的功能码一样,并表明从机已响应主机并且已进行相关的操作。
1.3 数据区:数据区包括需要由从机返送何种信息或执行什么动作。
二、MODBUS点表:MODBUS存储区以0XXXX,1XXXX,3XXXX,4XXXX标识,具体情况见下表:存储区标识名称类型读/写存储单元地址0XXXX 线圈位写00001-000021XXXX 开关量输入位读10001-100113XXXX 输入寄存器字只读30001-301454XXXX 保持寄存器字读写40001-40028其中,00001为合闸线圈地址,00002为分闸线圈地址。
1表示合,0表示分。
10001-10011为11个输入开关量的地址。
对应位中1表示合,0表示分。
L M311T点表如下:实时参数区寄存器内容MODBUS地址处理方式说明I/IM 30001 /10 电动机额定电流百分比Ia 30002 D1 A相电流Ib 30003 D1 B相电流Ic 30004 D1 C相电流IE 30005 D1 零序电流Δ% 30006 /10 电流不平衡度I1 30007 D1 正序电流I2 30008 D1 负序电流累计运行时间30009 直接转换累计运行时间电机起动次数30010 直接转换电机起动次数开关量状态30011 直接转换G8报警标志30012 直接转换G7电动机状态直接转换G7说明:当装置类型号为0X41H时,即LM-310T时,数据内容无效,作为备用。
仪表与上位机ModbusRTU通讯协议1、接口规格为与PC机或PLC编控仪联机以集中监测或控制仪表,仪表提供RS232、RS485两种数字通讯接口,光电隔离,其中采用RS232通讯接口时上位机只能接一台仪表,三线连接,传输距离约15米;采用RS485通讯接口时上位机需配一只RS232-485的转换器,最多能接64台仪表,二线连接,传输距离约一千米。
2、通讯协议(适合本厂所有1~16路仪表)(1)通讯波特率为1200、2400、4800、9600四档可调,数据格式为1个起始位、8个数据位,1个停止位,无校验位。
(2)上位机读一个参数(2字节)仪表编号功能代码(03)参数首地址读取的字数(0001)CRC161byte1byte2byte2byte2byte(3)仪表返回(2字节):仪表编号功能代码(03)读取的字节数(02)参数值CRC161byte1byte1byte2byte2byte(4)上位机写一个参数(2字节)及仪表返回(2字节)(帧格式相同):仪表编号功能代码(6)参数首地址参数值CRC161byte1byte2byte2byte2byte(5)参数代码及地址见仪表说明书通道显示值地址:1通道:1001H2通道:1002H3通道:1003H4通道:1004H5通道:1005H6通道:1006H7通道:1007H8通道:1008H9通道:1009H10通道:100AH11通道:100BH12通道:100CH13通道:100DH14通道:100EH15通道:100FH16通道:1010H(6)仪表主控输出状态地址:1通道:1101H2通道:1102H3通道:1103H4通道:1104H5通道:1105H6通道:1106H7通道:1107H8通道:1108H9通道:1109H10通道:110AH11通道:110BH12通道:110CH13通道:110DH14通道:110EH15通道:110FH16通道:1110H(7)仪表报警输出状态地址:1200HD15D14D13D12D11D10D9D8D7D6D5D4D3D2D1D0 AL16AL15AL14AL13AL12AL11AL10AL9AL8AL7AL6AL5AL4AL3AL2AL13.1).上位机对仪表写数据的程序部分应按仪表的规格加入参数限幅功能,以防超范围的数据写入仪表,使其不能正常工作,各参数代码及范围见《仪表说明书》2).上位机发读或写指令的间隔时间应大于或等于0.2秒,太短仪表可能来不及应答3).仪表未发送小数点信息,编上位机程序时应根据需要设置4).测量值为32767(7FFFH)表示HH(超上量程),为32512(7F00H)表示LL(超下量程)5).除了CRC校验字节低位在前外,其它所有双字节均高位在前,。
易语言串口通讯modbus协议模块上位机必备例子源代码1.引言1.1 概述在编写易语言串口通讯modbus协议模块上位机必备例子源代码之前,我们首先需要了解一些基本概念和背景知识。
本文介绍了该例子的目的和结构,以及引言、正文和结论三个主要部分的内容。
1.1概述Modbus协议是一种常用的串行通信协议,广泛应用于工业自动化领域。
它被设计用于在不同设备之间进行数据传输和通信。
Modbus协议简洁明了,易于实现和部署,因此被许多工业设备和上位机所采用。
易语言是一种面向过程的编程语言,易于学习和使用。
它提供了丰富的库和模块,方便我们进行串口通讯编程。
易语言的特点是语法简单易懂,同时也支持调用其他语言编写的DLL函数,可以实现更加复杂的功能。
本例子的目标是演示如何使用易语言编写一个串口通讯的Modbus 协议模块,并结合上位机的必备功能来实现数据的读写和显示。
在正文部分,我们将介绍Modbus协议的简要概述,包括其通信方式、数据格式、功能码等。
同时,我们还将介绍易语言中的串口通讯模块及其基本用法。
在结论部分,我们将提供一些实例源代码示例,以便读者更好地理解和使用这个例子。
此外,我们还将列举一些上位机必备的功能,以供读者参考和扩展应用。
通过这个例子,读者可以学习到如何使用易语言进行串口通讯编程,并了解Modbus协议在实际应用中的运用。
同时,读者也可以根据自己的需求和实际情况,对例子进行二次开发和改进,以适应不同的应用场景。
在下一节中,我们将详细介绍Modbus协议的相关知识,以便读者更好地理解本例子的内容和实现。
文章结构部分主要是对整篇文章的组织和安排进行介绍,以下是1.2 文章结构的内容:1.2 文章结构本文主要分为三个部分,包括引言、正文和结论,具体如下:1. 引言部分介绍了本文的概述、文章结构和目的。
在概述中,我们对易语言串口通讯modbus协议模块上位机必备例子源代码进行了简要介绍,指出了本文的主要内容和目标。
基于MODBUS协议信捷PLC与上位机通信在化工吸附分离系统中的应用化工吸附分离中,利用MODBUS通信协议将控制装置信捷PLC的数据上传到上位机PC,上位机通过VB编写的通信程序接收数据。
介绍了利用VB软件实现信捷PLC与PC的MODBUS通信的方法,并给出了通信协议和部分通信程序标签:MODBUS;信捷PLC;VB引言目前石化公司引进的芳烃联合装置,其中的化工吸附分离过程是一个比较复杂的过程,一旦过程发生故障,会引起产品质量问题。
为保证生产过程的安全稳定、必须实现生产过程的实时监控。
本控制系统底层系统下位机采用信捷XD3 PLC,上位机采用工控机,上下位机通过MODBUS协议实现通信[1],在PC端能在用户界面上采集数据、数据处理及控制信号的产生与传输。
1 控制装置构成化工吸附分离底层控制装置中的下位机采用XD3-60RT-E,其任务是对化工吸附分离设备的进料出料进行控制,对过程进行监督,发生故障时上位机可以观察到,并且及时的进行报警工作。
上位机采用PC,利用VB开发的界面与PLC 实时通信,对对化工吸附分离设备进行实时监控。
XD3通过编程电缆与工业PC 进行通信。
2 通信协议PC与XD3 PLC的MODBUS通信,采用主从应答方式,PC为主机,PLC 为从机[2]。
PC根据化工过程中的需要向PLC发出读写命令,PLC在接收到PC 的指令后,回应PC的指令。
在PC中,必须根据MODBUS协议编写通信程序。
2.1 RTU模式通信格式采用MODBUS-RTU通信数据格式,当设备使用RTU模式在MODBUS串行链路通信,报文中每个8位字节含有两个4 位十六进制字符。
这种模式的主要优点是较高的数据密度,在相同的波特率下比ASCII 模式有更高的吞吐率。
每个报文必须以连续的字符流传送。
RTU模式帧检验域采用循环冗余校验(CRC)[3]。
4 结束语通过PC与XD3 PLC的MODBUS通信程序的设计方法,一台PC可以和很多台PLC进行通信,采集到不同PLC的数据,监控到不同PLC的运行情况。
#include <bur/plc.h>#include <bur/plctypes.h>#include <drv_mbus.h>#include <string.h>#define _AR_I386_AUTOMATION_STUDIO__LOCAL MBMOpen_typ MOpen;_LOCAL MBMaster_typ Master;_LOCAL MBMClose_typ MClose;_LOCAL MBMCmd_typ MCmd;_LOCAL BOOL fMOpen, fMaster, fMClose, fMCmd,execute;_LOCAL USINT ascii;_LOCAL UINT statusMOpen, statusMaster, statusMClose, statusMCmd,timeout,recordnum;_LOCAL UINT order[14];/*ÉèÖÃÉÏ´«Ë³Ðò*/_LOCAL UDINT ident,counter;_LOCAL STRING device[32],mode[32],config[32],danwei[10];/* modbus VAR */_LOCAL BOOL LocalMB0[6],LocalMB1[5];/*_LOCAL USINT data[150];*/_LOCAL INT EventMB0,EventMB1,EventMB3,EventMB4,*pEventMB4,LocalMB3[5],LocalMB4[15],LocalA[6],*pLocalMB4;_LOCAL INT LocaloMB4[15];_LOCAL UINT i;/*void ShunXu(void); */_INIT void master_init (void){/* modbus VAR */strcpy(&danwei[0], "C");pEventMB4 = &EventMB4;pLocalMB4 = &LocalMB4[0];EventMB0 = 1;EventMB1 = 1;EventMB3 = 1;EventMB4 = 1;i = 0;/* init for OPEN */ascii = 0; /* 0 = RTU / 1 = ASCII */#ifdef _AR_I386_AUTOMATION_STUDIO_strcpy(&device[0], "SL1.SS1.IF1");if (!ascii) strcpy(&mode[0], "PHY=RS485/BD=9600/PA=E/DB=8"); else strcpy(&mode[0], "PHY=RS232/BD=9600/PA=E/DB=7");#elsestrcpy(&device[0], "SL1.SS1.IF1");if (!ascii) strcpy(&mode[0], "RS232,9600,E,8,1");else strcpy(&mode[0], "RS232,9600,E,7,1");#endifstrcpy(&config[0], "mb_cmd");timeout = 500;for(i=0;i<14;i++){order[i]=i+1;}/* modbus - Slave OPEN */MOpen.enable = 1;MOpen.pDevice = (UDINT) &device[0];MOpen.pMode = (UDINT) &mode[0];MOpen.pConfig = (UDINT) &config[0];MOpen.timeout = timeout;MOpen.ascii = ascii;MBMOpen(&MOpen);statusMOpen = MOpen.status;if (!statusMOpen) ident = MOpen.ident;fMaster = 0;fMCmd = 0;fMClose = 0;}_CYCLIC void master_cyclic (void){if (fMOpen){/* modbus - Master OPEN */MOpen.enable = 1;#ifdef _AR_I386_AUTOMATION_STUDIO_strcpy(&device[0], "SL1.SS1.IF1");if (!ascii) strcpy(&mode[0], "PHY=RS485/BD=9600/PA=E/DB=8");else strcpy(&mode[0], "PHY=RS232/BD=9600/PA=E/DB=7"); #elsestrcpy(&device[0], "SL1.SS1.IF1");if (!ascii) strcpy(&mode[0], "RS232,9600,E,8,1");else strcpy(&mode[0], "RS232,9600,E,7,1");#endifMOpen.pDevice = (UDINT) &device[0];MOpen.pMode = (UDINT) &mode[0];MOpen.pConfig = (UDINT) &config[0];MOpen.timeout = timeout;MOpen.ascii = ascii;MBMOpen(&MOpen);statusMOpen = MOpen.status;if (!statusMOpen){ident = MOpen.ident;fMOpen = 0;fMaster = 0;fMCmd = 0;fMClose = 0;}else{ident = 0;fMOpen = 0;}}/*if (fMaster){*//* modbus - Master */Master.enable = 1;Master.ident = ident;MBMaster(&Master);statusMaster = Master.status;execute = Master.execute;recordnum = Master.recordnum;if (!statusMaster){fMaster = 1;counter++;}else if (statusMaster == 65535){fMaster = 1;}else{fMaster = 0;}for(i=0;i<14;i++){LocaloMB4[i]=LocalMB4[order[i]-1]; }}/*void ShunXu(void){if(a1==0||a1>=15) a1=1;if(a2==0||a2>=15) a2=2;if(a3==0||a3>=15) a3=3;if(a4==0||a4>=15) a4=4;if(a5==0||a5>=15) a5=5;if(a6==0||a6>=15) a6=6;if(a7==0||a7>=15) a7=7;if(a8==0||a8>=15) a8=8;if(a9==0||a9>=15) a9=9;if(a10==0||a10>=15) a10=10;if(a11==0||a11>=15) a11=11;if(a12==0||a12>=15) a12=12;if(a13==0||a13>=15) a13=13;if(a14==0||a14>=15) a14=14; }*/_EXIT void slave_exit (void) {MClose.enable = 1;MClose.ident = ident;MBMClose(&MClose);}。
modbus协议例子Modbus协议是一种通信协议,用于建立主从设备之间的通信连接。
它被广泛应用于工业自动化领域,用于实现设备之间的数据交换和控制操作。
下面将列举10个以Modbus协议为例的应用场景和使用方法。
1. 控制器与传感器的数据交换:Modbus协议可以用于控制器与传感器之间的数据交换。
控制器作为Modbus主机,通过Modbus协议读取传感器的数据,实现对传感器的监控和控制。
2. 设备与上位机的通信:Modbus协议可以用于设备与上位机之间的通信。
上位机作为Modbus主机,通过Modbus协议读取或写入设备的数据,实现对设备的控制和监测。
3. 远程数据采集系统:Modbus协议可以用于远程数据采集系统。
通过Modbus协议,可以实现对远程设备的数据采集和监控,方便实时获取设备状态和数据信息。
4. 工业自动化控制系统:Modbus协议广泛应用于工业自动化控制系统。
通过Modbus协议,可以实现对各个设备的数据采集、传输和控制,实现工业过程的自动化控制。
5. 电力监控系统:Modbus协议可以用于电力监控系统。
通过Modbus协议,可以实现对电力设备的实时监测和控制,提高电力系统的运行效率和安全性。
6. 楼宇自动化系统:Modbus协议可以用于楼宇自动化系统。
通过Modbus协议,可以实现对楼宇设备的集中控制和监测,实现楼宇的智能化管理。
7. 温湿度监测系统:Modbus协议可以用于温湿度监测系统。
通过Modbus协议,可以实现对温湿度传感器的数据采集和监测,方便实时获取环境温湿度信息。
8. 智能家居系统:Modbus协议可以用于智能家居系统。
通过Modbus协议,可以实现对智能家居设备的控制和监测,实现家居的智能化管理和控制。
9. 智能交通系统:Modbus协议可以用于智能交通系统。
通过Modbus协议,可以实现对交通设备的控制和监测,提高交通系统的运行效率和安全性。
10. 医疗设备监控系统:Modbus协议可以用于医疗设备监控系统。
Modbus通讯命令说明
仪表可以采用Modbus-RTU模式进行上位机通讯,协议格式为:8个数据位、1个停止位、无校验位,发送接收数据都是以十六进制格式进行。
1、发送数据格式
说明:
1)参数的通讯地址用一个字节表示时,对应A2位置,A1默认为00H。
2)03、04指令均为读命令,其中04对应的数据不可写入,03与06地址对应参数地址,一个读取、一个写入。
3)A1、A2与A3、A4组成两个双字节的数据,CRC校验码是一个双字节数据,所有的数据都是高位在前,低位在后。
4)03、04指令读取数据时,A1、A2为开始读取的地址,A3、A4为连续读取数据的个数。
5)06指令中,A1、A2需要写入数据的地址,A3、A4表示要写入的数据。
2、返回数据格式
1)06指令写入数据时,发送与返回的数据一致。
2)03、04指令返回时局格式
说明:返回数据字节数为:N*2
3、上位机连续下写数据位10指令,支持此指令的仪表有XM708、XM808、XM908、XM707P、XM808P、XM908P、XMH、XMA、XMS、XMT、XMJM。
10指令发送数据格式举例为:
附:
C# XOR CRC16 校验码计算类
C# 带多项式参数的 CRC16计算
C#超级通信调试工具[v1.0][全新发布]。
#include <bur/plc.h>
#include <bur/plctypes.h>
#include <drv_mbus.h>
#include <string.h>
#define _AR_I386_AUTOMATION_STUDIO_
_LOCAL MBMOpen_typ MOpen;
_LOCAL MBMaster_typ Master;
_LOCAL MBMClose_typ MClose;
_LOCAL MBMCmd_typ MCmd;
_LOCAL BOOL fMOpen, fMaster, fMClose, fMCmd,
execute;
_LOCAL USINT ascii;
_LOCAL UINT statusMOpen, statusMaster, statusMClose, statusMCmd,timeout,recordnum;
_LOCAL UINT order[14];/*ÉèÖÃÉÏ´«Ë³Ðò*/
_LOCAL UDINT ident,
counter;
_LOCAL STRING device[32],
mode[32],
config[32],
danwei[10];
/* modbus VAR */
_LOCAL BOOL LocalMB0[6],
LocalMB1[5];
/*_LOCAL USINT data[150];*/
_LOCAL INT EventMB0,
EventMB1,
EventMB3,
EventMB4,
*pEventMB4,
LocalMB3[5],
LocalMB4[15],
LocalA[6],
*pLocalMB4;
_LOCAL INT LocaloMB4[15];
_LOCAL UINT i;
/*void ShunXu(void); */
_INIT void master_init (void)
{
/* modbus VAR */
strcpy(&danwei[0], "C");
pEventMB4 = &EventMB4;
pLocalMB4 = &LocalMB4[0];
EventMB0 = 1;
EventMB1 = 1;
EventMB3 = 1;
EventMB4 = 1;
i = 0;
/* init for OPEN */
ascii = 0; /* 0 = RTU / 1 = ASCII */
#ifdef _AR_I386_AUTOMATION_STUDIO_
strcpy(&device[0], "SL1.SS1.IF1");
if (!ascii) strcpy(&mode[0], "PHY=RS485/BD=9600/PA=E/DB=8"); else strcpy(&mode[0], "PHY=RS232/BD=9600/PA=E/DB=7");
#else
strcpy(&device[0], "SL1.SS1.IF1");
if (!ascii) strcpy(&mode[0], "RS232,9600,E,8,1");
else strcpy(&mode[0], "RS232,9600,E,7,1");
#endif
strcpy(&config[0], "mb_cmd");
timeout = 500;
for(i=0;i<14;i++)
{
order[i]=i+1;
}
/* modbus - Slave OPEN */
MOpen.enable = 1;
MOpen.pDevice = (UDINT) &device[0];
MOpen.pMode = (UDINT) &mode[0];
MOpen.pConfig = (UDINT) &config[0];
MOpen.timeout = timeout;
MOpen.ascii = ascii;
MBMOpen(&MOpen);
statusMOpen = MOpen.status;
if (!statusMOpen) ident = MOpen.ident;
fMaster = 0;
fMCmd = 0;
fMClose = 0;
}
_CYCLIC void master_cyclic (void)
{
if (fMOpen)
{
/* modbus - Master OPEN */
MOpen.enable = 1;
#ifdef _AR_I386_AUTOMATION_STUDIO_
strcpy(&device[0], "SL1.SS1.IF1");
if (!ascii) strcpy(&mode[0], "PHY=RS485/BD=9600/PA=E/DB=8");
else strcpy(&mode[0], "PHY=RS232/BD=9600/PA=E/DB=7"); #else
strcpy(&device[0], "SL1.SS1.IF1");
if (!ascii) strcpy(&mode[0], "RS232,9600,E,8,1");
else strcpy(&mode[0], "RS232,9600,E,7,1");
#endif
MOpen.pDevice = (UDINT) &device[0];
MOpen.pMode = (UDINT) &mode[0];
MOpen.pConfig = (UDINT) &config[0];
MOpen.timeout = timeout;
MOpen.ascii = ascii;
MBMOpen(&MOpen);
statusMOpen = MOpen.status;
if (!statusMOpen)
{
ident = MOpen.ident;
fMOpen = 0;
fMaster = 0;
fMCmd = 0;
fMClose = 0;
}
else
{
ident = 0;
fMOpen = 0;
}
}
/*if (fMaster)
{*/
/* modbus - Master */
Master.enable = 1;
Master.ident = ident;
MBMaster(&Master);
statusMaster = Master.status;
execute = Master.execute;
recordnum = Master.recordnum;
if (!statusMaster)
{
fMaster = 1;
counter++;
}
else if (statusMaster == 65535)
{
fMaster = 1;
}
else
{
fMaster = 0;
}
for(i=0;i<14;i++)
{
LocaloMB4[i]=LocalMB4[order[i]-1]; }
}
/*void ShunXu(void)
{
if(a1==0||a1>=15) a1=1;
if(a2==0||a2>=15) a2=2;
if(a3==0||a3>=15) a3=3;
if(a4==0||a4>=15) a4=4;
if(a5==0||a5>=15) a5=5;
if(a6==0||a6>=15) a6=6;
if(a7==0||a7>=15) a7=7;
if(a8==0||a8>=15) a8=8;
if(a9==0||a9>=15) a9=9;
if(a10==0||a10>=15) a10=10;
if(a11==0||a11>=15) a11=11;
if(a12==0||a12>=15) a12=12;
if(a13==0||a13>=15) a13=13;
if(a14==0||a14>=15) a14=14; }*/
_EXIT void slave_exit (void) {
MClose.enable = 1;
MClose.ident = ident;
MBMClose(&MClose);
}。