编写第一个VHDL程序难吗? 很难说,但是这里的主要是动机...
也许我本可以设法延迟这一时刻,但是一位邻居要求我制造一个矩形脉冲发生器,以便可以清楚地显示它,并且可以控制脉冲的频率和持续时间。
精度为0.1微秒...
我的看法落在一条带CPLD的围巾上(200卢布,一种),上面有指示器和按钮。 我想,一旦您应该开始处理这样的事情,...
尽管我用C语言编写所有内容,但我仍然爱Ada,但是选择写VHDL还是Verilog却不是。因此VHDL是独一无二的。 而且,在阅读了FPGA的介绍后,我意识到没有什么会复杂的(至少对于这样简单的任务而言)。
因此,一
开始就是让我们成为发电机的意思。 本机碎片的频率为50 MHz,也就是说,我们将其降低到10,这样时钟线的切换将在中间和结尾。 这是发生了什么事。
然后,您需要以某种方式显示和管理。 我们有两个值-周期的长度和脉冲的长度,因此,对于周期的长度,我们指定3个熟悉度(考虑十分之一),而对于周期的长度,则为3。
shared variable period : integer range 0 to 1000 := 500; shared variable duty : integer range 0 to 1000 := 250; shared variable dig1:std_logic_vector(3 downto 0):="0000"; shared variable dig2:std_logic_vector(3 downto 0):="0101"; shared variable dig3:std_logic_vector(3 downto 0):="0010"; shared variable di1:std_logic_vector(3 downto 0):="0000"; shared variable di2:std_logic_vector(3 downto 0):="0000"; shared variable di3:std_logic_vector(3 downto 0):="0101";
好吧,对于控制而言,来自按钮的信号是合适的,这些信号在板子的底部可见-只有4个,
因此,让两个分别控制周期和动量的变化,一个设定变化的符号,另一个控制打开和关闭发电机的输出...
这是管理 process(key1) begin if rising_edge(key1) then ready <= not ready; end if; end process; process(key3) begin if rising_edge(key3) then if key4 = '1' then inc_duty; else dec_duty; end if; end if; end process; process(key2) begin if rising_edge(key2) then if key4 = '1' then inc_period; else dec_period; end if; end if; end process;
在管理中有inc / dec程序,在这里
procedure inc_duty is begin if duty < period then duty := duty + 1; if dig1 = "1001" then dig1 := "0000"; if dig2 = "1001" then dig2 := "0000"; if dig3 = "1001" then dig3 := "0000"; else dig3 := dig3 + 1; end if; else dig2 := dig2 + 1; end if; else dig1 := dig1 + 1; end if; end if; end procedure; procedure dec_duty is begin if duty > 1 then duty := duty - 1; if dig1 = "0000" then dig1 := "1001"; if dig2 = "0000" then dig2 := "1001"; dig3 := dig3 - 1; else dig2 := dig2 - 1; end if; else dig1 := dig1 - 1; end if; end if; end procedure; procedure inc_period is begin if period < 1000 then period := period + 1; if di1 = "1001" then di1 := "0000"; if di2 = "1001" then di2 := "0000"; if di3 = "1001" then di3 := "0000"; else di3 := di3 + 1; end if; else di2 := di2 + 1; end if; else di1 := di1 + 1; end if; end if; end procedure; procedure dec_period is begin if period > 1 then period := period - 1; if di1 = "0000" then di1 := "1001"; if di2 = "0000" then di2 := "1001"; if di3 = "0000" then di3 := "1001"; else di3 := di3 - 1; end if; else di2 := di2 - 1; end if; else di1 := di1 - 1; end if; end if; end procedure;
它有点长而且很复杂(这就是为什么将其最小化的原因),但这是可以理解的。
好吧,我们需要以某种方式显示它-我们有一个7段指示器,其中有6个(实际上是8个)。 我们将显示时间,并且为了避免受到一点的影响,将显示十分之一微秒。
让他们循环显示当前数字:
process(tactX) begin case tactX is when"000"=> en_xhdl<="11111110"; when"001"=> en_xhdl<="11111101"; when"010"=> en_xhdl<="11111011"; when"011"=> en_xhdl<="11110111"; when"100"=> en_xhdl<="11101111"; when"101"=> en_xhdl<="11011111"; when"110"=> en_xhdl<="10111111"; when"111"=> en_xhdl<="01111111"; when others => en_xhdl<="01111111"; end case; end process; process(en_xhdl) begin case en_xhdl is when "11111110"=> data4<=dig1; when "11111101"=> data4<=dig2; when "11111011"=> data4<=dig3; when "11110111"=> data4<="1111"; when "11101111"=> data4<=di1; when "11011111"=> data4<=di2; when "10111111"=> data4<=di3; when "01111111"=> data4<="0000"; when others => data4<="1111"; end case; end process; process(data4) begin case data4 is WHEN "0000" => dataout_xhdl1 <= "11000000"; WHEN "0001" => dataout_xhdl1 <= "11111001"; WHEN "0010" => dataout_xhdl1 <= "10100100"; WHEN "0011" => dataout_xhdl1 <= "10110000"; WHEN "0100" => dataout_xhdl1 <= "10011001"; WHEN "0101" => dataout_xhdl1 <= "10010010"; WHEN "0110" => dataout_xhdl1 <= "10000010"; WHEN "0111" => dataout_xhdl1 <= "11111000"; WHEN "1000" => dataout_xhdl1 <= "10000000"; WHEN "1001" => dataout_xhdl1 <= "10010000"; WHEN OTHERS => dataout_xhdl1 <= "11111111"; END CASE; END PROCESS;
老实说,我承认我从围巾附带的源代码中删除了部分代码-它非常酷,而且写得很清楚! en_xhdl-该信号将控制在切换周期中哪个指示灯亮,dataout_xhdl1-该信号使LED亮,data4是一个临时寄存器并存储一个数字。
剩下的就是写一颗考虑所有事物的心-发电机本身。 这里的tactX是显示生成器,而cnt是脉冲位置计数器。 好吧,lin是发生器本身的信号。
process(tact) variable cntX : integer range 0 to 1000 := 0; variable cnt : integer range 0 to 1000 := 0; begin if rising_edge(tact) then if cntX = 0 then tactX <= tactX + 1; end if; cntX := cntX + 1; if cnt > period then cnt := 0; else cnt := cnt + 1; end if; if cnt = 0 then lin <= '0'; elsif cnt = duty then lin <= '1'; end if; end if; end process;
好吧,它仍然可以输出数据-这是不断进行的操作,因此它应该位于并行执行块中。
cat_led <= dataout_xhdl1; en_led <= en_xhdl; led1 <= not ready; out1 <= lin when ready = '1' else '0'; out2 <= not lin when ready = '1' else '0';
最后,将所有进程合并在一起-生成的Quarus Prime文件受到好评,并进行了编译,并报告说:
Top-level Entity Name v12 Family MAX II Device EPM240T100C5 Timing Models Final Total logic elements 229 / 240 ( 95 % ) Total pins 29 / 80 ( 36 % ) Total virtual pins 0 UFM blocks 0 / 1 ( 0 % )
尽管它是完全图形化的,但最繁琐的阶段仍然存在-为信号分配特定的引脚。 仅此而已-仍然需要将所有内容填充到设备中并进行检查! 有趣的是,我们设法将其保留在229个单元之内,因此已经剩下11个单元了-但实际上,界面和按钮几乎吞噬了所有内容。 实际上,发生器可以堆叠在多个单元中-英特尔有一份文档,其中描述了如何堆叠在1个LUT中-当然,不受控制...
因此,回答标题的问题-不,如果您了解C或Ada并了解数字电子产品的工作原理并不难,是的,如果您不了解基本知识也很困难...至少,我花了一天的时间来写,我开发过程和功能正常的设备使我感到非常高兴! 和邻居很高兴:)