Pelajaran Teach
Logik digital pada DE1-SoC dengan VHDL (4/6): pembilang dan daftar anjakan pilihan
Bina pembilang VHDL dengan pembahagi jam, kemudian cuba sambungan BCD dan daftar anjakan jika masa mengizinkan.
Kali pertama menggunakan LabsLand? Cipta akaun guru anda
Hasil pembelajaran
Menerangkan fungsi pembahagi jam dan menggunakannya untuk menjadikan tingkah laku 50 MHz kelihatan.
Membina pembilang 4 bit dan membaca nilainya pada LED serta paparan tujuh segmen.
Mengenal kerja BCD dan daftar anjakan sebagai sambungan pilihan.
Mengenal masalah lebar daftar, termasuk pemalar yang tidak muat dalam daftar yang diisytiharkan.
Pratonton aktiviti pelajar
Kandungan aktiviti
Pratonton sahaja. Dalam sesi kelas, pelajar boleh mengisi jawapan dan menyerahkan hasil kerja mereka kepada guru.
Daripada ingatan kepada gerakan: mengapa pembahagi jam diperlukan
10 min
Dalam Pelajaran 3, anda membina litar yang mengingati satu bit atau bait: flip-flop dan daftar muatan selari. Setiap satu mengemas kini nilai tersimpan pada pinggir jam. Kini anda menggunakan semula idea itu untuk membina litar yang bergerak sendiri pada setiap pinggir: pembilang yang maju 0, 1, 2, 3, .... Jika masa mengizinkan, sambungan pilihan menggunakan prinsip yang sama untuk daftar anjakan, yang menggerakkan bit ke sisi.
Jam CLOCK_50 papan ialah gelombang 50 MHz dengan 50,000,000 pinggir menaik sesaat. Jika pembilang 4 bit maju pada setiap pinggir, ia akan menghabiskan semua 16 nilai kira-kira tiga juta kali sesaat. LED hanya kelihatan kabur dan kamera jauh tidak sempat menunjukkan setiap langkah.
Oleh itu, kita menggunakan pembahagi jam. Pembahagi mengira pinggir CLOCK_50; apabila mencapai kiraan terminal DIV, ia menyongsangkan isyarat perlahan slow_clk dan mula mengira semula. Semakin besar DIV, semakin perlahan slow_clk. Litar utama dipacu oleh slow_clk, bukan terus oleh CLOCK_50, supaya gerakannya dapat dilihat.
Reka bentuk jujukan perlu mengisytiharkan jam. Templat blink.vhd tidak menyertakannya, maka setiap entiti dalam pelajaran ini menambah CLOCK_50 : in std_logic. Isyarat lain ialah SW(9 downto 0) (suis ke atas = 1), KEY(3 downto 0) (aktif-rendah: ditekan = 0), LEDR(9 downto 0) (aktif-tinggi) dan HEX0–HEX5 (tujuh segmen aktif-rendah).
Pembahagi mengira pinggir pantas CLOCK_50 dan hanya menyongsangkan slow_clk apabila mencapai DIV. Nilai DIV yang lebih besar menghasilkan gerakan lebih perlahan yang dapat diikuti oleh mata dan kamera.
Pembilang 4 bit yang dipacu terus oleh CLOCK_50 melangkah kira-kira tiga juta kali sesaat, sedangkan kamera hanya menangkap beberapa bingkai sesaat. Apakah yang sebenarnya kelihatan pada LED, dan mengapa?
Jika DIV digandakan daripada 33,333,333 kepada 66,666,666, bagaimanakah kadar langkah pembilang berubah secara anggaran, dan mengapa? Jawab dalam satu ayat.
Latihan 2-C: pembilang 4 bit dengan pembahagi jam
12 min
Pembilang ialah daftar yang nilai seterusnya bersamaan nilai semasa tambah satu. Pembilang 4 bit menyimpan 0 hingga 15; selepas 15, ia kembali ke 0 secara automatik kerana 15 + 1 = 10000 dalam perduaan dan hanya empat bit rendah (0000) disimpan.
Reka bentuk ini mempunyai dua bahagian. Pembahagi mengira pinggir CLOCK_50 hingga DIV dan menyongsangkan slow_clk. Pembilang bertambah satu pada setiap pinggir menaik slow_clk; KEY(0) menetapkannya semula kepada 0. Nilai dipaparkan dalam perduaan pada LEDR(3 downto 0) dan sebagai satu digit perenambelasan pada HEX0: 0–9, kemudian A–F bagi 10–15.
Pemasaan. Dengan DIV = 33,333,333, slow_clk disongsangkan selepas kira-kira 0.67 s. Satu langkah hanya berlaku pada pinggir menaik, dan gelombang segi empat memerlukan dua songsangan bagi satu tempoh penuh. Maka pembilang maju kira-kira setiap 1.33 s, iaitu lebih kurang 0.75 Hz.
Perangkap lebar daftar. Daftar pembahagi di sini selebar 27 bit. Daftar 26 bit hanya menyimpan hingga 2^26 − 1 = 67,108,863, jadi DIV = 100,000,000 tidak muat. Daftar 27 bit mencapai 2^27 − 1 = 134,217,727, maka 100,000,000 dan 8,333,333 kedua-duanya muat. Sentiasa pastikan pemalar muat dalam lebar yang diisytiharkan.
Catatan kejuruteraan. Memacu daftar terus daripada slow_clk terbahagi ialah jalan pintas pengajaran supaya gerakan jelas. Dalam reka bentuk pengeluaran, semua logik biasanya kekal pada CLOCK_50 dan menggunakan pemboleh jam, iaitu denyut satu kitaran yang membenarkan kemas kini. Ini memudahkan analisis pemasaan oleh alat sintesis.
-- Kod permulaan pelajar: lengkapkan baris TODO sebelum sintesis.
-- Pelajaran 4 - Latihan 2-C: pembilang 4 bit dengan pembahagi jam.
-- KEY(0)=set semula. LEDR(3 downto 0)=kiraan; HEX0=kiraan perenambelasan.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity blink is
port (
CLOCK_50 : in std_logic;
KEY : in std_logic_vector(3 downto 0);
LEDR : out std_logic_vector(9 downto 0);
HEX0 : out std_logic_vector(6 downto 0)
);
end entity blink;
architecture rtl of blink is
constant DIV : unsigned(26 downto 0) := TODO_VISIBLE_DIVIDER;
signal div_count : unsigned(26 downto 0) := (others => '0');
signal slow_clk : std_logic := '0';
signal count : unsigned(3 downto 0) := (others => '0');
function seg(d : unsigned(3 downto 0)) return std_logic_vector is
begin
case d is
when "0000" => return "1000000"; when "0001" => return "1111001";
when "0010" => return "0100100"; when "0011" => return "0110000";
when "0100" => return "0011001"; when "0101" => return "0010010";
when "0110" => return "0000010"; when "0111" => return "1111000";
when "1000" => return "0000000"; when "1001" => return "0010000";
when "1010" => return "0001000"; when "1011" => return "0000011";
when "1100" => return "1000110"; when "1101" => return "0100001";
when "1110" => return "0000110"; when "1111" => return "0001110";
when others => return "1111111";
end case;
end function;
begin
process(CLOCK_50)
begin
if rising_edge(CLOCK_50) then
if KEY(0) = '0' then
div_count <= (others => '0');
slow_clk <= '0';
elsif div_count = TODO_DIVIDER_LIMIT then
div_count <= (others => '0');
slow_clk <= not slow_clk;
else
div_count <= div_count + 1;
end if;
end if;
end process;
process(slow_clk, KEY)
begin
if KEY(0) = '0' then count <= (others => '0');
elsif rising_edge(slow_clk) then count <= TODO_NEXT_COUNT;
end if;
end process;
LEDR(3 downto 0) <= TODO_LED_COUNT;
LEDR(9 downto 4) <= (others => '0');
HEX0 <= TODO_HEX_COUNT;
end architecture rtl;Andaikan daftar pembahagi hanya 24 bit. Apakah nilai terbesarnya (2^24 − 1), dan adakah DIV = 33,333,333 masih muat? Terangkan dalam satu ayat.
Jalankan dan tetapkan semula pembilang
10 min
Bina pembilang pada papan sebenar, perhatikan ia maju, tetapkan semula, kemudian cuba dua nilai pembahagi lain.
Buka makmal VHDL DE1-SoC; editor memaparkan
blink.vhd.Gantikan seluruh fail dengan pembilang di atas, lengkapkan semua TODO, kekalkan entiti
blinkdan sahkanCLOCK_50 : in std_logic.Klik Synthesize. Tutup atau langkau lawatan jika menutup butang. Tunggu 1–3 minit, baiki ralat dan ulang sehingga binaan berjaya dengan 0 ralat. Amaran pemasaan dijangka bagi pembahagi pengajaran ini.
Klik Upload to FPGA dan tunggu papan serta kamera.
Perhatikan
LEDR(3 downto 0)danHEX0. Nilai baharu muncul kira-kira setiap 1.33 s. Sahkan LED perduaan sepadan dengan digit perenambelasan; contohnyaCsepadan dengan1100.Tekan dan tahan
KEY(0)untuk menetapkan kiraan kepada0, kemudian lepaskan dan lihat kiraan bermula semula.Pilihan: tukar
DIVkepada8,333,333(to_unsigned(8_333_333, 27)), sintesis dan perhatikan kiraan lebih pantas. Kemudian cuba100,000,000(to_unsigned(100_000_000, 27)) dan lihat ia lebih perlahan. Sambungan ini tidak diperlukan untuk bukti wajib.
Dengan DIV = 33,333,333, rekod beberapa nilai ketika muncul. Bagi setiap nilai, catat corak LEDR(3 downto 0), aksara HEX0 dan nilai perpuluhan. Kemudian tetapkan semula dengan KEY(0) dan sahkan kiraan kembali kepada 0.
| Pemerhatian # | LEDR(3 downto 0) (perduaan) | Aksara HEX0 | Nilai perpuluhan (0–15) |
|---|---|---|---|
Hantar bukti. Apabila HEX0 menunjukkan C (perpuluhan 12), ambil tangkap layar kamera; LEDR(3 downto 0) mesti menunjukkan 1100 pada masa yang sama.
Jika anda menjalankan sambungan dengan DIV = 8,333,333 dan DIV = 100,000,000, nilai manakah menghasilkan langkah lebih pantas dan kira-kira berapa kali lebih pantas?
Untuk menggunakan pembilang sebagai jam dengan ralat tidak melebihi satu saat dalam 24 jam, apakah yang perlu tepat selain pembilang? Namakan unsur utama dan jelaskan sebabnya.
Sambungan pilihan: pembilang BCD 0 hingga 9
7 min
Pembilang 4 bit biasa bergerak 0–15 dan menunjukkan A–F bagi enam nilai terakhir. Banyak paparan hanya memerlukan satu digit perpuluhan: 0, 1, 2, …, 9, kemudian kembali ke 0. Ini ialah pembilang BCD (perpuluhan berkod perduaan).
Daripada membiarkan daftar melilit selepas 15, kesan nilai 9 dan paksa nilai berikutnya kepada 0. Gantikan proses pembilang dengan:
process(slow_clk, KEY)
begin
if KEY(0) = '0' then count <= TODO_RESET_COUNT;
elsif rising_edge(slow_clk) then
if count = TODO_LAST_BCD_DIGIT then count <= TODO_WRAP_VALUE;
else count <= TODO_NEXT_COUNT;
end if;
end if;
end process;
Kekalkan pembahagi, tugasan serentak LEDR/HEX0 dan fungsi seg. Kini HEX0 hanya berkitar 0 hingga 9.
Edit entiti supaya kiraan kembali kepada
0selepas9.Jalankan sintesis, baiki ralat dan muat naik ke FPGA.
Perhatikan
HEX0berkitar0, 1, 2, …, 9, 0, 1, …tanpa mencapaiA. GunakanKEY(0)untuk menetapkan semula jika perlu.
(Sambungan BCD pilihan) Apakah nilai count pada pinggir selepas HEX0 menunjukkan 9, dan baris manakah yang memaksa nilai itu? Jika anda menjalankannya, tambah pemerhatian ketika HEX0 kembali kepada 0.
Sambungan pilihan: daftar anjakan 8 bit
9 min
Daftar anjakan ialah sederet flip-flop yang memindahkan setiap bit kepada jirannya pada setiap pinggir sementara satu bit baharu masuk di hujung. Ia penting bagi pautan bersiri seperti UART, SPI dan I2C, yang menghantar data satu bit pada satu masa.
Daftar shreg(7 downto 0) menjalankan tugasan ini pada setiap pinggir menaik slow_clk apabila anjakan didayakan:
shreg <= TODO_SHIFT_LEFT_UPDATE; -- TODO: anjak kiri dan masukkan SW(0) ke bit 0
Sebelah kanan mengambil tujuh bit rendah shreg(6 downto 0), menggerakkannya satu kedudukan ke atas dan memasukkan SW(0) ke bit 0. Semua bit bergerak ke hujung tinggi, jadi ini ialah anjakan kiri. SW(0) ialah input bersiri, KEY(0) ialah set semula dan KEY(1) ialah pemboleh anjakan; kedua-dua KEY aktif-rendah. Tahan KEY(1) untuk menganjak pada setiap detik.
Corak jangkaan. Bermula pada 0000_0000, masukkan empat 1: 0000_0001, 0000_0011, 0000_0111, 0000_1111. Kemudian masukkan empat 0: 0001_1110, 0011_1100, 0111_1000, akhirnya 1111_0000.
Nilai bit berbanding rupa. Rekod nilai perduaan dan rupa kamera. Susunan fizikal LED mungkin kelihatan terbalik berbanding penulisan bit (shreg(7) di satu sisi dan shreg(0) di sisi lain). Itu kesan orientasi, bukan ralat logik.
-- Kod permulaan pelajar: lengkapkan baris TODO sebelum sintesis.
-- Pelajaran 4 - Latihan 2-D: daftar anjakan 8 bit yang menganjak ke kiri.
-- SW(0)=input data bersiri, KEY(0)=set semula, KEY(1)=pemboleh anjakan. KEY aktif-rendah.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity blink is
port (
CLOCK_50 : in std_logic;
KEY : in std_logic_vector(3 downto 0);
SW : in std_logic_vector(9 downto 0);
LEDR : out std_logic_vector(9 downto 0)
);
end entity blink;
architecture rtl of blink is
constant DIV : unsigned(26 downto 0) := TODO_VISIBLE_DIVIDER;
signal div_count : unsigned(26 downto 0) := (others => '0');
signal slow_clk : std_logic := '0';
signal shreg : std_logic_vector(7 downto 0) := (others => '0');
begin
process(CLOCK_50)
begin
if rising_edge(CLOCK_50) then
if KEY(0) = '0' then
div_count <= (others => '0'); slow_clk <= '0';
elsif div_count = DIV then
div_count <= (others => '0'); slow_clk <= not slow_clk;
else
div_count <= div_count + 1;
end if;
end if;
end process;
process(slow_clk, KEY)
begin
if KEY(0) = '0' then
shreg <= (others => '0');
elsif rising_edge(slow_clk) then
if KEY(1) = '0' then shreg <= TODO_SHIFT_UPDATE;
end if;
end if;
end process;
LEDR(7 downto 0) <= TODO_SHIFT_OUTPUT;
LEDR(9 downto 8) <= (others => '0');
end architecture rtl;Bermula daripada 0000_0000 dengan KEY(1) ditahan, masukkan SW(0) = 1, 1, 0, 1 selama empat detik, yang terdahulu dahulu. Kira setiap langkah dan tulis shreg(7 downto 0) selepas detik keempat.
Sambungan pilihan: gerakkan bit merentasi LED
9 min
Bina daftar anjakan, lihat bit menyala bergerak sepanjang baris, kemudian lihat sifar mengikutinya.
Gantikan
blink.vhddengan daftar anjakan di atas, lengkapkan TODO, kekalkanblinkdanCLOCK_50 : in std_logic.Jalankan sintesis, baiki ralat dan muat naik ke FPGA.
Tekan dan lepaskan
KEY(0)untuk mengosongkan daftar.Tetapkan
SW(0)=1dan tahanKEY(1). Selepas empat detik, empat LED menyala (0000_1111).Tetapkan
SW(0)=0, terus tahanKEY(1)dan tunggu empat detik lagi hingga1111_0000.Lepaskan
KEY(1)untuk membekukan corak supaya mudah dibaca dan dirakam.
Tetapkan semula dan tahan KEY(1). Rekod empat detik dengan SW(0)=1, kemudian empat detik dengan SW(0)=0. Tulis shreg sebagai lapan bit dengan shreg(7) di kiri dan catat sama ada LED kelihatan terbalik pada kamera.
| Detik # | Input SW(0) | shreg(7 downto 0) (8 bit) | Kamera: LED menyala / terbalik? |
|---|---|---|---|
Hantar bukti. Selepas empat 1 dan empat 0, lepaskan KEY(1) untuk membekukan shreg = 1111_0000, ambil tangkap layar dan catat sama ada LED kelihatan terbalik.
Bandingkan nilai yang dikira (1111_0000) dengan LED dalam tangkap layar. Jika kelihatan terbalik, jelaskan sebab itu kesan orientasi/label dan bukan pepijat logik anjakan.
Pilihan: anjak kanan dan pembilang gelang
6 min
Anjak ke arah lain. Untuk menggerakkan setiap bit ke hujung rendah dan memasukkan bit baharu di bahagian atas (shreg(7)), tukar satu tugasan:
shreg <= TODO_SHIFT_RIGHT_UPDATE; -- TODO: anjak kanan dan masukkan SW(0) ke bit 7
Kini SW(0) masuk ke shreg(7) dan shreg(7 downto 1) turun ke shreg(6 downto 0).
Sambungan: pembilang gelang. Pembilang gelang menyuap balik output daftar sendiri supaya corak tetap beredar. Bina gelang anjak kiri dengan shreg(7) disuap ke bit 0. Set semula perlu memuatkan "00000001", dan baris anjakan ialah shreg <= shreg(6 downto 0) & shreg(7);. Tahan KEY(1) untuk melihat satu LED beredar.
Tukar satu baris anjakan kepada versi kanan, jalankan sintesis dan muat naik.
Tetapkan semula, tahan
KEY(1), masukkan empat1dan empat0, lalu sahkan bit bergerak ke arah bertentangan.Pilihan: bina pembilang gelang dengan set semula
"00000001"dan suapan balikshreg(7)ke bit0.
Dalam versi anjak kanan shreg <= SW(0) & shreg(7 downto 1);, bermula daripada 0000_0000, masukkan SW(0)=1 selama empat detik. Hujung manakah yang terisi, dan apakah nilai akhirnya?
Perkara yang anda bina
4 min
Dalam tiga ayat, terangkan: (1) cara pembahagi menjadikan gerakan pembilang kelihatan, (2) satu bukti konkrit yang dirakam daripada pembilang dan HEX0, dan (3) satu perangkap yang dielakkan, seperti pemalar yang tidak muat dalam daftar 27 bit. Jika anda mencuba sambungan BCD atau daftar anjakan, tambah satu ayat tentang bukti itu.