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