jSSC не отправляет данные в Arduino

У меня проблема с написанием функции jSSC. Кажется, моя плата Arduino Uno не получает данные из моей Java-программы.

У меня есть шаговый двигатель, управляемый платой Arduino Uno. Я сделал простую программу, которая имеет 2 кнопки. Один - для вращения по часовой стрелке, а другой - для вращения против часовой стрелки. Кнопка CW отправляет символ "H", а кнопка CCW отправляет символ "L". Теперь у меня есть:

  1. Я проверил из последовательной консоли IDE Arduino, что моя программа Arduino работает правильно. Когда я посылаю "H", двигатель вращается по часовой стрелке, а "L" - по часовой стрелке.
  2. Я сделал программу в обработке с двумя кнопками, посылающими 'H' и 'L'. Это сработало.
  3. Я сделал Java-программу с JSSC с двумя кнопками, посылающими 'H' и 'L'. ЭТО НЕ УДАЛОСЬ. Когда я нажимаю одну из кнопок в моей программе, я вижу, что индикатор "L" на плате мигает 3-4 раза, но ничего не происходит.
  4. Я попытался получить данные с моей доски с помощью JSSC, и это сработало. Кажется, проблема в написании функции.
  5. Я проверил с другой платой Arduino Uno, но результат тот же.

Моя программа на Java использует serialPort.writeByte((byte)'H'); а также serialPort.writeByte((byte)'L');

Есть идеи?

3 ответа

Вы пытались установить параметры для управления потоком. Поскольку при записи в интерфейс требуется разрешение.

serialPort.setParams(SerialPort.BAUDRATE_9600,
                                 SerialPort.DATABITS_8,
                                 SerialPort.STOPBITS_1,
                                 SerialPort.PARITY_NONE,false,true);//Set params. Also you can set params by this string: serialPort.setParams(9600, 8, 1, 0,RTSEnable,DTSEnable);
serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);

Может ли это быть проблема, связанная с перезагрузкой? Возможно, ваша функция Java использует вывод DTR, который подключен к выводу RESET; поэтому, когда вы пытаетесь отправить данные, вы просто сбрасываете плату.

Если вы хотите проверить, вы можете сделать еще один светодиод мигать при запуске или отправить что-то через последовательный интерфейс при настройке. Если вы получили этот отзыв, попробуйте посмотреть, как отключить DTR;)

Вы можете изменить класс Serial класса Processing (который работает довольно хорошо), чтобы избежать PApplet, если вы не планируете использовать его в своем Java-проекте:

/*
  PSerial - class for serial port goodness
  Part of the Processing project - http://processing.org

  Copyright (c) 2004-05 Ben Fry & Casey Reas
  Reworked by Gottfried Haider as part of GSOC 2013

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA
*/
import java.lang.reflect.Method;
import java.util.Map;

import jssc.SerialPort;
import jssc.SerialPortEvent;
import jssc.SerialPortEventListener;
import jssc.SerialPortException;
import jssc.SerialPortList;

public class Serial implements SerialPortEventListener {
          Object parent;
          public SerialPort port;
          Method serialAvailableMethod;
          Method serialEventMethod;

          byte[] buffer = new byte[32768];
          int inBuffer = 0;
          int readOffset = 0;

          int bufferUntilSize = 1;
          byte bufferUntilByte = 0;

          volatile boolean invokeSerialAvailable = false;

          // Things we are currently not exposing:
          // * hardware flow control
          // * state of the RING, RLSD line
          // * sending breaks


          public Serial(Object parent) {
            this(parent, "COM1", 9600, 'N', 8, 1);
          }


          public Serial(Object parent, int baudRate) {
            this(parent, "COM1", baudRate, 'N', 8, 1);
          }


          public Serial(Object parent, String portName) {
            this(parent, portName, 9600, 'N', 8, 1);
          }


          public Serial(Object parent, String portName, int baudRate) {
            this(parent, portName, baudRate, 'N', 8, 1);
          }


          public Serial(Object parent, String portName, int baudRate, char parity, int dataBits, float stopBits) {
            this.parent = parent;

            //parent.registerMethod("dispose", this);
            //parent.registerMethod("pre", this);

            // setup parity
            if (parity == 'O') {
              parity = SerialPort.PARITY_ODD;
            } else if (parity == 'E') {
              parity = SerialPort.PARITY_EVEN;
            } else if (parity == 'M') {
              parity = SerialPort.PARITY_MARK;
            } else if (parity == 'S') {
              parity = SerialPort.PARITY_SPACE;
            } else {
              parity = SerialPort.PARITY_NONE;
            }

            // setup stop bits
            int stopBitsIdx = SerialPort.STOPBITS_1;
            if (stopBits == 1.5f) {
              stopBitsIdx = SerialPort.STOPBITS_1_5;
            } else if (stopBits == 2) {
              stopBitsIdx = SerialPort.STOPBITS_2;
            }

            port = new SerialPort(portName);
            try {
              // the native open() call is not using O_NONBLOCK, so this might block for certain operations (see write())
              port.openPort();
              port.setParams(baudRate, dataBits, stopBitsIdx, parity);
              // we could register more events here
              port.addEventListener(this, SerialPort.MASK_RXCHAR);
            } catch (SerialPortException e) {
              // this used to be a RuntimeException before, so stick with it
              throw new RuntimeException("Error opening serial port " + e.getPortName() + ": " + e.getExceptionType());
            }

            serialEventMethod = findCallback("serialEvent");
            serialAvailableMethod = findCallback("serialAvailable");
          }

          private Method findCallback(final String name) {
            try {
              return parent.getClass().getMethod(name, this.getClass());
            } catch (Exception e) {
            }
            // Permit callback(Object) as alternative to callback(Serial).
            try {
              return parent.getClass().getMethod(name, Object.class);
            } catch (Exception e) {
            }
            return null;
          }


          public void dispose() {
            stop();
          }


          public void pre() {
            if (serialAvailableMethod != null && invokeSerialAvailable) {
              invokeSerialAvailable = false;
              try {
                serialAvailableMethod.invoke(parent, this);
              } catch (Exception e) {
                System.err.println("Error, disabling serialAvailable() for "+port.getPortName());
                System.err.println(e.getLocalizedMessage());
                serialAvailableMethod = null;
              }
            }
          }


          public int available() {
            return (inBuffer-readOffset);
          }


          public void buffer(int size) {
            bufferUntilSize = size;
          }


          public void bufferUntil(int inByte) {
            bufferUntilSize = 0;
            bufferUntilByte = (byte)inByte;
          }


          public void clear() {
            synchronized (buffer) {
              inBuffer = 0;
              readOffset = 0;
            }
          }


          public boolean getCTS() {
            try {
              return port.isCTS();
            } catch (SerialPortException e) {
              throw new RuntimeException("Error reading the CTS line: " + e.getExceptionType());
            }
          }


          public boolean getDSR() {
            try {
              return port.isDSR();
            } catch (SerialPortException e) {
              throw new RuntimeException("Error reading the DSR line: " + e.getExceptionType());
            }
          }


          public static Map<String, String> getProperties(String portName) {
            return SerialPortList.getPortProperties(portName);
          }


          public int last() {
            if (inBuffer == readOffset) {
              return -1;
            }

            synchronized (buffer) {
              int ret = buffer[inBuffer-1] & 0xFF;
              inBuffer = 0;
              readOffset = 0;
              return ret;
            }
          }


          public char lastChar() {
            return (char)last();
          }


          public static String[] list() {
            // returns list sorted alphabetically, thus cu.* comes before tty.*
            // this was different with RXTX
            return SerialPortList.getPortNames();
          }


          public int read() {
            if (inBuffer == readOffset) {
              return -1;
            }

            synchronized (buffer) {
              int ret = buffer[readOffset++] & 0xFF;
              if (inBuffer == readOffset) {
                inBuffer = 0;
                readOffset = 0;
              }
              return ret;
            }
          }


          public byte[] readBytes() {
            if (inBuffer == readOffset) {
              return null;
            }

            synchronized (buffer) {
              byte[] ret = new byte[inBuffer-readOffset];
              System.arraycopy(buffer, readOffset, ret, 0, ret.length);
              inBuffer = 0;
              readOffset = 0;
              return ret;
            }
          }


          public int readBytes(byte[] dest) {
            if (inBuffer == readOffset) {
              return 0;
            }

            synchronized (buffer) {
              int toCopy = inBuffer-readOffset;
              if (dest.length < toCopy) {
                toCopy = dest.length;
              }
              System.arraycopy(buffer, readOffset, dest, 0, toCopy);
              readOffset += toCopy;
              if (inBuffer == readOffset) {
                inBuffer = 0;
                readOffset = 0;
              }
              return toCopy;
            }
          }


          public byte[] readBytesUntil(int inByte) {
            if (inBuffer == readOffset) {
              return null;
            }

            synchronized (buffer) {
              // look for needle in buffer
              int found = -1;
              for (int i=readOffset; i < inBuffer; i++) {
                if (buffer[i] == (byte)inByte) {
                  found = i;
                  break;
                }
              }
              if (found == -1) {
                return null;
              }

              int toCopy = found-readOffset+1;
              byte[] dest = new byte[toCopy];
              System.arraycopy(buffer, readOffset, dest, 0, toCopy);
              readOffset += toCopy;
              if (inBuffer == readOffset) {
                inBuffer = 0;
                readOffset = 0;
              }
              return dest;
            }
          }


          public int readBytesUntil(int inByte, byte[] dest) {
            if (inBuffer == readOffset) {
              return 0;
            }

            synchronized (buffer) {
              // look for needle in buffer
              int found = -1;
              for (int i=readOffset; i < inBuffer; i++) {
                if (buffer[i] == (byte)inByte) {
                  found = i;
                  break;
                }
              }
              if (found == -1) {
                return 0;
              }

              // check if bytes to copy fit in dest
              int toCopy = found-readOffset+1;
              if (dest.length < toCopy) {
                System.err.println( "The buffer passed to readBytesUntil() is to small " +
                          "to contain " + toCopy + " bytes up to and including " +
                          "char " + (byte)inByte);
                return -1;
              }
              System.arraycopy(buffer, readOffset, dest, 0, toCopy);
              readOffset += toCopy;
              if (inBuffer == readOffset) {
                inBuffer = 0;
                readOffset = 0;
              }
              return toCopy;
            }
          }


          public char readChar() {
            return (char) read();
          }


          public String readString() {
            if (inBuffer == readOffset) {
              return null;
            }
            return new String(readBytes());
          }


          public String readStringUntil(int inByte) {
            byte temp[] = readBytesUntil(inByte);
            if (temp == null) {
              return null;
            } else {
              return new String(temp);
            }
          }


          public void serialEvent(SerialPortEvent event) {
            if (event.getEventType() == SerialPortEvent.RXCHAR) {
              int toRead;
              try {
                while (0 < (toRead = port.getInputBufferBytesCount())) {
                  // this method can be called from the context of another thread
                  synchronized (buffer) {
                    // read one byte at a time if the sketch is using serialEvent
                    if (serialEventMethod != null) {
                      toRead = 1;
                    }
                    // enlarge buffer if necessary
                    if (buffer.length < inBuffer+toRead) {
                      byte temp[] = new byte[buffer.length<<1];
                      System.arraycopy(buffer, 0, temp, 0, inBuffer);
                      buffer = temp;
                    }
                    // read an array of bytes and copy it into our buffer
                    byte[] read = port.readBytes(toRead);
                    System.arraycopy(read, 0, buffer, inBuffer, read.length);
                    inBuffer += read.length;
                  }
                  if (serialEventMethod != null) {
                    if ((0 < bufferUntilSize && bufferUntilSize <= inBuffer-readOffset) ||
                      (0 == bufferUntilSize && bufferUntilByte == buffer[inBuffer-1])) {
                      try {
                        // serialEvent() is invoked in the context of the current (serial) thread
                        // which means that serialization and atomic variables need to be used to
                        // guarantee reliable operation (and better not draw() etc..)
                        // serialAvailable() does not provide any real benefits over using
                        // available() and read() inside draw - but this function has no
                        // thread-safety issues since it's being invoked during pre in the context
                        // of the Processing applet
                        serialEventMethod.invoke(parent, this);
                      } catch (Exception e) {
                        System.err.println("Error, disabling serialEvent() for "+port.getPortName());
                        System.err.println(e.getLocalizedMessage());
                        serialEventMethod = null;
                      }
                    }
                  }
                  invokeSerialAvailable = true;
                }
              } catch (SerialPortException e) {
                throw new RuntimeException("Error reading from serial port " + e.getPortName() + ": " + e.getExceptionType());
              }
            }
          }


          public void setDTR(boolean state) {
            // there is no way to influence the behavior of the DTR line when opening the serial port
            // this means that at least on Linux and OS X, Arduino devices are always reset
            try {
              port.setDTR(state);
            } catch (SerialPortException e) {
              throw new RuntimeException("Error setting the DTR line: " + e.getExceptionType());
            }
          }


          public void setRTS(boolean state) {
            try {
              port.setRTS(state);
            } catch (SerialPortException e) {
              throw new RuntimeException("Error setting the RTS line: " + e.getExceptionType());
            }
          }


          public void stop() {
            try {
              port.closePort();
            } catch (SerialPortException e) {
              // ignored
            }
            inBuffer = 0;
            readOffset = 0;
          }


          public void write(byte[] src) {
            try {
              // this might block if the serial device is not yet ready (esp. tty devices under OS X)
              port.writeBytes(src);
              // we used to call flush() here
            } catch (SerialPortException e) {
              throw new RuntimeException("Error writing to serial port " + e.getPortName() + ": " + e.getExceptionType());
            }
          }


          public void write(int src) {
            try {
              port.writeInt(src);
            } catch (SerialPortException e) {
              throw new RuntimeException("Error writing to serial port " + e.getPortName() + ": " + e.getExceptionType());
            }
          }


          public void write(String src) {
            try {
              port.writeString(src);
            } catch (SerialPortException e) {
              throw new RuntimeException("Error writing to serial port " + e.getPortName() + ": " + e.getExceptionType());
            }
          }
        }

Вот пример класса, использующего выше:

public class SerialTest {

        public static void main(String[] args) {
                try{
                        Serial serial = new Serial(new SerialTest(),"/dev/tty.usbmodemfd121",115200);
                        serial.write("H");
                        serial.write("L");//can also try serial.write((int)'L');
                }catch(Exception e){
                        System.err.println("serial not connected!");
                }
        }
        public void serialAvailable(Serial s){
                System.out.println(s.toString());
        }

        public void serialEvent(Serial s){
                System.out.print("from serial:");
                System.out.println(s.read());
        }

}

Обязательно измените порт и скорость передачи данных на то, что использует ваш Arduino Uno.

В папке с последовательной библиотекой Processing вы также найдете собственные библиотеки JNI. Например, в Windows:

C:\Program Files\processing-2.1.2\modes\java\libraries\serial\library

Где DLL будет находиться в папках windows32 и windows64, в зависимости от того, что вы планируете использовать. Класс Serial выше почти такой же, как C:\Program Files\processing-2.1.2\modes\java\libraries\serial\src\processing\serial/Serial.java заменяя PApplet на Object.

Также здесь есть ссылка на библиотеку Processing Serial

Другие вопросы по тегам