简体   繁体   English

无法使用C#Mono(RaspberryPi)从串行端口读取

[英]Unable to read from Serial Port using C# Mono (RaspberryPi)

I'm attempting to write a C# library which looks at all available USB serial ports on a Raspberry Pi so that I can enumerate, identify and communicate with a set of Arduinos connected to the Pi via a USB hub. 我正在尝试编写一个C#库,它查看Raspberry Pi上所有可用的USB串行端口,以便我可以枚举,识别和通过USB集线器连接到Pi的一组Arduinos进行通信。

I am able to make this work on my windows machine (several Arduinos connected to my desktop computer) and have even been able to make it work on my Pi however, I am struggling to understand how to generalize the fix. 我能够在我的Windows机器上工作(几个Arduinos连接到我的桌面计算机),甚至能够使它在我的Pi上工作,但是,我很难理解如何推广修复。

If I attempt to run the program by itself on the Pi, I am able to open the serial port and send data however, I cannot receive anything from the Arduinos: I get timeout exceptions. 如果我试图在Pi上自己运行程序,我可以打开串口并发送数据但是,我无法从Arduinos收到任何东西:我得到超时异常。 I understand that Mono's implementation of SerialPort is limited and I must use SerialPort.ReadByte() instead of Readline() and the data received events (my solution is based on code from HowToSystemIOPorts ). 我知道Mono的SerialPort实现是有限的,我必须使用SerialPort.ReadByte()而不是Readline()和数据接收事件(我的解决方案基于HowToSystemIOPorts的代码)。 My Serial port enumeration is using a method outlined in another stack exchange response here . 我的串口枚举使用另一组交换响应概括的方法在这里

My timeout is currently set to 4 seconds, which is several orders of magnitude longer than I expect to receive the message. 我的超时当前设置为4秒,比我预期接收消息的时间长几个数量级。

After a lot of googling, I came across mention of using minicom to initialize the serial port here , which to my surprise allowed me to receive data from the Arduino. 经过大量的谷歌搜索,我发现在这里使用minicom来初始化串口,我惊讶地允许我从Arduino接收数据。 The biggest drawback is that I need to initialize the port using minicom and leave the process opening each time I boot the Pi. 最大的缺点是我需要使用minicom初始化端口,并在每次启动Pi时保持进程打开。 I also can't seem to figure out how to make this work with multiple Arduinos. 我似乎也无法弄清楚如何使用多个Arduinos来完成这项工作。


Here is what I have tried so far: 这是我到目前为止所尝试的:

  • Updated the Pi firmware and software to their latest versions 将Pi固件和软件更新到最新版本
  • Attempted to use both an Arduino MEGA 2560 R3 and Arduino UNO 试图同时使用Arduino MEGA 2560 R3和Arduino UNO
  • Changed the owner of the tty* ports (ttyACM0 and ttyUSB0 in this case) to both my user and group 将tty *端口的所有者(在本例中为ttyACM0和ttyUSB0)更改为我的用户和组
  • Successfully configured the port via minicom, left the process running and start the program and read/wrote data. 通过minicom成功配置了端口,使进程保持运行并启动程序并读取/写入数据。 A manual process which only seems to work for one Arduino at a time 一个手动过程,似乎一次只适用于一个Arduino
  • Successfully run the program in Windows without fault 在Windows中成功运行该程序没有错误
  • Verified the Arduinos are recognized by the Pi running "dmesg | grep tty" 验证了Arduinos被Pi运行“dmesg | grep tty”认可

Here is what I hope to solve: 这是我希望解决的问题:

  • Automatic setup/initialization of the Arduino serial ports. 自动设置/初始化Arduino串行端口。 Whether through a shell script run before the main program or within Mono code so that the code below can run as intended. 是通过shell脚本在主程序之前运行还是在Mono代码中运行,以便下面的代码可以按预期运行。

