对于下面的代码来说,这是一个效率问题,它是用C#中的MS编写的。如果没有任何解释,请告诉我,我会补充。该项目的这一部分所做的是:
像rotate()和stop()这样的调用是将数据写入9字节数组并将字节数组写入串口的命令。
现在,我的主要问题是步骤5,我在堆栈溢出上读到“如果您必须使用wait(),并且没有使用DataReceived实现的意义”。那么,我真的应该摆脱这个问题,还是有一个很好的方法来处理这个问题?如果我不使用wait(),它就会保存在停止命令之后发送的答案(每个命令也会发送一个答案)。
在第三步中使用DataReceived会更有效吗?在开始时,我将一个值保存为新0,并将这里读出的当前传感器与这个0值进行比较。
private void button13_Click(object sender, EventArgs e)
{
//rotate right speed
string Test = textBox4.Text;
byte[] A = new byte[9];
rotate(A, Test);
//read sensor
serialPort2.WriteLine("SR,00,002\r\n");
string b = serialPort2.ReadLine();
decimal caliber = decimal.Parse(Regex.Split(b, "SR,00,002,")[1]);
decimal b1 = 0;
do
{
serialPort2.WriteLine("SR,00,002\r\n");
string z = serialPort2.ReadLine();
b1 = decimal.Parse(Regex.Split(z, "SR,00,002,")[1]);
}
while (b1 <= caliber);
// stop motor
byte[] B = new byte[9];
stop(B);
//save position
System.Threading.Thread.Sleep(5000);
byte[] C = new byte[9];
getPosi(C);
System.Threading.Thread.Sleep(5000);
M = buf;
//move to 0
byte[] D = new byte[9];
MoveTo0(D);
}如果需要了解上面的代码:
//global variables
byte[] buf = new byte[9];
byte[] M = new byte[9];
private void button1_Click(object sender, EventArgs e) //Ports öffnen
{
serialPort3 = new SerialPort();
serialPort3.PortName = "COM6";
serialPort3.Handshake = Handshake.RequestToSend;
serialPort3.ReceivedBytesThreshold = 8;
serialPort3.DataReceived += new SerialDataReceivedEventHandler(DataRecievedHandler);
serialPort3.Open();
}
private void DataRecievedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
int bytes = serialPort3.BytesToRead;
byte[] buffer = new byte[bytes];
sp.Read(buffer, 0, bytes);
string hex = BitConverter.ToString(buffer);
hex.Replace("-", "");
MessageBox.Show(hex);
buf = buffer;
}其他方法:
private void rotate(byte[] A, string Test) //Rotate Motor Right
{
A = MB.TMCL_RMR(Test);
serialPort3.Write(A, 0, A.Length);
}
private void stop(byte[] B) // Stop Motor
{
B = MB.TMCL_MST();
serialPort3.Write(B, 0, B.Length);
}
private void getPosi(byte[] C) //Get Position
{
C = MB.GET_POSI();
serialPort3.Write(C, 0, C.Length);
}
private void MoveTo0(byte[] D) //Move to 0
{
D = MB.MoveTo0();
serialPort3.Write(D, 0, D.Length);
}例如,关于字节数组是如何创建的,它是从我的单独的马达控制类中得到的。每个十六进制引用一个特定的信息,最后一个字节是校验和.如果这个数组被发送到串口,它将请求电机位置作为回答。
public byte[] GET_POSI()
{
byte[] E = new byte[9];
E[0] = 0x1;
E[1] = 0x6;
E[2] = 0x1;
E[3] = 0x0;
E[4] = 0x0;
E[5] = 0x0;
E[6] = 0x0;
E[7] = 0x0;
E[8] = 0x08;
return E;
}代码按照我希望的那样工作,用于几个输入测试。我只是觉得可能有比Thread.Sleep()更好的方法。
发布于 2016-12-13 00:21:28
我猜您考虑过避免使用Thread.Sleep()方法,而不是您在标题中提到的Wait()。我无法测试您的代码,因为我既没有COM端口,也没有马达。我想给你一些关于如何改进你的代码的一般建议。让我们实现一些坚实而枯燥的原则。我将从类马达开始,它将代表您的设备。例如,您可以为此目的实现单例类。这有助于您将电机逻辑与其他逻辑分离开来,例如用户界面。我还可以想象您的端口设置是应用程序配置的一部分。
public sealed class Motor : IDisposable
{
public static readonly Motor Instance = new Motor();
private Motor()
{
MotorPort = new SerialPort();
MotorPort.PortName = "COM6";
MotorPort.Handshake = Handshake.RequestToSend;
MotorPort.ReceivedBytesThreshold = 8;
MotorPort.DataReceived += new SerialDataReceivedEventHandler(dataRecievedHandler);
MotorPort.Open();
}
public SerialPort MotorPort { get; private set; }
public decimal Position { get; private set; }
public void StopRotate() { }
public void StartRotate(string speed) { }
public void MoveToPosition(int position) { }
private void dataRecievedHandler(object sender, SerialDataReceivedEventArgs e)
{
}
public void Dispose()
{
if (MotorPort.IsOpen)
{
MotorPort.Close();
}
}
}而不是使用全局字段(M,buf),将它们封装到对象中,并设置适当的访问修饰符或更好地创建属性。使用有意义的名称您的字段和属性。使用资本化公约资本化公约。
您可以将重复字符串隔离为单独的静态类,以使字符串常量存储库更容易维护,不需要直接使用特定的字符串。
static class StringConstants
{
public const string Prefix = "SR,00,002,";
public const string PrefixCrLf = "SR,00,002\r\n";
}扩展方法可以简化代码并使其更具可读性。
static class Extensions
{
public static decimal GetDecimalOutput(this SerialPort port)
{
return decimal.Parse(Regex.Split(port.ReadLine(), StringConstants.Prefix)[1]);
}
public static void SendCommand(this SerialPort port)
{
port.WriteLine(StringConstants.PrefixCrLf);
}
}如果您已经实现了Motor.cs方法,则可以使用它或扩展它。
private void btnTest_Click(object sender, EventArgs e)
{
Motor.Instance.StartRotate(speed);
Thread.Sleep(5000);
Motor.Instance.StopRotate();
Motor.Instance.MoveToPosition(0);
//read sensor
serialPort2.SendCommand();
decimal caliber = serialPort2.GetDecimalOutput();
do
{
serialPort2.SendCommand();
actualValue = serialPort2.GetDecimalOutput();
}
while (actualValue <= caliber);
}我没有串口编程方面的经验,但我确信事件SerialPort.DataReceived应该像调用serialPort3那样用于调用订阅的方法。我不知道为什么要使用Thread.Sleep(),因为我看不到getPosi(C);方法。
发布于 2016-12-13 09:53:18
只是有件小事从我身上跳了出来:
private void rotate(byte[] A, string Test) //Rotate Motor Right
{
A = MB.TMCL_RMR(Test);
serialPort3.Write(A, 0, A.Length);
}为什么要传入一个字节数组,以便用第一行中的其他东西替换它?
private void SendRotateCommand(string speed)
{
var commandBytes = MB.TMCL_RMR(speed);
motorPort.Write(commandBytes, 0, commandBytes.Length);
}我猜到Test参数实际上是调用它的方法中的注释中的旋转速度。
你需要改进你的命名贯穿始终。您的代码非常简单,但是很难理解,因为命名太差了。
另一件小事:
public byte[] GET_POSI()
{
byte[] E = new byte[9];
E[0] = 0x1;
E[1] = 0x6;
E[2] = 0x1;
E[3] = 0x0;
E[4] = 0x0;
E[5] = 0x0;
E[6] = 0x0;
E[7] = 0x0;
E[8] = 0x08;
return E;
}可以更简单地写成:
public byte[] GET_POSI()
{
return new byte[] { 1, 6, 1, 0, 0, 0, 0, 0, 8 };
}我真不明白你想把这个职位留给什么。或者你是怎么做的。你在给马达发信息,它把东西送回来了。你收到一条信息,你就会明白这意味着什么,然后行动起来。
您还将DataReceived和SerialPort.ReadLine混合在一起--它们都使用相同的底层内存流,您应该使用其中一种--而不是两者都使用。
在等待操作完成时,您还会冻结大量的UI。可以接受来自用户的命令,然后随着操作的进展更新UI。当电机旋转时显示当前位置,当它到达正确的位置时,停止它。
https://codereview.stackexchange.com/questions/149640
复制相似问题