Mục lục:

Bộ tổng hợp âm thanh kỹ thuật số FPGA Basys3: 5 bước
Bộ tổng hợp âm thanh kỹ thuật số FPGA Basys3: 5 bước

Video: Bộ tổng hợp âm thanh kỹ thuật số FPGA Basys3: 5 bước

Video: Bộ tổng hợp âm thanh kỹ thuật số FPGA Basys3: 5 bước
Video: VHDL – FPGA. Bài 513: Đếm 3 số BCD hiển thị 3 led 7 đoạn, có start/stop, up/dw, chọn 4 tần số, xvn. 2024, Tháng Chín
Anonim
Image
Image
Bộ tổng hợp âm thanh kỹ thuật số FPGA Basys3
Bộ tổng hợp âm thanh kỹ thuật số FPGA Basys3
Bộ tổng hợp âm thanh kỹ thuật số FPGA Basys3
Bộ tổng hợp âm thanh kỹ thuật số FPGA Basys3

Bộ tổng hợp bàn phím sóng sin kỹ thuật số này sẽ nhận đầu vào của người dùng thông qua một loạt các công tắc tạm thời được bố trí giống như bàn phím và xuất ra sóng âm thanh qua loa. Dựa trên đầu vào của người dùng, thiết bị sẽ tạo ra các sóng sin với nhiều tần số khác nhau từ C4 đến C6. Người dùng có thể nhập các ghi chú từ C4 đến C6 (tổng cộng 25 nốt) và tối đa bốn phím cùng một lúc - nếu nhấn nhiều hơn bốn phím, bốn âm thấp nhất sẽ được phát.

Dự án này được thực hiện bởi Ryan Morris và Mavis Tsoi cho lớp Thiết kế kỹ thuật số Cal Poly CPE 133 của chúng tôi:)

Bước 1: Lý thuyết

Một bo mạch FPGA chỉ có thể xuất tín hiệu kỹ thuật số. Nói cách khác, nó chỉ có thể tạo ra điện áp cao (3.3V) hoặc điện áp thấp (0V). Tuy nhiên, tín hiệu âm thanh là tín hiệu tương tự và có thể có vô số mức tăng điện áp. Để giải quyết vấn đề này, chúng tôi sẽ sử dụng tín hiệu PWM (điều chế độ rộng xung) để mô phỏng một sóng tương tự. Nếu bạn không biết PWM là gì, hãy xem phần này:

Bước 2: Thành phần & Công cụ

  • Máy tính đã cài đặt Vivado
  • Chúng tôi sẽ sử dụng Vivado phiên bản 2017.2
  • Ban FPGA Basys3
  • 25 Công tắc giới hạn SPDT (chúng tôi đã sử dụng những công tắc này)
  • 30 dây jumper (một đầu nam, đầu kia không quan trọng), 12 inch
  • Máy cắt dây
  • Dụng cụ tuốt dây
  • Dây dự phòng để hàn
  • Resin-core hàn
  • Hàn sắt
  • Giắc cắm âm thanh nữ ¼”
  • Bộ khuếch đại / loa
  • Một cái gì đó để gắn các công tắc vào (chúng tôi đã sử dụng bảng xếp hạng + hộp gỗ)

Bước 3: Thiết lập hệ thống dây và phần cứng

Thiết lập hệ thống dây và phần cứng
Thiết lập hệ thống dây và phần cứng
Thiết lập hệ thống dây và phần cứng
Thiết lập hệ thống dây và phần cứng
Thiết lập hệ thống dây và phần cứng
Thiết lập hệ thống dây và phần cứng

Kiến Trúc Hệ Thống

Xem Hình 1: 25 đầu vào khả dụng → Bảng Basys3 → bộ khuếch đại & loa.

Đầu ra

Xem Hình 2: Bo mạch Basys3 → Giắc cắm âm thanh 1/2 Cái → Loa (với Bộ khuếch đại)

Đầu vào

Các kết nối pmod trên bo mạch Basys3 phải được kết nối với đất để thấy đầu vào thấp và sẽ không hoạt động bình thường nếu để như một mạch hở. Do đó, chúng tôi phải sử dụng công tắc SPDT cho tất cả các phím ghi chú của mình. Công tắc SPDT về cơ bản cho phép người dùng chuyển đổi giữa các mạch khi được nhấn, vì vậy chúng tôi sẽ sử dụng chúng làm “nút” để đầu vào tín hiệu thấp (0V) hoặc cao (3.3V) cho bảng Basys3.

Mỗi công tắc sẽ có đầu cuối NO (thường mở) được kết nối với đầu cuối 3.3V, NC (thường đóng) được kết nối với GND và đầu cuối COM (chung) được kết nối với đầu vào FPGA. Xem Hình 3.

Bởi vì chúng tôi có 25 công tắc hành trình, tất cả chúng sẽ chia sẻ một đường dây 3.3V chung và một đường dây GND chung. Sau đó, dây tín hiệu từ mỗi công tắc giới hạn sẽ được nhóm lại thành từng nhóm 8 và được nối với các kết nối pmod trên bảng Basys3 bằng cách sử dụng dây nhảy có thể khóa kéo để giảm thiểu sự lộn xộn hoành tráng mà chúng tôi sẽ thực hiện. Xem Hình 4 hoặc ví dụ về tám phím đầu tiên.

Bước 4: Thiết lập VHDL (Vivado)

Thiết lập VHDL (Vivado)
Thiết lập VHDL (Vivado)
Thiết lập VHDL (Vivado)
Thiết lập VHDL (Vivado)

Bộ tạo sóng sin và bộ tạo PWM lần đầu tiên được thử nghiệm để đảm bảo khái niệm của chúng tôi hoạt động, sau đó bộ giới hạn đầu vào và bộ cộng / bộ dịch biên độ được tích hợp. Chi tiết về chức năng và I / O của từng khối quy trình như trong Hình. Mã được hiển thị bên dưới, nhưng cũng được đính kèm dưới dạng tệp VHD và txt. Nếu có sự khác biệt, hãy xử lý các tệp VHD.

BTW: Chúng tôi có lẽ nên làm cho các dòng của chúng tôi ngắn hơn nhưng việc nhúng mã trên Guiductable cũng trở nên khá khó chịu để giải quyết, vì vậy khoảng cách không phải là lớn nhất và không có tô sáng cú pháp. Nếu bạn có Vivado và muốn làm theo mã, chúng tôi thực sự khuyên bạn chỉ cần tải xuống tệp.

Đầu tiên, chúng ta hãy xem xét mô-đun Máy tạo sóng hình sin.

thư viện IEEE; sử dụng IEEE. STD_LOGIC_1164. ALL; sử dụng IEEE. NUMERIC_STD. ALL; thực thể Wave_Generator là Cổng (Kích hoạt: trong STD_LOGIC; - Nhấn phím Freq_Cnt: trong STD_LOGIC_VECTOR (15 xuống 0); - Giá trị bộ đếm = 100MHz / (Lưu ý Tần số * 64 Phân chia của Sóng hình sin) (làm tròn đến số gần nhất) - được đổi tên from Freq wavegenCLK: in STD_LOGIC; - Basys3 100MHz CLK WaveOut: out STD_LOGIC_VECTOR (9 downto 0)); - Biên độ ký hiệu của sóng cuối Sóng_Generator; kiến trúc Hành vi của Wave_Generator là tín hiệu i: dãy số nguyên 0 đến 64: = 0; - chỉ mục của loại ngân hàng bộ nhớ biên độ loại bộ nhớ là mảng (0 đến 63) của dải số nguyên -64 đến 63; - tạo ngân hàng bộ nhớ (ROM) để giữ các giá trị biên độ - RAM hay ROM này chỉ là thắc mắc… biên độ tín hiệu: memory_type: = (0, 7, 13, 19, 25, 30, 35, 40, 45, 49, 52, 55, 58, 60, 62, 63, 63, 63, 62, 60, 58, 55, 52, 49, 45, 40, 35, 30, 25, 19, 13, 7, 0, -7, -13, -19, -25, -30, -35, -40, -45, -49, -52, -55, -58, -60, -62, -63, -63, -63, -62, - 60, -58, -55, -52, -49, -45, -40, -35, -30, -25, -19, -13, -7); - ngân hàng bộ nhớ biên độ cho quá trình bắt đầu sóng sin (wavegenCLK, Trigger) bộ đếm biến: unsigned (15 downto 0): = to_unsigned (0, 16); - bộ đếm bộ chia xung clock, được đổi tên từ count1 begin if (ising_edge (wavegenCLK)) then if (Trigger = '1') then - phím được nhấn bộ đếm: = counter + 1; if (counter = unsigned (Freq_Cnt)) then - Freq_Cnt = 100Mhz / (lưu ý freq * 64 phần chia của sóng sin) - đặt lại bộ đếm và gán dữ liệu biên độ cho bộ đếm đầu ra: = to_unsigned (0, 16); WaveOut <= STD_LOGIC_VECTOR (to_signed (biên độ (i), 10)); - gia số i cho lần đọc tiếp theo i <= i + 1; - đặt lại i nếu một sóng sin đã hoàn thành if (i = 63) then i <= 0; kết thúc nếu; kết thúc nếu; - (counter = unsigned (Freq_Cnt)) else - phím không được nhấn - đặt lại đầu ra, chỉ số biên độ và bộ đếm WaveOut <= "0000000000"; i <= 0; bộ đếm: = to_unsigned (0, 16); --output Biên độ = -64 khi không có nốt nào được phát kết thúc if; - (Trigger = '1') end if; - (tăng_edge (CLK)) kết thúc quá trình; cuối Hành vi;

Chúng tôi sẽ tạo ra một sóng sin kỹ thuật số trong Basys3 bằng cách sử dụng đồng hồ bên trong và ROM. ROM này sẽ lưu trữ 64 giá trị đại diện cho 64 biên độ trên một sóng hình sin. Xem Hình 1. 64 giá trị chúng tôi sử dụng mô phỏng một sóng sin với độ phân giải khá tốt.

Sử dụng đồng hồ bên trong, chúng tôi đếm đến một giá trị đại diện cho tốc độ đồng hồ chia cho tần số của sóng chúng tôi muốn và 64: Clk div = 100MHz / (Freq * 64) Mỗi khi bộ đếm của chúng tôi đạt đến giá trị đó, chúng tôi gọi một số từ ROM và gửi nó ra khỏi mô-đun tạo sóng của chúng tôi. Tần số của sóng của chúng ta sẽ phụ thuộc vào tốc độ mà chúng ta gọi là các biên độ này.

Chúng ta sẽ có 25 mô-đun con, mỗi mô-đun được liên kết với một tần số / nốt nhạc.

Đây là phần còn lại của mã gọi các mô-đun Bộ tạo sóng hình sin:

thư viện IEEE; sử dụng IEEE. STD_LOGIC_1164. ALL; sử dụng IEEE. NUMERIC_STD. ALL; thực thể Two_Octave_Synth là Port (CLK: in STD_LOGIC; O4: in STD_LOGIC_VECTOR (11 downto 0); O5: in STD_LOGIC_VECTOR (12 downto 0); output: out STD_LOGIC); end Two_Octave_Synth; Kiến trúc Hành vi của Two_Octave_Synth là thành phần Wave_Generator là Cổng (Kích hoạt: trong STD_LOGIC; Freq_Cnt: trong STD_LOGIC_VECTOR (15 xuống 0); wavegenCLK: trong STD_LOGIC; WaveOut: ra STD_LOGIC_VECTOR (9 xuống 0)); thành phần cuối; --------------------------- xuất tín hiệu từ bộ tạo sóng ------------------ ----- tín hiệu WaveC4, WaveCs4, WaveD4, WaveDs4, WaveE4, WaveF4, WaveFs4, WaveG4, WaveGs4, WaveA4, WaveAs4, WaveB4, WaveC5, WaveCs5, WaveD5, WaveDs5, WaveE5, WaveF5, WaveFs5, WaveG5, WaveGs5, WaveA5, WaveA5 WaveAs5, WaveB5, WaveC6: đã ký (9 xuống 0); -------------------------------- cho logic lựa chọn ghi chú -------------- ------ tín hiệu C4, Cs4, D4, Ds4, E4, F4, Fs4, G4, Gs4, A4, As4, B4, C5, Cs5, D5, Ds5, E5, F5, Fs5, G5, Gs5, A5, As5, B5, C6: unsigned (4 xuống 0); tín hiệu cntC4, cntCs4, cntD4, cntDs4, cntE4, cntF4, cntFs4, cntG4, cntGs4, cntA4, cntAs4, cntB4, cntC5, cntCs5, cntD5, cntF4, cntFs4, cntG4, cntGs4, cntA4, cntAs4, cntB4, cntC5, cntCs5, cntD5, cntDs5, cntE5, cntFs5: unsigned (4 xuống 0); lỗi tín hiệu: STD_LOGIC; ----------------------------------- để thêm sóng sin ----------- --------------- tín hiệu Wave0, Wave1, Wave2, Wave3: có dấu (9 xuống 0); - tín hiệu từ tín hiệu đầu ra của mô-đun Bộ tạo sóng WaveSum: STD_LOGIC_VECTOR (9 xuống 0); --signal cho các sóng sin tổng hợp (lời khen của 2 từ -512 đến 511) báo hiệu tích cựcWaveSum: STD_LOGIC_VECTOR (9 xuống 0); --được ký 0 đến 1023, để sử dụng trong bộ tạo PWM ----------------------------------- để tạo PWM ------------------------------- signal ping_length: unsigned (9 downto 0): = unsigned (positiveWaveSum); --signal off_length: unsigned (6 downto 0): = to_unsigned (127, 7) - unsigned (WAVE); signal PWM: unsigned (9 downto 0): = to_unsigned (0, 10); begin Note_C4: Bản đồ cổng Wave_Generator (Trigger => O4 (0), Freq_Cnt => X "1755", wavegenCLK => CLK, có dấu (WaveOut) => WaveC4); --5973, 261,63 Hz Note_Cs4: Bản đồ cổng Wave_Generator (Trigger => O4 (1), Freq_Cnt => X "1606", wavegenCLK => CLK, có dấu (WaveOut) => WaveCs4); - 5638, 277,18 Hz Lưu ý_D4: Bản đồ cổng Wave_Generator (Trigger => O4 (2), Freq_Cnt => X "14C9", wavegenCLK => CLK, có dấu (WaveOut) => WaveD4); --5321, 293,66 Hz Note_Ds4: Bản đồ cổng Wave_Generator (Trigger => O4 (3), Freq_Cnt => X "139F", wavegenCLK => CLK, có dấu (WaveOut) => WaveDs4); - 5023, 311,13 Hz Lưu ý_E4: Bản đồ cổng Wave_Generator (Trigger => O4 (4), Freq_Cnt => X "1285", wavegenCLK => CLK, có dấu (WaveOut) => WaveE4); --4741, 329,63 Hz Lưu ý_F4: Bản đồ cổng Wave_Generator (Trigger => O4 (5), Freq_Cnt => X "117B", wavegenCLK => CLK, có dấu (WaveOut) => WaveF4); --4475, 349,23 Hz Note_Fs4: Bản đồ cổng Wave_Generator (Trigger => O4 (6), Freq_Cnt => X "1080", wavegenCLK => CLK, có dấu (WaveOut) => WaveFs4); - 4224, 369,99 Hz Lưu ý_G4: Bản đồ cổng Wave_Generator (Trigger => O4 (7), Freq_Cnt => X "0F92", wavegenCLK => CLK, có dấu (WaveOut) => WaveG4); --3986, 392,00 Hz Note_Gs4: Bản đồ cổng Wave_Generator (Trigger => O4 (8), Freq_Cnt => X "0EB3", wavegenCLK => CLK, có dấu (WaveOut) => WaveGs4); - 3763, 415,30 Hz Lưu ý_A4: Bản đồ cổng Wave_Generator (Trigger => O4 (9), Freq_Cnt => X "0DE0", wavegenCLK => CLK, có dấu (WaveOut) => WaveA4); --3552, 440,00 Hz Note_As4: Bản đồ cổng Wave_Generator (Trigger => O4 (10), Freq_Cnt => X "0D18", wavegenCLK => CLK, có dấu (WaveOut) => WaveAs4); - 3352, 466,16 Hz Lưu ý_B4: Bản đồ cổng Wave_Generator (Trigger => O4 (11), Freq_Cnt => X "0C5C", wavegenCLK => CLK, có dấu (WaveOut) => WaveB4); --3164, 493,88 Hz -------------------------------------------- -------------------------------------------------- --------------------------- Note_C5: Bản đồ cổng Wave_Generator (Kích hoạt => O5 (0), Freq_Cnt => X "0BAB", wavegenCLK => CLK, có dấu (WaveOut) => WaveC5); --2987, 523,25 Hz Note_Cs5: Bản đồ cổng Wave_Generator (Trigger => O5 (1), Freq_Cnt => X "0B03", wavegenCLK => CLK, có dấu (WaveOut) => WaveCs5); - 2819, 554,37 Hz Lưu ý_D5: Bản đồ cổng Wave_Generator (Trigger => O5 (2), Freq_Cnt => X "0A65", wavegenCLK => CLK, có dấu (WaveOut) => WaveD5); --2661, 587,33 Hz Lưu ý_Ds5: Bản đồ cổng Wave_Generator (Kích hoạt => O5 (3), Freq_Cnt => X "09D0", wavegenCLK => CLK, có dấu (WaveOut) => WaveDs5); - 2512, 622,25 Hz Lưu ý_E5: Bản đồ cổng Wave_Generator (Trigger => O5 (4), Freq_Cnt => X "0943", wavegenCLK => CLK, có dấu (WaveOut) => WaveE5); --2371, 659,25 Hz Lưu ý_F5: Bản đồ cổng Wave_Generator (Trigger => O5 (5), Freq_Cnt => X "08Be", wavegenCLK => CLK, có dấu (WaveOut) => WaveF5); --2238, 698,46 Hz Lưu ý_Fs5: Bản đồ cổng Wave_Generator (Kích hoạt => O5 (6), Freq_Cnt => X "0840", wavegenCLK => CLK, có dấu (WaveOut) => WaveFs5); - 2112, 739,99 Hz Lưu ý_G5: Bản đồ cổng Wave_Generator (Trigger => O5 (7), Freq_Cnt => X "07CA", wavegenCLK => CLK, có dấu (WaveOut) => WaveG5); --1994, 783,99 Hz Lưu ý_Gs5: Bản đồ cổng Wave_Generator (Kích hoạt => O5 (8), Freq_Cnt => X "075A", wavegenCLK => CLK, có dấu (WaveOut) => WaveGs5); - 1882, 830,61 Hz Lưu ý_A5: Bản đồ cổng Wave_Generator (Trigger => O5 (9), Freq_Cnt => X "06F0", wavegenCLK => CLK, có dấu (WaveOut) => WaveA5); --1776, 880,00 Hz Note_As5: Bản đồ cổng Wave_Generator (Trigger => O5 (10), Freq_Cnt => X "068C", wavegenCLK => CLK, có dấu (WaveOut) => WaveAs5); - 1676, 932,33 Hz Lưu ý_B5: Bản đồ cổng Wave_Generator (Trigger => O5 (11), Freq_Cnt => X "062E", wavegenCLK => CLK, có dấu (WaveOut) => WaveB5); --1582, 987,77 Hz Lưu ý_C6: Bản đồ cổng Wave_Generator (Trigger => O5 (12), Freq_Cnt => X "05D6", wavegenCLK => CLK, có dấu (WaveOut) => WaveC6); --1494, 1046,5 Hz ------------ lưu ý logic lựa chọn ------------ C4 <= "0000" & O4 (0); Cs4 <= "0000" & O4 (1); D4 <= "0000" & O4 (2); Ds4 <= "0000" & O4 (3); E4 <= "0000" & O4 (4); F4 <= "0000" & O4 (5); Fs4 <= "0000" & O4 (6); G4 <= "0000" & O4 (7); Gs4 <= "0000" & O4 (8); A4 <= "0000" & O4 (9); As4 <= "0000" & O4 (10); B4 <= "0000" & O4 (11); C5 <= "0000" & O5 (0); Cs5 <= "0000" & O5 (1); D5 <= "0000" & O5 (2); Ds5 <= "0000" & O5 (3); E5 <= "0000" & O5 (4); F5 <= "0000" & O5 (5); Fs5 <= "0000" & O5 (6); G5 <= "0000" & O5 (7); Gs5 <= "0000" & O5 (8); A5 <= "0000" & O5 (9); As5 <= "0000" & O5 (10); B5 <= "0000" & O5 (11); C6 <= "0000" & O5 (12); cntC4 <= C4; cntCs4 <= C4 + Cs4; cntD4 <= C4 + Cs4 + D4; cntDs4 <= C4 + Cs4 + D4 + Ds4; cntE4 <= C4 + Cs4 + D4 + Ds4 + E4; cntF4 <= C4 + Cs4 + D4 + Ds4 + E4 + F4; cntFs4 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4; cntG4 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4; cntGs4 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4; cntA4 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4; cntAs4 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4; cntB4 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4; cntC5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5; cntCs5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5; cntD5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5; cntDs5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5; cntE5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5 + E5; cntF5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5 + E5 + F5; cntFs5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5 + E5 + F5 + Fs5; cntG5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5 + E5 + F5 + Fs5 + G5; cntGs5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5 + E5 + F5 + Fs5 + G5 + Gs5; cntA5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5 + E5 + F5 + Fs5 + G5 + Gs5 + A5; cntAs5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5 + E5 + F5 + Fs5 + G5 + Gs5 + A5 + As5; cntB5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5 + E5 + F5 + Fs5 + G5 + Gs5 + A5 + As5 + B5; cntC6 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5 + E5 + F5 + Fs5 + G5 + Gs5 + A5 + As5 + B5 + C6; Lựa chọn: quy trình (WaveC4, WaveCs4, WaveD4, WaveDs4, WaveE4, WaveF4, WaveFs4, WaveG4, WaveGs4, WaveA4, WaveAs4, WaveB4, WaveC5, WaveCs5, WaveD5, WaveDs5, WaveE5, WaveF5, WaveFs5, WaveAs5, WaveGs5, WaveGs5 WaveB5, WaveC6) bắt đầu if (cntC6 = "00000") then --------------- nếu không có tín hiệu nào được tạo ra Wave0 <= "0000000000"; Wave1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 <= "0000000000"; else if (O4 (0) = '1') then ------------------- ghi chú C4 đã phát Wave0 Wave0 Wave1 lỗi Wave0 Wave1 Wave2 lỗi Wave0 Wave1 Wave2 Wave3 lỗi Wave0 Wave1 Lỗi Wave2 Wave3 Lỗi Wave0 Wave1 Wave2 Wave3 lỗi Wave0 Wave1 Wave2 Wave3 lỗi Wave0 Wave1 Wave2 Wave3 lỗi Wave0 Wave1 Wave2 Wave3 lỗi Wave0 Wave1 Wave2 Wave3 lỗi Wave0 Wave1 Wave2 Wave3 lỗi Wave0 Wave1 Wave2 Wave3 lỗi Wave0 Wave1 Wave2 Wave3 lỗi Wave0 Wave1 Wave2 Wave3 lỗi Wave0 Wave1 Lỗi Wave2 Wave3 Lỗi Wave0 Wave1 Wave2 Wave3 lỗi Wave0 Wave1 Wave2 Wave3 lỗi Wave0 Wave1 Wave2 Wave3 lỗi Wave0 Wave1 Wave2 Wave3 lỗi Wave0 Wave1 Wave2 Wave3 lỗi Wave0 Wave1 Wave2 Wave3 lỗi Wave0 Wave1 Wave2 Wave3 lỗi Wave0 Wave1 Wave2 Wave3 lỗi Wave0 = SóngC6; Wave1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 Wave1 <= WaveC6; Wave2 <= "0000000000"; Wave3 Wave2 <= WaveC6; Lỗi Wave3 Wave3 Wave1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 Wave2 <= "0000000000"; Wave3 Lỗi Wave3 <= '1'; trường hợp kết thúc; kết thúc nếu; kết thúc nếu; kết thúc quá trình; ------------- bộ cộng sóng sin -------------------- WaveSum <= STD_LOGIC_VECTOR (Wave0 + Wave1 + Wave2 + Wave3); --------- tạo sóng sin tích cực cho pwm --------------------- positiveWaveSum <= not WaveSum (9) & WaveSum (8 xuống 0); ------------- Trình tạo PWM --------------------- quy trình (CLK) - số lượng biến: không dấu (1 xuống 0): = to_unsigned (0, 2); bắt đầu if (tăng_edge (CLK)) then --count: = count + 1; --if (count = to_unsigned (4, 2)) then --count: = to_unsigned (0, 2); --if (PWM = to_ if (PWM <ping_length) then output <= '1'; else output <= '0'; end if; PWM <= PWM + 1; ping_length <= unsigned (positiveWaveSum); --end nếu; kết thúc nếu; kết thúc quá trình; kết thúc Hành vi;

4 Bộ chọn Lưu ý Phần khó nhất của dự án này là chỉ chọn bốn tần số. Chúng tôi đã làm điều đó với toàn bộ câu lệnh lotta IF và chúng tôi sử dụng các tín hiệu thay vì các biến để quá trình có thể được mô phỏng và gỡ lỗi. Chúng tôi đã thử các phương pháp khác bằng cách sử dụng biến và vòng lặp FOR, nhưng gặp phải lỗi thời gian chạy. Vì vậy, cuối cùng, chúng tôi quyết định rằng nếu nó hoạt động, chúng tôi sẽ để nó yên. Không sửa cái gì mà amirite không bị hỏng?

Bốn sóng đầu ra được gắn nhãn Wave0, Wave1, Wave2, Wave3 - đây là những thứ sẽ được thêm vào với nhau để tạo thành đầu ra cuối cùng.

Nhìn vào mã, bạn sẽ thấy một loạt các tín hiệu có nhãn C4, Cs4, D4, Ds4, v.v. Đây là các tín hiệu 5 bit lấy kích hoạt tương ứng từ O4 (quãng tám 4) hoặc O5 (quãng tám 5) và tạo ra chúng 5-bit để thêm.

Tiếp theo, các biến cntC4, cntCs4, v.v. đại diện cho số lượng nốt nhạc thấp hơn nốt nhạc đích đã được chơi, bao gồm cả nốt nhạc đích. Ví dụ: nếu C4, E4, G4, A # 4 và D5 được chơi (hợp âm C9) thì cntC4 sẽ là 1, cntE4 sẽ là 2, cntG4 sẽ là 3, v.v.

Sau đó, bất cứ khi nào một nốt nhạc được phát, số đếm của nốt nhạc đích sẽ được kiểm tra để xem nơi móc tín hiệu nốt nhạc lên. Ví dụ, nếu nốt D5 được chơi (có nghĩa là O5 (2) cao) và cntD5 là 3, thì hiện tại có 3 nốt đang được chơi, với 2 nốt thấp hơn D5, vì vậy chúng tôi sẽ nối waveD5 thành Wave2 (sóng thứ ba đếm tín hiệu từ Wave0). Ngoài ra, nếu cntD5 là 5, thì hiện tại có 5 nốt đang được chơi, với 4 nốt thấp hơn D5, vì vậy chúng tôi sẽ chỉ để waveD5 treo và không làm gì với nó.

Sau đó, các câu lệnh IF được lặp lại để bao gồm các trường hợp cho tất cả 25 ghi chú.

Trình quảng cáo biên độ

Sau khi 4 sóng thấp nhất được chọn, chúng ta phải cộng chúng lại với nhau. Lý do chúng tôi sẽ chỉ thêm bốn nốt lại với nhau là vì ý tưởng PWM chúng tôi đang sử dụng cho đầu ra của mình chỉ có thể có độ phân giải nhất định cho đến khi PWM chạy quá chậm và người nói sẽ bắt đầu nhận sóng vuông PWM. Ví dụ: nếu chúng tôi sử dụng độ phân giải 8192 (13 bit), mỗi điểm trong số 8192 điểm đó phải tương ứng với một cạnh tăng của đồng hồ tích hợp. Vì vậy, 100MHz / 8192 = 12,2kHz, nằm trong phạm vi thính giác của con người.

Việc bổ sung các biên độ thực tế rất đơn giản, bạn chỉ cần đảm bảo rằng nó có thể chạy rất nhanh.

Đầu ra PWM

Chu kỳ nhiệm vụ của PWM sẽ đại diện cho biên độ của sóng đầu ra của chúng tôi tại thời điểm đó. Ví dụ: nếu chúng ta có dải biên độ từ 0 đến 128, 0 sẽ là chu kỳ nhiệm vụ 0%, 64 sẽ là 50%, 128 sẽ là 100%, v.v. PWM này sẽ chạy cực nhanh (của chúng ta là 97,6 kHz), nhanh đến mức người nói sẽ không nhận ra các sóng vuông riêng lẻ và thay vào đó nhìn vào điện áp trung bình, tạo ra tín hiệu “tương tự” của chúng tôi.

Tệp Ràng buộc

Có thể bạn đã kết nối phần cứng của mình theo cách khác, vì vậy chỉ cần đảm bảo tệp ràng buộc khớp với nhau.

Bước 5: Tải xuống mã

Dưới đây là mã, cả ở định dạng.txt và.vhd cho Vivado. Wave_Generator là mô-đun phụ của bộ tạo sóng và Two_Octave_Synth là mô-đun trên cùng với mọi thứ khác.

Đề xuất: