תוכן עניינים:

Basys3 FPGA אודיו דיגיטלי: 5 שלבים
Basys3 FPGA אודיו דיגיטלי: 5 שלבים

וִידֵאוֹ: Basys3 FPGA אודיו דיגיטלי: 5 שלבים

וִידֵאוֹ: Basys3 FPGA אודיו דיגיטלי: 5 שלבים
וִידֵאוֹ: MOON - 680D - DAC et lecteur réseau 2024, יולי
Anonim
Image
Image
Basys3 FPGA אודיו דיגיטלי
Basys3 FPGA אודיו דיגיטלי
Basys3 FPGA אודיו דיגיטלי
Basys3 FPGA אודיו דיגיטלי

סינתיסייזר מקלדת גל סינוס דיגיטלי זה יקח את כניסות המשתמש באמצעות סדרת מתגים רגעיים המונחים כמו מקלדת ויפיק גל שמע באמצעות רמקול. בהתבסס על כניסות משתמש, המכשיר ייצור גלי סינוס בתדרים שונים מ- C4 ועד C6. המשתמש יכול להזין הערות מ- C4 עד C6 (25 תווים בסך הכל), ועד ארבעה מקשים בו זמנית - אם תלחץ על יותר מארבעה מקשים, יושמעו ארבעת הצלילים הנמוכים ביותר.

הפרויקט הזה בוצע על ידי ריאן מוריס ומאוויס צוי לשיעור עיצוב דיגיטלי Cal Poly CPE 133 שלנו:)

שלב 1: תיאוריה

לוח FPGA יכול להוציא אותות דיגיטליים בלבד. במילים אחרות, הוא יכול לייצר רק מתח גבוה (3.3V) או מתח נמוך (0V). עם זאת, אותות שמע הינם אנלוגיים ויכולים להיות בעלי אינסוף מתחים במתח. כדי לעקוף זאת, נשתמש באות PWM (אפנון רוחב הדופק) כדי לחקות גל אנלוגי. אם אינך יודע מהו PWM, בדוק זאת:

שלב 2: רכיבים וכלים

  • מחשב עם Vivado מותקן
  • אנו נשתמש בגרסת Vivado 2017.2
  • לוח FPGA Basys3
  • 25 מתגי גבול SPDT (השתמשנו אלה)
  • 30 חוטי מגשר (קצה אחד זכר, קצה אחר לא משנה), 12 אינץ '
  • מספרי תיל
  • חשפניות חוטים
  • חוט חילוף להלחמה
  • הלחמה משרפת הליבה
  • מלחם
  • Jack”שקע שמע נשי
  • מגבר/רמקול
  • משהו להרכיב עליו את המתגים (השתמשנו בפרוטובארד + קופסת עץ)

שלב 3: התקנת חיווט וחומרה

התקנת חיווט וחומרה
התקנת חיווט וחומרה
התקנת חיווט וחומרה
התקנת חיווט וחומרה
התקנת חיווט וחומרה
התקנת חיווט וחומרה

אדריכלות מערכת

ראה איור 1: 25 כניסות זמינות → לוח Basys3 → מגבר ורמקול.

תְפוּקָה

ראה איור 2: לוח Basys3 → 1/2 שקע שמע נקבה → רמקול (עם מגבר)

קֶלֶט

חיבורי pmod בלוח Basys3 חייבים להיות מחוברים לקרקע על מנת לראות קלט נמוך ולא יפעלו כראוי אם יישארו כמעגל פתוח. בגלל זה, עלינו להשתמש במתגי SPDT עבור כל מפתחות ההערות שלנו. מתג SPDT בעצם מאפשר למשתמש לעבור בין מעגלים בלחיצה, לכן נשתמש בהם כ"כפתורים "שלנו כדי להזין אותות נמוכים (0V) או גבוהים (3.3V) ללוח Basys3.

בכל מתג יהיה מסוף 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 נבדקו תחילה על מנת לוודא שהרעיון שלנו פועל, ולאחר מכן משולבים מגביל הכניסה ומגדף המשרעת/המשנה. פרטי הפונקציה והקלט/פלט של כל בלוק תהליך הוא כפי שמוצג באיור. הקוד מוצג למטה, אך מצורף גם כקובצי VHD ו- txt. אם יש אי התאמות, עבור עם קבצי VHD.

BTW: כנראה שהיינו צריכים לקצר את השורות שלנו, אך גם הטמעת קוד ב- Instructables התבררה כמעצבנת למדי, כך שהמרווח אינו הגדול ביותר ואין הדגשת תחביר. אם יש לך Vivado ותרצה לעקוב אחר הקוד, אנו ממליצים לך פשוט להוריד את הקובץ.

