VHDL 中的 BCD 定时器
BCD Timer in VHDL
不久前出于好奇刚开始接触VHDL。
所以我尝试在 spartan 3 开发板上编写 BCD 定时器并且
不知何故我无法找出为什么它一直显示 'unexpected with' 错误。
所以如果我想拥有如图link所示的功能,
我该如何修改代码?任何帮助将不胜感激。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity w3 is
Port ( clk : in STD_LOGIC;
rst : in STD_LOGIC;
stp : in STD_LOGIC;
an : out STD_LOGIC_VECTOR (3 downto 0);
c : out STD_LOGIC_VECTOR (6 downto 0));
end w3;
architecture timer of w3 is
signal div1 : integer range 0 to 499999 :=0; -- 100Hz
signal ck100hz : std_logic; -- 100Hz output
signal div2 : integer range 0 to 249999 :=0; -- 200Hz
signal ck200hz : std_logic; -- 200Hz output
signal div3 : integer range 0 to 124999 :=0; -- 400Hz
signal ck400hz : std_logic; -- 400Hz output
signal index : integer range 0 to 9 :=0;
signal scan : std_logic_vector (3 downto 0);
signal S : std_logic;
signal disp : std_logic_vector (3 downto 0);
begin
process begin
wait until rising_edge(clk);
if div1 < 499999 then
ck100hz <= '0';
div1 <= div1+1;
else
ck100hz <= '1';
div1 <= 0;
end if;
if div2 < 249999 then
ck200hz <= '0';
div2 <= div2+1;
else
ck200hz <= '1';
div2 <= 0;
end if;
if div3 < 124999 then
ck400hz <= '0';
div3 <= div3+1;
else
ck400hz <= '1';
div3 <= 0;
end if;
end process;
process begin
wait until rising_edge(clk);
if rst = '1' then
index <= 0;
end if;
if stp = '1' then
index <= index;
end if;
if ck100hz = '1' then
if index < 3 then index <= index+1;
else index <= 0;
if index < 4 and index > 7 then index <= index+1;
else index <= 0;
if index < 8 and index > 11 then index <= index+1;
else index <= 0;
if index < 12 and index > 15 then index <= index+1;
else index <= 0;
end if;
end if;
end if;
end if;
end if;
end process;
process begin
wait until rising_edge(clk);
if ck400hz = '1' then
With scan select -- error unexpected With
an <= an(0) when "00",
an(1) when "01",
an(2) when "10",
an(3) when others;
end if;
end process;
process begin
wait until rising_edge(clk);
if ck200hz = '1' then
With S select -- error unexpected With
disp <= index integer range 0 to 3 when "00",
index integer range 4 to 7 when "01",
index integer range 8 to 11 when "10",
index integer range 12 to 15 when others;
end if;
end process;
with index select
C <= "1000000" when 0,
"1111001" when 1,
"0100100" when 2,
"0110000" when 3,
"0011001" when 4,
"0010010" when 5,
"0000010" when 6,
"1111000" when 7,
"0000000" when 8,
"0011000" when 9;
end timer;
对于low-active:
在 index = 0
的情况下,您应该将 0111111
分配给 C
。您必须启用几乎所有细分市场。现在您的内部计算将是 high-active。由于 PCB 布局,显示器本身是 low-active,因此在将其分配给 Cathode_n
端口之前,您应该反转整个 C
向量:Cathode_n <= not C;
注意,我使用 _n
指定此端口的 low-active 行为。
旧代码:
with index select
C <= "1000000" when 0,
"1111001" when 1,
-- ...
"0011000" when 9;
这应该是编写纯 high-active 代码时的目标:
with index select
C <= "0111111" when 0,
"0000110" when 1,
-- ...
"1100111" when 9;
Cathode_n <= not C;
High-active 表示:如果位为高 (1
),则事物处于活动状态。在您的情况下,一个 7 段显示器的 LED 被激活。根据 PCB 设计,您必须拉低 (0
) 才能激活灯。这是 low-active,因为低值会激活某些东西。
select语句需要指定1
应该点亮的位置,而不是要关闭的位置。更多 low-active 信号应该在代码中标记以表示不同的行为。只有 top-level 组件应将 high-active 信号转换为 low-active 信号,反之亦然。这确保了您设计的内部部分是纯粹的 high-active.
为否 driver:
S
和 scan
没有分配。两个信号分别是 'U'
或 "UUUU"
。
编辑:
每个信号分配都会在信号上创建一个 driver。目前,您的代码从未为 S
或 scan
分配任何值。因此 S
和 scan
的初始值成为信号的驱动值。您应该 运行 模拟并在波形中看到很多 U
s。
综合工具可能会报告:信号 S
已读取,但从未分配。
使用elsif
:
我重新格式化你太可怕了if-then-else构造:
if ck100hz = '1' then
if index < 3 then
index <= index+1;
else
index <= 0;
if index < 4 and index > 7 then
index <= index+1;
else
index <= 0;
if index < 8 and index > 11 then
index <= index+1;
else
index <= 0;
if index < 12 and index > 15 then
index <= index+1;
else
index <= 0;
end if;
end if;
end if;
end if;
end if;
现在我们看到,你的代码不能使用elsif,因为你在下一个[=81]之前的else分支中有赋值=]if 语句。另一方面,index <= 0;
分配是多余的,可以删除:
if ck100hz = '1' then
if index < 3 then
index <= index+1;
else
if index < 4 and index > 7 then
index <= index+1;
else
if index < 8 and index > 11 then
index <= index+1;
else
if index < 12 and index > 15 then
index <= index+1;
else
index <= 0;
end if;
end if;
end if;
end if;
end if;
现在我们可以将其转换为使用 elsif 分支:
if ck100hz = '1' then
if index < 3 then
index <= index + 1;
elsif index < 4 and index > 7 then
index <= index + 1;
elsif index < 8 and index > 11 then
index <= index + 1;
elsif index < 12 and index > 15 then
index <= index+1;
else
index <= 0;
end if;
end if;
更具可读性,对吧?
接下来,让我们检查您在该语句中的表达式:
elsif index < 4 and index > 7 then
index
不能同时小于4和大于7。因此,让我们进行综合并优化掉无法到达的分支:
if ck100hz = '1' then
if index < 3 then
index <= index + 1;
else
index <= 0;
end if;
end if;
好的,代码中的其他问题:
if rst = '1' then
index <= 0;
end if;
if stp = '1' then
index <= index;
end if;
if ck100hz = '1' then
-- ...
end if;
重置应始终具有最高优先级。在你的情况下,例如stp
具有更高的优先级。在好的情况下,您只是在浪费 FPGA 资源,在坏的情况下,综合无法将您的代码转换为 FPGA 中的原语。例如。 flip-flops 具有匹配的重置行为。
正确的实现:
if rst = '1' then
index <= 0;
elsif stp = '1' then
index <= index;
elsif ck100hz = '1' then
-- ...
end if;
我想现在,您有足够的输入来修复您的代码。
不久前出于好奇刚开始接触VHDL。
所以我尝试在 spartan 3 开发板上编写 BCD 定时器并且
不知何故我无法找出为什么它一直显示 'unexpected with' 错误。
所以如果我想拥有如图link所示的功能, 我该如何修改代码?任何帮助将不胜感激。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity w3 is
Port ( clk : in STD_LOGIC;
rst : in STD_LOGIC;
stp : in STD_LOGIC;
an : out STD_LOGIC_VECTOR (3 downto 0);
c : out STD_LOGIC_VECTOR (6 downto 0));
end w3;
architecture timer of w3 is
signal div1 : integer range 0 to 499999 :=0; -- 100Hz
signal ck100hz : std_logic; -- 100Hz output
signal div2 : integer range 0 to 249999 :=0; -- 200Hz
signal ck200hz : std_logic; -- 200Hz output
signal div3 : integer range 0 to 124999 :=0; -- 400Hz
signal ck400hz : std_logic; -- 400Hz output
signal index : integer range 0 to 9 :=0;
signal scan : std_logic_vector (3 downto 0);
signal S : std_logic;
signal disp : std_logic_vector (3 downto 0);
begin
process begin
wait until rising_edge(clk);
if div1 < 499999 then
ck100hz <= '0';
div1 <= div1+1;
else
ck100hz <= '1';
div1 <= 0;
end if;
if div2 < 249999 then
ck200hz <= '0';
div2 <= div2+1;
else
ck200hz <= '1';
div2 <= 0;
end if;
if div3 < 124999 then
ck400hz <= '0';
div3 <= div3+1;
else
ck400hz <= '1';
div3 <= 0;
end if;
end process;
process begin
wait until rising_edge(clk);
if rst = '1' then
index <= 0;
end if;
if stp = '1' then
index <= index;
end if;
if ck100hz = '1' then
if index < 3 then index <= index+1;
else index <= 0;
if index < 4 and index > 7 then index <= index+1;
else index <= 0;
if index < 8 and index > 11 then index <= index+1;
else index <= 0;
if index < 12 and index > 15 then index <= index+1;
else index <= 0;
end if;
end if;
end if;
end if;
end if;
end process;
process begin
wait until rising_edge(clk);
if ck400hz = '1' then
With scan select -- error unexpected With
an <= an(0) when "00",
an(1) when "01",
an(2) when "10",
an(3) when others;
end if;
end process;
process begin
wait until rising_edge(clk);
if ck200hz = '1' then
With S select -- error unexpected With
disp <= index integer range 0 to 3 when "00",
index integer range 4 to 7 when "01",
index integer range 8 to 11 when "10",
index integer range 12 to 15 when others;
end if;
end process;
with index select
C <= "1000000" when 0,
"1111001" when 1,
"0100100" when 2,
"0110000" when 3,
"0011001" when 4,
"0010010" when 5,
"0000010" when 6,
"1111000" when 7,
"0000000" when 8,
"0011000" when 9;
end timer;
对于low-active:
在 index = 0
的情况下,您应该将 0111111
分配给 C
。您必须启用几乎所有细分市场。现在您的内部计算将是 high-active。由于 PCB 布局,显示器本身是 low-active,因此在将其分配给 Cathode_n
端口之前,您应该反转整个 C
向量:Cathode_n <= not C;
注意,我使用 _n
指定此端口的 low-active 行为。
旧代码:
with index select
C <= "1000000" when 0,
"1111001" when 1,
-- ...
"0011000" when 9;
这应该是编写纯 high-active 代码时的目标:
with index select
C <= "0111111" when 0,
"0000110" when 1,
-- ...
"1100111" when 9;
Cathode_n <= not C;
High-active 表示:如果位为高 (1
),则事物处于活动状态。在您的情况下,一个 7 段显示器的 LED 被激活。根据 PCB 设计,您必须拉低 (0
) 才能激活灯。这是 low-active,因为低值会激活某些东西。
select语句需要指定1
应该点亮的位置,而不是要关闭的位置。更多 low-active 信号应该在代码中标记以表示不同的行为。只有 top-level 组件应将 high-active 信号转换为 low-active 信号,反之亦然。这确保了您设计的内部部分是纯粹的 high-active.
为否 driver:
S
和 scan
没有分配。两个信号分别是 'U'
或 "UUUU"
。
编辑:
每个信号分配都会在信号上创建一个 driver。目前,您的代码从未为 S
或 scan
分配任何值。因此 S
和 scan
的初始值成为信号的驱动值。您应该 运行 模拟并在波形中看到很多 U
s。
综合工具可能会报告:信号 S
已读取,但从未分配。
使用elsif
:
我重新格式化你太可怕了if-then-else构造:
if ck100hz = '1' then
if index < 3 then
index <= index+1;
else
index <= 0;
if index < 4 and index > 7 then
index <= index+1;
else
index <= 0;
if index < 8 and index > 11 then
index <= index+1;
else
index <= 0;
if index < 12 and index > 15 then
index <= index+1;
else
index <= 0;
end if;
end if;
end if;
end if;
end if;
现在我们看到,你的代码不能使用elsif,因为你在下一个[=81]之前的else分支中有赋值=]if 语句。另一方面,index <= 0;
分配是多余的,可以删除:
if ck100hz = '1' then
if index < 3 then
index <= index+1;
else
if index < 4 and index > 7 then
index <= index+1;
else
if index < 8 and index > 11 then
index <= index+1;
else
if index < 12 and index > 15 then
index <= index+1;
else
index <= 0;
end if;
end if;
end if;
end if;
end if;
现在我们可以将其转换为使用 elsif 分支:
if ck100hz = '1' then
if index < 3 then
index <= index + 1;
elsif index < 4 and index > 7 then
index <= index + 1;
elsif index < 8 and index > 11 then
index <= index + 1;
elsif index < 12 and index > 15 then
index <= index+1;
else
index <= 0;
end if;
end if;
更具可读性,对吧?
接下来,让我们检查您在该语句中的表达式:
elsif index < 4 and index > 7 then
index
不能同时小于4和大于7。因此,让我们进行综合并优化掉无法到达的分支:
if ck100hz = '1' then
if index < 3 then
index <= index + 1;
else
index <= 0;
end if;
end if;
好的,代码中的其他问题:
if rst = '1' then
index <= 0;
end if;
if stp = '1' then
index <= index;
end if;
if ck100hz = '1' then
-- ...
end if;
重置应始终具有最高优先级。在你的情况下,例如stp
具有更高的优先级。在好的情况下,您只是在浪费 FPGA 资源,在坏的情况下,综合无法将您的代码转换为 FPGA 中的原语。例如。 flip-flops 具有匹配的重置行为。
正确的实现:
if rst = '1' then
index <= 0;
elsif stp = '1' then
index <= index;
elsif ck100hz = '1' then
-- ...
end if;
我想现在,您有足够的输入来修复您的代码。