问题描述
我正在研究
如上图所示,地址从 0000
到 0006
依次排列寄存器被跳过3次,下一个地址是 0009
,之后它再次顺序执行,直到地址 003A
。然后再次跳过寄存器,依次从 0100
到 012E
。
我只想读取某些寄存器,即从 0000
到 0002
而不是从 000E
到 003A
,最后从 0100
到 012E
。一种方法是一帧一帧地发送,然后处理数据。但是我想在一个请求中发送它们。
我要执行以下操作。
-
组合请求并将其发送到一帧中
var req1 = new byte [] {Convert.ToByte(iterations.hex),0x03、0x00、0x00、0x00 ,0x03}; // msn和电表ID
var req2 = new byte [] {Convert.ToByte(iterations.hex),0x03、0x00、0x0E, 0x00,0x46}; //能量值
var req3 = new byte [] {Convert.ToByte(iterations.hex),0x03、0x01、0x00、0x00、0x48}; / /其他能量值
var项目= req1.concat (req2).concat(req3);
我不确定这种方法是否行得通。我不知道该怎么做,但由于处理程序
不断读取端口,所以我不想一一发送帧。
- 收集所有请求数据,然后保存数据。
任何帮助将不胜感激。
假设
未提供详细的用例,因此我假设用例需要持续发送读取请求并处理响应。
如何发送请求?
-----
选择不多,要么一次阅读,要么将它们分成小块。
这取决于您的[波特率](https://en.wikipedia.org/wiki/Baud)和所需的探测间隔。
假定从0x000〜0x003A + 0x0100〜0x012E读取的批量读为T,从0x0000〜0x012E读取的批量读为3T。
您可以在计算通信时间。
- 如果所需的间隔远大于3T,则从0x0000〜0x012E进行读取似乎可以。
- 如果所需的间隔接近1〜 3T,然后增加波特率或使用多个批量读取都可以。
我的建议是一般读取两个区域0x000〜0x003A + 0x0100〜0x012E
如何设计
----
我的建议是不断重复发送和收集它。这是一所古老的学校,但对于以后的维护者来说很容易理解。
下面是抽象发送和接收状态机的伪代码。
枚举EReadState {
首先,
第二个,
第三个
}
EReadState状态= EReadState.First; //如果需要读取两个以上的区域,则使用枚举
ManualResetEvent mre = new ManualResetEvent();
void StartPolling()
{
while(true){
switch(state){
case首先:
SendFirstPartRequest();
休息时间;
情况第二:
SendSecondPartRequest();
休息时间;
情况第三:
SendThirdPartRequest();
休息时间;
}
mre.WaitOne()/等待接收到一个数据
//不要忘记实现您的中断条件
}
}
void Receive()
{
var data = ... //获取数据
state = setNextState(data); //如果收到了第一部分,则将状态设置为第二。
mre.Set(); //转到下一个发送
}
I am working on modbus protocol in C#
. I am able to send a single request and get a response from it. I am using a DataReceivedHandler
to read from incoming port
public ModBusEngine()
{
//serial port settings and opening it
port.ReadTimeout = 500;
port.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
port.Open();
}
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
//port.ReadTimeout = 200;
// send request and waiting for response
// the request needs: slaveId, dataAddress, registerCount
Thread.Sleep(200);
Console.WriteLine("Bytes recieved are " + port.BytesToRead);
try
{
receivedBytes = port.BaseStream.Read(buffer, 0, (int)buffer.Length);
var receiveData = BitConverter.ToString(buffer, 0, receivedBytes);
var finalData = receiveData.Replace("-", "");
new Thread(() =>
{
SaveData(finalData);
}).Start();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message.ToString());
}
}
I am writing to a port in another method
private void ModbusMethod(Iterations iterations)
{
Console.WriteLine("Starting Modbuss Scheduling data...");
try
{
var items = new byte[]{ Convert.ToByte(iterations.hex), 0x03, 0x00, 0x00, 0x00, 0x03 };
//iterations.hex is device id
var crc = BitConverter.GetBytes(ModRTU_CRC(items, items.Length)); //ComputeChecksum(items);
var dataItems = items.Concat(crc).ToArray();
port.BaseStream.Write(dataItems, 0, dataItems.Length);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message.ToString());
}
}
I am successfully able to send are receive a response.
What I want to do now?
There are multiple registers from which I can get data from the device. These addresses are not completely in sequential order. For example, see below pictures
As shown in the above images addresses from 0000
to 0006
are in a sequence then the register is skipped 3 times and the next address is 0009
after that it's again sequential till the address 003A
. Then again registers are skipped and start from 0100
to 012E
in sequence.
I only want to read certain registers i.e. from 0000
to 0002
than from 000E
to 003A
and finally from 0100
to 012E
. One way is to send the frame one by one and then do the needful with the data. But I want to send them in a single request.
I want to do the following.
Combining the request and send it in one frame
var req1 = new byte[]{ Convert.ToByte(iterations.hex), 0x03, 0x00, 0x00, 0x00, 0x03 };// msn and meter id
var req2 = new byte[]{ Convert.ToByte(iterations.hex), 0x03, 0x00, 0x0E, 0x00, 0x46 }; // energy values
var req3 = new byte[]{ Convert.ToByte(iterations.hex), 0x03, 0x01, 0x00, 0x00, 0x48 };// energy values other
var items = req1.concat(req2).concat(req3);
I am not sure that this approach will work or not. I don't know how to do it but I don't want to send the frame one by one as the handler
is continuously reading the port.
- Collect all the requests data and then save the data.
Any help would be highly appreciated.
Assumption
Detail use case isn't provided, so I'll assume this use case needs to continuously sending read requests and process responses.
How to send request?-----Not much choice, either read at once or split them into small areas.It depends on your [baudrate](https://en.wikipedia.org/wiki/Baud) and required probe interval.
Assume a bulk read from 0x000~0x003A + 0x0100~0x012E is T and read from 0x0000~0x012E is 3T.You may calculate communication time here.
- If required interval is much greater than 3T, then read from 0x0000~0x012E seems okay for this case.
- If required interval is near 1~3T, then either increasing baudrate or using multiple bulk read are okay.
My suggestion is to read two area 0x000~0x003A + 0x0100~0x012E as a general case, since at least reduce read time by T.
How to design----My suggestion is keep repeating send and collect it. It's old school but easy to understand for future maintainer.
Following are pseudo code for a state machine while abstracting send and receive.
enum EReadState{
First,
Second,
Third
}
EReadState state = EReadState.First; // I use enum if you have more than two areas need to be read
ManualResetEvent mre = new ManualResetEvent();
void StartPolling()
{
while(true){
switch( state ){
case First:
SendFirstPartRequest();
break;
case Second:
SendSecondPartRequest();
break;
case Third:
SendThirdPartRequest();
break;
}
mre.WaitOne() / wait for one data received
// Don't forget implement your break condition
}
}
void Receive()
{
var data = ... // get data
state = setNextState( data ); // If first part is received, set state to second.
mre.Set(); // Go to next send
}
这篇关于在C#中处理Modbus RTU框架的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!