ראשית, בואו נסתכל על מודול מחולל הגל הסיני.

ספריית IEEE; השתמש ב- IEEE. STD_LOGIC_1164. ALL; השתמש ב- IEEE. NUMERIC_STD. ALL; ישות Wave_Generator היא יציאה (טריגר: ב- STD_LOGIC; - לחיצת מקשים Freq_Cnt: ב- STD_LOGIC_VECTOR (15 עד 0); מ- Freq wavegenCLK: ב- STD_LOGIC; - Basys3 100MHz CLK WaveOut: החוצה STD_LOGIC_VECTOR (9 עד 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); - מונה מחלק השעונים, ששמו שונה מספירה 1 מתחיל אם (עולה_דג '(wavegenCLK)) ואז אם (טריגר =' 1 ') ואז- לוחצים על המקש counter: = counter + 1; אם (counter = unsigned (Freq_Cnt)) אז - Freq_Cnt = 100Mhz / (הערה freq * 64 מחלקות של גל הסינוס) - אפס מונה והקצה נתוני משרעת למונה הפלט: = to_unsigned (0, 16); WaveOut <= STD_LOGIC_VECTOR (to_signed (משרעת (i), 10)); - תוספת i לקריאה הבאה i <= i + 1; - אפס i אם גל סינוס אחד הושלם אם (i = 63) אז i <= 0; סוף אם; סוף אם; - (counter = unsigned (Freq_Cnt)) else- לא נלחץ על מקש- איפוס פלט, אינדקס משרעת ומונה WaveOut <= "0000000000"; i <= 0; counter: = to_unsigned (0, 16); -פלט אמפליטודה = -64 כאשר לא מנגנים פתק מסתיימים אם; - (טריגר = '1') סוף אם; - תהליך סיום (עולה_דג '(CLK)); סוף התנהגותי;

ניצור גל סינוס דיגיטלי ב- Basys3 באמצעות השעון הפנימי ו- ROM. ROM זה יאחסן 64 ערכים המייצגים 64 אמפליטודות על גל סינוס. ראה איור 1. 64 הערכים בהם אנו משתמשים מחקים גל סינוס ברזולוציה די טובה.

באמצעות השעון הפנימי, אנו סופרים לערך המייצג את מהירות השעון מחולק בתדירות הגל הרצוי לנו ו -64: Clk div = 100MHz / (Freq * 64) בכל פעם שהמונה שלנו מגיע לערך זה, אנו מתקשרים למספר את ה- ROM ושלח אותו ממודול מחולל הגלים שלנו. תדירות הגל שלנו תהיה תלויה בכמה מהר אנו מכנים אמפליטודות אלו.

יהיו לנו 25 תת-מודולים, כל אחד משויך לתדר/פתק אחד.

להלן קוד הקוד המכנה את המודולים של מחולל הגל הסיני:

ספריית 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 הוא יציאה (טריגר: ב- STD_LOGIC; Freq_Cnt: ב- STD_LOGIC_VECTOR (15 עד 0); wavegenCLK: ב STD_LOGIC; WaveOut: החוצה STD_LOGIC_VECTOR (9 למטה 0)); רכיב קצה; --------------------------- אותות פלט ממחולל הגלים ------------------ ----- אות WaveC4, WaveCs4, WaveD4, WaveDs4, WaveE4, WaveF4, WaveFs4, WaveG4, WaveGs4, WaveA4, WaveAs4, WaveB4, WaveC5, WaveCs5, WaveD5, WaveDs5, Wave5, Wave5, Wave5 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, cntCs, cnt5, cnt5, cnt5, cnt5, cnt5, cnt5s: ללא סימן (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); -מיועד 0 עד 1023, לשימוש בגנרטור PWM ----------------------------------- ליצירת PWM ------------------------------- אות ping_length: unsigned (9 downto 0): = unsigned (positiveWaveSum); -סימן off_length: unsigned (6 downto 0): = to_unsigned (127, 7) -unsigned (WAVE); אות PWM: unsigned (9 downto 0): = to_unsigned (0, 10); התחל Note_C4: מפת יציאת Wave_Generator (טריגר => O4 (0), Freq_Cnt => X "1755", wavegenCLK => CLK, חתום (WaveOut) => WaveC4); --5973, 261.63 הרץ Note_Cs4: מפת יציאת Wave_Generator (טריגר => O4 (1), Freq_Cnt => X "1606", wavegenCLK => CLK, חתום (WaveOut) => WaveCs4);-5638, 277.18 הרץ הערה_ד 4: מפת יציאת Wave_Generator (טריגר => O4 (2), Freq_Cnt => X "14C9", wavegenCLK => CLK, חתומה (WaveOut) => WaveD4); --5321, 293.66 הרץ Note_Ds4: מפת יציאת Wave_Generator (טריגר => O4 (3), Freq_Cnt => X "139F", wavegenCLK => CLK, חתום (WaveOut) => WaveDs4);-5023, 311.13 הרץ הערה_ E4: מפת יציאת Wave_Generator (טריגר => O4 (4), Freq_Cnt => X "1285", wavegenCLK => CLK, חתומה (WaveOut) => WaveE4); --4741, 329.63 הרץ Note_F4: מפת יציאת Wave_Generator (טריגר => O4 (5), Freq_Cnt => X "117B", wavegenCLK => CLK, חתום (WaveOut) => WaveF4); --4475, 349.23 הרץ Note_Fs4: מפת יציאת Wave_Generator (טריגר => O4 (6), Freq_Cnt => X "1080", wavegenCLK => CLK, חתום (WaveOut) => WaveFs4);-4224, 369.99 הרץ הערה_ג 4: מפת יציאת Wave_Generator (טריגר => O4 (7), Freq_Cnt => X "0F92", wavegenCLK => CLK, חתומה (WaveOut) => WaveG4); --3986, 392.00 Hz Note_Gs4: מפת יציאת Wave_Generator (טריגר => O4 (8), Freq_Cnt => X "0EB3", wavegenCLK => CLK, חתום (WaveOut) => WaveGs4);-3763, 415.30 הרץ הערה_א 4: מפת יציאת Wave_Generator (טריגר => O4 (9), Freq_Cnt => X "0DE0", wavegenCLK => CLK, חתומה (WaveOut) => WaveA4); --3552, 440.00 Hz Note_As4: מפת יציאת Wave_Generator (טריגר => O4 (10), Freq_Cnt => X "0D18", wavegenCLK => CLK, חתומה (WaveOut) => WaveAs4);-3352, 466.16 הרץ הערה_ב 4: מפת יציאת Wave_Generator (טריגר => O4 (11), Freq_Cnt => X "0C5C", wavegenCLK => CLK, חתומה (WaveOut) => WaveB4); --3164, 493.88 הרץ -------------------------------------------- -------------------------------------------------- --------------------------- הערה_ C5: מפת יציאת Wave_Generator (טריגר => O5 (0), Freq_Cnt => X "0BAB", wavegenCLK => CLK, חתום (WaveOut) => WaveC5); --2987, 523.25 הרץ Note_Cs5: מפת יציאת Wave_Generator (טריגר => O5 (1), Freq_Cnt => X "0B03", wavegenCLK => CLK, חתום (WaveOut) => WaveCs5);-2819, 554.37 הרץ הערה_ד 5: מפת יציאת Wave_Generator (טריגר => O5 (2), Freq_Cnt => X "0A65", wavegenCLK => CLK, חתומה (WaveOut) => WaveD5); --2661, 587.33 הרץ Note_Ds5: מפת יציאת Wave_Generator (טריגר => O5 (3), Freq_Cnt => X "09D0", wavegenCLK => CLK, חתום (WaveOut) => WaveDs5);-2512, 622.25 הרץ הערה_ E5: מפת יציאת Wave_Generator (טריגר => O5 (4), Freq_Cnt => X "0943", wavegenCLK => CLK, חתומה (WaveOut) => WaveE5); --2371, 659.25 הרץ הערה_פ 5: מפת יציאת Wave_Generator (טריגר => O5 (5), Freq_Cnt => X "08Be", wavegenCLK => CLK, חתומה (WaveOut) => WaveF5); --2238, 698.46 הרץ Note_Fs5: מפת יציאת Wave_Generator (טריגר => O5 (6), Freq_Cnt => X "0840", wavegenCLK => CLK, חתום (WaveOut) => WaveFs5);-2112, 739.99 הרץ הערה_ג 5: מפת יציאת Wave_Generator (טריגר => O5 (7), Freq_Cnt => X "07CA", wavegenCLK => CLK, חתומה (WaveOut) => WaveG5); --1994, 783.99 הרץ Note_Gs5: מפת יציאת Wave_Generator (טריגר => O5 (8), Freq_Cnt => X "075A", wavegenCLK => CLK, חתום (WaveOut) => WaveGs5);-1882, 830.61 הרץ הערה_א 5: מפת יציאת Wave_Generator (טריגר => O5 (9), Freq_Cnt => X "06F0", wavegenCLK => CLK, חתומה (WaveOut) => WaveA5); --1776, 880.00 Hz הערה_אס 5: מפת יציאת Wave_Generator (טריגר => O5 (10), Freq_Cnt => X "068C", wavegenCLK => CLK, חתומה (WaveOut) => WaveAs5);-1676, 932.33 הרץ הערה_ב 5: מפת יציאת Wave_Generator (טריגר => O5 (11), Freq_Cnt => X "062E", wavegenCLK => CLK, חתומה (WaveOut) => WaveB5); --1582, 987.77 הרץ הערה_C6: מפת יציאת Wave_Generator (טריגר => O5 (12), Freq_Cnt => X "05D6", wavegenCLK => CLK, חתומה (WaveOut) => WaveC6); --1494, 1046.5 הרץ ------------ לוגיקת בחירת הערות ------------ 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, Wave5, Wave5, Wave, Wave5, Wave, Wave WaveB5, WaveC6) מתחילים אם (cntC6 = "00000") ואז --------------- אם לא יוצרים אותות Wave0 <= "0000000000"; Wave1 <= "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 Wave0 Wave1 Wave1 Wave2 Wave1 Wave2 Wave Wave2 Wave3 שגיאה Wave0 Wave1 Wave2 Wave3 שגיאה Wave0 Wave1 Wave2 Wave3 שגיאה Wave0 Wave1 Wave2 Wave3 טעות Wave0 Wave1 Wave2 Wave3 טעות Wave0 Wave1 Wave2 Wave0 Wave1 Wave2 Wave3 Wave2 Wave1 Wave2 Wave = WaveC6; Wave1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 Wave1 <= WaveC6; Wave2 <= "0000000000"; Wave3 Wave2 <= WaveC6; שגיאה Wave3 Wave3 Wave1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 Wave2 <= "0000000000"; Wave3 Wave3 שגיאה <= '1'; מקרה סיום; סוף אם; סוף אם; סוף תהליך; ------------- adder wave sinus -------------------- WaveSum <= STD_LOGIC_VECTOR (Wave0 + Wave1 + Wave2 + Wave3); --------- הפוך את גל הסינוס לחיובי עבור pwm --------------------- positiveWaveSum <= not WaveSum (9) & WaveSum (8 downto 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'; סוף אם; PWM <= PWM + 1; ping_length <= unsigned (positiveWaveSum); --end אם; סיום אם; סיום תהליך; סיום התנהגותי;

