我有2类型的设备,它们有不同的协议,并与单个串行端口连接。通过协议,我的意思是串口配置是不同的。
我有一个协议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;
}
}
}在上面的代码中,我检查了如果p_id等于01,那么应该执行modbus串口配置。但是,如果p_id是02,那么应该会遇到ytlbus串口配置。这两种设备具有不同的波特率和奇偶校验位。所以我试着让他们
另外,我有一个定时器,它是60秒。因此,每隔一秒钟,就会初始化下一个定时器。
例如。如果p_id是01,则代码将波特率设置为9600,奇偶校验设置为Even。然后调用SerialDataRecievedEventHandler,它将检查来自设备的任何传入数据,并将管理数据转储到DB中。
然后,代码将检查表mdc_meter_config中的设备详细信息,并从中获取相关信息。所有的详细信息都被一个一个地添加到所有设备的列表中。同时,这一时间也将得到落实。在这种情况下,所有设备的时间是相同的,即60秒。
然后将该列表传递给一个变量,然后将其传递给一个ElapsedEventHandler函数。frame发送由它处理。
同样,对于p_id等于02,唯一的区别是它将波特率设置为38400,奇偶设置为None。
我面临什么问题?
上面的代码运行,我面临的问题是,这两种情况同时工作。也就是说,对于01,它将工作,然后同时跳到02条件。下面是图片

它应该完成任何p_id值的工作,然后完成其他p_id值的工作。
更新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.
System.IO.Ports.InternalResources.WinIOError(Int32 errorCode的
,System.IO.Ports.SerialStream.EndRead(IAsyncResult asyncResult的String str)在System.Threading.Tasks.TaskFactory
1.FromAsyncTrimPromise1.Complete(TInstance thisRef的System.IO.Stream.<>c.b__43_1(流,IAsyncResult asyncResult),F:\MDC Development\Scheduler\CommunicationProfile\CombinedEngine.cs:line 1198 ( System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task任务)在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task任务) System.Runtime.CompilerServices.TaskAwaiter.GetResult() at CommunicationProfile.SerialPortExtensions.d__1.MoveNext() ( F:\MDC Development\Scheduler\CommunicationProfile\CombinedEngine.cs:line 1207 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task任务)在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task任务)在System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at CommunicationProfile.CombinedEngine.d__27.MoveNext():\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注意:,当设备启动时,上面的方法应该是连续运行的,每隔一秒钟就会发送数据。
任何帮助都将不胜感激。
发布于 2020-10-12 08:01:03
上一次代码修订的主要问题是,您调用的是没有Work()的await,因此调用只是创建一个异步后台任务,而不是等待它的完成。此外,此功能不应存在于构造函数中,而应存在于单独的async方法中。
第二个建议是从循环中删除if/switch语句,并将区分这些协议所需的数据放在一个单独的类中。您可以在这个类中放置每个协议所需的任何附加属性:
// 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循环就不需要区分这些协议:
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.");
}
}https://stackoverflow.com/questions/64203396
复制相似问题