求一份c++builder 如何编写modbus rtu的modbus通信程序

C++ Builder(3)
&一、引言&&&
&   目前,在用计算机进行数据传输时,常用的是串行通信方式。用C++&& Builder来编写串行通信程序时,可以调用Windows&& API函数,也可以利用VB中的MSComm控件。&& 利用&& API函数编写实际应用程序时,往往要考虑多线程的问题,这样编出来的程序不但十分庞大,而且结构比较复杂,继承性差,维护困难。但是使用串行通信控件就相对简单一些,而且功能强大,性能安全可靠。本文就简单的介绍一下在C++&& Builder中利用MSComm控件进行编程。&&&
&   二、MSComm控件的常用属性和事件&&&
&   MSComm&& 控件通过串行端口传输和接收数据,为应用程序提供串行通讯功能。具体的来说,它提供了两种处理通信问题的方法:一是事件驱动(Event-driven)方法,一是查询法。&&&
&   事件驱动方式&&&
&   在使用事件驱动法设计程序时,每当有新字符到达,或端口状态改变,或发生错误时,MSComm控件将解发OnComm事件,而应用程序在捕获该事件后,通过检查MSComm控件的CommEvent属性可以获知所发生的事件或错误,从而采取相应的操作。这种方法的优点是程序响应及时,可靠性高。&&&
&   查询方式&&&&&
&   查询方式实质上还是事件驱动,但在有些情况下,这种方式显得更为便捷。在程序的每个关键功能之后,可以通过检查&& CommEvent&& 属性的值来查询事件和错误。如果应用程序较小,并且是自保持的,这种方法可能是更可取的。&&&
&   1.MSComm&& 控件的常用属性&&&
&   CommPort属性:设置或返回通讯端口号,可以设置为1到16之间的任何值,本系统采用缺省值2;&&&
&   Settings属性:以字符串形式设置或返回波特率、奇偶校验、数据位和停止位,本系统采用缺省&#2,n,8,1&;&&&
&   PortOpen属性:设置或返回通讯口的状态以及打开和关闭端口,可通过把该属性设置为true或者false来打开或者关闭端口;&&&
&   InBufferSize和OutBufferSize属性:分别设置接收和发送缓冲区分配的内存数量,单位为字节,缺省值分别为1024byte和512byte;&&&
&   InputLen属性:确定希望从接收缓冲区移出的字符数量,当InputLen=0时,一次把接收缓冲区的字符全部移出;&&&
&   Input属性:从接收缓冲区中读出数据,然后将该数据从缓冲区移走。&&&
&   OutPut属性:向发送缓冲区传递待发送的数据。&&&
&   InBufferCount和OutBufferCount属性:分别确定当前驻留在接收缓冲区等待被取出和发送缓冲区准备发送的字符数量,这两个属性设置为0,接收和发送缓冲区的内容将被清除;&&&
&   InputMode属性:设置接收传入数据的格式,设置为0采用文本形式,设置为1采用二进制格式,本系统设置为二进制格式进行发送和接收;&&&
&   SThreshold属性:保存一个产生发送OnComm事件的界限值,本系统设置该属性为0,发送数据时不产生OnComm事件;&&&
&   RThreshold属性:设定当接收几个字符时触发OnComm事件,本系统设置该属性为1,每接收一个字符就产生一个OnComm事件;&&&
&   2.MSComm控件的事件&&&
& MSCOMM控件只使用一个事件OnComm,用属性CommEvent的十七个值来区分不同的触发时机。主要有以下几个:&&&
&   (1)CommEvent=1时:传输缓冲区中的字符个数已少于Sthreshold(可设置的属性值)个。&&&
&   (2)CommEvent=2时:接收缓冲区中收到Rthreshold(可设置的属性值)个字符,利用此事件可编写接收数据的过程。&&&
&   (3)CommEvent=3时:CTS线发生变化。&&&
&   (4)CommEvent=4时:DSR线发生变化。&&&&&
&   (5)CommEvent=5时:CD线发生变化。&&&&&
&   (6)CommEvent=6时:检测到振铃信号。&&&&&
&   另外十种情况是通信错误时产生,即错误代码。&&&&&
& 三、程序的实现&&&
&   1.注册MSComm控件&&&
&   众所周知,C++Builder本身并不提供串行通讯控件MSComm,但我们却可以通过注册后直接使用它。启动C++Builder5.0后,然后选择C++Builder主菜单中的Component菜单项,单击Import&& Active&& Control命令,弹出Import&& Active窗口,选择Microsoft&& Comm&& Control6.0,再选择Install按钮执行安装命令,系统将自动进行编译,编译完成后即完成MSComm控件在C++Builder中的注册,系统默认安装在控件板的Active页,接下来我们就可以像使用C++Builder本身提供的控件那样使用新注册的MSComm控件了。(前提条件是你的机子上安装了Visual&&
Basic,或者有它的库)&&&
&   2.具体实现&&&
&   新建一个工程Project1,把注册好的MSComm控件加入到窗体中,然后再加入5个ComboBox用来设置串口的属性,4个Button分别用来&打开串口&&& &关闭串口&&发送数据&&保存数据&&& ,2个Memo控件分别用来显示接收到的数据和发送的数据。再加入一个Shape控件用来标明串口是否打开。&&&
&   ComboBox1用来设置串口号,通过它的Items属性设置1,2,3,4四个列表项分别表示COM1,COM2,COM3,COM4口。ComboBox2用来设置波特率,ComboBox3用来设置奇偶校验位,ComboBox4用来设置数据位,ComboBox5用来设置停止位。他们的缺省值分别是9600,n,8,1。&&&
&   Button1用来打开串口,Button2用来关闭串口,Button3用来发送数据,Button4用来保存数据。Memo1用来显示发送的数据,Memo2显示接收的数据。Shape1的Shape属性设置为stCircle。&&&
& 下面给出部分源码:&&&
& __fastcall&& TForm1::TForm1(TComponent*&& Owner)&&&
& :&& TForm(Owner)&&&
& if(MSComm1-&PortOpen==true)&&&
& Button1-&Enabled=&&&
& Button2-&Enabled=&&&
& Button3-&Enabled=&&&
& Button4-&Enabled=&&&
& Shape1-&Brush-&Color=clG&&&
& Button2-&Enabled=&&&
& Button2-&Enabled=&&&
& Button3-&Enabled=&&&
& Button4-&Enabled=&&&
& Shape1-&Brush-&Color=clR&&&
& void&& __fastcall&& TForm1::Button1Click(TObject&& *Sender)&& /&& /打开串口&&&
& if(MSComm1-&PortOpen!=true)&&&
& MSComm1-&CommPort=StrToInt(ComboBox1-&Text);//选择串口号&&&
& MSComm1-&Settings=&&&
& ComboBox2-&Text+&,&+&&&
& ComboBox3-&Text+&,&+&&&
& ComboBox4-&Text+&,&+&&&
& ComboBox5-&T&& file://设置串口的属性波特率、奇偶校验、数据位和、//停止位。&&&
& MSComm1-&InputMode=0;//设置传入数据的格式,0表示文本形式&&&
& MSComm1-&PortOpen=//打开串口&&&
& Button1-&Enabled=&&&
& Button2-&Enabled=&&&
& Button3-&Enabled=&&&
& Button4-&Enabled=&&&
& Shape1-&Brush-&Color=clG&&&
& void&& __fastcall&& TForm1::Button2Click(TObject&& *Sender)&& /&& /关闭串口&&&
& if(MSComm1-&PortOpen!=false)&&&
& MSComm1-&PortOpen=&&&
& Button1-&Enabled=&&&
& Button2-&Enabled=&&&
& Button3-&Enabled=&&&
& Button4-&Enabled=&&&
& Shape1-&Brush-&Color=clR&&&
& Button1-&Enabled=&&&
& Button2-&Enabled=&&&
& Shape1-&Brush-&Color=clR&&&
&   MSComm控件的Input和Output属性在Object&& Inspector中是看不到的,而且在C++Builder环境下这两个属性已不在是VB、VC中的原类型,而是OleVariant类型,也就是Ole万能变量,这就需要我们在发送接收数据时要把数据转换成Ole类型。&&&
& void&& __fastcall&& TForm1::Button3Click(TObject&& *Sender)&& file://发送Memo2中的数据&&&
& MSComm1-&Output=StringToOleStr(Memo2-&Text);&& file://把AnsiString型转化成//Ole形式。&&&
&   通过OnComm事件接收数据,必须把MSComm的RThreshold属性设置为大于0,只有这样在接收到字符时才会产生一个OnComm事件。&&&
& void&& __fastcall&& TForm1::MSComm1Comm(TObject&& *Sender)&&&
& AnsiString&&&& file://声明一个AnsiString类型的变量&&&
& OleVariant&&&& file://声明一个用于接收数据的OleVariant变量。&&&
& if(MSComm1-&CommEvent==comEvReceive)&&&
& //&& 接收缓冲区中是否收到Rthreshold个字符。&&&
& if(MSComm1-&InBufferCount)//&& 是否有字符驻留在接收缓冲区等待被取出&&&
& s=MSComm1-&I//接收数据&&&
& str=s.AsType(varString);&& file://把接收到的OleVariant变量转换成AnsiString类型&&&
& Memo1-&Text=Memo1-&Text+//把接收到的数据显示在Memo1中。&&&
&   要保存数据应该再加入一个SaveDialog模块&&&
& void&& __fastcall&& TForm1::Button4Click(TObject&& *Sender)&&&
& file://把Memo1中的数据保存在指定的文件中&&&
& AnsiString&& filename1;&&&
& SaveDialog1-&Filter=&Text&& files&& (*.txt)|*.txt|All&& files&& (*.*)|*.*&;//文件类型过滤器&&&
& SaveDialog1-&FilterIndex=2;&&&
& if(SaveDialog1-&Execute())&&&
& filename1=SaveDialog1-&FileN&&&
& Memo1-&Lines-&SaveToFile(filename1);//把收到的数据保存在文件filename1中&&&
&   四、结束语&&&
&   上面给出了C++&& Builder中利用MSComm控件进行串行通信编程的实现和部分源码,有了上面的参照读者可以根据实际需要编写出具有发送文件和接收文件功能的程序。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1207次
排名:千里之外>> 这是一个用C++开发的 Modbus 简单读写程序
这是一个用C++开发的 Modbus 简单读写程序
所属分类:
下载地址:
ModCppReadWriteC__.z文件大小:604.51 kB
分享有礼! 》
请点击右侧的分享按钮,把本代码分享到各社交媒体。
通过您的分享链接访问Codeforge,每来2个新的IP,您将获得0.1 积分的奖励。
通过您的分享链接,每成功注册一个用户,该用户在Codeforge上所获得的每1个积分,您都将获得0.2 积分的分成奖励。
这是一个用C++开发的 Modbus 简单读写程序-This is a development with C Modbus read and write simple procedures
Sponsored links
源码文件列表
温馨提示: 点击源码文件名可预览文件内容哦 ^_^
JohnMakeModSimple.aps21.52 kB02-17-99 15:06
JohnMakeModSimple.clw1.59 kB02-17-99 15:04
2.17 kB02-12-99 16:19
JohnMakeModSimple.dsp4.78 kB02-15-99 16:56
JohnMakeModSimple.dsw601.00 B02-15-99 16:56
1.42 kB02-12-99 16:19
JohnMakeModSimple.ncb73.00 kB02-17-99 15:09
JohnMakeModSimple.opt47.50 kB02-17-99 15:09
JohnMakeModSimple.plg1.07 kB02-17-99 14:47
6.80 kB02-17-99 09:43
7.01 kB02-17-99 09:54
1.81 kB02-16-99 11:06
10.08 kB02-15-99 10:39
3.86 kB02-15-99 10:39
ModiconC++SimpleReadWrite.pdf738.39 kB02-17-99 14:55
3.46 kB02-12-99 16:19
971.00 B02-15-99 16:52
JohnMakeModSimple.ico1.05 kB02-12-99 16:19
JohnMakeModSimple.rc2409.00 B02-12-99 16:19
215.00 B02-12-99 16:19
987.00 B02-12-99 16:19
(提交有效评论获得积分)
评论内容不能少于15个字,不要超出160个字。
评价成功,多谢!
下载ModCppReadWriteC__.z
CodeForge积分(原CF币)全新升级,功能更强大,使用更便捷,不仅可以用来下载海量源代码马上还可兑换精美小礼品了
您的积分不足,优惠套餐快速获取 30 积分
10积分 / ¥100
30积分 / ¥200原价 ¥300 元
100积分 / ¥500原价 ¥1000 元
订单支付完成后,积分将自动加入到您的账号。以下是优惠期的人民币价格,优惠期过后将恢复美元价格。
支付宝支付宝付款
微信钱包微信付款
更多付款方式:、
您本次下载所消耗的积分将转交上传作者。
同一源码,30天内重复下载,只扣除一次积分。
鲁ICP备号-3 runtime:Elapsed:157.946ms - init:0.1;find:1.1;t:0.5;tags:0.3;related:125.2;comment:0.2; 27.69
登录 CodeForge
还没有CodeForge账号?
Switch to the English version?
^_^"呃 ...
Sorry!这位大神很神秘,未开通博客呢,请浏览一下其他的吧天极传媒:天极网全国分站
您现在的位置: &&
用C++ Builder编程实现串行通信
 ∮C++ Builder来编写串行通信程序,我们需要用到几个Windows API函数而不像在DOS下那样直接操作串口和中断芯片。这几个函数有OpenFile、CloseFile,GetCommState、SetCommState等。Microsoft的Visual Basic 中有一个OCX控件MSComm32,在VB中用它做串行通信程序很方便,将它装入Builder 3中,它的Input和Output属性是UnKnown,即Builder 3不认识MSComm32的这两个属性,我们升级到Borland 的C++ Builder4.0,在Object Inspector中将不再看到这两个属性,但它们仍然存在,这两个属性的类型是OleVariant,也就是Ole万能变量,使用这种类型方法如下:
  在要发送数据时,我们声明一个发送数据缓冲区,然后重置它的大小,填充它的元素,发送它,例如:
  buff[200];//请声明为全局变量
  OleVariant TxB//声明一个OleVariant 变量
  TxBuff=VarArrayCreate(OPENARRAY(int,(0,n)),varByte);//重置它的大小,为0~n,int 为n的类型。
  //varByte为TxBuff每一个元素的类型。
  for(int i=0;i<n+1;i++)TxBuff.PutElement(buff[i],i);