בורר הערות החלק החלק הכי מסובך בפרויקט זה הוא בחירת ארבעה תדרים בלבד. עשינו את זה עם הרבה הצהרות 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 תווים, כאשר 2 תווים נמוכים מ- D5, כך נתחבר את waveD5 ל- Wave2 (הגל השלישי ספירת אותות מ- Wave0). לחלופין, אם cntD5 הוא 5, אז כרגע מתנגנים 5 תווים, כאשר 4 תווים נמוכים מ- D5, אז פשוט נשאיר את waveD5 תלוי ולא נעשה עם זה כלום.

לאחר מכן חוזרים על הצהרות IF כדי לכסות את המקרים של כל 25 ההערות.

Adder Amplitude

לאחר בחירת 4 הגלים הנמוכים ביותר עלינו להוסיף אותם יחד. הסיבה שנוסיף רק ארבע תווים ביחד היא מכיוון שרעיון ה- PWM בו אנו משתמשים עבור הפלט שלנו יכול לקבל רק רזולוציה מסוימת עד שה- PWM פועל לאט מדי והרמקול יתחיל לאסוף את הגל המרובע של PWM. לדוגמה, אם היינו משתמשים ברזולוציה של 8192 (13 סיביות), כל אחת מ- 8192 הנקודות הזו צריכה להתאים לקצה עולה של השעון המשולב. אז, 100MHz / 8192 = 12.2kHz, וזה בטווח הטווח של שמיעה אנושית.

התוספת בפועל של המשרעות היא סופר פשוטה, אתה רק צריך לוודא שהיא יכולה לרוץ ממש מהר.

פלט PWM

מחזור העבודה של PWM ייצג את משרעת גל הפלט שלנו באותו רגע. לדוגמה, אם יש לנו טווח משרעת של 0 עד 128, 0 יהיה מחזור עבודה של 0%, 64 יהיה 50%, 128 יהיה 100%וכו '. PWM זה יפעל מהר במיוחד (שלנו הוא 97.6 קילוהרץ), כל כך מהר שהרמקול לא יזהה את הגלים המרובעים האישיים ובמקום זאת יסתכל על המתח הממוצע ויוצר את האות ה"אנלוגי "שלנו.

קובץ אילוצים

ייתכן שחיברת את החומרה שלך אחרת, אז רק וודא שקובץ האילוצים תואם.

שלב 5: הורדות קוד

להלן הקוד, הן בפורמט.txt והן ב-.vhd ל- Vivado. Wave_Generator הוא תת המודול של מחולל הגלים, ו- Two_Octave_Synth הוא המודול העליון עם כל השאר.

מוּמלָץ: