Portal - FPGA para Todos

Recepção Serial - RS232

Recepção Serial - RS232

O projeto descrito nesse artigo tem como objetivo a implementação de um receptor serial com base no protocolo RS232, sendo um projeto complementar ao transmissor serial RS232, detalhado em outro artigo.

Essa página demonstrará o exemplo de um projeto descrito em VHDL e simulado no Modelsim-Altera®, através de um testbench, que será a entrada de dados da simulação e é escrito em VHDL.

Os equipamentos necessários para a implementação e teste de projeto são:

Descrição do Funcionamento

Como já foi citado acima, o projeto baseia-se no protocolo de comunicação serial RS232. Este protocolo utiliza como inicio de transmissão um pulso em nível lógico baixo e como término um pulso em nível lógico alto, dessa forma pode-se sincronizar a transmissão. 

Figura 1: Forma de onda da transmissão serial RS232.

A leitura será feita em uma frequência de 9600 bits/s, tomando apenas uma amostra por pulso de dado. As saídas serão um dado de 8 bits, um sinal de indicação que o dado está pronto para a leitura, um sinal indicando a erro de overrun (Dado não lido sobrescrito) e um indicando o erro de transmissão. Quando houver um erro de overrun o programa continuará funcionando, sendo este sinal a forma de indicar ao dispositivo que está adquirindo os dados de que dado(s) foi/foram perdido(s). O erro de transmissão faz com que o programa pare de receber dados, pois quando ocorre um erro de transmissão o receptor perde a sincronia com o transmissor.

Descrição em VHDL

 

Nesse projeto serão usados 15 portas do CPLD, sendo 4 entradas e 11 saídas. As entradas são Rx, clock, resetn e leitura (sinal indicando que o dado de saída foi lido). As saídas serão: dado de 8 bits, erro de overrun, erro de transmissão e ready (sinal indicando que o dado está pronto para ser lido).

entity RECEBE_SERIAL is
port
(
RX, CLOCK, RESETn, LEITURA : std_logic;
READY, ERRO_OVERRUN, ERRO_SERIAL : out std_logic := '0';
SAIDA : out std_logic_vector(7 downto 0) := "00000000"
);
end entity;

Dentro da architecture será declarada a máquina de estados que indicará o estado do receptor, juntamente com o signal auxiliar para fazer a leitura do dado. Os estados serão: espera (onde o receptor está esperando o início de uma transmissão), recepção (onde estará recebendo os dados), entrega (onde atribuirá a saída o dado recebido) e erro (onde ficará quando ocorrer erro de transmissão).

signal DADO : std_logic_vector(9 downto 0):= "0000000001";
-- 10 bits por causa do stop bit e do start bit
type ESTADOS is ( ESPERA, RECEPCAO, ENTREGA, ERRO);
-- maquina de estado do modulo de recepção
signal SERIAL : ESTADOS := ESPERA;

O processo principal tem na sua lista de sensibilidade o clock, o reset e o rx (para identificar o start bit). Dentro do processo principal será utilizado o uma variável de contagem para fazer o preescaler e uma para indicar qual bit está sendo lido. A variável flag_ready funciona para indicar o valor de ready e ela se faz necessária devido a impossibilidade de ler valores de saída dentro do código.

variable CONTA : integer range 0 to 2500 := 0;
variable CONT : integer range 0 to 10 := 0;
variable FLAG_READY : std_logic := '0';

A primeira parte do processo descreve o funcionamento quando o botão de reset está pressionado.

-- Condições de reset
if (RESETn = '0') then
    DADO <= "0101010101";
    CONTA := 0;
    CONT := 0;
    ERRO_SERIAL <= '0';
    ERRO_OVERRUN <= '0';
    SERIAL <= ESPERA;

Em seguida é implementado a identificação do start bit.

    -- Identifica o envio de um start bit
elsif RX = '0' and SERIAL = ESPERA then
    SERIAL <= RECEPCAO;

Na rotina principal, primeiramente faz-se a verificação de leitura do dado de saída. Em seguida são declaradas as ações dependendo do estado. Quando está recebendo é necessário fazer o preescaler de 2500, pois a comunicação ocorre a 9600 bits/s, o clock do kit é 24MHz e só está se tomando uma amostra do dado, no centro do pulso. Cada vez que ocorre o estouro de contagem do preecaler o toma-se uma amostra do dado e armazena no signal dado e incrementa-se a variável cont, que indica qual bit está sendo lido. Depois de armazenar o décimo bit, faz-se o teste se o start bit e o stop bit estão corretos, caso estejam o programa segue para o estado entrega, caso não o programa vai para o estado erro. 

-- identifica se DADO na SAIDA foi lido
if LEITURA = '0' and SERIAL /= ERRO then
    FLAG_READY := '0';
    ERRO_OVERRUN <= '0';
end if;
 
-- Definições da máquina de ESTADOS
case SERIAL is
    when RECEPCAO =>
-- preescaler para a correta temporização da comunicação, 9600 Bits/s
        CONTA := CONTA + 1;
        if CONTA = 2500 then 
            DADO (CONT) <= RX;
            CONTA := 0;
            CONT := CONT + 1;
 
-- Final da transmissão e verificação de ERROs na transmissão
        elsif CONT = 10 and DADO(0) = '0' and DADO(9) = '1' then
            SERIAL <= ENTREGA;
            CONT := 0;
        elsif CONT = 10 then
            SERIAL <= ERRO;
        end if;
 

No estado entrega o programa atualiza o valor do dado de saída verifica se o valor antigo foi lido, se não ele acusa erro de overrun, e sinaliza que o dado está pronto para ser lido. Quando o programa esta no estado erro ele acusa o erro de comunicação e fica esperando o programa ser "resetado". Quando está no estado espera o programa atribui zero a variável responsável por indicar qual o bit esta sendo lido e 1250 ao valor inicial do preescaler, a variável conta, pois na primeira medida é preciso que se conte apenas metade do pulso. 

    when ENTREGA =>
        SAIDA <= DADO (8 downto 1); -- Seleciona apenas os DADOs validos
        if FLAG_READY = '1' then -- Verifica se o DADO antigo havia sido lido
            ERRO_OVERRUN <= '1';
        end if;
        FLAG_READY := '1'; -- Sinaliza a chegada do DADO
        SERIAL <= ESPERA;
    when ERRO => 
        ERRO_SERIAL <= '1';
    when others => 
    -- A primeira LEITURA precisa ser na metade de um periodo (centro do pulso)
        CONTA := 1250;
        CONT := 0;
end case;   

Por ultimo atualiza-se o valor de ready com o da flag ready.

READY <= FLAG_READY;

 

Figura 2: Resultado da Analise e Sintese.

Simulação

A simulação será baseada no envio de dados utilizando os princípios do protocolo RS232 e a verificação de que os dados foram lidos corretamente. Também serão emuladas as situações de erro. Primeiramente fazem-se as declarações dos signals, nesse exemplo serão usados os mesmos nomes utilizados no código fonte.

signal RX, RESETn, CLOCK, LEITURA : std_logic;
signal READY, ERRO_SERIAL, ERRO_OVERRUN : std_logic;
signal SAIDA : std_logic_vector(7 downto 0);
 
begin
 
UUT: entity work.recebe_serial
port map
(
    RX, CLOCK, RESETn, LEITURA,
    READY, ERRO_OVERRUN, ERRO_SERIAL,
    SAIDA
);

As primeiras instruções da simulação emulam o pressionamento do botão de reset e os pulsos de clock.

 GERA_CLOCK:
process
begin
-- simulação do pressionamento do botão de reset.
RESETn <= '0' after 0 ms,
'1' after 1  ms,
'0' after 50 ms;
 
CLOCK <= '0';
wait for 1 ms;
-- rotina de geração de CLOCK
while RESETn = '1' loop
CLOCK <= not CLOCK;
wait for 20833 ps;
end loop;
wait;
end process;

 

A segunda parte da simulação emula o envio dos dados hexadecimais 55, F0, 0F, 91 e FF, de forma a testar no envio dos dois últimos dados a sinalização de erro. Abaixo segue a programação para o envio do primeiro dado:

process
begin
RX <= '1';
LEITURA <= '0';
wait for 2ms;
-- Enviando 0x"55"
RX <='0';
wait for 104 us;
RX <='1';
wait for 104us; 
RX <='0';
wait for 104 us;
RX <='1';
wait for 104us;
RX <='0';
wait for 104 us;
RX <='1';
wait for 104us;
RX <='0';
wait for 104 us;
RX <='1';
wait for 104us;
RX <='0';
wait for 104 us;
RX <='1';
wait for 1ms;
LEITURA <= '1';
wait for 5 us;
LEITURA <= '0';
wait for 100 us;
                                                                                                       

As formas de ondas observadas na simulação foram:

 simulacao

 Figura 3: Formas de ondas obtidas na simulação.

Estrutura Física

 Teste

Figura 4: Circuito montado.

Para o funcionamento do projeto é apenas necessário o kit CPLD_7064, mas para teste foi utilizado um kit uCduíno (o programa utilizado está junto aos arquivos de projeto disponíveis no final da página) enviando um número (a cada requisição de envio o microcontrolador incrementa em 1 o número enviado) de forma serial, o CPLD_7064 receberá os dados e apresentará as saídas em duas placas de LEDs (uma apresentará os dados e a outra o sinais de erro) e uma placa de botões controlará os pulsos de reset e leitura. Os fios presente na montagem são responsáveis por: o marrom por interligar o terra das duas placas e o azul pela ligação entre Rx e Tx. O CPLD utlizado foi o EPM7064 da família MAX7000S

Montagem e Roteamento

As placas de LEDs serão colocadas nos conectores CON1 e CON2 e a placa de teclado será conectado no conector CON3, como mostrado nas ilutrações abaixo feitas no software fritizing.

Figura 5: Ligação do kit de LEDs na protoboard.

Figura 6: Conexão da placa de botões.

Utilizando o pino 16 como Rx, a distribuição de pinos do CPLD fica da seguinte forma:

pinagem-2

Figura 7: Atribuição de pinos do CPLD.

Gravação e Teste

A gravação do projeto segue os passos descritos no tutorial. Para testar o funcionamento do circuito utilizou-se um kit uCduíno enviando dados para o CPLD e o CPLD mostra os dados nos LEDs, como apresentado no vídeo no início da página.

Arquivos de Projeto

Quem está Online

Temos 21 visitantes e Nenhum membro online

Apoio

Login Form