八周造个CPU(?):LED秒表实验

板子

照片

board.png

检查设备状态

其实根本就没有检查,总之插上就可以访问控制页面了。(我有一个USB接口坏了,所以之前访问不了)

board_control.png

实验指导书对应

  • 手动时钟 → touch_btn[4]
  • RST →touch_btn[5]
  • 50M CLK→clk_in
  • L[n] → leds[15:0]
  • DPY0 →leds[23:16],DPY1 →leds[31:24]
  • SW[n] → dip_sw[n]
  • RAM1 → base_ram
  • RAM2 → ext_ram

用LED显示秒表

程序

Timer的程序是从实验指导书上抄的,做了一点改动,因为板子上的rst按下时为‘’1'`。但是,诡异的是,实际效果是按下rst时秒表计数暂停,而非置0。

clock.vhd

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
 
entity clock is
    Port ( clk : in STD_LOGIC;
           rst : in STD_LOGIC;
           seg1 : out UNSIGNED (6 downto 0);
           seg2 : out UNSIGNED (6 downto 0));
end clock;
 
architecture Behavioral of clock is
    signal clk_out: STD_LOGIC := '0';
    signal cnt: UNSIGNED(25 downto 0) := "00000000000000000000000000";
    signal cnt_H: UNSIGNED(3 downto 0) := "0000";
    signal cnt_L: UNSIGNED(3 downto 0) := "0000";
begin
 
    -- 时钟分频,产生1HZ时钟信号clk_out
    process(clk)
    begin
        if rising_edge(clk) then
            cnt <= cnt + "1";
            if cnt = "00000000000000000000000000" then
                clk_out <= '0';
            end if;
            if cnt = "10111110101111000010000000" then
                cnt <= "00000000000000000000000000";
                clk_out <= '1';
            end if;
        end if;
    end process;
 
    -- 秒表计数,分别产生十位和个位
    process(clk_out, rst)
        variable tmp_L, tmp_H: UNSIGNED(3 downto 0) := "0000";
    begin
        if rst = '1' then
            cnt_H <= "0000";
            cnt_L <= "0000";
        else
            if rising_edge(clk_out) then
                tmp_L := cnt_L + "1";
                if tmp_L > "1001" then
                    tmp_L := "0000";
                    tmp_H := cnt_H + "1";
                    if tmp_H > "1001" then
                        tmp_H := "0000";
                    end if;
                end if;
            end if;
        end if;
        cnt_L <= tmp_L;
        cnt_H <= tmp_H;
    end process;
 
    -- 个位译码到七段数码管显示
    process(cnt_L)
    begin
        case cnt_L is
            when "0000" => 
                seg1 <= not "1000000";
            when "0001" => 
                seg1 <= not "1111001";
            when "0010" => 
                seg1 <= not "0100100";
            when "0011" => 
                seg1 <= not "0110000";
            when "0100" => 
                seg1 <= not "0011001";
            when "0101" => 
                seg1 <= not "0010010";
            when "0110" => 
                seg1 <= not "0000010";
            when "0111" => 
                seg1 <= not "1111000";
            when "1000" => 
                seg1 <= not "0000000";
            when "1001" => 
                seg1 <= not "0010000";
            when others => 
                seg1 <= not "1111111";
        end case;
    end process;
 
    -- 十位译码到七段数码管显示
    process(cnt_H)
    begin
        case cnt_H is
            when "0000" => 
                seg2 <= not "1000000";
            when "0001" => 
                seg2 <= not "1111001";
            when "0010" => 
                seg2 <= not "0100100";
            when "0011" => 
                seg2 <= not "0110000";
            when "0100" => 
                seg2 <= not "0011001";
            when "0101" => 
                seg2 <= not "0010010";
            when "0110" => 
                seg2 <= not "0000010";
            when "0111" => 
                seg2 <= not "1111000";
            when "1000" => 
                seg2 <= not "0000000";
            when "1001" => 
                seg2 <= not "0010000";
            when others => 
                seg2 <= not "1111111";
        end case;
    end process;
 
end Behavioral;

test_bench.v

相比实验指导书上做了一点改动。(显然,从vhdl改到了verilog)

`timescale 1ns / 1ns
module Timer_testbench();

    reg CLOCK_50;
    reg rst;
    wire[6:0] seg1;
    wire[6:0] seg2;

    // The CLOCK flips every 10 ns, so the frequency is 50MHZ
    initial begin
        CLOCK_50 = 1'b0;
        forever #10 CLOCK_50 = ~CLOCK_50;
    end 

    initial begin
        rst = 1'b1;
        #1000 rst = 1'b0;
    end

    clock clock0(
        .clk(CLOCK_50),
        .rst(rst),
        .seg1(seg1),
        .seg2(seg2)
    );

endmodule

clock.xdc

set_property PACKAGE_PIN D18 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property PACKAGE_PIN H19 [get_ports rst]
set_property IOSTANDARD LVCMOS33 [get_ports rst]

set_property PACKAGE_PIN H14 [get_ports {seg1[0]}]
set_property PACKAGE_PIN H16 [get_ports {seg1[1]}]
set_property PACKAGE_PIN F15 [get_ports {seg1[2]}]
set_property PACKAGE_PIN H15 [get_ports {seg1[3]}]
set_property PACKAGE_PIN G15 [get_ports {seg1[4]}]
set_property PACKAGE_PIN G19 [get_ports {seg1[5]}]
set_property PACKAGE_PIN J8 [get_ports {seg1[6]}]

set_property PACKAGE_PIN E5 [get_ports {seg2[0]}]
set_property PACKAGE_PIN D6 [get_ports {seg2[1]}]
set_property PACKAGE_PIN G8 [get_ports {seg2[2]}]
set_property PACKAGE_PIN G7 [get_ports {seg2[3]}]
set_property PACKAGE_PIN G6 [get_ports {seg2[4]}]
set_property PACKAGE_PIN F4 [get_ports {seg2[5]}]
set_property PACKAGE_PIN G5 [get_ports {seg2[6]}]

set_property IOSTANDARD LVCMOS33 [get_ports {seg1[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg1[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg1[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg1[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg1[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg1[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg1[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg2[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg2[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg2[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg2[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg2[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg2[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg2[6]}]

Debug

模拟仿真

Vivado自带的仿真恐怕很辣鸡,跑了一分多钟才跑1s,简直是浪费人生。当然,平时的时域肯定比1s要小得多……

8位数码管的端口映射

调LED显示调到怀疑人生!

32位的示例工程约束文件(.xdc)里是这么写的:

#DPY0
set_property PACKAGE_PIN D16 [get_ports {leds[16]}]
set_property PACKAGE_PIN F15 [get_ports {leds[17]}]
set_property PACKAGE_PIN H15 [get_ports {leds[18]}]
set_property PACKAGE_PIN G15 [get_ports {leds[19]}]
set_property PACKAGE_PIN H16 [get_ports {leds[20]}]
set_property PACKAGE_PIN H14 [get_ports {leds[21]}]
set_property PACKAGE_PIN G19 [get_ports {leds[22]}]
set_property PACKAGE_PIN J8 [get_ports {leds[23]}]

#DPY2
set_property PACKAGE_PIN H9 [get_ports {leds[24]}]
set_property PACKAGE_PIN G8 [get_ports {leds[25]}]
set_property PACKAGE_PIN G7 [get_ports {leds[26]}]
set_property PACKAGE_PIN G6 [get_ports {leds[27]}]
set_property PACKAGE_PIN D6 [get_ports {leds[28]}]
set_property PACKAGE_PIN E5 [get_ports {leds[29]}]
set_property PACKAGE_PIN F4 [get_ports {leds[30]}]
set_property PACKAGE_PIN G5 [get_ports {leds[31]}]

所以此时的问题是,怎么把这些和8段数码管对上?好吧,8段数码管是有一套标准的映射的——(以下1表示亮,0表示暗,当然这取决于用的是什么类型的数码管了……)

数字 0 1 2 3 4 5 6 7 8 9
输出到数码管的vector 1000000 1111001 0100100 0110000 0011001 0010010 0000010 1111000 0000000 0010000

其中对(7段)数码管的默认标号大概长这样:

-----6-----
|         |
1         5
|         |
-----0-----
|         |
2         4
|         |
-----3-----

所以leds数组的编号和这个默认编号有什么关系呢?试了一圈,答案是根本没有!!(当然,也可能是他遵守了什么很高级的规定,但我根本没有理解。)

最后试出来的约束文件长这样:

# 右边的数码管
set_property PACKAGE_PIN H14 [get_ports {seg1[0]}]
set_property PACKAGE_PIN H16 [get_ports {seg1[1]}]
set_property PACKAGE_PIN F15 [get_ports {seg1[2]}]
set_property PACKAGE_PIN H15 [get_ports {seg1[3]}]
set_property PACKAGE_PIN G15 [get_ports {seg1[4]}]
set_property PACKAGE_PIN G19 [get_ports {seg1[5]}]
set_property PACKAGE_PIN J8 [get_ports {seg1[6]}]
# D16应该对应小数点,但我大概用不到

# 左边的数码管
set_property PACKAGE_PIN E5 [get_ports {seg2[0]}]
set_property PACKAGE_PIN D6 [get_ports {seg2[1]}]
set_property PACKAGE_PIN G8 [get_ports {seg2[2]}]
set_property PACKAGE_PIN G7 [get_ports {seg2[3]}]
set_property PACKAGE_PIN G6 [get_ports {seg2[4]}]
set_property PACKAGE_PIN F4 [get_ports {seg2[5]}]
set_property PACKAGE_PIN G5 [get_ports {seg2[6]}]
# H9应该对应小数点,但我大概用不到

说起来,这个芯片的管脚分配也挺乱的,不知道是按照什么原则分配的。

在图形界面里一个个点着设端口映射的时候就很有安全感,比自己狂敲代码舒服一些。

现在Vivado编译到Bit Stream大概需要2分钟,不知道CPU要编译多久。

照片

timer.jpg


新增一则回应
除非特别注明,本页内容采用以下授权方式: Creative Commons Attribution-ShareAlike 3.0 License