Ajuda porta serial TCC! :D

Olá galerinha, estou com um grande problema e gostaria de uma ajuda dos senhores…

Estou fazendo um projeto para o TCC e gostaria de manipular os dados atraves de uma porta serial usando o java. O problema no entanto é que toda as vezes que eu faço a leitura da porta serial, ele lê esses dados picotados! O baud rating do java e o do Arduino que estou usando estão ambos setados em 9600…

Era para ser uma simples tarefa de leitura, mas a parte do java esta complicada! ;\

Parte do codigo eu peguei do blog do prototipo!

[code]package serial;

import gnu.io.CommPortIdentifier;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.TooManyListenersException;

/**
*

  • @author prototipo
    */
    public class SerialComm implements SerialPortEventListener {

    String total = new String();

    InputStream inputStream;

    public void execute() {

     String portName = getPortNameByOS();
    
     CommPortIdentifier portId = getPortIdentifier(portName);
     if(portId != null) {
    
         try {
     SerialPort serialPort = (SerialPort) portId.open(this.getClass().getName(), 2000);
    
             inputStream = serialPort.getInputStream();
    
             serialPort.addEventListener(this);
    
             serialPort.notifyOnDataAvailable(true);
    
             serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8,
     				   SerialPort.STOPBITS_1,
     				   SerialPort.PARITY_NONE);
    
         }
         catch (PortInUseException e) {}
    
         catch (IOException e) {}
    
         catch (UnsupportedCommOperationException e) {
             e.printStackTrace();
         }
         catch (TooManyListenersException e) {}
    
     } else {
         System.out.println("Porta Serial não disponível");
     }
    

    }

    /**

    • Get The port name
      **/
      private String getPortNameByOS() {

      String osname = System.getProperty(“os.name”,"").toLowerCase();
      if ( osname.startsWith(“windows”) ) {
      // windows
      return “COM4”;
      } else if (osname.startsWith(“linux”)) {
      // linux
      return “/dev/ttyS0”;
      } else if ( osname.startsWith(“mac”) ) {
      // mac
      return “???”;
      } else {
      System.out.println(“Sorry, your operating system is not supported”);
      System.exit(1);
      return null;
      }

    }
    /**
    *Get the Port Identifier
    **/
    private CommPortIdentifier getPortIdentifier(String portName) {
    Enumeration portList = CommPortIdentifier.getPortIdentifiers();
    Boolean portFound = false;
    while (portList.hasMoreElements()) {
    CommPortIdentifier portId = (CommPortIdentifier) portList.nextElement();
    if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
    System.out.println("Available port: " + portId.getName());
    if (portId.getName().equals(portName)) {
    System.out.println("Found port: "+portName);
    portFound = true;
    return portId;
    }
    }

     } 
    
     return null;
    

    }

    public void serialEvent(SerialPortEvent event) {

     switch (event.getEventType()) {
     case SerialPortEvent.BI:
     case SerialPortEvent.OE:
     case SerialPortEvent.FE:
     case SerialPortEvent.PE:
     case SerialPortEvent.CD:
     case SerialPortEvent.CTS:
     case SerialPortEvent.DSR:
     case SerialPortEvent.RI:
     case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
     	break;
     case SerialPortEvent.DATA_AVAILABLE:
     	total ="";
     	readSerial();
     	System.out.println(total);
     	break;
     }
    

    }

    /**

    • Buffer to hold the reading
      */
      private byte[] readBuffer = new byte[400];

    private void readSerial() {
    try {
    int availableBytes = inputStream.available();
    if (availableBytes > 0) {
    // Read the serial port
    inputStream.read(readBuffer, 0, availableBytes);

             // Print it out
             //System.out.println(
                     //new String(readBuffer, 0, availableBytes));
             total = total+new String(readBuffer, 0, availableBytes);
         }
     } catch (IOException e) {
     }
    

    }

}
[/code]

O simplório codigo em C:

void setup() {
  Serial.begin(9600);
}

void loop() {
  int sensorValue = analogRead(1);
  delay(150);
  int sensorValue2 = analogRead(0);
  delay(150);
  int sensorValue3 = analogRead(2);
  delay(150);
  sensorValue = (sensorValue*1.3012)
  sensorValue2 = (sensorValue2*1.3012);
  sensorValue3 = (sensorValue3*1.3012);
  String sv = String (sensorValue,DEC);
  String sv2 = String (sensorValue2,DEC);
  String sv3 = String (sensorValue3,DEC);

  String porta =(sv+" "+sv2+" "+sv3);
  Serial.println(porta);
  delay(250);
  
}

O que eu leio com o programa da Rogercom ou o simulador de porta serial do Arduino é isso, ou seja que eu desejo ler na porta serial pelo java:

Uploaded with ImageShack.us

O que eu estou lendo é isso:

Uploaded with ImageShack.us

Teria como alguem me da uma ajuda? Estou meio desesperado pois sou leigo no assunto :expressionless:

Acredito que o Delay esteja avacalhando com a comunicação.
Procure utilizar uma abordagem por threads.

+++

Olá meu caro, obrigado pela atenção e sugestão!

Então amigo, eu testei enviando os dados pelo RX TX do rogercom e mesmo sem delay ele fragmenta os dados lidos… :\

Eu esqueci de mencionar que eu estou usando a arquitetura 64 bits do Windows 7 e estou usando a seguinte os bins daqui http://www.cloudhopper.com/opensource/rxtx/ . Isto pode vir a influenciar? São os bins " aconselhaveis" pela rxtx wiki lá…

Por favor galerinha preciso de ajuda! :smiley:

Para comunicação serial, utilizo o driver COMM.JAR da SUN.

Acredito que seu problema esteja no envio ( programa em ‘C’ acima ).
Não é uma boa prática em programação o uso de Delay() se não estiver numa Thread, pois isso trava o processamento do sistema.

+++

Para tirar a prova e isolar o problema, tente receber com o Hiperterminal do Windows.
Se o comportamento indesejado for o mesmo, a tese acima estará confirmada.

+++

Olá, tudo bem?

Então amigo, quando eu uso o simulador de porta serial do arduino ou o programa RXTX da rogercom, eles não “picotam” a informação… No windows 7 não existe mais o bom e velho hiperterminal, mas estes outros programas que citei simulam o comportamento do mesmo… Nesses programas os dados obtidos não estão fragmentados, apenas quando eu faço a leitura pelo java os dados lidos ficam comprometidos.

Obrigado pela atenção. :smiley:

OBS: Por exemplo a primeira imagem é o simulador de serial do compilador do arduino com o mesmo já coletando os dados, perceba que a string não foi fragmentada. Já no segundo caso o mesmo tipo de leitura esta sendo feita no java e apresenta a informação incerta. :?

Só pra tentar entender :

Quando voce fala em ‘simulação’, refere-se á uma recepção real dos dados da placa ?
( estou pedindo essa confirmação porque em eletronica embarcada, usamos esse termo para aplicativos que por software emulam um hardware ).

Bom, se for este o caso, isso quer dizer que os Delay()´s acima não são a causa do problema, mas mesmo assim acho conveniente testar uma diminuição dos valores dos tempos.

Poderia postar o trecho do Arduíno que configura os demais parametros da serial ?
( a única informação no código acima foi o Baud-rate ).

+++

Um teste :

Diminui bastante a velocidade e avalia se isso diminui a incidencia de erros.

+++

Olá Andre, obrigado pela atenção.

Vou lhe falar sobre meus testes realizados:

O arduino em operação coletando informações está ligado a COM4, posso fazer a leitura dessa COM4 com o proprio compilador do arduino (com o arduino plugado e já enviando os dados), pelo programa da ROGERCOM que abre a COM4 e faz a leitura e com o Java.

Quando eu abro com o compilador ou com o programa da ROGERCOM a string não é fragmentada e o dado é lido sem grandes complicações. Já quando eu abro para fazer a leitura com o java a informação lida é comprometida e fragmentada.

Outro teste realizado foi também com o programa da ROGERCOM enviando a String, mesmo sem loop e delays quando eu mando a informação para a leitura no java o programa “quebra” a string em pedaços… Gerando uma informação errada.

Então amigo, estou usando as seguintes configurações:

9600 de baud

sem bit de paridade

1 stop bit e cordão de 8 bits.

Nos 3 programas ( compilador, rogercom e java ) as configurações estão setadas iguais a da placa.

No entanto um fato curioso acabou de ocorrer…

Reiniciei o PC e agora o java está lendo de forma “certa” a serial… O estranho é que eu não mexi em absolutamente nada… Apenas reiniciei o PC…

Agora minhas suspeitas estão aumentando em relação aos bins, visto que uma hora a leitura é feita de forma correta, outra hora ela é feita de forma erronia…

Ensuma, muito estranho…

Alguem já passou por isso ou sabe alguma forma de deixar isto estavel?

Obrigado pessoal!

Insere um teste de Debug entre as linhas 143/144 ( System.out.println(e) ??? ) pois pode estar ocorerndo alguma excessão que não trava o processa mas pode não estar sendo detectada.

+++

Então amigo, fiz o teste e aparentemente não dá nenhuma exceção…

Ontem fiquei fazendo testes aqui em casa e curiosamente descobri uma coisa que melhorou muito o problema… Quanto mais eu elevo o baud rate, melhor fica a leitura no java…

Com 9600 ele lê a string e picota em 3 partes praticamente… Com 250000 de baud rate ele lê aproximadamente 5 string certas e pega uma 6º string com a fragmentação apenas no utimo dado da string, e então volta para 5 certas e 1 corrompida… Infelizmente o arduino não passa de 250000 o baud, o máximo que consegui foi isso, mas tendeu a dar uma estabilizada… O estranho no entanto é o acréscimo de baud melhorar a leitura no java… Alguem aí já passou por isso?

Só uma coisinha que preciso explicar. Se você não entender isso, vai quebrar a cabeça até morrer. E eu não gosto de ver gente se suicidando porque não sabe a verdade dos fatos.

O JavaComm não lê tudo de uma vez só (daí você estar achando que “as coisas vêm picotadas”).

Em vez disso, ele normalmente lê as coisas de 8 em 8 bytes, ou de 16 em 16 bytes - depende um pouco do hardware que implementa a comunicação serial no seu computador.
(Como você deve saber, o INS16550, que é o chip emulado pelo hardware de seu computador que tem suporte a interface serial, contém um buffer de 16 bytes o qual, depois de cheio (ou depois de transcorrido um determinado tempo) gera uma interrupção de hardware, a qual seu sistema operacional (não importa se Windows, Linux ou Solaris) irá atender.
O que ocorre é que o JavaComm retorna imediatamente com os dados que estão no buffer (quer sejam 8 ou 16 bytes) a cada vez que o sistema operacional diz que há alguma coisa disponível para ser lida.

E é por isso que “seu software parece funcionar melhor com taxas de comunicação mais altas”. Isso é porque, a taxas de comunicação mais altas, o buffer normalmente está cheio na hora de você ler os dados. Quando as taxas são mais baixas, normalmente há só 1 ou 2 bytes para serem lidos, e um timeout (bem baixo por sinal) transcorreu de forma que o INS16550 emitiu uma interrupção e avisou o sistema operacional que há alguma coisa para ser lida.

OK?

Não use taxas mais altas que 115200 a menos que você tenha certeza que o sistema operacional e seu hardware estejam preparados para isso. Taxas mais altas que 115200 baud (coisa bem mixuruca, por sinal) começam a dar problemas de incompatibilidade. Sem contar que pode ser que você realmente comece a perder dados porque seu programa não está preparado e coisas que estavam em algum buffer de entrada ou saída possam se perder.

Olá todos, muito obrigado amigo pela resposta contendo a explicação…

Para contornar o fato eu tentei fazer uma concatenação de strings com startswith e endswith, mas mesmo assim o endswith não opera direito, aparentemente o java lê algo a mais no fim que não concorda com o endswith :… Isso está me dando uma dor de cabeça hahahhaa.

Na verdade eu fiz alguns testes durante 10 minutos ligado com 250000 de baud e poucos dados foram corrompidos cerca de 95% dos dados chegaram com sucesso… Eu entendi o que você quiz dizer, quanto maior o baud maior o mais dados sao transportados por bloco… Mas eu não sei como contornar sem ser com esta “gambiarra”, sem ela os dados vem são lidos separadamente ;\ … Alguma sugestão amigo?

Obrigado novamente pela atenção!

Tio - só vou fazer o seguinte reparo: procure não empregar Strings quando o que você quer tratar são sequências de bytes.

Pode até criar uma classe que se comporte como uma String, mas que seja um encapsulamento de um array de bytes, ou sei lá o que é melhor para seu problema (talvez uma fila circular, por exemplo).

Mas Strings corrompem os bytes - isso é problema com codificação. Para provar esse ponto, tente rodar as seguintes linhas de programa:

byte[] bytes = new byte[256];
for (int i = 0; i < 256; ++i) bytes[i] = (byte) i; // até aqui não houve corrupção nenhuma...
String s = new String (bytes); // aqui houve corrupção dos dados. Vamos mostrar onde é que os bytes
// foram corrompidos.
byte[] bytesCorrompidos = s.getBytes();
for (int i = 0; i < bytesCorrompidos.length; ++i) {
    if (bytesCorrompidos[i] != (byte) i) System.out.printf ("Erro (%d): byte %02X -> corrompido para o byte %02X%n", 
        i, bytesCorrompidos[i] & 0xFF, i & 0xFF);
}

Faz um novo teste de Debug :

Após cada 1 Byte recebido ser impresso, imprime também ( intercalando ) a variável availableBytes.
Inclusive, dá uma olhada nessa página, onde a rotina de recepção é ligeiramente diferente na recepção :

Sugestões para contornar :

1 ) Utilizar empacotamento dos dados, com byte verificador/detector de erros : STX-nDADOS-CRC-ETX
2 ) Baixar novamente o driver rxtx, de preferencia de uma revisão diferente
3 ) Tentar usar o COMM.JAR que utilizo sem problemas.

+++

Olá pessoal do forum, tudo bem?

Então galera, consegui achar uma solução “coxa” além de deixar o baud altissimo… O que estou fazendo é o seguinte:

package bodin.net;

import gnu.io.CommPortIdentifier;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.TooManyListenersException;
import java.util.concurrent.TimeUnit;

/**
 *
 * @author prototipo
 */
public class SerialComm implements SerialPortEventListener {

    InputStream inputStream;

    public void execute() {

        String portName = getPortNameByOS();

        CommPortIdentifier portId = getPortIdentifier(portName);
        if(portId != null) {

            try {
		SerialPort serialPort = (SerialPort) portId.open(this.getClass().getName(), 10000);

                inputStream = serialPort.getInputStream();

                serialPort.addEventListener(this);

                serialPort.notifyOnDataAvailable(true);

                serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8,
						   SerialPort.STOPBITS_1,
						   SerialPort.PARITY_NONE);

            }
            catch (PortInUseException e) {}

            catch (IOException e) {}

            catch (UnsupportedCommOperationException e) {
                e.printStackTrace();
            }
            catch (TooManyListenersException e) {}

        } else {
            System.out.println("Porta Serial não disponível");
        }
    }

    /**
     * Get The port name
     **/
    private String getPortNameByOS() {

        String osname = System.getProperty("os.name","").toLowerCase();
        if ( osname.startsWith("windows") ) {
                // windows
                return "COM8";
        } else if (osname.startsWith("linux")) {
                // linux
                return "/dev/ttyS0";
        } else if ( osname.startsWith("mac") ) {
                // mac
                return "???";
        } else {
                System.out.println("Sorry, your operating system is not supported");
                System.exit(1);
                return null;
        }

    }
    /**
     *Get the Port Identifier
     **/
    private CommPortIdentifier getPortIdentifier(String portName) {
        Enumeration portList = CommPortIdentifier.getPortIdentifiers();
	Boolean portFound = false;
        while (portList.hasMoreElements()) {
                CommPortIdentifier portId = (CommPortIdentifier) portList.nextElement();
                if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
                        System.out.println("Available port: " + portId.getName());
                        if (portId.getName().equals(portName)) {
                                System.out.println("Found port: "+portName);
                                portFound = true;
                                return portId;
                        }
                }

        }

        return null;

    }

    public void serialEvent(SerialPortEvent event) {

		switch (event.getEventType()) {
		case SerialPortEvent.BI:
		case SerialPortEvent.OE:
		case SerialPortEvent.FE:
		case SerialPortEvent.PE:
		case SerialPortEvent.CD:
		case SerialPortEvent.CTS:
		case SerialPortEvent.DSR:
		case SerialPortEvent.RI:
		case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
			break;
		case SerialPortEvent.DATA_AVAILABLE:
                    try {
    TimeUnit.MILLISECONDS.sleep(500); // 
} catch (InterruptedException ignored) {  
}
			byte[] readBuffer = new byte[1024];
			try {
			   int numBytes = 0;
				while (inputStream.available() > 0) {
					numBytes = inputStream.read(readBuffer);
				}
				String result  = new String(readBuffer);
                                result = result.substring(0, numBytes);
                                int x = 0;
				System.out.println(result+"\n");

			} catch (IOException e) {}

			break;
		}
	}

}

ATENTEM que eu tive que colocar um breve DELAY para que o buffer não seja lido “direto”… Assim o buffer só é lido quando a informação chega completa!

Vale lembrar que este 500 não é um padrão, ele depende do tamanho da string que você está enviando, para isso é necessário “calibrar”…

Agora pessoal, preciso de uma ajuda!

Eu sou horrivel com o tratamento de Strings e gostaria da ajuda dos senhores para desossar esta string e passa-la para INT…

Bom pessoal o problema agora é o seguinte (bem mais simples por sinal hahaha).

O meu codigo c do arduino:

[code]const int AN = 0;
const int AN2 = 1;
conts int AN3 = 2;
const int RX = 5;

void setup()
{
Serial.begin(9600);
pinMode(RX, OUTPUT);
}

long anVolt, inches,inches2,inches3, cm;
int sum = 0;
int avgRange = 60;

void loop()
{
for (int i = 0; i < avgRange; i++)
{
anVolt = analogRead(AN);
sum += anVolt;
}
inches = 1.3915 * sum / avgRange;
sum = 0;

for (int i = 0; i < avgRange; i++)
{
anVolt = analogRead(AN2);
sum += anVolt;
}
inches2 = 1.3915 * sum / avgRange;
sum = 0;

for (int i = 0; i < avgRange; i++)
{
anVolt = analogRead(AN3);
sum += anVolt;
}
inches3 = 1.3915 * sum / avgRange;
sum = 0;

Serial.print("[");
Serial.print(inches);
Serial.print("]");
Serial.println();
Serial.print("{");
Serial.print(inches2);
Serial.print("}");
Serial.println();
Serial.print("(");
Serial.print(inches3);
Serial.print(")");
Serial.println();
delay(1000);
}
[/code]

A string que recebo fica com o seguinte formato:

O que eu peço aos senhores é a ajuda para desossar está string, ou seja…
Atribuir o valor entre os colchetes a uma variavel int, atribuir o que esta entre parenteses a outra variavel int e por fim o que está entre variaveis a uma terceira variavel int distinta… Teria como os senhore me ajudarem?

Grato!

Obrigado pela atenção pessoal!

1 curtida

Peço carinhosamente a ajuda dos amigos!

Obrigado! :wink: