gpt4 book ai didi

c# - 在 C# 中以编程方式更改串行端口配置

转载 作者:行者123 更新时间:2023-12-03 16:58:49 31 4
gpt4 key购买 nike

我有 2具有不同协议(protocol)并与单个串行端口连接的设备类型。通过协议(protocol),我的意思是串行端口配置不同。
我有一个协议(protocol) ID p_id通过它我可以检查当前正在读取哪个设备。下面是我的代码
下面是我的主要函数,它调用了一个名为 CombinedEngine 的类

 static class Program
{
private static CombinedEngine _eng;
static async Task Main(string[] args)
{
try
{
_eng = new CombinedEngine();
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message.ToString());
//_log.Error(ex, ex.Message);
}
}
while(true);
}
组合引擎类
class CombinedEngine
{
SerialPort port = new SerialPort();
public CombinedEngine()
{

try
{

var p = mdc.mdc_protocol.ToList();

if(p.Count > 0)
{
foreach(var pr in p)
{
var p_id = pr.protocol_id;

if(p_id=="01")//modbus
{
if (port.IsOpen)
port.Close();

port = new SerialPort("COM8", 9600, Parity.Even, 8, StopBits.One);
port.ReadTimeout = 500;
port.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
port.Open();

Console.WriteLine("Port opened successfully for modbus...");
Console.WriteLine("I am Recieving for modbus...");


var result = mdc.mdc_meter_config.Where(m => m.config_flag == 0)
.Where(m=>m.p_id == p_id).ToList();

if (result.Count > 0)
{
foreach (var item in result)
{
var iteration = new Iterations()
{
hex = (string)item.m_hex,
row_id = (string)item.row_id,
device_id = (int)item.meter_id,
protocol_id = (string)item.p_id,
command_id = (string)item.command_id,
config_flag = (int)item.config_flag,
msn = (string)item.msn,
time = (string)item.time
};
confList.Add(iteration);
time = Convert.ToDouble(item.time);
}

var modbus = confList.Where(x => x.protocol_id == "01").ToList();

aTimer = new System.Timers.Timer();


// Create a timer...
aTimer = new System.Timers.Timer();
// Hook up the Elapsed event for the timer.
aTimer.Interval = time * 1000.0;
aTimer.Elapsed += (sender, e) => MyModbusMethod(sender, e, modbus, aTimer);
aTimer.AutoReset = true;
aTimer.Enabled = true;

}
else
{

Console.WriteLine("No Data available");
}
}
else if(p_id=="02")//ytl_bus
{
if (port.IsOpen)
port.Close();

port = new SerialPort("COM8", 38400, Parity.None, 8, StopBits.One);
port.ReadTimeout = 500;
port.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
port.Open();

Console.WriteLine("Port opened successfully for ytlbus...");
Console.WriteLine("I am Recieving for ytlbus...");


var result = mdc.mdc_meter_config.Where(m => m.config_flag == 0)
.Where(m => m.p_id == p_id).ToList();

if (result.Count > 0)
{
foreach (var item in result)
{
var iteration = new Iterations()
{
hex = (string)item.m_hex,
row_id = (string)item.row_id,
device_id = (int)item.meter_id,
protocol_id = (string)item.p_id,
command_id = (string)item.command_id,
config_flag = (int)item.config_flag,
msn = (string)item.msn,
time = (string)item.time
};
confList.Add(iteration);
time = Convert.ToDouble(item.time);
}


var ytlbus = confList.Where(x => x.protocol_id == "02").ToList();



aTimer = new System.Timers.Timer();


// Create a timer...
aTimer = new System.Timers.Timer();
// Hook up the Elapsed event for the timer.
aTimer.Interval = time * 1000.0;
aTimer.Elapsed += (sender, e) => MyElapsedMethod(sender, e,ytlbus , aTimer);
aTimer.AutoReset = true;
aTimer.Enabled = true;

}
else
{

Console.WriteLine("No Data available");
}

}




}

}


}
catch (Exception ex)
{
Console.WriteLine("Error at Line " + LineNumber(), ex.Message.ToString());
throw ex;
}


}


}
在上面的代码中,我检查了 if p_id等于 01然后 modbus串行端口配置应该完成。但是如果 p_id02然后 ytlbus应该会遇到串口配置。两种设备都有不同的波特率和奇偶校验位。所以我试图设置它们
另外,我有一个计时器,它是 60秒。所以在每个 60 之后秒,下一个定时器将被初始化。
例如。如果 p_id01该代码将波特率设置为 9600Even 的平价.然后 SerialDataRecievedEventHandler调用它将检查来自设备的任何传入数据,并将管理转储到 DB 中的数据。 .
然后代码将从表中检查设备详细信息 mdc_meter_config并从中取出相关信息。所有设备的所有详细信息都将一一添加到列表中。此外,时间将被执行。在这种情况下,所有设备的时间都是相同的,即 60 秒。
然后将该列表传递给一个变量,然后将该变量传递给 ElapsedEventHandler。功能。 frame发送由它处理。 p_id 也一样。等于 02唯一的区别是它将波特率设置为 38400None 的平价.
我面临什么问题?
上面的代码运行,我面临的问题是两个条件同时工作。即对于 01 ,它将工作,然后同时跳转到 02健康)状况。下面是图片
enter image description here
它应该完成任何 p_id 的工作。值,然后为其他 p_id 完成工作值(value)。
更新 1
我已经更新了我的代码。添加了一个新的 async功能,只添加了一个计时器。
并添加了一个串口扩展类
    public static class SerialPortExtensions
{
public async static Task ReadAsync(this SerialPort serialPort, byte[] buffer, int offset, int count)
{
var bytesToRead = count;
var temp = new byte[count];

while (bytesToRead > 0)
{
var readBytes = await serialPort.BaseStream.ReadAsync(temp, 0, bytesToRead);
Array.Copy(temp, 0, buffer, offset + count - bytesToRead, readBytes);
bytesToRead -= readBytes;
}
}

public async static Task<byte[]> ReadAsync(this SerialPort serialPort, int count)
{
var buffer = new byte[count];
await serialPort.ReadAsync(buffer, 0, count);
return buffer;
}
}

public CombinedEngine()
{
try
{
var p = mdc.mdc_protocol.ToList();

if (p.Count > 0)
{
foreach (var pr in p)
{
var p_id = pr.protocol_id;

if (p_id == "01")//modbus
{
if (port.IsOpen)
port.Close();
comm = true;
port = new SerialPort("COM8", 9600, Parity.Even, 8, StopBits.One);
port.ReadTimeout = 500;
//port.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
port.Open();
Work();

Console.WriteLine("Port opened successfully for modbus...");
Console.WriteLine("I am Recieving for modbus...");

}
else if (p_id == "02")//ytl_bus
{
if (port.IsOpen)
port.Close();
comm = true;
port = new SerialPort("COM8", 38400, Parity.None, 8, StopBits.One);
port.ReadTimeout = 500;
//port.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
port.Open();
Work();

Console.WriteLine("Port opened successfully for ytlbus...");
Console.WriteLine("I am Recieving for ytlbus...");

}
var result = mdc.mdc_meter_config.Where(m => m.config_flag == 0).ToList();
if (result.Count > 0)
{
foreach (var item in result)
{
var iteration = new Iterations()
{
hex = (string)item.m_hex,
row_id = (string)item.row_id,
device_id = (int)item.meter_id,
protocol_id = (string)item.p_id,
command_id = (string)item.command_id,
config_flag = (int)item.config_flag,
msn = (string)item.msn,
time = (string)item.time
};
confList.Add(iteration);
time = Convert.ToDouble(item.time);
}

var modbus = confList.Where(x => x.protocol_id == "01").ToList();
var ytlbus = confList.Where(x => x.protocol_id == "02").ToList();

//ModbusMethod(modbus);

aTimer = new System.Timers.Timer();
// Create a timer...
aTimer = new System.Timers.Timer();
// Hook up the Elapsed event for the timer.
aTimer.Interval = time * 1000.0;
aTimer.Elapsed += (sender, e) => MyElapsedMethod(sender, e, ytlbus, modbus, aTimer);
//aTimer.Elapsed += OnTimedEvent(iterations, dataItems);
aTimer.AutoReset = true;
aTimer.Enabled = true;

}
else
{

//Console.WriteLine("No Data available");
}

}

}


}
catch (Exception ex)
{
Console.WriteLine("Error at Line " + LineNumber(), ex.Message.ToString());
throw ex;
}
finally
{
}


}

public async void Work()
{
try
{
var data = await port.ReadAsync(4096);
Console.WriteLine("Data at Line " + LineNumber(), data.ToString());
//DoStuff(data);
}
catch (Exception ex)
{
Console.WriteLine("Error at Line " + LineNumber(), ex.Message.ToString());
}
}
我现在得到的错误是 The I/O operation has been aborted because of either a thread exit or an application request.

at System.IO.Ports.InternalResources.WinIOError(Int32 errorCode, String str)at System.IO.Ports.SerialStream.EndRead(IAsyncResult asyncResult)at System.IO.Stream.<>c.b__43_1(Stream stream, IAsyncResult asyncResult)at System.Threading.Tasks.TaskFactory1.FromAsyncTrimPromise1.Complete(TInstance thisRef, Func3 endMethod, IAsyncResult asyncResult, Boolean requiresSynchronization) at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()at CommunicationProfile.SerialPortExtensions.d__0.MoveNext() in F:\MDC Development\Scheduler\CommunicationProfile\CombinedEngine.cs:line 1198at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)at System.Runtime.CompilerServices.TaskAwaiter.GetResult()at CommunicationProfile.SerialPortExtensions.d__1.MoveNext() in F:\MDC Development\Scheduler\CommunicationProfile\CombinedEngine.cs:line 1207at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()at CommunicationProfile.CombinedEngine.d__27.MoveNext() in F:\MDC Development\Scheduler\CommunicationProfile\CombinedEngine.cs:line 368


错误发生在以下几行
var readBytes = await serialPort.BaseStream.ReadAsync(temp, 0, bytesToRead);//1198 line
await serialPort.ReadAsync(buffer, 0, count);//1207 line
var data = await port.ReadAsync(4096); // 368 line
注:上述方法应在设备上电时连续运行,并在每个 60 后发送数据。秒。
任何帮助将不胜感激。

最佳答案

您的代码的最新版本的主要问题是您正在调用 Work()没有 await ,所以调用只是创建一个异步后台任务,而不是等待它的完成。此外,此功能不应存在于构造函数中,而应存在于单独的 async 中。方法。
第二个建议是删除 if/switch循环中的语句,并将区分这些协议(protocol)所需的数据放在单独的类中。您可以在此类中放置每个协议(protocol)所需的任何其他属性:

// contains specific settings for each ProtocolId
class ProtocolCfg
{
public string ProtocolId { get; set; }
public string PortName { get; set; }
public int BaudRate { get; set; }
public Parity Parity { get; set; }
public int DataBits { get; set; }
public StopBits StopBits { get; set; }

public ProtocolCfg(string id, string port, int baud, Parity parity, int bits, StopBits stop)
{
ProtocolId = id; PortName = port; BaudRate = baud; Parity = parity;
DataBits = bits; StopBits = stop;
}
}
有了这个,你的 for loop 不需要区分这些协议(protocol):
class CombinedEngine
{
readonly ProtocolCfg[] _portConfigs;

public CombinedEngine(ProtocolCfg[] portConfigs)
{
// just assign the field and do nothing else
_portConfigs = portConfigs;
}

public async Task Run(CancellationToken cancelToken)
{
// repeat indefinitely
while (!cancelToken.IsCancellationRequested)
{
// run all protocols
foreach (var portcfg in _portConfigs)
{
SerialPort serialPort = null;

try
{
// init using current config
serialPort = new SerialPort(
portcfg.PortName, portcfg.BaudRate, portcfg.Parity,
portcfg.DataBits, portcfg.StopBits);

serialPort.ReadTimeout = 500;

// await data
var data = await serialPort.ReadAsync(4096);

// do something with this data
Console.WriteLine($"P{portcfg.ProtocolId}: {data.Length}B received");

// do other stuff here

// wait between protocol changes if needed?
await Task.Delay(500, cancelToken);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
finally
{
serialPort?.Close();
serialPort?.Dispose();
}
}

// wait between iterations?
await Task.Delay(500, cancelToken);
}
}
}
调用 Run 时函数,记住它是异步的,所以你需要调用 await .但是,您可能还想在控制台中等待按键,因此在这种情况下,您将存储返回的 Task在变量中,并在需要时取消它:
class Program
{
static void Main(string[] args)
{
// define all possible protocols
var protocols = new[]
{
new ProtocolCfg("01", "COM8", 9600, Parity.Even, 8, StopBits.One),
new ProtocolCfg("02", "COM8", 38400, Parity.None, 8, StopBits.One)
};

// we will need this to tell the async task to end
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;

// note that this constructor does not do anything of importance
var engine = new CombinedEngine(protocols);

// this is where all the work is done, pass the cancellation token
var task = engine.Run(token);

// wait until Q is pressed
Console.WriteLine("Running, press Q to quit... ");
ConsoleKey k;
do { k = Console.ReadKey().Key; }
while (k != ConsoleKey.Q);

// shutdown
tokenSource.Cancel();
task.Wait();
Console.WriteLine("Done.");
}
}

关于c# - 在 C# 中以编程方式更改串行端口配置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64203396/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com