สารบัญ:

Basy3 FPGA Digital Audio Synthesizer: 5 ขั้นตอน
Basy3 FPGA Digital Audio Synthesizer: 5 ขั้นตอน

วีดีโอ: Basy3 FPGA Digital Audio Synthesizer: 5 ขั้นตอน

วีดีโอ: Basy3 FPGA Digital Audio Synthesizer: 5 ขั้นตอน
วีดีโอ: FPGA Programming with Verilog : Full Adder BASYS3 2024, พฤศจิกายน
Anonim
Image
Image
ซินธิไซเซอร์เสียงดิจิตอล Basy3 FPGA
ซินธิไซเซอร์เสียงดิจิตอล Basy3 FPGA
ซินธิไซเซอร์เสียงดิจิตอล Basy3 FPGA
ซินธิไซเซอร์เสียงดิจิตอล Basy3 FPGA

ซินธิไซเซอร์คีย์บอร์ดคลื่นไซน์ดิจิตอลนี้จะนำอินพุตของผู้ใช้ผ่านชุดสวิตช์ชั่วขณะที่วางเหมือนแป้นพิมพ์และส่งสัญญาณเสียงผ่านลำโพง ตามอินพุตของผู้ใช้ อุปกรณ์จะสร้างคลื่นไซน์ของความถี่ต่างๆ ตั้งแต่ C4 ถึง C6 ผู้ใช้สามารถป้อนโน้ตจาก C4 ถึง C6 (รวม 25 โน้ต) และสูงสุดสี่ปุ่มพร้อมกัน - หากกดปุ่มมากกว่าสี่ปุ่ม สี่เสียงต่ำสุดจะถูกเล่น

โครงการนี้ทำโดย Ryan Morris และ Mavis Tsoi สำหรับคลาส Cal Poly CPE 133 Digital Design:)

ขั้นตอนที่ 1: ทฤษฎี

บอร์ด FPGA สามารถส่งสัญญาณดิจิตอลเท่านั้น กล่าวอีกนัยหนึ่ง สามารถผลิตแรงดันไฟฟ้าสูง (3.3V) หรือแรงดันไฟฟ้าต่ำ (0V) เท่านั้น อย่างไรก็ตาม สัญญาณเสียงเป็นแบบแอนะล็อกและสามารถเพิ่มแรงดันไฟฟ้าได้หลายเท่า เพื่อหลีกเลี่ยงปัญหานี้ เราจะใช้สัญญาณ PWM (การปรับความกว้างพัลส์) เพื่อจำลองคลื่นแอนะล็อก หากคุณไม่รู้ว่า PWM คืออะไร ให้ลองดูที่

ขั้นตอนที่ 2: ส่วนผสม & เครื่องมือ

  • คอมพิวเตอร์ที่ติดตั้ง Vivado
  • เราจะใช้ Vivado เวอร์ชัน 2017.2
  • บอร์ด Basy3 FPGA
  • 25 SPDT Limit Switches (เราใช้สิ่งเหล่านี้)
  • สายจัมเปอร์ 30 เส้น (ตัวผู้ปลายข้างหนึ่ง ปลายอีกข้างไม่สำคัญ) 12 นิ้ว
  • เครื่องตัดลวด
  • เครื่องปอกสายไฟ
  • ลวดสำรองสำหรับการบัดกรี
  • ประสานแกนเรซิน
  • หัวแร้ง
  • แจ็คเสียงตัวเมีย ¼”
  • เครื่องขยายเสียง/ลำโพง
  • บางอย่างสำหรับติดสวิตช์ (เราใช้โปรโตบอร์ด + กล่องไม้)

ขั้นตอนที่ 3: การติดตั้งสายไฟและฮาร์ดแวร์

การติดตั้งสายไฟและฮาร์ดแวร์
การติดตั้งสายไฟและฮาร์ดแวร์
การติดตั้งสายไฟและฮาร์ดแวร์
การติดตั้งสายไฟและฮาร์ดแวร์
การติดตั้งสายไฟและฮาร์ดแวร์
การติดตั้งสายไฟและฮาร์ดแวร์

ระบบสถาปัตยกรรม

ดูรูปที่ 1: 25 อินพุตที่ใช้ได้ → บอร์ด Basy3 → แอมพลิฟายเออร์และลำโพง

เอาท์พุต

ดูรูปที่ 2: บอร์ด Basy3 → แจ็คเสียงตัวเมีย 1/2 → ลำโพง (พร้อมแอมพลิฟายเออร์)

ป้อนข้อมูล

การเชื่อมต่อ pmod บนบอร์ด Basys3 ต้องเชื่อมต่อกับกราวด์เพื่อดูอินพุตที่ต่ำ และจะไม่ทำงานอย่างถูกต้องหากปล่อยไว้เป็นวงจรเปิด ด้วยเหตุนี้ เราจึงต้องใช้สวิตช์ SPDT สำหรับแป้นบันทึกย่อทั้งหมดของเรา โดยทั่วไปแล้ว สวิตช์ SPDT จะอนุญาตให้ผู้ใช้สลับระหว่างวงจรต่างๆ เมื่อกด ดังนั้นเราจะใช้เป็น "ปุ่ม" เพื่อป้อนสัญญาณต่ำ (0V) หรือสูง (3.3V) ไปยังบอร์ด Basy3

สวิตช์แต่ละตัวจะมีขั้วต่อ NO (เปิดตามปกติ) ที่เชื่อมต่อกับขั้วต่อ 3.3V, NC (ปิดปกติ) ที่เชื่อมต่อกับ GND และขั้วต่อ COM (ทั่วไป) ที่เชื่อมต่อกับอินพุต FPGA ดูรูปที่ 3

เนื่องจากเรามีลิมิตสวิตช์ 25 ตัว พวกเขาทั้งหมดจะใช้สาย 3.3V ทั่วไปและสาย GND ทั่วไป จากนั้นสายสัญญาณจากลิมิตสวิตช์แต่ละอันจะรวมกันเป็นกลุ่มละ 8 ตัวและเชื่อมต่อกับการเชื่อมต่อ pmod บนบอร์ด Basys3 โดยใช้สายจัมเปอร์แบบซิปได้เพื่อลดความยุ่งเหยิงที่เราจะเกิดขึ้น ดู รูปภาพ 4 หรือตัวอย่างแปดปุ่มแรก

ขั้นตอนที่ 4: การตั้งค่า VHDL (Vivado)

การตั้งค่า VHDL (Vivado)
การตั้งค่า VHDL (Vivado)
การตั้งค่า VHDL (Vivado)
การตั้งค่า VHDL (Vivado)

เครื่องกำเนิดคลื่นไซน์และเครื่องกำเนิด PWM ได้รับการทดสอบก่อนเพื่อให้แน่ใจว่าแนวคิดของเราทำงาน จากนั้นตัวจำกัดอินพุตและแอมพลิจูดแอดเดอร์/ชิฟเตอร์ถูกรวมเข้าด้วยกัน รายละเอียดของฟังก์ชันและ I/O ของแต่ละบล็อกกระบวนการดังแสดงในรูป รหัสแสดงอยู่ด้านล่าง แต่ยังแนบเป็นไฟล์ VHD และ txt หากมีความคลาดเคลื่อน ให้ไปที่ไฟล์ VHD

BTW: เราอาจจะทำให้บรรทัดของเราสั้นลง แต่การฝังโค้ดบน Instructables ก็กลายเป็นเรื่องน่ารำคาญที่จะจัดการด้วย ดังนั้นการเว้นวรรคจึงไม่มากที่สุดและไม่มีการเน้นไวยากรณ์ หากคุณมี Vivado และต้องการทำตามโค้ด เราขอแนะนำให้คุณดาวน์โหลดไฟล์

ขั้นแรก ให้ดูที่โมดูล Sine Wave Generator

ไลบรารี IEEE ใช้ IEEE. STD_LOGIC_1164. ALL; ใช้ IEEE. NUMERIC_STD. ALL; เอนทิตี Wave_Generator คือพอร์ต (Trigger: ใน STD_LOGIC; -- กดปุ่ม Freq_Cnt: ใน STD_LOGIC_VECTOR(15 downto 0); -- Counter value = 100MHz / (Note Frequency*64 Divisions of Sine Wave) (ปัดเศษเป็นจำนวนที่ใกล้เคียงที่สุด) -- เปลี่ยนชื่อ จากความถี่ wavegenCLK: ใน STD_LOGIC; -- Basy3 100MHz CLK WaveOut: ออก STD_LOGIC_VECTOR(9 downto 0)); -- ลงนามความกว้างของคลื่นสิ้นสุด Wave_Generator; สถาปัตยกรรม พฤติกรรมของ Wave_Generator เป็นสัญญาณ i: ช่วงจำนวนเต็ม 0 ถึง 64:= 0; -- ดัชนีของประเภทหน่วยความจำแอมพลิจูด memory_type คืออาร์เรย์ (0 ถึง 63) ของช่วงจำนวนเต็ม -64 ถึง 63; -- สร้างธนาคารหน่วยความจำ (ROM) เพื่อเก็บค่าแอมพลิจูด -- RAM หรือ ROM นี้แค่สงสัยว่า… แอมพลิจูดของสัญญาณ: 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); -- ธนาคารหน่วยความจำแอมพลิจูดสำหรับกระบวนการเริ่มต้นคลื่นไซน์ (wavegenCLK, ทริกเกอร์) ตัวนับตัวแปร: ไม่ได้ลงชื่อ (15 ลงไป 0):= to_unsigned (0, 16); -- ตัวนับนาฬิกา เปลี่ยนชื่อจาก count1 เริ่มต้นถ้า (rising_edge(wavegenCLK)) แล้วถ้า (Trigger = '1') แล้ว -- คีย์ถูกกด counter:= counter + 1; ถ้า (ตัวนับ = ไม่ได้ลงนาม (Freq_Cnt)) ดังนั้น - Freq_Cnt = 100Mhz / (บันทึกความถี่ * 64 ส่วนของคลื่นไซน์) - รีเซ็ตตัวนับและกำหนดข้อมูลแอมพลิจูดให้กับตัวนับเอาต์พุต:= to_unsigned (0, 16); WaveOut <= STD_LOGIC_VECTOR (to_signed (แอมพลิจูด (i), 10)); -- เพิ่ม i สำหรับการอ่านครั้งต่อไป i <= i + 1; -- รีเซ็ต i หากคลื่นไซน์หนึ่งอันเสร็จสิ้น if (i = 63) แล้ว i <= 0; สิ้นสุดถ้า; สิ้นสุดถ้า; -- (ตัวนับ = ไม่ได้ลงนาม (Freq_Cnt)) อื่น ๆ -- ไม่ได้กดปุ่ม -- รีเซ็ตเอาต์พุต ดัชนีแอมพลิจูด และตัวนับ WaveOut <= "0000000000"; ผม <= 0; ตัวนับ:= to_unsigned(0, 16); --output Amplitude = -64 เมื่อไม่มีโน้ตเล่นสิ้นสุดหาก; -- (ทริกเกอร์ = '1') สิ้นสุด if; -- (rising_edge(CLK)) สิ้นสุดกระบวนการ; สิ้นสุดพฤติกรรม;

เราจะสร้างคลื่นไซน์ดิจิตอลใน Basy3 โดยใช้นาฬิกาภายในและ ROM ROM นี้จะเก็บค่า 64 ค่าที่แสดงถึง 64 แอมพลิจูดบนคลื่นไซน์ ดูรูปที่ 1 ค่า 64 ค่าที่เราใช้จำลองคลื่นไซน์ที่มีความละเอียดค่อนข้างดี

การใช้นาฬิกาภายใน เรานับเป็นค่าที่แทนความเร็วนาฬิกาหารด้วยความถี่ของคลื่นที่เราต้องการและ 64: Clk div = 100MHz / (Freq * 64) ทุกครั้งที่ตัวนับของเราถึงค่านั้น เราจะเรียกตัวเลขจาก ROM และส่งออกจากโมดูลเครื่องกำเนิดคลื่นของเรา ความถี่ของคลื่นของเราจะขึ้นอยู่กับความเร็วที่เราเรียกว่าแอมพลิจูดเหล่านี้

เราจะมีโมดูลย่อย 25 โมดูล แต่ละโมดูลจะเชื่อมโยงกับความถี่/บันทึกหนึ่งรายการ

นี่คือโค้ดที่เหลือที่เรียกใช้โมดูล Sine Wave Generator:

ไลบรารี IEEE ใช้ IEEE. STD_LOGIC_1164. ALL; ใช้ IEEE. NUMERIC_STD. ALL; เอนทิตี Two_Octave_Synth คือพอร์ต (CLK: ใน STD_LOGIC; O4: ใน STD_LOGIC_VECTOR (11 ลดลงเป็น 0); O5: ใน STD_LOGIC_VECTOR (12 ลดลงเป็น 0); เอาต์พุต: ออก STD_LOGIC); จบ Two_Octave_Synth; สถาปัตยกรรม พฤติกรรมของ Two_Octave_Synth เป็นส่วนประกอบ Wave_Generator คือ Port (Trigger: ใน STD_LOGIC; Freq_Cnt: ใน STD_LOGIC_VECTOR(15 downto 0); wavegenCLK: ใน STD_LOGIC; WaveOut: out STD_LOGIC_VECTOR(9 downto 0)); ส่วนประกอบท้าย ---------------------------------- สัญญาณออกจากเครื่องกำเนิดคลื่น ------------------ ----- สัญญาณ WaveC4, WaveCs4, WaveD4, WaveDs4, WaveE4, WaveF4, WaveFs4, WaveG4, WaveGs4, WaveA4, WaveAs4, WaveB4, WaveC5, WaveCs5, WaveD5, WaveDs5, WaveE5, WaveF5, WaveFs5, WaveG5, WaveGs5, WaveGs5 WaveAs5, WaveB5, WaveC6: ลงนามแล้ว (9 เหลือ 0); -------------------------------- สำหรับตรรกะการเลือกโน้ต -------------- ------ สัญญาณ 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: ไม่ได้ลงนาม (4 เหลือ 0); สัญญาณ cntC4, cntCs4, cntD4, cntDs4, cntE4, cntF4, cntFs4, cntG4, cntGs4, cntA4, cntAs4, cntB4, cntC5, cntCs5, cntD5, cntDs5, cntE5, cntF5, cntCs5, cntD5, cntDs5, cntE5, cntF5: ไม่ได้ลงนาม (4 เหลือ 0); สัญญาณผิดพลาด: STD_LOGIC; ----------------------------------- สำหรับการเพิ่มคลื่นไซน์ ----------- --------------- สัญญาณ Wave0, Wave1, Wave2, Wave3: ลงนามแล้ว (9 ลดลงเป็น 0); --สัญญาณจากสัญญาณเอาท์พุตของโมดูล Wave Generator WaveSum: STD_LOGIC_VECTOR (9 ลดลงเป็น 0); --สัญญาณสำหรับคลื่นไซน์รวม (คำชมเชยของ 2 -512 ถึง 511) สัญญาณ positiveWaveSum: STD_LOGIC_VECTOR(9 ลดลงเหลือ 0); --unsigned 0 ถึง 1023 สำหรับใช้ในเครื่องกำเนิด PWM ----------------------------------- สำหรับการสร้าง PWM ------------------------------- สัญญาณ ping_length: unsigned (9 downto 0):= unsigned(positiveWaveSum); --signal off_length: unsigned (6 ลดลง 0):= to_unsigned(127, 7) - unsigned(WAVE); สัญญาณ PWM: unsigned (9 ลดลง 0):= to_unsigned(0, 10); เริ่ม Note_C4: Wave_Generator พอร์ตแมป (Trigger => O4(0), Freq_Cnt => X"1755", wavegenCLK => CLK, ลงชื่อ (WaveOut) => WaveC4); --5973, 261.63 Hz Note_Cs4: Wave_Generator port map (Trigger => O4(1), Freq_Cnt => X"1606", wavegenCLK => CLK, signed(WaveOut) => WaveCs4);--5638, 277.18 Hz Note_D4: แผนที่พอร์ต Wave_Generator (ทริกเกอร์ => O4(2), Freq_Cnt => X"14C9", wavegenCLK => CLK, ลงชื่อ (WaveOut) => WaveD4); --5321, 293.66 Hz Note_Ds4: Wave_Generator port map (Trigger => O4(3), Freq_Cnt => X"139F", wavegenCLK => CLK, signed(WaveOut) => WaveDs4);--5023, 311.13 Hz Note_E4: แผนที่พอร์ต Wave_Generator (ทริกเกอร์ => O4 (4), Freq_Cnt => X"1285", wavegenCLK => CLK, ลงนาม (WaveOut) => WaveE4); --4741, 329.63 Hz Note_F4: Wave_Generator port map (Trigger => O4(5), Freq_Cnt => X"117B", wavegenCLK => CLK, signed(WaveOut) => WaveF4); --4475, 349.23 Hz Note_Fs4: Wave_Generator port map (Trigger => O4(6), Freq_Cnt => X"1080", wavegenCLK => CLK, signed(WaveOut) => WaveFs4);--4224, 369.99 Hz Note_G4: แผนที่พอร์ต Wave_Generator (ทริกเกอร์ => O4 (7), Freq_Cnt => X"0F92", wavegenCLK => CLK, ลงชื่อ (WaveOut) => WaveG4); --3986, 392.00 Hz Note_Gs4: Wave_Generator port map (Trigger => O4(8), Freq_Cnt => X"0EB3", wavegenCLK => CLK, signed(WaveOut) => WaveGs4);--3763, 415.30 Hz Note_A4: แผนที่พอร์ต Wave_Generator (ทริกเกอร์ => O4 (9), Freq_Cnt => X"0DE0", wavegenCLK => CLK, ลงชื่อ (WaveOut) => WaveA4); ---3552, 440.00 Hz Note_As4: Wave_Generator port map (Trigger => O4(10), Freq_Cnt => X"0D18", wavegenCLK => CLK, signed(WaveOut) => WaveAs4);--3352, 466.16 Hz Note_B4: แผนที่พอร์ต Wave_Generator (ทริกเกอร์ => O4 (11), Freq_Cnt => X"0C5C", wavegenCLK => CLK, ลงชื่อ (WaveOut) => WaveB4); ---3164, 493.88 เฮิร์ตซ์ -------------------------------------------- -------------------------------------------------- ---------------------------- Note_C5: Wave_Generator พอร์ตแมป (Trigger => O5(0), Freq_Cnt => X"0BAB", wavegenCLK => CLK ลงนามแล้ว (WaveOut) => WaveC5); --2987, 523.25 Hz Note_Cs5: Wave_Generator port map (Trigger => O5(1), Freq_Cnt => X"0B03", wavegenCLK => CLK, signed(WaveOut) => WaveCs5);--2819, 554.37 Hz Note_D5: แผนที่พอร์ต Wave_Generator (ทริกเกอร์ => O5(2), Freq_Cnt => X"0A65", wavegenCLK => CLK, ลงชื่อ (WaveOut) => WaveD5); --2661, 587.33 Hz Note_Ds5: Wave_Generator port map (Trigger => O5(3), Freq_Cnt => X"09D0", wavegenCLK => CLK, signed(WaveOut) => WaveDs5);--2512, 622.25 Hz Note_E5: แผนที่พอร์ต Wave_Generator (ทริกเกอร์ => O5 (4), Freq_Cnt => X"0943", wavegenCLK => CLK, ลงชื่อ (WaveOut) => WaveE5); --2371, 659.25 Hz Note_F5: แผนที่พอร์ต Wave_Generator (ทริกเกอร์ => O5 (5)), Freq_Cnt => X"08Be", wavegenCLK => CLK, ลงนาม (WaveOut) => WaveF5); ---2238, 698.46 Hz Note_Fs5: Wave_Generator port map (Trigger => O5(6), Freq_Cnt => X"0840", wavegenCLK => CLK, signed(WaveOut) => WaveFs5);--2112, 739.99 Hz Note_G5: แผนที่พอร์ต Wave_Generator (ทริกเกอร์ => O5 (7), Freq_Cnt => X"07CA", wavegenCLK => CLK, ลงชื่อ (WaveOut) => WaveG5); -- 1994, 783.99 Hz Note_Gs5: Wave_Generator port map (Trigger => O5(8), Freq_Cnt => X"075A", wavegenCLK => CLK, signed(WaveOut) => WaveGs5);--1882, 830.61 Hz Note_A5: แผนที่พอร์ต Wave_Generator (ทริกเกอร์ => O5 (9), Freq_Cnt => X"06F0", wavegenCLK => CLK, ลงชื่อ (WaveOut) => WaveA5); ---1776, 880.00 Hz Note_As5: Wave_Generator port map (Trigger => O5(10), Freq_Cnt => X"068C", wavegenCLK => CLK, signed(WaveOut) => WaveAs5);--1676, 932.33 Hz Note_B5: แผนที่พอร์ต Wave_Generator (Trigger => O5 (11)), Freq_Cnt => X"062E", wavegenCLK => CLK, ลงชื่อ (WaveOut) => WaveB5); ---1582, 987.77 Hz Note_C6: Wave_Generator port map (Trigger => O5(12), Freq_Cnt => X"05D6", wavegenCLK => CLK, signed(WaveOut) => WaveC6); ---1494, 1046.5 Hz ------------ ตรรกะการเลือกโน้ต ------------ 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; การเลือก: กระบวนการ (WaveC4, WaveCs4, WaveD4, WaveDs4, WaveE4, WaveF4, WaveFs4, WaveG4, WaveGs4, WaveA4, WaveAs4, WaveB4, WaveC5, WaveCs5, WaveD5, WaveDs5, WaveE5, WaveF5, WaveFs5, WaveG5, WaveA5, WaveGs) WaveB5, WaveC6) เริ่มต้นหาก (cntC6 = "000000") จากนั้น --------------- หากไม่มีการสร้างสัญญาณ Wave0 <= "0000000000"; คลื่น 1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 <= "0000000000"; อื่น ๆ ถ้า (O4(0) = '1') แล้ว ------------------- หมายเหตุ C4 เล่น Wave0 Wave0 Wave1 ข้อผิดพลาด Wave0 Wave1 Wave2 ข้อผิดพลาด Wave0 Wave1 Wave2 Wave3 ข้อผิดพลาด Wave0 Wave1 ข้อผิดพลาด Wave2 Wave3 Wave0 Wave1 Wave2 Wave3 ข้อผิดพลาด Wave0 Wave1 Wave2 Wave3 ข้อผิดพลาด Wave0 Wave1 Wave2 Wave3 ข้อผิดพลาด Wave0 Wave1 Wave2 Wave3 ข้อผิดพลาด Wave0 Wave1 Wave2 Wave3 ข้อผิดพลาด Wave0 Wave1 Wave2 Wave3 ข้อผิดพลาด Wave0 Wave1 Wave2 Wave3 ข้อผิดพลาด Wave0 Wave1 Wave2 Wave3 ข้อผิดพลาด Wave0 Wave1 ข้อผิดพลาด Wave2 Wave3 Wave0 Wave1 Wave2 Wave3 ข้อผิดพลาด Wave0 Wave1 Wave2 Wave3 ข้อผิดพลาด Wave0 Wave1 Wave2 Wave3 ข้อผิดพลาด Wave0 Wave1 Wave2 Wave3 ข้อผิดพลาด Wave0 Wave1 Wave2 Wave3 ข้อผิดพลาด Wave0 Wave1 Wave2 Wave3 ข้อผิดพลาด Wave0 Wave1 Wave2 Wave3 ข้อผิดพลาด Wave0 Wave1 Wave2 Wave3 ข้อผิดพลาด Wave0 < = WaveC6; คลื่น 1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 Wave1 <= WaveC6; Wave2 <= "0000000000"; Wave3 Wave2 <= WaveC6; ข้อผิดพลาด Wave3 Wave3 Wave1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 Wave2 <= "0000000000"; ข้อผิดพลาด Wave3 Wave3 <= '1'; กรณีสิ้นสุด; สิ้นสุดถ้า; สิ้นสุดถ้า; สิ้นสุดกระบวนการ -------------- แอดเดอร์เวฟไซน์-------------------- WaveSum <= STD_LOGIC_VECTOR(Wave0 + Wave1 + Wave2 + Wave3); --------- ทำให้คลื่นไซน์เป็นบวกสำหรับ pwm --------------- positiveWaveSum <= ไม่ใช่ WaveSum (9) & WaveSum (8 ลดลงเหลือ 0); -------------- เครื่องกำเนิด PWM --------------- กระบวนการ (CLK) -- จำนวนตัวแปร: ไม่ได้ลงชื่อ (1 ลดลงเป็น 0):= to_unsigned(0, 2); เริ่มต้นถ้า (rising_edge(CLK)) แล้ว --count:= count + 1; --if (count = to_unsigned(4, 2)) แล้ว --count:= to_unsigned(0, 2); --if (PWM = to_ if (PWM < ping_length) แล้วเอาต์พุต <= '1'; เอาต์พุตอื่น <= '0'; end if; PWM <= PWM + 1; ping_length <= unsigned (positiveWaveSum); --end if; end if; สิ้นสุดกระบวนการ; สิ้นสุดพฤติกรรม;

4 หมายเหตุ Selector ส่วนที่ยากที่สุดของโปรเจ็กต์นี้คือการเลือกความถี่เพียงสี่ความถี่ เราทำโดยใช้คำสั่ง IF จำนวนมาก และเราใช้สัญญาณแทนตัวแปรเพื่อให้สามารถจำลองและแก้จุดบกพร่องของกระบวนการได้ เราลองใช้วิธีอื่นโดยใช้ตัวแปรและ FOR ลูป แต่พบข้อผิดพลาดขณะทำงาน สุดท้ายแล้ว เราตัดสินใจว่าถ้ามันได้ผล เราจะปล่อยให้มันอยู่คนเดียวอย่าซ่อมสิ่งที่ไม่ใช่อามิไรต์เสีย?

คลื่นเอาต์พุตสี่คลื่นมีชื่อว่า Wave0, Wave1, Wave2, Wave3 ซึ่งเป็นสิ่งที่จะถูกรวมเข้าด้วยกันเพื่อสร้างเอาต์พุตสุดท้าย

เมื่อดูโค้ด คุณจะเห็นกลุ่มสัญญาณที่มีป้ายกำกับว่า C4, Cs4, D4, Ds4 เป็นต้น ซึ่งเป็นสัญญาณ 5 บิตที่รับทริกเกอร์ที่เกี่ยวข้องจาก O4 (อ็อกเทฟ 4) หรือ O5 (อ็อกเทฟ 5) มาสร้างเป็น 5 บิตสำหรับการเพิ่ม

ถัดไป ตัวแปร cntC4, cntCs4 ฯลฯ จะแสดงจำนวนโน้ตที่ต่ำกว่าโน้ตเป้าหมายที่เล่น รวมถึงโน้ตเป้าหมาย ตัวอย่างเช่น หากเล่น C4, E4, G4, A#4 และ D5 (คอร์ด C9) cntC4 จะเป็น 1, cntE4 จะเป็น 2, cntG4 จะเป็น 3 เป็นต้น

จากนั้น เมื่อใดก็ตามที่มีการเล่นโน้ต การนับสำหรับโน้ตเป้าหมายจะถูกตรวจสอบเพื่อดูว่าจะเชื่อมสัญญาณโน้ตไปที่ใด ตัวอย่างเช่น หากเล่นโน้ต D5 (ซึ่งหมายความว่า O5(2) สูง) และ cntD5 คือ 3 แสดงว่าขณะนี้มีการเล่นโน้ต 3 ตัว โดยที่ตัวโน้ตต่ำกว่า D5 2 ตัว เราจะขอ waveD5 กับ Wave2 (คลื่นลูกที่สาม) นับสัญญาณจาก Wave0) อีกทางหนึ่ง ถ้า cntD5 เป็น 5 แสดงว่าขณะนี้มีการเล่นโน้ตอยู่ 5 ตัว โดยมี 4 ตัวที่ต่ำกว่า D5 ดังนั้นเราจะปล่อยให้ waveD5 ค้างและไม่ทำอะไรกับมัน

คำสั่ง IF จะถูกทำซ้ำเพื่อให้ครอบคลุมกรณีสำหรับบันทึกย่อทั้ง 25 รายการ

แอมพลิจูดแอดเดอร์

หลังจากเลือกคลื่นต่ำสุด 4 คลื่นแล้ว เราต้องรวมเข้าด้วยกัน เหตุผลที่เราจะเพิ่มโน้ตสี่ตัวเข้าด้วยกันก็เพราะแนวคิด PWM ที่เราใช้สำหรับเอาต์พุตของเราสามารถมีความละเอียดได้เพียงบางส่วนเท่านั้นจนกว่า PWM จะทำงานช้าเกินไปและลำโพงจะเริ่มรับคลื่นสี่เหลี่ยม PWM ตัวอย่างเช่น หากเราใช้ความละเอียด 8192 (13 บิต) แต่ละ 8192 คะแนนจะต้องสอดคล้องกับขอบที่เพิ่มขึ้นของนาฬิกาออนบอร์ด ดังนั้น 100MHz / 8192 = 12.2kHz ซึ่งอยู่ในช่วงการได้ยินของมนุษย์

การเพิ่มแอมพลิจูดที่เกิดขึ้นจริงนั้นง่ายมาก คุณเพียงแค่ต้องแน่ใจว่ามันสามารถทำงานได้อย่างรวดเร็ว

เอาต์พุต PWM

รอบการทำงานของ PWM จะแสดงแอมพลิจูดของคลื่นเอาท์พุตของเราในขณะนั้น ตัวอย่างเช่น หากเรามีช่วงแอมพลิจูด 0 ถึง 128, 0 จะเป็นรอบการทำงาน 0%, 64 จะเป็น 50%, 128 จะเป็น 100% เป็นต้น PWM นี้จะทำงานเร็วมาก (ของเราคือ 97.6 kHz) เร็วมากจนผู้พูดจำคลื่นสี่เหลี่ยมแต่ละคลื่นไม่ได้ แต่ให้มองที่แรงดันไฟฟ้าเฉลี่ยแทน ทำให้เกิดสัญญาณ "แอนะล็อก" ของเรา

ไฟล์ข้อจำกัด

คุณอาจเชื่อมต่อฮาร์ดแวร์ของคุณแตกต่างออกไป ดังนั้น ตรวจสอบให้แน่ใจว่าไฟล์ข้อจำกัดตรงกัน

ขั้นตอนที่ 5: ดาวน์โหลดโค้ด

ด้านล่างนี้คือโค้ด ทั้งในรูปแบบ.txt และ.vhd สำหรับ Vivado Wave_Generator เป็นโมดูลย่อยของ wave generator และ Two_Octave_Synth เป็นโมดูลอันดับต้น ๆ ที่มีทุกอย่างอื่น

แนะนำ: