Arduino. Detectando erros na comunicação serial


Porque é vital detectar erros na comunicação?

Quando estamos trabalhando com dispositivos que necessitam de se comunicar, precisamos nos preocupar com os erros na comunicação. Estes erros irão ocorrer, geralmente em quantidades muito pequenas se tudo tiver sido bem dimensionado, porém basta um erro em um milhão de bytes trocados para que um grande problema possa ocorrer. Temos que nos lembrar que redes de sensores geram milhares de mensagens entre si, e mesmo um percentual pequeno de erros deve ser identificado.

Redes de sensores. A comunicação é vital!

A biblioteca de comunicação serial do arduino é muito simples de utilizar e resolve muito bem a maioria dos casos. Mas o seu tratamento de erros é nenhum. Precisamos de ter uma outra solução se desejamos ter uma confiabilidade adequada a equipamentos profissionais.

Felizmente, o hardware do ATMEGA386 e dos demais processadores utilizados nas diferentes versões de arduino oferecem a possibilidade de identificação de erros de comunicação, especificamente erros de paridade, erros de quadro e erros de sobre-escrita. Se somarmos esta indicação de erro a um tratamento pelo firmware, podemos aumentar em muito a confiabilidade na comunicação.

No endereço https://github.com/greiman/SerialPort encontramos uma biblioteca para comunicação serial que oferece a funcionalidade desejada de teste da comunicação serial no nível do hardware. Seguindo as sugestões do próprio autor fizemos algumas modificações de configuração para se adequar mais ao nosso caso. A biblioteca com estas configurações você encontra na página https://cadernodelaboratorio.com.br/scripts-softwares-e-arquivos-de-configuracao/ , sob o nome pack170908.tar.gz.

Instalando a biblioteca SerialPort.zip

Descomprima o arquivo pack170908.tar.gz em um diretório a sua escolha

Inicie a IDE do arduino. Selecione o menu Sketch/Incluir biblioteca/Adicionar biblioteca .zip

No diálogo que se segue, selecione o arquivo SerialPort.zip

Após a instalação, selecione o menu Sketch/Incluir biblioteca. A SerialPort deverá estar na área de “Contributed bibliotecas”.

Implementando um programa de comunicação.

Usaremos a usart com a configuração 9600,7E1, o que significa velocidade de 9600 bauds, 7 bits de dados, paridade par e um(1) stop bit. Infelizmente, o emulador de terminais que vem junto ao ambiente arduino somente opera com 8N1, ou seja, oito bits de dados, sem paridade e 1 stop bit. Sugerimos o uso do programa picocom como emulador de terminais. Para saber como instalar e configurar este programa visite a página:

https://cadernodelaboratorio.com.br/2015/05/13/picocom-um-emulador-de-terminais-para-o-linux/ .

Para utilizar a nova biblioteca de comunicação serial os seguintes comandos básicos são utilizados:

Para incluir a biblioteca e instanciar um objeto de comunicação serial:

#include <SerialPort.h>  //comunicacao serial
USE_NEW_SERIAL;         //usaremos a porta serial 0
                        // unica disponivel no UNO

Para definir a velocidade e parâmetros de comunicação:

//inicializacao da interface serial
NewSerial.begin(9600, SP_7_BIT_CHAR | SP_EVEN_PARITY | SP_1_STOP_BIT );

Para enviar uma mensagem através da porta serial:

NewSerial.println("Bem vindo ao caderno de laboratorio");

Para ler um byte da serial

chLido= NewSerial.read();  //le um caracter da serial para montar o comando

Para identificar erros na leitura de um byte

nErro = NewSerial.getRxError();


// Erros capturados
// SP_RX_BUF_OVERRUN
// SP_RX_DATA_OVERRUN
// SP_FRAMING_ERROR
// SP_PARITY_ERROR
 
 
if (nErro) 
	{			
	//em caso de erro  descarta dados recebidos e reinicia leitura
    //inicializacao dos ponteiros de insercao e buffer de recepcao de comandos
	cIndexEscrita=0;
	chPDU[0]=0;
    // limpa os erros
    NewSerial.clearRxError();
    //envia mensagem indicadora de erro
    sprintf(chBufferSaida,":%d,255,1",nEndereco);
	NewSerial.println(chBufferSaida);
	} 

Para montar uma linha de comando recebida via serial

if(chLido != -1)    // se tiver um caracter le e armazena no buffer de recepção
  {
  if(chLido != 0x0d)  //joga fora os 0x0d caso existam
    { 
    chPDU[cIndexEscrita]= chLido;
    
    if(chLido == 0x0A)  // delimitador de final de comando detectdo
      {
      chPDU[cIndexEscrita]=0;  
      processaCmd();  //ao final do comando chama a decodificacao
      cIndexEscrita=0;  //prepara para um novo comando
      chPDU[0]=0;
      }
    else
      {  
      ++cIndexEscrita;
      cIndexEscrita &= (MAX_LEN_ENTRADA -1);
      }
    }
  }

Como processar a linha de comando recebida das serial

/*
 * 
 * processaCmd verifica se o comando é para este sistema (através do 
 * endereco) e se sim, extrai o comando e o parametro contidos na PDU
 * Chama a rotina adequada para processar este comando
 */
  

void processaCmd()
{
int nCmd;
uint8_t nEnderecoPDU;


//verifica se o primeiro caracter é um :

if (chPDU[0] == ':')
	{
	// obtem o endereco da PDU
	strcpy(chEnd,strtok(chPDU+1,","));
	nEnderecoPDU= atoi(chEnd);
		
	if (nEnderecoPDU == nEndereco) //verifica se comando é para esta placa
		{
		// obtem o comando
		strcpy(chCmd,strtok(NULL,","));	
		nCmd= atoi(chCmd);	
	
		// obtem o parametro
		strcpy(chParam,strtok(NULL,","));
		
		if(nCmd > (NUMERO_MAXIMO_FUNCOES-1) ||  nCmd < 0)
			{
			//envia mensagem indicadora de erro	
			sprintf(chBufferSaida,":%d,255,3",nEndereco);
			NewSerial.println(chBufferSaida);
			}	  
		else 
			//chama a rotina correspondente
			(*func[nCmd])(); 
		
		}
	else
		{ //descarta PDU que nao pertence a placa
		cIndexEscrita=0;
		chPDU[0]=0;
		}
		
	}
else
	{ //descarta PDU mal formada
	cIndexEscrita=0;
	chPDU[0]=0;
	//envia mensagem indicadora de erro
	sprintf(chBufferSaida,":%d,255,2",nEndereco);
	NewSerial.println(chBufferSaida);
	}

}	

Obtenha o programa completo na página https://cadernodelaboratorio.com.br/scripts-softwares-e-arquivos-de-configuracao/ , sob o nome pack170908.tar.gz. Utilizando o ambiente padrão do arduino compile e transfira para um arduino UNO.

Testando a comunicação serial

Execute o picocom (ou o emulador de terminais de sua preferencia) com os seguintes parâmetros a partir da linha de comando:

picocom /dev/ttyACM0 -pe -d7 –omap crlf

Ou seja, estamos abrindo o picocom na porta ttyACM0 (porta padrão para o UNO), com paridade par (even) e sete bits de dados. O caractere de saída cr será substituído por lf.

Com o arduino conectado, logo após abrirmos o picocom a mensagem Bem vindo ao caderno de laboratorio será apresentada na tela.

Digite no terminal do picocom:

:0,1 A resposta será: :0,demo serialPort v1.0 . Como o comando “1” é o único comando implementado não dá para testar muito mais do que isto, mas pelo menos estamos sabendo que a interface serial está funcionando corretamente.

Se você digitar uma PDU mal formada, por exemplo 0,1<enter, o retorno indicará o erro correspondente.

Missão cumprida!. Temos um framework de comunicação robusto, que verifica a ocorrência de diferentes erros, e que servirá de base para muitos de nossos projetos.

Até a próxima!

 

Deixe um comentário