FPGA – Projeto de Relógio Digital com Sincronização via Porta Serial

O projeto utiliza o desenvolvedor AC703 da Xiaomei, implementando quatro contadores hierárquicos para gerenciar sgeundos, minutos, horas e dias. É necessário converter valores decimais para BCD para exibição e entre ASCII para comunicação serial. A protocolo de comunicação serial exige reconhecimento de caracteres específicos (":"), com formatação "HH:MM:SS".

Código do Módulo Principal

module clock_sistema(
   clock_entrada,
   reset_n,
   rx_pronto,
   dados_rx,
   saida_display,
   tx_serial
);
parameter TAMANHO_RX = 48;
parameter TAMANHO_TX = 72;
parameter TAMANHO_DISP = 32;

parameter DIVISOR_FREQ = 26;
parameter DIVISOR_CONTADOR = 50_000_000;
parameter SEGUNDOS_BITS = 6;
parameter MINUTOS_BITS = 6;
parameter HORAS_BITS = 5;
parameter BCD_BITS = 8;
parameter ASCII_BITS = 16;
parameter DECIMAL_BITS = 6;

input clock_entrada;
input reset_n;
input [TAMANHO_RX-1:0] dados_rx;
input rx_pronto;
output [TAMANHO_DISP-1:0] saida_display;
output tx_serial;

reg [TAMANHO_DISP-1:0] saida_display;
wire tx_serial;

reg [TAMANHO_TX-1:0] buffer_tx;
reg [DIVISOR_FREQ-1:0] contador_divisao;
wire sinal_contagem_divisao;
wire fim_contagem_divisao;

reg [SEGUNDOS_BITS-1:0] contador_segundos;
wire sinal_contagem_segundos;
wire fim_contagem_segundos;

reg [MINUTOS_BITS-1:0] contador_minutos;
wire sinal_contagem_minutos;
wire fim_contagem_minutos;

reg [HORAS_BITS-1:0] contador_horas;
wire sinal_contagem_horas;
wire fim_contagem_horas;

wire [BCD_BITS-1:0] bcd_segundos;
wire [BCD_BITS-1:0] bcd_minutos;
wire [BCD_BITS-1:0] bcd_horas;
wire [ASCII_BITS-1:0] ascii_segundos;
wire [ASCII_BITS-1:0] ascii_minutos;
wire [ASCII_BITS-1:0] ascii_horas;
wire [DECIMAL_BITS-1:0] decimal_segundos;
wire [DECIMAL_BITS-1:0] decimal_minutos;
wire [DECIMAL_BITS-1:0] decimal_horas;

reg sinal_configuracao;

always @(posedge clock_entrada or negedge reset_n) begin
   if(!reset_n)
      contador_divisao <= 0;
   else if(sinal_contagem_divisao) begin
      if(fim_contagem_divisao)
         contador_divisao <= 0;
      else
         contador_divisao <= contador_divisao + 1;
   end
end
assign sinal_contagem_divisao = 1;
assign fim_contagem_divisao = sinal_contagem_divisao && (contador_divisao == DIVISOR_CONTADOR - 1 || sinal_configuracao);

// Lógica de contagem para segundos
always @(posedge clock_entrada or negedge reset_n) begin
   if(!reset_n) begin
      contador_segundos <= 0;
   end
   else if(sinal_contagem_segundos) begin
      if(fim_contagem_segundos)
         contador_segundos <= 0;
      else
         contador_segundos <= contador_segundos + 1;
   end
   else if(sinal_configuracao)
      contador_segundos <= decimal_segundos;
end
assign sinal_contagem_segundos = fim_contagem_divisao && !sinal_configuracao;
assign fim_contagem_segundos = sinal_contagem_segundos && (contador_segundos == 60 - 1);

// Lógica de contagem para minutos
always @(posedge clock_entrada or negedge reset_n) begin
   if(!reset_n) begin
      contador_minutos <= 0;
   end
   else if(sinal_contagem_minutos) begin
      if(fim_contagem_minutos)
         contador_minutos <= 0;
      else
         contador_minutos <= contador_minutos + 1;
   end
   else if(sinal_configuracao)
      contador_minutos <= decimal_minutos;
end
assign sinal_contagem_minutos = fim_contagem_segundos && !sinal_configuracao;
assign fim_contagem_minutos = sinal_contagem_minutos && (contador_minutos == 60 - 1);

// Lógica de contagem para horas
always @(posedge clock_entrada or negedge reset_n) begin
   if(!reset_n) begin
      contador_horas <= 0;
   end
   else if(sinal_contagem_horas) begin
      if(fim_contagem_horas)
         contador_horas <= 0;
      else
         contador_horas <= contador_horas + 1;
   end
   else if(sinal_configuracao)
      contador_horas <= decimal_horas;
end
assign sinal_contagem_horas = fim_contagem_minutos && !sinal_configuracao;
assign fim_contagem_horas = sinal_contagem_horas && (contador_horas == 24 - 1);

