sábado, 17 de maio de 2014

Comunicação serial assíncrona em Linux

Introdução


Existem basicamente dois tipos de comunicação serial: síncrona e assíncrona. Neste artigo será apresentado um exemplo de software para comunicação serial assíncrona. Na transmissão serial os bits são transmitidos um após o outro em um único canal. No modo assíncrono não é necessário um clock para sincronismo entre transmissor e receptor. O sincronismo é feito através de bits no próprio canal de dados. 

Em sistemas embarcados é muito importante o uso da comunicação UART, porque é uma das formas que temos para externar o que está acontecendo internamento no processador. A comunicação UART é usada também para configuração e operação de certos periféricos como modens GSM e módulos de GPS. E é o método mais usado para operar uma placa com Linux Embarcado. Vídeo: Exemplo de UART para Linux.

O termo UART é um acrônimo para Universal Asynchronous Receiver-Transmitter. Na forma assíncrona, dois fios são usados para transmitir dados, um para TX e outro para RX, em regime full-duplex, ou seja, uma transmissão bi-direcional. O inicio e o fim da transmissão é indicado através de um bit de start e um bit de stop, que são mudanças no nível de tensão. Veja abaixo um típico byte numa transmissão UART.



Para que a comunicação seja feita com sucesso, a transmissor e o receptor devem operar na mesma taxa de transferência de bits, dada em bps(bits por segundo). Por exemplo, se o transmissor opera a 9600 bps, o receptor deve necessariamente operar a 9600 bps para que haja o "entendimento" do que está sendo transmitido. Não confunda taxa de transferência com baud rate, são conceitos distintos. É um erro muito comum entre iniciantes e mesmo desenvolvedores experientes esquecer de configurar o transmissor e receptor na mesma taxa de transferência.

O esquema de transmissão usado na UART para representar um byte pode ser 8 bits de dados mais um bit de paridade para indicação de erros de transmissão. O controle de fluxo dos bits por ser feito por hardware ou por software.

Taxa de Erro de Bit


BER Bit-error-rate ou taxa de erro de bit é uma razão que mede a quantidade de erros num byte que está sendo transmitido, ou um valor que serve para indicar a taxa de bits errados durante uma transmissão eletrônica. Está diretamente relacionada com o SNR(Signal-to-noise ratio), que é a relação a Relação sinal-ruído. O BER pode ser expressa como a relação entre o número de bits recebidos com erro e o número total de bits transmitidos: BER = número de bits errados / número de bits transmitidos.

Toda transmissão digital ou analógica está sujeita a erros e interferências como atenuação, ruídos, ecos, interferências eletromagnéticas, etc. Desta forma, um dos critérios mais utilizados para analisar o desempenho de sistemas digitais é a taxa de bits errados (BER - Bit Error Rate). Exemplos: 
BER = 1 x 10^-4 (1 bit errado a cada 10 mil bits transmitidos).
BER = 3 x 10^-6 (3 bits errados a cada 1 milhão de bits transmitidos)

Métodos de detecção de erros


A premissa fundamental sobre redes de dados é que elas devem ser capazes de transferir dados de um dispositivo a outro com total precisão. Um sistema que não pode ou não consegue garantir a entrega de dados, isto é, sem integridade da informação, pelo dispositivo receptor é essencialmente inútil. Além disso, toda vez que dados estiverem sendo transmitidos entre nós de uma rede eles podem ser corrompidos durante a passagem. Muitos fatores podem afetar, modificar ou destruir um ou mais bits de uma seqüência de dados. A maioria dos sistemas de alta confiabilidade dispõem de mecanismos para detecção e correção de erros.

Os dados podem ser corrompidos durante uma transmissão. Os erros devem ser detectados e corrigidos para que uma comunicação seja considerada confiável. A correção de erros pode ser realizada de muitas formas diferentes. As duas mais comuns são a correção de erros baseada na retransmissão e a correção antecipada de erros.

O conceito subjacente à correção de erros pode ser compreendido mais facilmente se examinarmos o caso mais simples: os erros isolados. Os erros isolados são detectados adicionando um bit de redundância (paridade). Um único bit adicional consegue detectar erros isolados em qualquer seqüência de bits porque ele deve distinguir entre duas condições: erro e sem erro. Já que um bit possui dois estados (0 ou 1), esses dois estados são suficientes para este tipo de detecção.

Método de paridade


O método de paridade é considerado ineficiente, porém é o mais utilizado na detecção de erros. Na hora da transmissão da informação o transmissor adiciona um bit de redundância (ou bit de paridade) após ou antes da sequência de bits que pertence à mensagem. 

O teste ou verificação da paridade, além de ser o mecanismo de detecção de erros mais comum é também o de menor custo. 

A verificação de paridade é um dos mecanismos mais simples para detecção de erros: a cada caractere transmitido é acrescentado um bit de tal modo que o total de bits ‘1’ seja par ou impar. Se o total de bits ‘1’ for par é adicionado 0, se o total de bits ‘1’ for impar é adicionado 1. É habitual a utilização de paridade par para comunicações assíncronas como a UART e a paridade ímpar para comunicações síncronas.

Exemplo de software para Linux Embarcado


#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#define BAUDRATE1 B4800
#define BAUDRATE2 B38400
#define BAUDRATE3 B57600
#define BAUDRATE4 B115200
#define UART "/dev/ttyS1"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
int main()
{
    int fd;
    fd_set readfds;
    struct termios oldtio,newtio;

    printf("Inicializando Uart3\n");  
    /************************************************/
    fd = open (UART, O_RDWR | O_NOCTTY);
    if (fd == -1) {
printf("Erro ao abrir %s\n", UART);
return fd;
    }
    else {
printf("Device %s aberto!\n", UART);
fcntl(fd, F_SETFL, 0);
    }
    FD_ZERO(&readfds);
    FD_SET(fd, &readfds);    
    // save current port settings
    tcgetattr(fd,&oldtio);
    //---------------------------------------------------------------------------------------
    // setting serial port configurations
    //bzero(&newtio, sizeof(newtio));
    memset(&newtio, 0, sizeof(newtio));
    newtio.c_cflag = BAUDRATE4 | CRTSCTS | CS8 | CLOCAL | CREAD;
    newtio.c_iflag = IGNPAR;
    newtio.c_oflag = 0;
    newtio.c_lflag = 0;          // set input mode (non-canonical, no echo,...)
    newtio.c_cc[VTIME]    = 0;   // inter-character timer unused
    newtio.c_cc[VMIN]     = 1;   // blocking read until x chars received
    tcflush(fd, TCIFLUSH);
    tcsetattr(fd,TCSANOW,&newtio);
    /************************************************/
    printf("Testando UART3\n");
    write(fd,"Testando UART3 aqui!\n", sizeof("Testando UART3 aqui!\n"));
    close(fd);
    printf("\nFim do teste!\n");
    return (0);
}

Lembre de escolher o BAUDRATE correto para que a transmissão funcione e você deverá saber qual a entrada /dev/ttySx está associado ao dispositivo UART que você deseja usar. No meu caso é /dev/ttyS1.

Nenhum comentário:

Postar um comentário