vhdl - DE0 Nano LED 连续亮灭
问题描述
请理解我的代码技能非常低。我正在努力学习变得更好。
使用 DE0 Nano 板,我正在尝试编写 VHDL 来模拟板上所有可用的 LED(其中 8 个)
我将它们标记为 LED0 ~ LED7。使用 50 MHZ 和 1/2 秒计数器,我想按顺序操作各个 LED。
例如,如果这些单独的位代表 LED 的开和关。1|0|0|0|0|0|0|0 -> 0|1|0|0|0|0|0|0 -> 0|0|1|0|0|0|0|0 和很快。最后,计数器将重置为 0 以再次重复该序列。
请在下面查看我的代码以及这些问题/问题。
1)我在第 8 个 LED 后暂停了 1/2 秒。为什么?我该如何解决?
2)即使我将变量计数器设置为 8,它也会重复为 16,因此我必须将计数器重置为 0。(在代码中标记为问题 2)
3)有没有更好的方法来编写这些代码?这完全是一团糟。您能否就我可以用来缩短此代码的任何其他功能或方法提供提示?
如果有任何问题,请告诉我!
非常感谢您的帮助。
entity ledtest is
port(
clk_50mhz : in std_logic ;
reset_btn : in std_logic;
green_led : out std_logic_vector(7 downto 0)
);
end entity;
architecture behave of ledtest is
signal clk_1hz : std_logic ;
signal scaler : integer range 0 to 25000000 ;
signal counter : integer range 0 to 8;
signal LED : std_logic_vector(7 downto 0);
begin
clk_1hz_process : process( clk_50mhz , reset_btn )
begin
if (reset_btn = '0') then
clk_1hz <= '0';
scaler <= 0;
counter <= 0;
elsif(rising_edge(clk_50mhz)) then
if (scaler < 25000000) then
scaler <= scaler + 1 ;
clk_1hz <= '0';
else
scaler <= 0;
clk_1hz <= '1';
counter <= counter + 1;
if (counter >= 8) then --------question 2
counter <= 0;
end if;
end if;
end if;
end process clk_1hz_process;
blinking_process : process (clk_1hz,reset_btn)
begin
if (reset_btn = '0') then
LED(0) <= '0';
elsif rising_edge(clk_1hz) AND counter = 1 then
LED(0) <= not LED(0) ;
LED(7) <= '0' ;
elsif rising_edge(clk_1hz) AND counter = 2 then
LED(1) <= not LED(1) ;
LED(0) <= not LED(0) ;
elsif rising_edge(clk_1hz) AND counter = 3 then
LED(2) <= not LED(2) ;
LED(1) <= not LED(1) ;
elsif rising_edge(clk_1hz) AND counter = 4 then
LED(3) <= not LED(3) ;
LED(2) <= not LED(2) ;
elsif rising_edge(clk_1hz) AND counter = 5 then
LED(4) <= not LED(4) ;
LED(3) <= not LED(3) ;
elsif rising_edge(clk_1hz) AND counter = 6 then
LED(5) <= not LED(5) ;
LED(4) <= not LED(4) ;
elsif rising_edge(clk_1hz) AND counter = 7 then
LED(6) <= not LED(6) ;
LED(5) <= not LED(5) ;
elsif rising_edge(clk_1hz) AND counter = 8 then
LED(7) <= not LED(7) ;
LED(6) <= not LED(6) ;
end if;
end process blinking_process;
green_led(0) <= LED(0);
green_led(1) <= LED(1);
green_led(2) <= LED(2);
green_led(3) <= LED(3);
green_led(4) <= LED(4);
green_led(5) <= LED(5);
green_led(6) <= LED(6);
green_led(7) <= LED(7);
end behave;
解决方案
如果您的读者真的眯着眼睛,他们可以将原始帖子视为一个问题和两个问题。(问题是单数。)
请在下面查看我的代码以及这些问题/问题。
1)我在第 8 个 LED 后暂停了 1/2 秒。为什么?我该如何解决?
有 9 个计数器值(0 到 8),只有 8 个 LED(7 到 0)。在将 counter 分配为 0 和再次递增 1 之间的半秒内没有分配发生。
2)即使我将变量计数器设置为 8,它也会重复为 16,因此我必须将计数器重置为 0。(在代码中标记为问题 2)
这个问题与 1) 有关。评估计数器大于或等于 8 的要求是由将计数器分配给 8 引起的,同样有 9 个值并且只有 8 个 LED。请注意,这是同步加载到 0 而不是异步复位。
3)有没有更好的方法来编写这些代码?这完全是一团糟。您能否就我可以用来缩短此代码的任何其他功能或方法提供提示?
因为您试图直接进入 FPGA 而不是模拟,所以重点应该与问题 1) 以及如何解决它有关。还有一些综合问题,这里通过在 if 语句elsif
替代条件中添加使能来控制时钟。还有设计规范复杂性和与代码行数相关的调试工作量的问题。
首先,所有 LED 元件都有触发器和计数器。我们可以通过使用环形计数器(不要与 Johnson 计数器混淆)将每个 LED 元件的触发器数量减少到一个。
(std_logic_vector) 的分配green_led
可以来自 LED (std_logic_vector),而不是逐个元素。赋值两侧的元素索引之间存在一对一的对应关系。
此外,为了允许模拟,您可以虚拟化加载到scalar
. 这具有更少的时钟代表半秒的效果。这个想法是模拟不必每秒进行 1 亿次时钟转换(上升沿和下降沿)的 10 多秒。
将所有这些放在一起,代码将更改为:
library ieee;
use ieee.std_logic_1164.all;
entity ledtest is
generic (half_second: integer := 24999999); -- zero identity
-- the generic allows fewer clocks per second for simulation
port (
clk_50mhz: in std_logic;
reset_btn: in std_logic;
green_led: out std_logic_vector(7 downto 0)
);
end entity;
architecture behave of ledtest is
signal clk_1hz: std_logic;
signal scaler: integer range 0 to half_second;
-- signal counter: integer range 0 to 8; -- DELETED
signal ring_counter: std_logic_vector (7 downto 0); -- ADDED
signal LED: std_logic_vector (7 downto 0);
signal LED0I: std_logic; -- ADDED
begin
LED0I <= '1' when LED = "00000000" else
'0';
clk_1hz_process:
process (clk_50mhz, reset_btn)
begin
if reset_btn = '0' then
clk_1hz <= '0';
scaler <= 0;
-- counter <= 0;
elsif rising_edge(clk_50mhz) then
if scaler /= half_second then
scaler <= scaler + 1;
clk_1hz <= '0';
else
scaler <= 0;
clk_1hz <= '1';
-- counter <= counter + 1;
-- if counter >= 8 then --------question 2
-- counter <= 0;
-- end if;
end if;
end if;
end process clk_1hz_process;
blinking_process:
process (clk_1hz, reset_btn)
begin
if reset_btn = '0' then
LED <= (others => '0');
-- LED(0) <= '0';
elsif rising_edge(clk_1hz) then
LED <= LED(6 downto 0) & (LED(7) or LED0I);
-- ring counter with a roulette ball lauch after reset
-- elsif rising_edge(clk_1hz) AND counter = 1 then
-- LED(0) <= not LED(0);
-- LED(7) <= '0';
-- elsif rising_edge(clk_1hz) AND counter = 2 then
-- LED(1) <= not LED(1);
-- LED(0) <= not LED(0);
-- elsif rising_edge(clk_1hz) AND counter = 3 then
-- LED(2) <= not LED(2);
-- LED(1) <= not LED(1);
-- elsif rising_edge(clk_1hz) AND counter = 4 then
-- LED(3) <= not LED(3);
-- LED(2) <= not LED(2);
-- elsif rising_edge(clk_1hz) AND counter = 5 then
-- LED(4) <= not LED(4);
-- LED(3) <= not LED(3);
-- elsif rising_edge(clk_1hz) AND counter = 6 then
-- LED(5) <= not LED(5);
-- LED(4) <= not LED(4);
-- elsif rising_edge(clk_1hz) AND counter = 7 then
-- LED(6) <= not LED(6);
-- LED(5) <= not LED(5);
-- elsif rising_edge(clk_1hz) AND counter = 8 then
-- LED(7) <= not LED(7);
-- LED(6) <= not LED(6);
end if;
end process blinking_process;
green_led <= led;
-- green_led(0) <= LED(0);
-- green_led(1) <= LED(1);
-- green_led(2) <= LED(2);
-- green_led(3) <= LED(3);
-- green_led(4) <= LED(4);
-- green_led(5) <= LED(5);
-- green_led(6) <= LED(6);
-- green_led(7) <= LED(7);
end architecture behave;
(另请注意,默认的通用值标量已重置并加载到已递减以包括单位 0 在 250,000,000 个时钟为半秒。相等性测试half_second
比使用幅度比较更简单。)
使用环形计数器降低了复杂性,并绕过了计数器范围为 9 的问题。
环形计数器增加了一个繁荣,复位值全是'0',由LED0I
用于在复位后启动环形计数器的信号检测。它可以防止所有 LED 在复位期间点亮。
您可以使用时钟数为半秒到小得多的测试台,从而允许使用小型波形转储文件进行快速仿真:
library ieee;
use ieee.std_logic_1164.all;
entity ledtest_tb is
end entity;
architecture foo of ledtest_tb is
signal clk: std_logic := '0';
signal reset_btn: std_logic := '1';
signal green_led: std_logic_vector (7 downto 0);
begin
DUT:
entity work.ledtest
generic map (half_second => 7)
port map (
clk_50mhz => clk,
reset_btn => reset_btn,
green_led => green_led
);
CLOCK:
process
begin
wait for 0.5 sec / 7;
clk <= not clk;
if now > 19 sec then
wait;
end if;
end process;
STIMULUS:
process
begin
wait for 0.5 sec;
reset_btn <= '0';
wait for 0.5 sec;
reset_btn <= '1';
wait;
end process;
end architecture;
这给出了:
您可以消除 ledtest 的测试台实例化中的通用映射,以演示使用 50 MHz 时钟模拟每个时钟转换所固有的仿真时间和转储文件大小的差异。这里的想法是对模拟进行故障排除比从你所看到的(这里是 LED)中猜测更容易。因为简化了代码描述,所以需要使用原始代码作为起点进行调试。它确实依赖于数字电子和 VHDL 的知识。
使用 ghdl 和 gtkwave 进行模拟。
推荐阅读
- javascript - 从 nodeJs 上的字体标签中提取文本
- javascript - 滑块值添加到日期
- python - 使用 Pyglet 在 on_mouse_press 上插入文本
- javascript - 在线或外部的 CSS 更好
- java - Java在数字末尾添加“0”
- python - 什么是 pandas dataframe.ne 方法以及为什么使用它?
- python - Python 中内部 hash() 函数的复杂性
- r - 使用自动绘图在多变量生存分析中绘制单图
- gcc - STM32 系列中链接脚本部分的 ALIGN(n) 差异
- python - 如何在 csv 文件上运行 FOR LOOP