always @(posedge clock_entrada or negedge reset_n) begin
   if(!reset_n)
      saida_display <= 0;
   else
      saida_display <= {bcd_horas, 4'hF, bcd_minutos, 4'hF, bcd_segundos};
end

always @(posedge clock_entrada or negedge reset_n) begin
   if(!reset_n)
      buffer_tx <= 0;
   else
      buffer_tx <= {ascii_horas, 8'h3A, ascii_minutos, 8'h3A, ascii_segundos, 8'h0A};
end

always @(posedge clock_entrada or negedge reset_n) begin
   if(!reset_n)
      sinal_configuracao <= 0;
   else if(rx_pronto)
      sinal_configuracao <= 1;
   else
      sinal_configuracao <= 0;
end

uart_transmissor uart_transmissor_inst(
   .clock(clock_entrada),
   .reset_n(reset_n),
   .dados(buffer_tx),
   .ativar_transmissao(contador_divisao == 2 && sinal_contagem_divisao),
   .saida_tx(tx_serial)
);

conversor_decimal_bcd conversor_segundos(
   .clock(clock_entrada),
   .reset_n(reset_n),
   .valor_decimal(contador_segundos),
   .saida_bcd(bcd_segundos)
);

conversor_decimal_bcd conversor_minutos(
   .clock(clock_entrada),
   .reset_n(reset_n),
   .valor_decimal(contador_minutos),
   .saida_bcd(bcd_minutos)
);

conversor_decimal_bcd conversor_horas(
   .clock(clock_entrada),
   .reset_n(reset_n),
   .valor_decimal(contador_horas),
   .saida_bcd(bcd_horas)
);

conversor_decimal_ascii conversor_ascii_segundos(
   .clock(clock_entrada),
   .reset_n(reset_n),
   .valor_decimal(contador_segundos),
   .saida_ascii(ascii_segundos)
);

conversor_decimal_ascii conversor_ascii_minutos(
   .clock(clock_entrada),
   .reset_n(reset_n),
   .valor_decimal(contador_minutos),
   .saida_ascii(ascii_minutos)
);

conversor_decimal_ascii conversor_ascii_horas(
   .clock(clock_entrada),
   .reset_n(reset_n),
   .valor_decimal(contador_horas),
   .saida_ascii(ascii_horas)
);

conversor_ascii_decimal conversor_decimal_segundos(
   .clock(clock_entrada),
   .reset_n(reset_n),
   .entrada_ascii(dados_rx[15:0]),
   .saida_decimal(decimal_segundos)
);

conversor_ascii_decimal conversor_decimal_minutos(
   .clock(clock_entrada),
   .reset_n(reset_n),
   .entrada_ascii(dados_rx[31:16]),
   .saida_decimal(decimal_minutos)
);

conversor_ascii_decimal conversor_decimal_horas(
   .clock(clock_entrada),
   .reset_n(reset_n),
   .entrada_ascii(dados_rx[47:32]),
   .saida_decimal(decimal_horas)
);

endmodule

Módulo Top-Level

module clock_top_level(
   clock_entrada,
   reset_n,
   rx_serial,
   saida_cp,
   saida_st,
   saida_ds,
   tx_serial
);

input clock_entrada;
input reset_n;
input rx_serial;

output saida_cp;
output saida_st;
output saida_ds;
output tx_serial;

wire saida_cp;
wire saida_st;
wire saida_ds;

wire [31:0] dados_display;
wire enable_sinal;
wire [15:0] dados_saida;
wire [7:0] selecao;
wire [7:0] segmentos;
wire tx_serial;

wire [47:0] dados_relogio;
wire rx_pronto;

clock_sistema clock_inst(
   .clock_entrada(clock_entrada),
   .reset_n(reset_n),
   .rx_pronto(rx_pronto),
   .dados_rx(dados_relogio),
   .saida_display(dados_display),
   .tx_serial(tx_serial)
);

receptor_uart receptor_inst(
   .reset_n(reset_n),
   .clock(clock_entrada),
   .rx_serial(rx_serial),
   .rx_pronto(rx_pronto),
   .dados_recebidos(dados_relogio)
);

driver_hc595 driver_inst(
   .clock(clock_entrada),
   .reset_n(reset_n),
   .enable(enable_sinal),
   .dados(dados_saida),
   .cp_saida(saida_cp),
   .st_saida(saida_st),
   .ds_saida(saida_ds)
);

conversor_hex conversor_inst(
   .clock(clock_entrada),
   .reset_n(reset_n),
   .dados_exibicao(dados_display),
   .selecao(selecao),
   .segmentos(segmentos),
   .enable(enable_sinal)
);

assign dados_saida = {segmentos, selecao};

endmodule

Tags: FPGA Verilog UART BCD ASCII

Publicado em 10-12 00:03