MODBUS是一种国际标准的通讯协议,用于不同厂商之间的设备交换数据(一般是工业用途);
所谓协议,也可以理解为上面有人说的"语言"吧,简单的说是软件.
一般情况下,两台设备通过MODBUS协议传输数据:
TCP三种模式:
而MODBUS TCP则是为了顺应当今世界发展潮流,什么都可以用Ethernet网或Internet来连接,传送数据.所以又MODBUS TCP模式,该模式的硬件接口就是以太网(Ethernet)口了,也就是我们电脑上一般用的网络口了.
你用vb还是vc?
看OnComm事件应该是vb吧.
(参照出处):
MSComm控件使用详解
摘要:本文详细介绍了MSComm控件在串口编程中使用.
目 次
MSComm控件两种处理通讯的方式
CommPort属性
RThreshold 属性
CTSHolding 属性
SThreshold 属性
CDHolding 属性
DSRHolding 属性
Settings 属性
InputLen 属性
EOFEnable 属性
Handshake 常数
OnComm 常数
InputMode 常数
错误消息
MSComm 控件通过串行端口传输和接收数据,为应用程序提供串行通讯功能.MSComm控件在串口编程时非常方便,程序员不必去花时间去了解较为复杂的API函数,而且在VC、VB、Delphi等语言中均可使用. Microsoft Communications Control(以下简称MSComm)是Microsoft公司提供的简化Windows下串行通信编程的ActiveX控件,它为应用程序提供了通过串行接口收发数据的简便方法.具体的来说,它提供了两种处理通信问题的方法:一是事件驱动(Event-driven)方法,一是查询法.
①MSComm控件两种处理通讯的方式
MSComm控件提供下列两种处理通讯的方式:事件驱动方式和查询方式.
①1 事件驱动方式
事件驱动通讯是处理串行端口交互作用的一种非常有效的方法.在许多情况下,在事件发生时需要得到通知,例如,在串口接收缓冲区中有字符,或者 Carrier Detect (CD) 或 Request To Send (RTS) 线上一个字符到达或一个变化发生时.在这些情况下,可以利用 MSComm 控件的 OnComm 事件捕获并处理这些通讯事件.OnComm 事件还可以检查和处理通讯错误.所有通讯事件和通讯错误的列表,参阅 CommEvent 属性.在编程过程中,就可以在OnComm事件处理函数中加入自己的处理代码.这种方法的优点是程序响应及时,可靠性高.每个MSComm 控件对应着一个串行端口.如果应用程序需要访问多个串行端口,必须使用多个 MSComm 控件.
查询方式实质上还是事件驱动,但在有些情况下,这种方式显得更为便捷.在程序的每个关键功能之后,可以通过检查 CommEvent 属性的值来查询事件和错误.如果应用程序较小,并且是自保持的,这种方法可能是更可取的.例如,如果写一个简单的电话拨号程序,则没有必要对每接收一个字符都产生事件,因为唯一等待接收的字符是调制解调器的"确定"响应.
MSComm 控件有很多重要的属性,但首先必须熟悉几个属性.
CommPort 设置并返回通讯端口号.
Settings 以字符串的形式设置并返回波特率、奇偶校验、数据位、停止位.
PortOpen 设置并返回通讯端口的状态.也可以打开和关闭端口.
Input 从接收缓冲区返回和删除字符.
Output 向传输缓冲区写一个字符串.
下面分别描述:
CommPort属性 设置并返回通讯端口号.
语法 object.CommPort[value ] (value 一整型值,说明端口号.)
注意:必须在打开端口之前设置 CommPort 属性.
RThreshold 属性:在 MSComm 控件设置 CommEvent 属性为 comEvReceive 并产生 OnComm 之前,设置并返回的要接收的字符数.
语法 object.Rthreshold [ = value ](value 整型表达式,说明在产生 OnComm 事件之前要接收的字符数. )
说明 当接收字符后,若 Rthreshold 属性设置为 0(缺省值)则不产生 OnComm 事件.例如,设置 Rthreshold 为 1,接收缓冲区收到每一个字符都会使 MSComm 控件产生 OnComm 事件.
CTSHolding 属性:确定是否可通过查询 Clear To Send (CTS) 线的状态发送数据.Clear To Send 是调制解调器发送到相联计算机的信号,指示传输可以进行.该属性在设计时无效,在运行时为只读.
语法: object.CTSHolding(Boolean)
Mscomm 控件的 CTSHolding 属性设置值:
True Clear To Send 线为高电平.
False Clear To Send 线为低电平.
说明:如果 Clear To Send 线为低电平 (CTSHolding = False) 并且超时时,MSComm 控件设置 CommEvent 属性为 comEventCTSTO (Clear To Send Timeout) 并产生 OnComm 事件.
Clear To Send 线用于 RTS/CTS (Request To Send/Clear To Send) 硬件握手.如果需要确定 Clear To Send 线的状态,CTSHolding 属性给出一种手工查询的方法.
详细信息 有关握手协议,请参阅 Handshaking 属性.
SThreshold 属性: MSComm 控件设置 CommEvent 属性为 comEvSend 并产生 OnComm 事件之前,设置并返回传输缓冲区中允许的最小字符数.
语法 object.SThreshold [ = value ]
value 整形表达式,代表在 OnComm 事件产生之前在传输缓冲区中的最小字符数.
常数 值 描述
comNone 0 无握手.
comXonXoff 1 XOn/Xoff 握手.
comEvSend 1 发送事件.
Error 常数
comEventBreak 1001 接收到中断信号
comEventTxFull 1010 传输缓冲区满
comEventDCB 1011 检索端口 设备控制块 (DCB) 时的意外错误
comInputModeText 0 (缺省)通过 Input 属性以文本方式取回数据.
comInputModeBinary 1 通过 Input 属性以二进制方式检取回数据.
CDHolding 属性:通过查询 Carrier Detect (CD) 线的状态确定当前是否有传输.Carrier Detect 是从调制解调器发送到相联计算机的一个信号,指示调制解调器正在联机.该属性在设计时无效,在运行时为只读.
语法 object.CDHolding
设置值:CDHolding 属性的设置值为:
设置 描述
True Carrier Detect 线为高电平
False Carrier Detect 线为低电平
说明:注意当 Carrier Detect 线为高电平 (CDHolding = True) 且超时时,MSComm 控件设置CommEvent 属性为 comEventCDTO(Carrier Detect 超时错误),并产生 OnComm 事件.
注意 在主机应用程序中捕获一个丢失的传输是特别重要的,例如一个公告板,因为呼叫者可以随时挂起(放弃传输).
Carrier Detect 也被称为 Receive Line Signal Detect (RLSD).
数据类型 Boolean
DSRHolding 属性:确定 Data Set Ready (DSR) 线的状态.Data Set Ready 信号由调制解调器发送到相连计算机,指示作好操作准备.该属性在设计时无效,在运行时为只读.
语法:object.DSRHolding
object 所在处表示对象表达式,其值是"应用于"列表中的对象.
DSRHolding 属性返回以下值:
值 描述
True Data Set Ready 线高
False Data Set Ready 线低
说明:当 Data Set Ready 线为高电平 (DSRHolding = True) 且超时时,MSComm 控件设置 CommEvent 属性为 comEventDSRTO(数据准备超时)并产生 OnComm 事件.
当为 Data Terminal Equipment (DTE) 机器写 Data Set Ready/Data Terminal Ready 握手例程时该属性是十分有用的.
数据类型:Boolean
Settings 属性: 设置并返回波特率、奇偶校验、数据位、停止位参数.
语法: object.Settings[ = value]
Value 由四个设置值组成,有如下的格式:
"BBBB,P,D,S"
BBBB 为波特率,P 为奇偶校验,D 为数据位数,S 为停止位数.value 的缺省值是:
InputLen 属性:设置并返回 Input 属性从接收缓冲区读取的字符数.
语法 object.InputLen [ = value]
InputLen 属性语法包括下列部分:
value 整型表达式,说明 Input 属性从接收缓冲区中读取的字符数.
说明:InputLen 属性的缺省值是 0.设置 InputLen 为 0 时,使用 Input 将使 MSComm 控件读取接收缓冲区中全部的内容.
若接收缓冲区中 InputLen 字符无效,Input 属性返回一个零长度字符串 ("").在使用 Input 前,用户可以选择检查 InBufferCount 属性来确定缓冲区中是否已有需要数目的字符.该属性在从输出格式为定长数据的机器读取数据时非常有用.
EOFEnable 属性:确定在输入过程中 MSComm 控件是否寻找文件结尾 (EOF) 字符.如果找到 EOF 字符,将停止输入并激活 OnComm 事件,此时 CommEvent 属性设置为 comEvEOF,
语法:object.EOFEnable [ = value ]
EOFEnable 属性语法包括下列部分:
value 布尔表达式,确定当找到 EOF 字符时,OnComm 事件是否被激活,如"设置值"中所描述.
value 的设置值:
True 当 EOF 字符找到时 OnComm 事件被激活.
False (缺省)当 EOF 字符找到时 OnComm 事件不被激活.
说明:当 EOFEnable 属性设置为 False,OnComm 控件将不在输入流中寻找 EOF 字符.
错误消息(MS Comm 控件)
下表列出 MSComm 控件可以捕获的错误:
///-----------------------------------------------------
串口数据接收方式
①.、 在OnComm 事件中接收数据:
这种方式能充分MSCOMM控件的特性.OnComm 事件还可以检查和处理通讯错误;可以通过检查 CommEvent 属性的值来查询事件和错误;对于不定长数据以及对数据进行处理比较复杂的情况,此法不是很方便.
Private Sub MSComm_OnComm ()
Select Case MSComm1.CommEvent
' 错误
Case comEventBreak ' 收到 Break.
Case comEventCDTO ' CD (RLSD) 超时.
Case comEventCTSTO ' CTS Timeout.
Case comEventDSRTO ' DSR Timeout.
Case comEventFrame ' Framing Error
Case comEventOverrun '数据丢失.
Case comEventRxOver'接收缓冲区溢出.
Case comEventRxParity' Parity 错误.
Case comEventTxFull '传输缓冲区已满.
Case comEventDCB '获取 DCB] 时意外错误
' 事件
Case comEvCD ' CD 线状态变化.
Case comEvCTS ' CTS 线状态变化.
Case comEvDSR ' DSR 线状态变化.
Case comEvRing ' Ring Indicator 变化.
Case comEvReceive ' 收到 RThreshold # of chars.
Case comEvSend ' 传输缓冲区有 Sthreshold 个字符 '
Case comEvEof ' 输入数据流中发现 EOF 字符
End Select
End Sub
A、定时器轮循法
对于数据包方式收发数据以及不需即时响应情况,用轮循法更好些.实际上轮循法最大的好处在于集中处理数据而且不太占用CPU.轮循法要注意定时采集的时间片段大小;这里用二进制收发模式;使属性RThreshold、SThreshold为0,屏蔽ONCOMM事件.
InputMode = comInputModeBinary
RThreshold = 0
SThreshold = 0
Private Sub TmrComm_Timer()
'采用轮循法采集数据
Dim Rx_buff() As Byte
Dim okstring As String
Dim ReceivedLen As Integer
On Error GoTo ErrorHandler
TmrComm.Enabled = False '关闭定时器
If commport.InBufferCount 0 Then
ReceivedLen = commport.InBufferCount
Rx_buff = commport.Input
okstring = StrConv(tempbyte, vbUnicode)
....
End If
If Instr(okstring ,":@END*",vbBinaryCompare) Then
TmrComm.Enabled = True '打开定时器
B、直接轮循法
此法用于接收少量控制命令字;
' 保存输入子串的缓冲区
Dim Instring As String
' 使用 COM1.
MSComm1.CommPort = 1
' 当输入占用时,
' 告诉控件读入整个缓冲区.
MSComm1.InputLen = 0
' 打开端口.
MSComm1.PortOpen = True
' 将 attention 命令送到调制解调器.
' 确保
' 调制解调器以"OK"响应.
' 等待数据返回到串行端口.
Do
DoEvents
Buffer$ = Buffer$ MSComm1.Input
Loop Until InStr(Buffer$, "OK" vbCRLF)
' 从串行端口读 "OK" 响应.
' 关闭串行端口.
MSComm1.PortOpen = False
如何处理不定长数据的接收
在处理串口通讯时,经常会遇到不定长数据的接收.由于通讯任务不同及编程要求的差异所以采用的方法也有所不同.本文就此问题进行探讨.不定长数据从数据格式上分,可分为有格式和无格式.
第一段:无格式不定长数据的接收
这种格式在实际串口通讯中用得不多,一般只用传送字符串数据.问题在于怎么判断接收结束.一般用时间延迟的方法解决.
A、对于非握手式通讯,可用一个定时器定时轮循接收,并假定每个轮循接收完成.用ONCOMM事件接收也可,只是不如定时器定时轮循接收简便.
B、对于握手方式通讯,可用直接轮循法提高接收的准确性.下面是实现此法的函数:
Function sComm(sCommand As String, comReceive As MSComm) As String
Dim nReceiveCount As Integer
If comReceive.PortOpen = False Then
comReceive.PortOpen = True
comReceive.Output = sCommand
nReceiveCount = comReceive.InBufferCount
Loop Until comReceive.InBufferCount = nReceiveCount
If comReceive.PortOpen = True Then
sComm = comReceive.Input
End Function
注:此函数参照了xth一文.
此法一般是能确保数据接收的正确,但由于WINDOWS是多任务操作系统,当有耗时的进程运行时会丢失数据.如果系统会出现这种情况,可增大函数sleep()的参数值.
第二段:不定长格式数据的接收
对于不定长数据接收最好的方法是制定通讯协议,比如定义开始字符和结束字符.由于单片机系统通讯一般不太复杂,没必要去制定一套象通用计算机间通讯的协议,而根据单片机系统的大小和性能要求制定通讯协议.实际上为便于交流、维护以及一致性,可制定一套可伸缩的通讯协议.定义了开始字符和结束字符就容易实现不定长格式数据通讯,但在实际通讯编程还是容易出现一些比较隐蔽的通讯错误.下面就常用方法分别进行分析.
A、定时器轮循法.
假定每个轮循期数据接收完毕,并在每个轮循期处理数据,由于有开始字符和结束字符很容易确定接收数据的完整性.好象合理设定轮循时间值就万无一失了,但被动接收数据时无论如何也找不合适的轮循时间值,因为启动定时器和数据到来基本不同步,这就会出现一次发送的数据被分在两个轮循期接收,所以被动接收数据时不能假定每个轮循期数据接收完毕.在接收到结束字符后才确定一次数据接收完毕就可解决此问题.
B、OnComm事件法.
对于不定长数据的接收,最佳方法可能是在OnComm事件中启动定时器轮循接收,并同时停止OnComm事件的触发,接收完毕后或超时开启OnComm事件.
由于C语言不能返回两个参数,所以用数组指针.
void Filt(char code[],char c)
{
if(c=='F')
}
else
code[1]=0XFF; /*0XFF作为标记code[1]不可能产生0XFF*/
else if(c=='H')
code[1]=0xFE; /*转换完成标记*/
if(code[1]==0XFE)
code[1]=0XFF; /*接收下一个码的标记*/
code[0]=code[0]+code[1];
code[1]=0XFE;
发送时:
SendChar[0]=c; /*c为待发ASCII码*/
Filt(SendChar,'F');
if(SendChar(1)==0XFF)
..... /*发送SendChar[0]*/
...... /*发送SendChar[0],SendChar[1]*/
接收时:
.....
ReceiveChar[0]=c0; /*c0接收的ASCII码*/
Filt(ReceiveChar,'H');
if(ReceiveChar[1]==0xFF)
ReceiveChar[1]=c1; /*c1为下一个*/
Filt(ReceiveChar,'H);
else if(ReceiveChar[1]==0xFE)
...... /*存储转换后的ReceiveChar[0]*/
以上代码仅提供一种思路,实际情况视编程需要而定.
串口通讯问答录
①.、Q:各位vb高手:我有一个问题想请教一下.我从COM口用BIN方式接收到数据(一串汉字),存入一BYTE数组,但无法还原为一串汉字,我认为是ANSI和UNICODE的转换,请问如何转换.
JY
发:
Dim ytemp() As Byte
Dim stemp As String
stemp = "土嘎嘎的粉丝们大家好!"
ytemp = StrConv(stemp, vbFromUnicode)
Debug.Print UBound(ytemp)
MSComm1.Output = ytemp
收:
Private Sub mscTest_OnComm()
'中文收发
Dim yTemp() As Byte
Dim i As Integer
If mscTest.InBufferCount 0 Then
i = mscTest.InBufferCount
yTemp = mscTest.Input
stemp = StrConv(yTemp, vbUnicode)
txtTest1.Text = stemp
Deson
--------------------------------------------------------------------------------
Private Sub OkBtn_Click()
Dim Data() as byte
Dim Temp as variant
redim data(10)
For i = 0 to 10
next
temp = data
mscomm.output = temp
end Sub
A:接收方式使用了文本方式,用二进制方式即可.
网关=反向代理+负载均衡+各种策略,技术实现也有多种多样,有基于 nginx 使用 lua 的实现,比如 openresty、kong;也有基于 zuul 的通用网关;还有就是 golang 的网关,比如 tyk.
这篇文章主要是讲如何基于 golang 实现一个简单的网关.
转自: troy.wang/docs/golang/posts/golang-gateway/
整理:go语言钟文文档:
启动两个后端 web 服务(代码)
这里使用命令行工具进行测试
具体代码
直接使用基础库 httputil 提供的NewSingleHostReverseProxy即可,返回的reverseProxy对象实现了serveHttp方法,所以呢可以直接作为 handler.
director中定义回调函数,入参为*http.Request,决定如何构造向后端的请求,比如 host 是否向后传递,是否进行 url 重写,对于 header 的处理,后端 target 的选择等,都可以今天这一节完成.
director今天这一节具体做了:
modifyResponse中定义回调函数,入参为*http.Response,用于修改响应的信息,比如响应的 Body,响应的 Header 等信息.
最终依旧是返回一个ReverseProxy,然后将这个对象作为 handler 传入即可.
随便 random 一个整数作为索引,然后取对应的地址即可,实现比较简单.
使用curIndex进行累加计数,一旦超过 rss 数组的长度,则重置.
后端真实节点包含三个权重:
操作步骤:
一致性 hash 算法,主要是用于分布式 cache 热点/命中问题;这里用于基于某 key 的 hash 值,路由到固定后端,但是只能是基本满足流量绑定,一旦后端目标节点故障,会自动平移到环上最近的那么个节点.
实现:
每一种不同的负载均衡算法,只需要实现添加以及获取的接口即可.
然后使用工厂方法,根据传入的参数,决定使用哪种负载均衡策略.
作为网关,中间件必不可少,这类包括请求响应的模式,一般称作洋葱模式,每一层都是中间件,一层层进去,然后一层层出来.
中间件的实现一般有两种,一种是使用数组,然后配合 index 计数;一种是链式调用.