Here is my connection code: 这是我的连接代码:

    public bool StartArduinoComms()
    {
        string[] ports = GetPortNames();
        foreach (string port in ports)
        {
            mLogger.LogMessage(ProsthesisCore.Utility.Logger.LoggerChannels.Arduino, string.Format("Found serial port {0}", port));
        }

        bool foundCorrectArduino = false;

        var idPacket = new ArduinoMessageBase();
        idPacket.ID = ArduinoMessageValues.kIdentifyValue;

        string jsonOutput = Newtonsoft.Json.JsonConvert.SerializeObject(idPacket);

        foreach (string port in ports)
        {
            SerialPort serialPort = new SerialPort(port, kArduinoCommsBaudRate);
            serialPort.Parity = Parity.None;
            serialPort.DataBits = 8;
            serialPort.StopBits = StopBits.One;

            //Only check unopened ports
            if (!serialPort.IsOpen)
            {
                serialPort.Open();

                //Disable telemtry just incase
                var toggle = new { ID = ArduinoMessageValues.kTelemetryEnableValue, EN = false };
                string disableTelem = Newtonsoft.Json.JsonConvert.SerializeObject(toggle);
                serialPort.Write(disableTelem);

                //Discard any built up data
                serialPort.DiscardInBuffer();
                serialPort.Write(jsonOutput);
                serialPort.ReadTimeout = kIDTimeoutMilliseconds;

                string response = string.Empty;
                for (int i = 0; i < kNumRetries; ++i)
                {
                    try
                    {
                        //This is guaranteed to timeout if not configured through minicom
                        response = ReadLine(serialPort);
                        break;
                    }
                    //Catch case where the serial port is unavailable. MOve to next port
                    catch (TimeoutException)
                    {
                        continue;
                    }
                }

                if (!string.IsNullOrEmpty(response))
                {
                    //Perform response validation
                }
                else
                {
                    //Got no response
                }

                if (!foundCorrectArduino)
                {
                    serialPort.Close();
                }
            }
        }

        return foundCorrectArduino;
    }
    /// <summary>
    /// From https://stackoverflow.com/questions/434494/serial-port-rs232-in-mono-for-multiple-platforms
    /// </summary>
    /// <returns></returns>
    private static string[] GetPortNames()
    {
        int p = (int)Environment.OSVersion.Platform;
        List<string> serial_ports = new List<string>();

        // Are we on Unix?
        if (p == 4 || p == 128 || p == 6)
        {
            string[] ttys = System.IO.Directory.GetFiles("/dev/", "tty*");
            foreach (string dev in ttys)
            {
                //Arduino MEGAs show up as ttyACM due to their different USB<->RS232 chips
                if (dev.StartsWith("/dev/ttyS") || dev.StartsWith("/dev/ttyUSB") || dev.StartsWith("/dev/ttyACM"))
                {
                    serial_ports.Add(dev);
                }
            }
        }
        else
        {
            serial_ports.AddRange(SerialPort.GetPortNames());
        }

        return serial_ports.ToArray();
    }

Have a look at stty command. 看看stty命令。 It will let you set/read teminal settings 它可以让你设置/读取终端设置

http://linux.about.com/od/lna_guide/a/gdelna38t01.htm will give a rundown on it's use. http://linux.about.com/od/lna_guide/a/gdelna38t01.htm将对其使用情况进行概述。 It would be easier to call out to than minicom, and the settings stay on the device. 呼叫比minicom更容易,并且设置保留在设备上。

I have done something like the same as you before. 我做过类似你以前的事情。 I had to read and write data through USB Serial adapter, and didnt use minicom. 我不得不通过USB串口适配器读写数据,并没有使用minicom。 It may not be god code but i found that inorder to read the data I could create a new thread and have that check for data, my code include a lot of stuff but basicly i did this: 它可能不是上帝代码,但我发现,为了读取数据,我可以创建一个新的线程,并检查数据,我的代码包括很多东西,但基本上我这样做:

System.Threading.Thread newThread;
newThread = new System.Threading.Thread(this.check_get_data);

and the check_get_data method 和check_get_data方法

public void check_get_data ()
    {
        byte tmpByte = 0;
        while (m_objSerialPort.BytesToRead != 0) {
            tmpByte = (byte)m_objSerialPort.ReadByte ();
            DoSomethingWithByte(tmpByte);
            Thread.Sleep(20);
        }
    }

this is currently running with two usbserials. 目前正在运行两个usbserials。 dont know if it helps but hope you find your solution 不知道它是否有帮助,但希望你找到你的解决方案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM