VHDL-код для однооктавного цифрового фортепиано

Для генерации разных частот. Сигнал, я использовал 3 разных способа. Один для Do(440 Гц) и Re(494 Гц), с использованием внешних часов 8 МГц. Другой путь для Меня (523 Гц) и Фа (587), просто задерживая, как требуется. Другой способ - для So(659 Гц) La(698 Гц) и Ti(784 Гц), используя требуемую задержку вместе с циклом for. Цикл for используется для генерации сигнала в течение 1 секунды, так как сигнал равен "1". Тем не менее, использование внешних часов работает хорошо, но сталкивается с проблемой двумя другими способами. Может кто-нибудь, пожалуйста, помогите мне в этом. Какой из трех использованных способов лучше..??? Есть ли другой способ сделать то же самое...??? Заранее спасибо.

----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity piano is
    Port ( do : in  STD_LOGIC;
           re : in  STD_LOGIC;
           me : in  STD_LOGIC;
           fa : in  STD_LOGIC;
           so : in  STD_LOGIC;
           la : in  STD_LOGIC;
           ti : in  STD_LOGIC;
           clk_8mhz : in  STD_LOGIC; --using the exterrnal clock of 8mhz.
           spek : out  STD_LOGIC);   --o/p connected to the speaker.
end piano;

architecture pbev of piano is
 signal Counter440: integer:= 0;
 signal Counter494: integer:= 0;
 signal temp: integer:= 0;
 signal clk_440hz: std_logic:= '0';
 signal clk_494hz: std_logic:= '0';
begin
 Prescaler440 : process(clk_8mhz) --process to convert 8mhz freq to 440hz.
 begin
        if rising_edge(clk_8mhz) then
            if Counter440 < 18180 then --8mhz/18181 = 440hz
                Counter440 <= Counter440 + 1;
            else
                clk_440hz <= not clk_440hz;
                Counter440 <= 0;
            end if;
        end if;
 end process Prescaler440; --gives o/p clk_440 as sq. wave of 440hz freq.

 Prescaler494 : process(clk_8mhz) --process to convert 8mhz freq to 494hz.
 begin
        if rising_edge(clk_8mhz) then
            if Counter494 < 16192 then --8mhz/16193 = 494hz
                Counter494 <= Counter494 + 1;
            else
                clk_494hz <= not clk_494hz;
                Counter494 <= 0;
            end if;
        end if;
 end process Prescaler494; --gives o/p clk_494 as sq. wave of 494hz freq.

pianoproc : process(do,re,me,fa,so,la,ti,clk_8mhz)
begin

if (do = '1') then
 spek <= clk_440hz; -- speaker gets i/p wave of 440hz.

elsif (re = '1') then
 spek <= clk_494hz; -- speaker gets i/p wave of 494hz.

elsif (me = '1') then
 spek <= '1'
 after 956023 ns; --1/(523 hz) = 1912045ns // (1912045/2) = 956023ns.
 spek <= '0'
 after 956023 ns;

elsif (fa = '1') then --1/(587 hz) = 1703577ns // (1703577/2) = 851789ns.
 spek <= '1'
 after 851789 ns;
 spek <= '0'
 after 851789 ns;

elsif (so <= '1') then
for temp in 0 to 659 loop --loop continues to generate sq. wave of 659hz for 659*(758725*2) ns = 1sec
   spek <= '1'
  after 758725 ns; --1/(659 hz) = 1517450ns // (1517450/2) = 758725ns
  spek <= '0'
  after 758725 ns;
end loop;


elsif (la <= '1') then
for temp in 0 to 698 loop --loop continues to generate sq. wave of 698hz for 698*(758725*2) ns = 1sec
 spek <= '1'
 after 716332 ns; --1/(698 hz) = 1432664ns // (1432664/2) = 716332ns
 spek <= '0'
 after 716332 ns;
end loop;

elsif (ti <= '1') then
for temp in 0 to 784 loop --loop continues to generate sq. wave of 784hz for 784*(637755*2) ns = 1sec
 spek <= '1'
 after 637755 ns; --1/(784 hz) = 1275510ns // (1275510/2) = 637755ns
 spek <= '0'
 after 637755 ns;
end loop;

else spek <= '0';

end if;
end process pianoproc;
end pbev;

1 ответ

Решение

Код

for temp in 0 to 659 loop 
  spek <= '1' after 758725 ns; --1/(659 hz) = 1517450ns // (1517450/2) = 758725ns
  spek <= '0' after 758725 ns;
end loop;

Графики 2 * 659 переходов на "спек", все происходящие 758 мс после ввода цикла. Последний переход побеждает, который устанавливает spek в '0'.

for temp in 0 to 659 loop 
   spek <= '1' after 758725 ns, '0' after 1517450 ns;
   wait for 1517450ns;
end loop;

Вероятно, ближе к тому, что вы хотите.

Однако для синтеза, как говорят другие комментарии, код для "do" или "re" работает (и синтезирует!).

Еще один момент, о котором стоит задуматься: проще позволить компилятору самому генерировать все смешные константы - тогда, если вы измените такой параметр, как тактовая частота, вам не нужно тратить час на калькулятор...

clk_freq   : natural := 8000000;
clk_period : time := 1 sec / clk_freq;

или для сим-версии,

procedure note (freq : natural; duration : time) is
-- not synthesisable!
begin
   for temp in 1 to freq * duration / 1 sec loop 
      spek <= '1' after 1 sec / freq / 2, '0' after 1 sec / freq;
      wait for 1 sec / freq;
   end loop;
end note;

...
if (la <= '1') then
   note(698, 1 sec);
elsif
Другие вопросы по тегам