Copyright (c) 2003 by Valery Sklyarov and Iouliia Skliarova: DETUA, IEETA, Aveiro University, Portugal
Exemplo 3. Projecto que demonstra como visualizar dados num LCD (liquid crystal display) que contém 2 linhas de 16 caracteres cada Pressione = = 11 Com este botão pode-se incrementar o dígito esquerdo Com este botão pode-se incrementar o dígito direito Pressione = = 11
Tipo do projecto Esquema do nível superior Ficheiro de restrições do utilizador Esquema do somador Módulo criado com Core Generator que converte códigos binários em BCD Construição da linha A+B=C Controlo de botões, interruptores e LEDs Controlador do LCD RAM do LCD Gerador de sinais de controlo para o LCD Nome do projecto
Slide seguinte
7 89
Endereço binário Valores hexadecimais 18 Escrever na tabela os valores 0,1,…,18
28 Clique duas vezes com o botão esquerdo do rato
49 50 Aparecerá uma nova fonte no projecto
LCD RAM
Carregue duas vezes no botão esquerdo do rato
top.sch inclui os 4 seguintes módulos funcionais: Esquema do somador Controlo de botões, interruptores e LEDs Controlador do LCD Construição da linha A+B=C
Esquema do somador Controlo de botões, interruptores e LEDs Controlador do LCD Construição da linha A+B=C
Pressione Ctrl-R para rodar 6 7 mover com o rato 5 ADSU4 e CD4CE são componentes da bibliotaca da Xilinx 8 mover com o rato
Somador/subtractor de 4 bits com os sinais de Carry-In, Carry-Out e Overflow process(A,ADD,B) begin if (ADD=1) then S <=A+B; else S <=A-B; end if; end process
Contador BCD de 4 bits com os sinais de clock enable e clear assíncrono process(C,CLR) begin if(CLR=1) then Q<=0000; elsif (Cevent and C=1) then if (CE=1) then if (Q=1001) then Q<=0000; elsif (Q=1011) then Q<=0110; elsif (Q=1101) then Q<=0100; elsif (Q=1111) then Q<=0010; else Q <= Q + 1; end if; end process; para corrigir erros process Q begin if (Q=1001) then TC<=1; else TC<=0; end if; end process; CEO <= TC and CE; TC-Terminal Count
Para adicionar símbolos de entrada/saída Para adicionar nomes Para adicionar taps Componente de biblioteca Componente de biblioteca Conversor BCD criado Componente de biblioteca Componente de biblioteca Para adicionar fios Opções de zoom
Para abrir o componente criado com Core generator Clique com o botão direito do rato
1 2 3 escrever Modificar aspecto gráfico do símbolo mover 4 5 Clicar o botão direito do rato 6 12
Pressionar o botão Esc write 12 Clicar com o botão esquerdo do rato Escrever bus Del bus4 Clicar com o botão esquerdo do rato 5 Clicar duas vezes com o botão esquerdo do rato Clicar com o botão esquerdo do rato Clicar com o botão esquerdo do rato Clicar duas vezes com o botão esquerdo do rato
Bloco lsdram criado com Core Generator Endereço da porta A Dados para a porta A write enable relógio Endereço da porta B Dados para a porta B
5 + 6 = 11 Linha composta por 3 carácteres: espaço, sinal + e espaço Linha com 3 carácteres
entity display is Port (clk48 : in std_logic; -- relógio 48 MHz rst : in std_logic; -- reset we : out std_logic; -- write enable da RAM wclk : out std_logic; -- relógio da RAM lcdout : out std_logic_vector(7 downto 0); -- dados para a RAM aout : out std_logic_vector(4 downto 0); -- endereço da RAM (porta A) sign : in std_logic; -- sinal da operação(+ ou -) digit1 : in std_logic_vector(3 downto 0); -- primeiro operando digit2 : in std_logic_vector(3 downto 0); -- segundo operando result : in std_logic_vector(4 downto 0) -- resultado ); end display;
architecture Behavioral of display is signal state : std_logic_vector(4 downto 0); signal line : string(1 to 3); -- linha para 3 caracteres: espaço, sinal, espaço constant line1: string(1 to 3) := " = "; -- linha para 3 caracteres: espaço, =, espaço begin process(clk48, rst) –- sequência dos estados begin if rst= '1' then state '0'); -- inicialização elsif rising_edge(clk48) then state <= state + 1; end if; end process; we <= '1'; -- write enable da RAM wclk <= not clk48; -- relógio da RAM
aout <= state; -- o estado corrente representa -- o endereço da porta A da RAM process(clk48, rst) –- escreve dados na porta A -- da RAM begin if sign = '1' then line <= " + "; -- põe na linha respectiva o sinal + elseline <= " - "; -- põe na linha respectiva -- o sinal " - " (não é utilizado neste exemplo) end if; if rst= '1' then null; -- a operação não é executada elsif rising_edge(clk48) then –- se o sinal de -- reset for inactivo, executa-se o código seguinte case state is –- escreve 10 caracteres na primeira linha do LCD: -- 1 para operando 1; 3 para + ; 1 para -- operando 2; 3 para = ; 2 para o resultado
when "11111"=> -- escreve o primeiro caracter lcdout <= "0011" & digit1;-- operando 1 when "00000"=> -- escreve o segundo caracter lcdout<=std_logic_vector(to_unsigned(character'pos(line(1)), 8)); when "00001"=> -- escreve o terceiro caracter lcdout<=std_logic_vector(to_unsigned(character'pos(line(2)), 8)); when "00010"=> -- escreve o quarto caracter lcdout<=std_logic_vector(to_unsigned(character'pos(line(3)), 8)); when "00011"=> -- escreve o quinto caracter lcdout <= "0011" & digit2; -- operando 2 when "00100"=> -- escreve o sexto caracter lcdout<=std_logic_vector(to_unsigned(character'pos(line1(1)), 8)); when "00101"=> -- escreve o sétimo caracter lcdout<=std_logic_vector(to_unsigned(character'pos(line1(2)), 8)); when "00110"=> -- escreve o oitavo caracter lcdout<=std_logic_vector(to_unsigned(character'pos(line1(3)), 8)); when "00111"=> -- escreve o nono caracter lcdout<=" " & result(4); -- resultado: 1º dígito when "01000"=> -- escreve o décimo caracter lcdout<="0011" & result(3 downto 0); -- resultado: 2º dígito when others => lcdout <= x"20"; é o código ASCII do espaço end case; end if; end process; end Behavioral;
O bloco l_b_s pode ser construído com base no bloco led_but_sw considerado no exemplo 2
-- as linhas que diferem do exemplo 2 estão em vermelho entity l_b_s is -- o código é semelhante ao do exemplo anterior Port (clk48: in std_logic-- relógio 48 MHz rst: in std_logic;-- reset externo buttons : out std_logic_vector(1 downto 0); -- valores dos botões para incrementar/decrementar os operandos cpld_rw: inout std_logic; -- CPLD read/write cpld_cs: out std_logic; -- CPLD chip select a: out std_logic_vector(2 downto 1); d: inoutstd_logic_vector(7 downto 0) ); -- a – endereço do registo do CPLD, d – dados de/para o CPLD end l_b_s; when "0001" =>cpld_cs <= '0'; when "0010" =>lpb <= d; buttons(1 downto 0) <= not d(1 downto 0); when "0011"=>cpld_cs <= '1'; when "0100"=>a <= "10";
Desenvolvido pela Trenz Electronic GmbH.
entradas saídas Dados da porta B da RAM Endereço da porta B da RAM (só serve para leitura) entrada do relógio entrada do reset Chip select Read/Write Dados para o LCD Endereço para o LCD
entity lcd is port ( clk48: in std_logic; -- relógio 48 MHz rst: in std_logic; -- reset ext_a: out std_logic_vector(2 downto 0); -- endereço do LCD ext_d: out std_logic_vector(7 downto 0); -- dados do LCD ext_rw: out std_logic; -- LCD read/write cs_lcd: out std_logic;-- chip select do LCD (activo a 1) csn_lcd: out std_logic;-- chip select do LCD (activo a 0) ram_adr: out std_logic_vector(4 downto 0); -- endereço da porta B da RAM ram_data: in std_logic_vector(7 downto 0) -- dados da porta B da RAM ); end lcd;
architecture bhv of lcd is signal clk: std_logic; -- relógio local signal div: unsigned (14 downto 0); -- para obter relógio local signal reset: std_logic; -- reset local signal cmd: std_logic_vector (7 downto 0);-- dados para o lcd signal rs: std_logic; -- selecção do registo para o lcd signal idx: integer range 0 to 3; -- índice para a sincronização do lcd signal cs: std_logic;-- chip select para o lcd signal cnt: unsigned (5 downto 0);-- contador de comandos begin process(clk48, rst)-- geração do relógio local begin if rst= '1' then div '0'); elsif rising_edge(clk48) then div<= div + 1; end if; end process; clk<= div(div'left);-- clk é o relógio local
process(clk, rst)-- sequência de índices (idx) begin if rst= '1' then idx <= 0; elsif rising_edge(clk) then if idx= 3 then idx<= 0; else idx<= idx + 1; end if; end if;-- idx obtém os valores: 0,1,2,3,0,1,2,3,0,1,2,3,0,etc. end process; process(clk, rst) begin if rst= '1' then cs <= '0'; ext_a '0'); ext_d '0'); elsif rising_edge(clk) then case idx is when 0=> ext_a <= "00" & rs; when 1=> cs <= '1'; ext_d<= cmd; -- escrever dados, activar o chip select when 2=> cs <= '0'; -- desactivar o chip select when 3=> null; -- data hold time end case;
end if; end process; ext_rw<= '0';-- escrever sempre cs_lcd <= cs;-- atribuir sinais externos csn_lcd<= '0';-- direcção de fluxo de dados: sempre para o LCD process(clk, rst)-- escrever dados da porta B da RAM para o LCD begin if rst= '1' then-- se o reset externo for activo cmd<= x"00"; -- código de controlo é (não -- há informação) rs<= '1'; reset<= '1';-- inicializar o LCD ram_adr<= "00000"; -- começar do endereço 0 da porta B da RAM cnt '0'); -- inicializar o contador de comandos elsif rising_edge(clk) then-- na transição ascendente do relógio local if (reset ='0') then-- se o sinal reset do LCD estiver inactivo if idx = 2 thencnt <= cnt + 1; -- incrementar o contador end if; case cnt is-- ler dados da porta B da RAM
-- visualização de dados (16 caracteres) na linha 0 do LCD (na linha superior) when "000000" => ram_adr <= "00000"; cmd <= x"02"; rs <= '0'; -- inicializar o cursor when "000001" => ram_adr <= "00000"; cmd <= ram_data; rs <= '1'; -- linha 0 posição 1 when "000010" => ram_adr <= "00001"; cmd <= ram_data; rs <= '1'; -- linha 0 posição 2 when "000011" => ram_adr <= "00010"; cmd <= ram_data; rs <= '1'; -- linha 0 posição 3 when "000100" => ram_adr <= "00011"; cmd <= ram_data; rs <= '1'; -- linha 0 posição 4 when "000101" => ram_adr <= "00100"; cmd <= ram_data; rs <= '1'; -- linha 0 posição 5 when "000110" => ram_adr <= "00101"; cmd <= ram_data; rs <= '1'; -- linha 0 posição 6 when "000111" => ram_adr <= "00110"; cmd <= ram_data; rs <= '1'; -- linha 0 posição 7 when "001000" => ram_adr <= "00111"; cmd <= ram_data; rs <= '1'; -- linha 0 posição 8 when "001001" => ram_adr <= "01000"; cmd <= ram_data; rs <= '1'; -- linha 0 posição 9 when "001010" => ram_adr <= "01001"; cmd <= ram_data; rs <= '1'; -- linha 0 posição 10 when "001011" => ram_adr <= "01010"; cmd <= ram_data; rs <= '1'; -- linha 0 posição 11 when "001100" => ram_adr <= "01011"; cmd <= ram_data; rs <= '1'; -- linha 0 posição 12 when "001101" => ram_adr <= "01100"; cmd <= ram_data; rs <= '1'; -- linha 0 posição 13 when "001110" => ram_adr <= "01101"; cmd <= ram_data; rs <= '1'; -- linha 0 posição 14 when "001111" => ram_adr <= "01110"; cmd <= ram_data; rs <= '1'; -- linha 0 posição 15 when "010000" => ram_adr <= "01111"; cmd <= ram_data; rs <= '1'; -- linha 0 posição visualização de dados (16 caracteres) na linha 1 do LCD (na linha inferior) when "010001" => ram_adr <= "00000"; cmd <= x"C0"; rs <= '0'; -- segunda linha when "010010" => ram_adr <= "10000"; cmd <= ram_data; rs <= '1'; -- linha 1 posição 1 when "010011" => ram_adr <= "10001"; cmd <= ram_data; rs <= '1'; -- linha 1 posição 2 when "010100" => ram_adr <= "10010"; cmd <= ram_data; rs <= '1'; -- linha 1 posição 3 when "010101" => ram_adr <= "10011"; cmd <= ram_data; rs <= '1'; -- linha 1 posição 4
when "010110" => ram_adr <= "10100"; cmd <= ram_data; rs <= '1'; -- linha 1 posição 5 when "010111" => ram_adr <= "10101"; cmd <= ram_data; rs <= '1'; -- linha 1 posição 6 when "011000" => ram_adr <= "10110"; cmd <= ram_data; rs <= '1'; -- linha 1 posição 7 when "011001" => ram_adr <= "10111"; cmd <= ram_data; rs <= '1'; -- linha 1 posição 8 when "011010" => ram_adr <= "11000"; cmd <= ram_data; rs <= '1'; -- linha 1 posição 9 when "011011" => ram_adr <= "11001"; cmd <= ram_data; rs <= '1'; -- linha 1 posição 10 when "011100" => ram_adr <= "11010"; cmd <= ram_data; rs <= '1'; -- linha 1 posição 11 when "011101" => ram_adr <= "11011"; cmd <= ram_data; rs <= '1'; -- linha 1 posição 12 when "011110" => ram_adr <= "11100"; cmd <= ram_data; rs <= '1'; -- linha 1 posição 13 when "011111" => ram_adr <= "11101"; cmd <= ram_data; rs <= '1'; -- linha 1 posição 14 when "100000" => ram_adr <= "11110"; cmd <= ram_data; rs <= '1'; -- linha 1 posição 15 when "100001" => ram_adr <= "11111"; cmd <= ram_data; rs <= '1'; -- linha 1 posição 16 when others => ram_adr <= "00000"; cmd <= x"02"; rs <= '0';cnt <= "000000"; end case; else -- se o sinal reset do LCD estiver activo if idx = 2 thencnt <= cnt + 1; end if; case cnt is when "000000" => cmd <= x"38"; rs <= '0';-- Function Set (8-bit, Dual Line) -- esperar (consulte a documentação do LCD para detalhes) when "100100" => cmd <= x"38"; rs <= '0';-- Function Set (8-bit, Dual Line) when "101000" => cmd <= x"38"; rs <= '0';-- Function Set (8-bit, Dual Line) when "101100" => cmd <= x"38"; rs <= '0';-- Function Set (8-bit, Dual Line)
when "110000" => cmd <= x"0c"; rs <= '0'; -- Display On/Off (display on, cursor off, cursor blink of when "110100" => cmd <= x"06"; rs <= '0'; -- Entry Mode Set (increment on, display shift off) when "111000" => cmd <= x"01"; rs <= '0'; -- Limpar o display when "111100" => cmd <= x"02"; rs <= '0'; -- Inicializar o cursor when "111111" => reset <= '0'; cnt <= "000000"; when others => null; end case; end if; end process; end bhv;
NET "clk48in" TNM_NET = "clk48in"; TIMESPEC "TS_clk48in"=PERIOD "clk48in" 48 MHz HIGH 50 %; NET "clk48in" LOC = "t9"; NET "init" LOC = "p15"; # botão RESET NET "ext_a " LOC = "H15"; # endereço para o LCD NET "ext_a " LOC = "F16"; NET "ext_a " LOC = "H13"; NET "csn_lcd" LOC = "G14"; # chip select do LCD NET "cs_lcd" LOC = "G13"; NET "ext_rw" LOC = "D16"; # LCD read/write NET "ext_d " LOC = "G12"; # dados para o LCD NET "ext_d " LOC = "F13"; NET "ext_d " LOC = "F12"; NET "ext_d " LOC = "E14"; NET "ext_d " LOC = "E13"; NET "ext_d " LOC = "D15"; NET "ext_d " LOC = "D14"; NET "ext_d " LOC = "C16";
NET "cpld_cs" LOC = "m16"; # chip select do CPLD NET "cpld_rw" LOC = "m15"; # CPLD read/write NET "d " LOC = "P16"; # dados para o CPLD NET "d " LOC = "L16"; NET "d " LOC = "L13"; NET "d " LOC = "J14"; NET "d " LOC = "G15"; NET "d " LOC = "f14"; NET "d " LOC = "e15"; NET "d " LOC = "b16"; NET "a " LOC = "t10"; # endereço do CPLD NET "a " LOC = "m10";