//填充元素,其中buff为你定义的一个固定数组,其中有你要发的数据。
  MSComm1->Output=TxB//发送数据,MSComm1为你放在窗体上的一个MSComm32控件。
  按收数据时请看下面的例子:
  int buff[200];//声明一个存储接收数据的缓冲区,全局变量
  int ByteN//收到的字节数
  int BuffP//接收缓冲区的指针,请声明为全局变量,
  OleVariant RxB//一个用于接收的OleVariant变量,
  if(MSComm1->InBufferCount>0)RxBuff=Communica1->I//如果缓冲区中有多于一个字节的数据
  ByteNum=RxBuff.Array?HighBound(1);//将实际读的字节数取出
  for(int i=0;i<ByteNum+1;i++){buff[BuffPtr++]=RxBuff.GetElement(i);}//将接收数据读入自己的缓冲区
  在Object Inspector的Event标签中只有一个事件OnComm,这个事件在MSComm32控件收到数据时会被调用,但你必须设置RThreshold属性。这是一个门槛,表示收到几个字节就发送通知消息,如果为零,就不发送通知消息,这样你的OnComm函数就不会得到执行,TThreshold是发送门槛,不要忘记Settings。
  另外值得注意的是MSComm32的OnComm事件不是很准确,有时候会丢失,你不能过分依赖这个
裨颍7⑸牟皇欠⒉怀鍪荩褪墙邮詹坏绞?最好的办法是使用一个定时控件,需要的时候就去读MSComm32控件的缓冲区。
(武汉 刘纪锋)
责任编辑:)
欢迎在新浪微博上关注我们
笔记本手机数码家电modbus-TCP 协议文档:/link?url=ImagoC3DE1p0D55S7qbzXrSaQ4wbaY93gB3kEmPiHx_CnnNsrdkz1vYA93uTBtvmbzxhRrcBoPc8YNl9UqJqlRAV1r3Tm2tYoOfdTU1zcVG
简单来说就是吧modbus RTU的报文做修改后使用TCP协议传输,通常modbus-TCP使用502端口。
报文&#26684;式在文档后部有了,写得很清楚,多了MBAP报头,去除了CRC校验,因为TCP协议已经可以保证报文的正确。
code如下,socket编程代码参考了网上,故标为转载;
#pragma once
#include &stdio.h&
#include&windows.h&
#pragma comment(lib, &Ws2_32.lib&)
class M_Client
//Constructor
M_Client(const char* Addr, int Port, int Id);
int Connect();
//发送TCP包
int SendMsg(const char* msg, int len);
void Close();
//发送modbus包
void Modbus_sender_single(int Ref, int addr, int value);
const char*
#include &M_Client.h&
#include &errno.h&
M_Client::M_Client(const char* Addr, int Port, int Id)
address = A
int M_Client::Connect()
int rlt = 0;
//用于记录错误信息并输出
//启动WinSock
WSAData wsaD
iErrMsg = WSAStartup(MAKEWORD(1, 1), &wsaData);
if (iErrMsg != NO_ERROR)
printf(&failed with wsaStartup error : %d\n&, iErrMsg);
//创建Socket
m_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_sock == INVALID_SOCKET)
//创建Socket失败
printf(&socket failed with error : %d\n&, WSAGetLastError());
//目标服务器数据
sockaddr_in sockaddrS
sockaddrServer.sin_family = AF_INET;
sockaddrServer.sin_port = htons(port);
sockaddrServer.sin_addr.s_addr = inet_addr(address);
//连接,sock与目标服务器连接
iErrMsg = connect(m_sock, (sockaddr*)&sockaddrServer, sizeof(sockaddrServer));
if (iErrMsg & 0)
printf(&connect failed with error : %d\n&, iErrMsg);
printf(&Error: %d\n&, errno);
int M_Client::SendMsg(const char* msg, int len)
int rlt = 0;
int iErrMsg = 0;
//发送消息,指定sock发送消息
iErrMsg = send(m_sock, msg, len, 0);
if (iErrMsg & 0)
//发送失败
printf(&send msg failed with error : %d\n&, iErrMsg);
void M_Client::Close()
closesocket(m_sock);
void M_Client::Modbus_sender_single(int Ref, int addr, int value)
//写一个寄存器,使用功能码16,修改后就可以写多个
unsigned char Temp_buf[20];
Temp_buf[0] = R
Temp_buf[1] = 0;
Temp_buf[2] = 0;
Temp_buf[3] = 0;
Temp_buf[4] = 0;//从ID开始到最后的字节数
Temp_buf[5] = 9;
Temp_buf[6] =//从机ID
Temp_buf[7] = 16;//命令代码
Temp_buf[8] = (addr-1)/256;//addr head //开始的地址
Temp_buf[9] = (addr-1) % 256;
Temp_buf[10] = 0;//number of addr
//地址的长度
Temp_buf[11] = 1;
Temp_buf[12] = 2;//# of Bytes for values
//一共多少byte的值
Temp_buf[13] = value/256;//values
//具体的值,这里我只改一个寄存器,就写一个值
Temp_buf[14] = value%256;
SendMsg((char*)Temp_buf, 15);
//将报文发出,15为报文长度,这里是固定的
测试代码:
#include &M_Client.h&
int main()
M_Client client(&127.0.0.1&,502,10); //连接本地回路,502端口,10号从机
client.Connect();
client.Modbus_sender_single(0, 145, 24323);// 将145号寄存器写为24323(十进制)
client.Close();
system(&pause&);
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:6253次
排名:千里之外

我要回帖

更多关于 modbus通信协议 的文章

 

随机推荐