نغمات Atmega8. صفارات الإنذار الصوتية البسيطة على MK AVR. باستخدام وحدة الصوت

توضح المقالة مبادئ التوليف الموسيقي على AVR. يتيح لك البرنامج المضمن تحويل أي ملف midi إلى مصدرفي C لوحدات التحكم الدقيقة AVR لإضافة تشغيل الأجزاء الموسيقية إلى التطورات الجاهزة. يعتبر مثال على استخدام البرنامج في صندوق الموسيقى.

أولاً، فيديو قصير عن كيفية عمل كل شيء:

ما يسمح به البرنامج

يتيح لك برنامج الكمبيوتر الحصول على مصدر C لـ CodeVision AVR، الذي يقوم بتشغيل ملف midi المحدد:

1. قم بتوصيل common\hxMidiPlayer.h، common\hxMidiPlayer.c بمشروعك. انسخ القوالب ATMega8Example\melody.h، وATMega8Example\melody.c، وATMega8Example\hxMidiPlayer_config.h واتصل.
2. قم بتشغيل MidiToC.exe
3. قم بتحميل ملف ميدي.
4. إعداد المشغل: معدل أخذ العينات، وعدد القنوات، والشكل الموجي، وما إلى ذلك. يقوم البرنامج بتشغيل اللحن بنفس الطريقة التي سيعزف بها AVR.
5. انقر فوق "إنشاء تكوين المشغل" والصق المصدر في hxMidiPlayer_config.h.
6. انقر فوق "إنشاء رمز اللحن" والصق المصدر في melody.c
7. في مشروعنا، قمنا بتطبيق طريقة Player_Output() لإخراج الصوت عبر PWM أو DAC خارجي.
8. اضبط المؤقت على معدل أخذ العينات واستدعاء Player_TimerFunc() من المقاطعة.
9. اتصل بـ Player_StartMelody(&s_melody, 0).

يتم تشغيل اللحن من مقاطعة المؤقت. وهذا يعني أنه أثناء التشغيل يمكن لوحدة التحكم الدقيقة أيضًا القيام بعمل مفيد.

كيف تعمل

سأحاول في بقية المقالة أن أشرح بإيجاز كيفية تنفيذ كل هذا. ولسوء الحظ، لن يكون قصيرًا جدًا - فهناك الكثير من المواد. إذا لم تكن مهتمًا، فيمكنك الانتقال فورًا إلى قسمي "وصف البرنامج" و"Player API".

ما هي الموسيقى

الموسيقى عبارة عن سلسلة من الأصوات ذات ترددات ومدد مختلفة. يجب أن يتوافق تردد التوافقي الأساسي للصوت مع تردد نغمة معينة. إذا كان تردد اهتزاز الأصوات يختلف عن ترددات النغمات، يبدو لنا أن الموسيقي "خارج اللحن".

طاولة. ترددات الملاحظة، هرتز.

جميع النغمات مقسمة إلى أوكتافات، 7 نوتات في كل منها + 5 نغمات نصفية (مفاتيح سوداء على البيانو). تختلف ترددات النغمات في الأوكتافات المجاورة مرتين بالضبط.

يحتوي أبسط مشغل موسيقى على جدول به تسلسل النوتات (النوتة + المدة) للحن وجدول بترددات النوتة. لتوليف الصوت يتم استخدام إحدى قنوات المؤقت والتي تشكل تعرجا:

لسوء الحظ، فإن مثل هذا العازف البدائي لديه شكل موجة ثابت (موجة مربعة)، وهي ليست مشابهة جدًا للآلات الموسيقية الحقيقية، ويمكنه عزف نغمة واحدة فقط في كل مرة.

يحتوي اللحن الحقيقي على جزأين على الأقل (منفرد + جهير)، وعند العزف على البيانو، تستمر النغمة السابقة في العزف عند بدء النغمة التالية. من السهل فهم ذلك من خلال تذكر بنية البيانو - حيث تتوافق كل نغمة مع سلسلة منفصلة. يمكننا أن نصدر عدة أوتار صوتية في نفس الوقت عن طريق تمرير أيدينا على المفاتيح.

تحتوي بعض وحدات التحكم الدقيقة على قنوات توقيت متعددة، ويمكن استخدامها لتشغيل نغمات متعددة في وقت واحد. ولكن عادةً ما تكون هذه القنوات مورداً قيماً، ولا يُنصح باستخدامها جميعها. ما لم يكن، بالطبع، مجرد صنع صندوق الموسيقى.
في المجموع، للحصول على تعدد الأصوات والأصوات المختلفة للآلات الموسيقية، تحتاج إلى استخدام تركيب الصوت.

تركيب الصوت على AVR

يستخدم hxMidiPlayer التوليف الصوتي ويمكنه تشغيل تعدد الأصوات بأشكال موجية مختلفة. يقوم المشغل بحساب سعة إشارة الخرج في معالج مقاطعة المؤقت بتردد 8-22 كيلو هرتز (مقدار طاقة المعالج كافية؛ ويعتمد أيضًا على شكل الموجة وعدد القنوات).

يمكن شرح مبدأ التوليف الصوتي باستخدام مثال التوليف الجيبي.

لنأخذ جدولاً بالحجم 64، في كل خلية تُكتب قيم سعة الجيب عند نقاط الفهرس * 2 * PI / 64 (فترة واحدة):

فلاش ثابت ثابت uint8_t s_sineTable[ 64 ] = ( 0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8D, 0x8F, 0x90, 0x91, 0x93, 0x93, 0x94, 0x95, 0x95, 0x 9 5, 0x95, 0x95, 0x94 , 0x93, 0x93, 0x91, 0x90, 0x8F, 0x8D, 0x8C, 0x8A, 0x88, 0x86, 0x84, 0x82, 0x80, 0x7E, 0x7C, 0x7A, 0x78, 0x76, 0x74, 0x73, 0 ×7 1، 0x70، 0x6F، 0x6D، 0x6D، 0x6C، 0x6B، 0x6B، 0x6B، 0x6B، 0x6B، 0x6C، 0x6D، 0x6D، 0x6F، 0x70، 0x71، 0x73، 0x74، 0x76، 0x78، 0x7A، 0x7C، 0x7E );

128 (0x80) يقابل الصفر، 255 (0xff) يقابل أكبر نقطة موجبة، 0 يقابل أكبر نقطة سالبة.

لنفترض الآن أننا سنقوم بإخراج القيم من الجدول إلى DAC خارجي في مقاطعة مؤقت يتم استدعاؤها بتردد 1000 هرتز:

ثابت uint8_t s_index = 0; // مقارنة مخرجات Timer1 مقاطعة روتين خدمة المقاطعة void timer1_compa_isr(void) ( SetDac(s_sineTable[ s_index]); if (s_index == 63) ( s_index = 0; ) else ( s_index++; ) )

ماذا سنحصل نتيجة لذلك؟ سنحصل على تذبذبات جيبية بتردد 1000/64 هرتز.

الآن دعونا نزيد الفهرس في المقاطعة ليس بمقدار 1، بل بمقدار اثنين.
من الواضح أن تردد تذبذب الخرج سيكون بالفعل 1000/64 * 2 هرتز.

بشكل عام، للحصول على التردد F، تحتاج إلى زيادة المؤشر في الجدول عن طريق:
إضافة = ف/1000*64

يمكن أن يكون هذا الرقم كسريًا، ولكن للحصول على سرعة عالية، يتم استخدام حساب النقطة الثابتة.

يؤثر عدد الإدخالات في الجدول وتكرار المؤقت على جودة الصوت المركب. في حالتنا، يكفي 64 إدخالًا في الجدول لكل فترة، ويكون تردد المؤقت 12 كيلو هرتز. الحد الأدنى لتردد المؤقت المقبول هو 8 كيلو هرتز، والتردد المثالي هو 44 كيلو هرتز.

من الواضح أنه مع تردد مؤقت قدره 12 كيلو هرتز، يمكننا توليد موجات مربعة بحد أقصى 6 كيلو هرتز، حيث أننا نحتاج إلى إجراء مفتاحين على الأقل في كل فترة. ومع ذلك، سيظل من الممكن التعرف على الترددات الأعلى إذا تم حساب حالة الإخراج بشكل صحيح عند كل علامة مؤقت.

يمكنك إدخال قيم لفترة التذبذبات غير الجيبية في الجدول والحصول على صوت مختلف.

التوهين

إذا كانت الآلة الموسيقية تعتمد على الأوتار (على سبيل المثال، البيانو)، فبعد الضغط على المفتاح، يتلاشى الصوت بسلاسة. للحصول على صوت مركب أكثر طبيعية، تحتاج إلى تقليل سعة الاهتزازات بسلاسة بعد بدء النغمة ("لف" الاهتزازات في شكل توهين - "مغلف").

يحتوي المشغل على جدول الانحلال الذي يستخدمه لتقليل سعة الجيب (أو أي شكل موج آخر) من لحظة بدء النغمة.
"الجيب" "الملفوف" في مثل هذه القشرة يشبه صوت صندوق الموسيقى الميكانيكي.

توليف متعرج

يسمح الشكل الخاص للموجة المتعرجة بتبسيط عملية التوليف بشكل كبير. لا يتم استخدام الجداول في هذه الحالة. يكفي حساب الحالة (1 أو 0) التي يجب أن يكون لها الإخراج عند تردد معين عند علامة المؤقت الحالية. ويتم ذلك باستخدام حساب الأعداد الصحيحة ويعمل بسرعة كبيرة، وهو ما يفسر شعبية استخدام موجة مربعة لتشغيل الألحان في أجهزة الاستقبال ذات 8 بت.

مثال: إعلان العداد:

ثابت uint16_t s_counter = 0;

والتي سنزيدها بمقدار 0x8000 في كل مقاطعة للمؤقت، وسيتم إخراج الجزء الأكثر أهمية من العداد إلى المنفذ:

// مقارنة مخرجات Timer1 مقاطعة روتين خدمة المقاطعة void timer1_compa_isr(void) ( PORTA.0 = (s_counter >> 15) & 1; s_counter += 0x8000; )

نظرًا لأن 0x8000 + 0x8000 = 0x10000، فإن المتغير s_counter يفيض، ويتم تجاهل البت السابع عشر، ويتم كتابة 0x0000 إلى المتغير.
وبالتالي، مع تردد مؤقت قدره 8 كيلو هرتز، سيكون الخرج عبارة عن موجة مربعة تبلغ 4 كيلو هرتز.
إذا قمت بزيادة العداد بمقدار 0x4000، فستحصل على موجة مربعة تبلغ 2 كيلو هرتز.

وبشكل عام يمكنك الحصول على التردد F بإضافة:
إضافة = F / 8000 * 0x10000

على سبيل المثال، للحصول على موجة مربعة بتردد 1234 هرتز، تحتاج إلى إضافة 0x277C. سيختلف التكرار الفعلي قليلًا عن التكرار المعطى، لأننا نقرب الحد إلى عدد صحيح. هذا مقبول في المزج.

توليف أصوات الآلات الحقيقية

يمكنك رقمنة صوت النغمة قبل البيانو (باستخدام ADC لتخزين قيم سعة الصوت في الذاكرة على فترات منتظمة):
ثم قم بتشغيل الصوت (باستخدام DAC لإخراج القيم المسجلة على فترات منتظمة).

بشكل عام، لتجميع الطبول، تحتاج إلى تسجيل أصوات الطبول وتشغيلها في اللحظة المناسبة. في وحدات التحكم ذات 8 بت، يتم استخدام "الضوضاء البيضاء" بدلاً من أصوات الطبل. يتم الحصول على قيم سعة "الضوضاء البيضاء" باستخدام المولد أرقام عشوائية. تكاليف الذاكرة ضئيلة.
يستخدم hxMidiPlayer "الضوضاء البيضاء" لتركيب الطبلة.

خلط القنوات

يتم حساب سعة الصوت عند علامة مؤقت معينة لكل قناة على حدة. للحصول على قيمة السعة النهائية، تحتاج إلى إضافة قيم جميع القنوات. بشكل صحيح، من الضروري ضبط المجموع، نظرًا لأن جهارة الصوت المدرك يخضع لاعتماد لوغاريتمي، ولكن في مثل هذا المركب البسيط، سيتعين عليك الاكتفاء بعملية إضافة بسيطة. ولذلك، فإن السعة القصوى لكل قناة هي 255/N.

إخراج الصوت من AVR

بعد إجراء جميع الحسابات اللازمة، يتلقى اللاعب مستوى الإشارة الذي يحتاج إلى تحويله إلى التناظرية. لهذه الأغراض، يمكنك استخدام DAC أو PWM خارجي.
تجدر الإشارة هنا إلى أنه من المستحسن في كلتا الحالتين تصفية الإشارة المستقبلة - لإزالة الضوضاء عالية التردد التي تنشأ بسبب التردد المنخفض للتوليف والتقريب.

الإخراج إلى DAC الموازي الخارجي

نظرًا لأنه من غير المنطقي استخدام شرائح DAC دقيقة، فإن مثل هذه المشاريع عادةً ما تعتمد على مصفوفة R2R:

باستخدام هذا المخطط، نقوم ببساطة بإخراج السعة المحسوبة إلى المنفذ:

PORTB = عينة؛

عيوب:
1) إخراج مصفوفة R2R كذلك اشارة ضعيفة، يعد استخدام مكبر الصوت التناظري أمرًا إلزاميًا؛
2) من الضروري استخدام 5 دبابيس على الأقل (ويفضل 8)؛
هذه الطريقة مبررة فقط في حالة عدم وجود قنوات PWM مجانية.

(لحفظ الدبابيس، يمكنك استخدام ADC خارجي مع واجهة SPI).

بوم

إذا كانت هناك قناة PWM مجانية، فإن أسهل طريقة هي استخدام هذه الطريقة.

تهيئة PWM (ATMEga8):

// تهيئة المؤقت/العداد 2 // مصدر الساعة: ساعة النظام // قيمة الساعة: 20000.000 كيلو هرتز // الوضع: PWM سريع أعلى = 0xFF // إخراج OC2: PWM ASSR غير مقلوب = 0x00؛ TCCR2=0x69; TCNT2=0x00; OCR2=0x00; وإخراج العينة: void Player_Output(uint8_t Sample) ( OC2 = Sample.)

تتضمن الممارسة الشائعة لاستخدام PWM تسهيل إشارة الخرج باستخدام مرشح RC:

لسوء الحظ، بعد التصفية، تضعف الإشارة كثيرًا، لذلك يتعين عليك إنشاء مضخم صوت تناظري لتوصيل مكبر الصوت.

لتبسيط الدائرة، من الأفضل أن تظل "رقمية" حتى السماعة نفسها. نظرًا لأن مكبر الصوت الرخيص لا يزال غير قادر على إعادة إنتاج الترددات التي تزيد عن 30 كيلو هرتز، فلا داعي لتصفيتها. سيقوم الناشر نفسه "بتصفية" ترددات PWM العالية.

إذا كنت بحاجة إلى الحصول على مزيد من التيار، يمكنك استخدام مكبر للصوت الترانزستور. تم تحديد R1 لتوفير التيار المطلوب لمكبر الصوت.

هذه هي الطريقة التي يمكنك من خلالها توصيل مكبرات الصوت الصغيرة من الألعاب:

بالنسبة للسماعات الأكبر حجمًا، من الأفضل تجميع محرك الأقراص باستخدام ترانزستورين وتثبيت مرشح LC لإزالة الضوضاء:

يعمل Capacitor C1 على الحد من التيار عبر السماعة عندما لا يعمل PWM. أيضًا، نظرًا لإدراج مكثف متسلسل، تصل إشارة متناظرة حول الصفر إلى مكبر الصوت. وبالتالي، سيتحرك مخروط السماعة بالنسبة إلى الوضع المركزي "المريح"، مما يؤثر بشكل إيجابي على جودة الصوت.
في هذه الحالة، تعمل الترانزستورات في وضع التبديل، لذلك ليست هناك حاجة للتعويض عن الإزاحة الأساسية.

PWM، اتصال ثنائي

عيب الدائرتين الأوليين هو أن مكبر الصوت مزود بالتيار في اتجاه واحد. إذا قمنا بتغيير اتجاه التيار، فيمكن زيادة الحجم مرتين دون تجاوز الطاقة المسموح بها. للقيام بذلك، يتم توصيل مكبر الصوت إلى طرفين من وحدة التحكم الدقيقة - غير مقلوب ومقلوب، على سبيل المثال OC1A و /OC1A. إذا لم يكن هناك إخراج غير مقلوب، يمكنك استخدام القناة الثانية في الوضع المقلوب (OC1B):

// تهيئة المؤقت/العداد 1 // مصدر الساعة: ساعة النظام // قيمة الساعة: 24500,000 كيلو هرتز // الوضع: PWM سريع أعلى = 0x00FF // إخراج OC1A: Non-Inv. // إخراج OC1B: مقلوب // مانع الضوضاء: إيقاف // التقاط الإدخال عند حافة السقوط // مقاطعة تجاوز سعة Timer1: إيقاف // مقاطعة التقاط الإدخال: إيقاف // مقارنة مقاطعة المطابقة: إيقاف // مقارنة مقاطعة مطابقة B: إيقاف TCCR1A =0xB1; TCCR1B=0x09; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; باطلة Player_Output (عينة uint8_t) (OCR1A = عينة؛ OCR1B = عينة؛)

PWM، دبوسان، مضخم صوت من الفئة D

عيب الدوائر المقترحة هو استهلاك التيار أثناء الصمت.
"الصمت" بالنسبة لنا يتوافق مع مستوى الإشارة 128، أي PWM مع ملء 50٪ - يتدفق التيار دائمًا عبر السماعة!

من خلال تغيير البرنامج قليلاً، يمكنك الحصول على برنامج قوي إلى حد ما ومكبر صوت من فئة الأجهزة D:

Void Player_Output(uint8_t Sample) ( if (sample >= 128) ( TCCR2=0x21; //عادي، واضح عند مقارنة المطابقة TCCR2=0x21 | 0x80; //CLEAR OC2 PORTC.0 = 0; TCCR2=0x69; //non -عكس PWM OCR2 = (عينة-128) * 2؛) آخر // إذا (عينة< 128) { TCCR2=0x31; //normal, set on compare match TCCR2=0x31 | 0x80; //SET OC2 PORTC.0 = 1; TCCR2=0x79; //inverting PWM OCR2 = (128-sample) *2; } }

في هذه الحالة، يتم توصيل زوج واحد من الترانزستورات بمخرج PWM، والثاني - بمخرج رقمي عادي.

وكما ترون من الكود، فإننا نعتبر الإشارة فوق 128 تيارًا موجهًا في اتجاه واحد، والإشارة أقل من 128 تيارًا موجهًا في الاتجاه الآخر. عند 128، يتم توصيل طرفي مكبر الصوت بنفس طرف مصدر الطاقة ولا يوجد تيار. عند الانحراف عن المستوى 128، يزداد ملء PWM، ويتدفق تيار القطبية المقابلة عبر السماعة.

إحدى النقاط المهمة في التنفيذ هي التبديل القسري لمخرج PWM إلى الحالة المطلوبة في وقت تبديل الطرف الثاني (الرقمي العادي) (PORTC.0). يتم تخزين الكتابة في سجل OCR2 مؤقتًا للتخلص من مواطن الخلل في PWM. نحن بحاجة إلى تبديل إخراج PWM على الفور، دون انتظار نهاية الفترة.

الدائرة الأخيرة هي IMHO الخيار الأفضل من حيث البساطة وتوفير الطاقة وإخراج الطاقة.

إخراج الصوت مع شكل موجة SquareWave

عند تجميع التعرج، يتم استخدام خوارزميات مبسطة.

تقوم كل قناة (بما في ذلك الطبول) بإخراج إما 0 أو 1. وبالتالي، يقوم القرص الدوار ذو 3 قنوات بإخراج قيم في النطاق 0..3. لذلك، عند استخدام PWM، يبدو إجراء الإخراج كما يلي:

Void Player_Output (عينة uint8_t) (OCR2 = عينة * (255 / HXMIDIPLAYER_CHANNELS_COUNT)؛)

إذا كنت لا تستخدم PWM، فعندئذٍ لإخراج لحن ثلاثي القنوات، يكفي مخرجان رقميان عاديان ومصفوفة R2R ذات 2 بت.

تنسيق ميدي

إذا نظرت إلى رمز اللحن الناتج، يمكنك بسهولة أن ترى أن المصفوفة تستخدم أرقامًا متكررة من نطاق صغير. هذا أمر مفهوم: يستخدم اللحن عددًا محدودًا من النغمات ضمن 1-2 أوكتاف، وإيقاع اللحن ثابت - تأخيرات متساوية، وعدد القنوات في حدود 0..15.
كل هذا يعني أنه يمكن تقليل المصفوفة الناتجة بشكل كبير من خلال تطبيق نوع من خوارزمية الضغط.
توفر الخوارزميات مثل ZIP ضغطًا جيدًا، ولكنها تتطلب أيضًا مساحة كبيرة من الذاكرة لتشغيلها (قاموس ZIP - 64 كيلو بايت). يمكننا استخدام طريقة ضغط بسيطة جدًا لا تتطلب أي ذاكرة تقريبًا، وجوهرها كما يلي.

في البايت الواحد، يتم توزيع كافة الأرقام بالتساوي في النطاق 0...255، ويتم تمثيل كل رقم بـ 8 بتات. في حالتنا، بعض الأرقام أكثر شيوعًا من غيرها. إذا قمت بتشفير الأرقام التي تحدث بشكل متكرر باستخدام عدد أقل من البتات، والأرقام الأقل تكرارًا باستخدام المزيد، فيمكنك الحصول على زيادة في الذاكرة.

نختار طريقة تشفير ثابتة: مجموعات البتات 000,001 و010 (الطول - 3 بتات) ستمثل الأرقام الثلاثة الأكثر تكرارًا. مجموعات البت 0110، 0111 (الطول – 4 بتات) – الرقمان التاليان الأكثر شيوعًا، وما إلى ذلك:

//000..010 - 0..2 //011 × 3..4 //100 xx 5..8 //101 xxx 9..16 //110 xxx 17..24 //111 فوري

المجموعة التي تبدأ بـ 111 (الطول - 11 بت) ستقوم بتشفير جميع الأرقام الأخرى.
قد تكون طريقة ترميز البت مختلفة. لقد جربت عدة طرق واخترت هذه الطريقة لأنها تعطي أفضل النتائج في مثل هذه البيانات.

يبدو إجراء الضغط كما يلي:
1. احسب العدد الإجمالي للرقم X في الدفق لـ X = .
2. قم بالفرز حسب تكرار الظهور في الدفق.
3. خذ أول 25 رقمًا. سيتم ترميزها في أجزاء أقل.
4. تشفير دفق الإدخال.

الإخراج عبارة عن مصفوفة من الأرقام الـ 25 الأكثر تكرارًا ودفق البت.
يتيح لك هذا الضغط تحقيق ضغط بنسبة 50% بأقل تكلفة للذاكرة والأداء. ولسوء الحظ، يؤدي هذا إلى زيادة رمز المشغل، لذا لا يوصى بالضغط للألحان القصيرة.

تخزين ترددات المذكرة

يعد تخزين ترددات جميع الملاحظات في جدول من الذاكرة أمرًا مكلفًا للغاية. في الواقع، هناك صيغة لتحديد تكرار النغمة من خلال رقمها المتوسط:

F = 2^((N - 69)/12) * 440، هرتز

لكن حساب القوة الكسرية أمر صعب للغاية. بدلاً من ذلك، يقوم المشغل بتخزين 12 ترددًا للنوتة الموسيقية في الأوكتاف العلوي. يتم تحديد ترددات النغمات في الأوكتافات السفلية عن طريق تقليل التردد بمقدار 2 ^ Y مرات أكثر، حيث Y هو عدد الأوكتافات السفلية.

مواصلة تطوير الضغط

غالبًا ما يحتوي اللحن على أجزاء متكررة ("جوقات"، "آيات"). من خلال العثور على أجزاء متكررة وتقديم اللحن على شكل أجزاء، يمكنك تقليل اللحن بنسبة 50% أخرى، دون قضاء أي وقت تقريبًا كبشوالإنتاجية. لم أقم بتنفيذ مثل هذه الخوارزمية حتى لا أعقد المشروع.

وصف البرنامج

النافذة الرئيسية لبرنامج المحول:

يتيح لك زر تحميل Midi تحميل ملف midi. يبدأ البرنامج على الفور في تشغيل الملف بالمعلمات المحددة حاليًا، ومحاكاة الصوت الذي سيكون في الجهاز.

تعرض نافذة المعلومات (4):
– الطول – طول جزء اللحن المحدد بالمللي ثانية؛
- الحد الأقصى لقنوات المركب النشطة - الحد الأقصى لعدد قنوات المركب النشطة في نفس الوقت؛
- الحد الأقصى لقنوات الطبلة النشطة - الحد الأقصى لعدد قنوات المركب النشطة في نفس الوقت والتي تنتج "الطبول"؛
- الحد الأقصى لنوتات الاستريو النشطة - الحد الأقصى لعدد القنوات التي تعيد إنتاج نفس النغمة (انظر أدناه)؛
- الحجم المقدر بالبايت - حجم اللحن بالبايت. في وضع "العينة المخصصة"، يتم عرض الحجم كـ A+B، حيث A هو حجم اللحن، وB هو حجم العينة. حجم رمز المشغل غير محدد هنا.

تعرض نافذة التقدم موضع التشغيل الحالي.
يمكنك النقر على شريط التقدم لبدء التشغيل من النقطة المحددة.
تسمح لك مربعات الإدخال الموجودة على اليسار واليمين بتحديد بداية ونهاية جزء اللحن بالمللي ثانية.

تشير العلامة "لا توجد قنوات كافية لتشغيل اللحن" باللون الأحمر إلى عدم وجود قنوات تركيب كافية لتشغيل اللحن بالإعدادات الحالية. إذا لم يجد اللاعب قناة مجانية، فإنه يقوم بإيقاف تشغيل النوتة الأقدم. في كثير من الحالات سوف يعمل هذا بشكل جيد. من المنطقي زيادة عدد القنوات فقط عندما يبدو اللحن غير صحيح للأذن.

يمكن تقسيم الإعدادات إلى إعدادات المشغل وإعدادات معالجة ملفات midi. سيتمكن اللاعب من تشغيل رمز اللحن الناتج إذا تم إنشاء تكوين المشغل ورمز اللحن بنفس إعدادات المشغل. بالإضافة إلى ذلك، سيتمكن اللاعب من تشغيل اللحن الذي تم إنشاء رمزه للاعب بعدد أصغر (ولكن ليس أكبر) من القنوات.

تتضمن إعدادات أجهزة المشغل ما يلي:

- معدل أخذ العينات - تردد التوليف. يتم تحديد الحد الأقصى لتردد الانصهار تجريبيا. استنادًا إلى Atmega 16MHz، يمكنك البدء بسرعة 12000 هرتز لمشغل ذو 6 قنوات، وزيادتها حسب الرغبة حتى يصبح تشويه اللحن ملحوظًا عن طريق الأذن في مشغل الأجهزة. يعتمد الحد الأقصى للتردد على عدد القنوات وشكل الموجة وتعقيد اللحن نفسه.

– الشكل الموجي – الشكل الموجي :
– موجة مربعة – متعرج.
- جيب - جيب؛
– جيب + ظرف – جيب مع توهين؛
- شكل الموجة * + المغلف - خيارات مختلفة للموجات غير الجيبية مع أو بدون توهين؛
– عينة مخصصة – استخدم عينة من الأداة.

يتيح لك زر "تحميل العينة" تحميل عينة من ملف WAV. يجب أن يكون ملف WAV بتنسيق PCM 8 بت أحادي، و4173 هرتز، وC-5. تلميح: يمكنك زيادة التردد وخفض النغمة، لكن قم بتغيير طبقة الصوت في إعدادات المشغل. لا توجد عمليات فحص للتنسيق - إذا كان التنسيق مختلفًا، فلن يتم تشغيل الصوت بشكل صحيح.
درجة الصوت - يسمح لك بتغيير درجة الصوت. على سبيل المثال، لتشغيل 1 أوكتاف أعلى، تحتاج إلى ضبط درجة الصوت +12.

استخدم الضغط - استخدم ضغط اللحن.
تمكين مُركِّب الطبول – تمكين مُركِّب الطبول.

قنوات المشغل: عدد قنوات آلة النطق (الحد الأقصى لعدد النغمات التي سيتم إصدارها في وقت واحد).

تتضمن إعدادات معالجة ملفات Midi ما يلي:

عادة، مثل هذا الضبط الدقيق غير مطلوب. يمكن ترك هذه الإعدادات كإعداد افتراضي.

واجهة برمجة تطبيقات المشغل

يوجد تطبيق المشغل في الملفات Common\hxMidiPlayer.c وCommon\hxMidiPlayer.h. يجب تضمين هذه الملفات في المشروع. تحتاج أيضًا إلى إنشاء ملف hxMidiPlayer_config.h، حيث تحتاج إلى وضع التكوين.
المشغل مكتوب بلغة C بدون إدراجات التجميع، مما يجعل من السهل نقله إلى وحدات التحكم الدقيقة الأخرى.

الفراغ الخارجي Player_StartMelody(const flash TMelody* _pMelody, uint16_t _delay);

ابدأ تشغيل اللحن. _delay يضبط التأخير الأولي قبل التشغيل، 255 وحدة = ثانية واحدة.

باطل Player_Stop();

توقف عن عزف اللحن.

المنطق الخارجي Player_IsPlaying();

يُرجع خطأ إذا انتهى تشغيل اللحن.

الفراغ الخارجي Player_WaitFinish();

انتظر حتى يتم الانتهاء من تشغيل اللحن.

الفراغ الخارجي Player_TimerFunc();

يجب استدعاء هذه الوظيفة في مقاطعة مؤقت بمعدل أخذ العينات المحدد في التكوين. عند انتهاء تشغيل اللحن، لن تحتاج إلى إجراء أي مكالمات.

الفراغ الخارجي Player_Output(uint8_t Sample);

يجب أن يتم تنفيذها من قبل المستخدم. يتم استدعاؤه بواسطة اللاعب عند الحاجة إلى إخراج العينة التالية.

الفراغ الخارجي Player_Started();

يجب أن يتم تنفيذها من قبل المستخدم. يتم استدعاؤه عندما يبدأ اللاعب في عزف اللحن. يمكن استخدامها لتكوين المقاطعات الموقت.

الفراغ الخارجي Player_Finished();

يجب أن يتم تنفيذها من قبل المستخدم. يتم الاتصال به عندما ينتهي اللاعب من عزف اللحن. يمكن استخدامه لتعطيل مقاطعات المؤقت أو بدء تشغيل نغمة أخرى.

//#تعريف الملاحظات_TO_EEPROM //#تعريف SINETABLE_TO_EEPROM //#تعريف ENVELOPE_TO_EEPROM

يجب عدم التعليق على هذه الأسطر في ملف hxMidiPlayer_config.h إذا كان من الضروري وضع جدول الملاحظات وجدول الجيب وجدول التوهين في ملف eeprom.

مشاريع نموذجية

ATMega644Example – مشروع لـ ATMega644، 25 ميجا هرتز، مخرج PWM على PB3.

متطلبات الذاكرة

طاولة. حجم اللاعب والألحان في الفلاش.

*عند إضافة لاعب إلى مشروع موجود غير فارغ، سيكون حجم الكود أصغر

**لا توجد قنوات كافية لتشغيل اللحن العادي

اللحن 1: bach_minuet_in_g.mid، 35 ثانية
اللحن 2: yiruma-river_flows_in_you.mid، 165 ثانية
اللحن 3: فرانز شوبرت – Serenade.mid، 217 ثانية

كما ترون من الجدول، في الحد الأدنى من التكوين، يمكنك الضغط على لحن طويل إلى حد ما حتى في ATTiny2313. يمكن أن يؤدي الضغط إلى تقليل اللحن بأكثر من الضعف، لكن حجم رمز المشغل يزيد بمقدار 600 بايت تقريبًا.

يمكن وضع جداول ملاحظات الجيب والتحلل في EEPROM، مما يوفر حوالي 16 و50 و100 بايت من الفلاش على التوالي.

عند استخدام عينة من ملف wav، تحتاج إلى إضافة حجم العينة بالبايت إلى حجم رمز المشغل.

مثال الاستخدام

كمثال لاستخدام المشغل، دعونا نفكر في عملية إنشاء صندوق الموسيقى.

نحن نأخذ صندوق MDF جاهز:

باعتبارنا وحدة تحكم دقيقة، فإننا نأخذ حزمة ATTiny85 في حزمة SO-8 باعتبارها الأرخص مع كمية كبيرة من الذاكرة. سنقوم برفع تردد التشغيل إلى 27 ميجا هرتز للحصول على تردد تركيبي قدره 18 كيلو هرتز مع 4 قنوات Sine + Envelope.

مكبر الصوت سيكون من فئة D مع 4 ترانزستورات لتوفير البطاريات.

تعمل الترانزستورات في وضع التبديل ويمكن أن تكون من أي نوع. يتم اختيار المحث L1 والمكثف C6 حسب الذوق للحصول على صوت بدون ضوضاء عالية التردد. يمكن رفع مستوى R1 وR2 إلى 2K لخفض مستوى الصوت وتقليل ارتداد مكبر الصوت.

يتناسب مفتاح الحد من محرك الأقراص بشكل مثالي، كما لو تم إنشاؤه خصيصًا للمربع (يعمل على الفتح - عند فتح الغطاء، يتم توفير الطاقة للوحة):

توجد مصادر البرامج الثابتة في دليل ATTiny85MusicBox.

8 كيلو بايت يناسب:
1) المشغل: 18000 هرتز، 4 قنوات، جيب + ظرف، درجة الصوت +12، ضغط، تشغيل الألحان واحدًا تلو الآخر (يتم تخزين الأخير في EEPROM)
2) ييروما - يتدفق النهر في داخلك
3) فرانز شوبرت - سيريناد
4) بي. تشايكوفسكي "أكتوبر"

النتيجة بالفيديو:

مزيد من التطوير

من حيث المبدأ، يمكن تطوير اللاعب بشكل أكبر، ليصل إلى مشغل Midi أو MOD كامل. أنا شخصياً أعتقد أنه للحصول على لحن عالي الجودة، سيكون من الأسهل توصيل بطاقة SD وتشغيل أي ملفات WAV منها بأكثر من ذلك بكثير. أفضل جودةمما يمكن الحصول عليه بشكل عام عن طريق تركيب البرمجيات. ومثل هذا اللاعب أبسط بكثير في البرامج والأجهزة. يضيف مكان hxMidiPlayer صوتًا جيدًا للمشاريع الجاهزة عندما يتبقى عدد قليل من الأرجل ومساحة صغيرة في الفلاش. إنها تتواءم مع هذه المهمة "بشكل ممتاز" بالفعل في شكلها الحالي.

أعتقد أن هذا يمكن أن ينهي مشكلة إنشاء جميع أنواع صناديق/أجراس الموسيقى على AVR :)

استغرق استمرار الدرس وقتا طويلا، وهو أمر مفهوم، وكان علي أن أتقن العمل مع بطاقات الذاكرة والملفات نظام الدهون. ولكن مع ذلك، حدث ذلك، الدرس جاهز - في الواقع، معجزة العام الجديد.

من أجل عدم التحميل الزائد للمقال بالمعلومات، لن أصف هيكل تنسيق ملف WAV، هناك معلومات أكثر من كافية في محركات البحث. يكفي أن نقول أنه إذا قمت بفتح ملف باستخدام نوع ما من محرر Hex، فإن أول 44 بايت تحتوي على جميع المعلومات حول نوع الملف، ومعدل أخذ العينات، وعدد القنوات، وما إلى ذلك. إذا كنت بحاجة إلى تحليل الملف، فاقرأ هذا رأس وسوف تكون سعيدا.

تبدأ بيانات الحمولة عند 44 بايت، وتحتوي بشكل أساسي على مستويات الجهد التي يتكون منها الصوت. لقد تحدثنا بالفعل عن مستويات الجهد في الجزء الأخير من الدرس. وبالتالي، كل شيء بسيط، تحتاج إلى إخراج هذه الخطوات إلى السماعة بتردد أخذ العينات للملف.

كيفية جعل مكبر الصوت يهز جسديا؟ تحتاج إلى إخراج مستويات الجهد هذه باستخدام PWM، أو استخدام R2R. على أية حال، فهو سهل الاستخدام للغاية، قم بقراءة الرقم ووضعه إما في OCR أو PORTx. ثم، بعد فترة زمنية معينة، قمت باستبدال القيمة التالية وهكذا حتى نهاية الملف.

على سبيل المثال، ملف wav معين، تأتي البيانات من البايتات 44=0x2C، الرقم 0x80 مكتوب هناك، نعيد إنتاج الصوت، على سبيل المثال، بواسطة PWM للمؤقت الأول، نكتب OCR1A=0x80؛ لنفترض أن تردد أخذ العينات هو 8 كيلو هرتز، لذلك يجب ضبط المقاطعة على نفس التردد. في المقاطعة، استبدل القيمة التالية 0x85 بعد 1/8000 = 125 ميكروثانية.

كيفية ضبط المقاطعة على 8 كيلو هرتز؟ دعونا نتذكر أنه إذا كان المؤقت يعمل بتردد 250 كيلو هرتز، فيجب استبدال سجل مقارنة المقاطعة (250/8)-1=31-1 أو 0x1E. مع PWM، كل شيء بسيط أيضًا، فكلما زاد التردد الذي يعمل به، كلما كان ذلك أفضل.

لكي تعمل البرامج الثابتة، سنتفق على أن محرك الأقراص المحمول بتنسيق FAT32، وذلك باستخدام PetitFat lib من الدرس 23.2. الملف بتنسيق wav، إما 8 كيلو هرتز أو 22.050 كيلو هرتز، أحادي. اسم الملف 1.wav. دعونا نحلل البرامج الثابتة.

#يشمل #include "diskio.h" #include "pff.h" unsigned char buffer[ 512 ] ; /* المخزن المؤقت الذي يتم نسخ المعلومات من محرك الأقراص المحمول فيه */عدد كثافة العمليات غير الموقعة المتقلبة؛ // عداد البيانات المنسوخةمقاطعة [TIM2_COMP] باطلة timer2_comp_isr(void) // المقاطعة التي يتم فيها استبدال القيم(OCR1A = المخزن المؤقت[عدد]؛ // إخراج الصوت إلى مكبر الصوتإذا (++ العد >= 512) // زيادة العدادالعد = 0 ; // إذا تمت إعادة تعيين 512) باطلة رئيسية(باطلة) (unsigned int br; /* عداد قراءة/كتابة الملف */غير موقعة شار buf = 0 ; // متغير يحدد أي جزء من المخزن المؤقت سيتم قراءته FATFS خ؛ /* مساحة العمل (كائن نظام الملفات) لمحركات الأقراص المنطقية */بورتب= 0x00 ; DDRB= 0x02 ; // قفز الرقائق ocr1a // تهيئة الموقت/العداد 1// مصدر الساعة: ساعة النظام // قيمة الساعة: 8000,000 كيلو هرتز // الوضع: PWM سريع أعلى = 0x00FF // إخراج OC1A: Non-Inv. TCCR1A = 0x81 ; TCCR1B = 0x09 ; TCNT1= 0x00 ; OCR1A= 0x00 ; // تهيئة المؤقت/العداد 2// مصدر الساعة: ساعة النظام // قيمة الساعة: 250,000 كيلو هرتز // الوضع: CTC top=OCR2 TCCR2= 0x0B ; TCNT2= 0x00 ; //OCR2=0x1E; // إعداد سجل المقارنة لـ 8 كيلو هرتزالتعرف الضوئي على الحروف2 = 0xA ; // لـ 22 كيلو هرتز #asm("sei") // تهيئة المؤقت (المؤقتات)/العداد (العدادات).إذا (disk_initialize() == 0) // تهيئة محرك الأقراص المحمول(pf_mount(&fs) ; //تتعدد نظام الملفات pf_open("1.wav"); // افتح موضوعًا pf_lseek(44) ; // حرك المؤشر إلى 44 pf_read(buffer, 512 ,& br) ; // لأول مرة نبتلع 512 بايت مرة واحدةتيمسك = 0x80 ; // قم بتشغيل الموسيقى أثناء (1) ( if (! buf && count> 255 ) // إذا تم إعادة إنتاج أكثر من 255 بايت،( pf_read(& buffer[ 0 ], 256 ,& br) ; // ثم نقرأ المعلومات من محرك الأقراص المحمول في النصف الأول من المخزن المؤقتبوف= 1 ; إذا (ر< 256 ) // إذا كان المخزن المؤقت لا يحتوي على 256 قيمة، فهذا يعني نهاية الملفاستراحة ؛ ) إذا (برتقالي && العد< 256 ) { pf_read(& buffer[ 256 ] , 256 ,& br) ; // اقرأ الجزء الثاني من المخزن المؤقت من محرك الأقراص المحمولبوف = 0 ; إذا (ر< 256 ) break ; } } TIMSK = 0x00 ; //глушим все pf_mount(0x00 ) ; // تفكيك الحجاب) بينما (1) ( ) )

#يشمل #include "diskio.h" #include "pff.h" المخزن المؤقت للحرف غير الموقع؛ /* المخزن المؤقت الذي يتم نسخ المعلومات من محرك الأقراص المحمول فيه */ volatile unsigned int count; // عداد مقاطعة البيانات المنسوخة void timer2_comp_isr(void) // المقاطعة التي يتم فيها استبدال القيم ( OCR1A = buffer؛ // إخراج الصوت إلى مكبر الصوت if (++count >= 512) // زيادة عدد العداد = 0; // إذا تم إعادة تعيين 512 ) void main(void) ( unsigned int br; /* عداد قراءة/كتابة الملف */ unsigned char buf = 0; // متغير يحدد أي جزء من المخزن المؤقت تتم قراءته FATFS fs; /* العمل المنطقة (كائن نظام الملفات) لمحركات الأقراص المنطقية */ PORTB=0x00; DDRB=0x02; // القفز على الرقاقة ocr1a // تهيئة المؤقت/العداد 1 // مصدر الساعة: ساعة النظام // قيمة الساعة: 8000,000 كيلو هرتز // الوضع: قمة PWM سريعة = 0x00FF // إخراج OC1A: بدون مخزون TCCR1A=0x81; TCCR1B=0x09; TCNT1=0x00; OCR1A=0x00; // تهيئة المؤقت/العداد 2 // مصدر الساعة: ساعة النظام // قيمة الساعة : 250,000 كيلو هرتز // الوضع: CTC top= OCR2 TCCR2=0x0B; TCNT2=0x00; //OCR2=0x1E; //ضبط سجل المقارنة لـ 8 كيلو هرتز OCR2=0xA; // لـ 22 كيلو هرتز #asm("sei") // تهيئة المؤقت (المؤقتات)/العداد (العدادات) للمقاطعة (المقاطعات) if(disk_initialize()==0) //تهيئة محرك الأقراص المحمول ( pf_mount(&fs); // تركيب نظام الملفات pf_open("1.wav"); // افتح الفرع pf_lseek(44); // حرك المؤشر إلى 44 pf_read(buffer, 512,&br); // لأول مرة نبتلع 512 بايت مرة واحدة TIMSK=0x80; // قم بتشغيل الموسيقى while(1) ( if(!buf && count>255) // إذا تم تشغيل أكثر من 255 بايت، ( pf_read(&buffer, 256,&br);// ثم اقرأ المعلومات من الفلاش قم بالقيادة في النصف الأول من المخزن المؤقت buf=1؛ if (br< 256) //если буфер не содержит 256 значений значит конец файла break; } if(buf && count<256) { pf_read(&buffer, 256,&br); // читаем во вторую часть буфера с флешки buf = 0; if (br < 256) break; } } TIMSK = 0x00; //глушим все pf_mount(0x00); //демонтируем фат } while (1) { } }

للتحقق، نقوم بتوصيل مكبر الصوت بمنفذ OCR1A عبر مكثف 100 فائق التوهج، و"+" بمنفذ المتحكم الدقيق، و"-" بمكبر الصوت. "-" مكبر الصوت إلى الأرض، "+" إلى المكثف.

لا تتوقع إشارة عالية عند الإخراج، فأنت بحاجة إلى مكبر للصوت لإصدار صوت عالٍ. وهذا واضح في الفيديو. للاختبار، قمت بتحميل الديك بـ 8 كيلو هرتز والمسار بـ 22 كيلو هرتز.

يمكن لأولئك الذين يرغبون زيادة تردد المؤقت 2 بأمان من أجل تشغيل ملفات 44 كيلو هرتز، وتظهر التجارب أنه من الممكن تحقيق جودة صوت جيدة جدًا. في الفيديو الصوت ضعيف والجودة رديئة لكن في الحقيقة هذا بسبب أنني صورته بالكاميرا.

أقوم أيضًا بنشر المواد المقدمة من Apparatchik - الكود المصدري لدول مجلس التعاون الخليجي، والذي تم من خلاله كتابة البرنامج الثابت لـ CAVR.

والفيديو مع تشغيل 44 كيلو هرتز.

أغتنم هذه الفرصة لأهنئ الجميع بالعام الجديد، وأتمنى أن تعمل جميع البرامج الثابتة والأجهزة من أجلك :)

مشروع مشغل wav على Atmega8

لقد كتبت وحدة برمجية تتيح لك إضافة وظيفة تشغيل الألحان أو التسلسلات الصوتية إلى أي مشروع تقريبًا على وحدة التحكم الدقيقة AVR.

ميزات الوحدة:

سهولة التكامل مع مشروع جاهز

يتم استخدام المؤقت t2 ذو 8 بتات فقط، بينما يظل من الممكن استخدامه للاقتراع أو تكوين الفترات الزمنية

الوحدة قابلة للتعديل لتناسب أي تردد لمولد الساعة تقريبًا

يتم تحديد درجة النغمات كثوابت رمزية (C0، A2، وما إلى ذلك) أو بالهرتز

يتم تحديد المدد بالشكل القياسي (أرباع، وأثمان، وما إلى ذلك) أو بالمللي ثانية

من الممكن ضبط وتيرة تشغيل اللحن وعدد تكراراته

أثناء التشغيل، يمكن إيقاف اللحن مؤقتًا


توصيل وحدة الصوت

1. انسخ كافة ملفات الوحدة النمطية (tone.h، sound.h، sound.c) إلى مجلد المشروع.

2. قم بتوصيل ملف sound.c بالمشروع.

بالنسبة إلى IAR `a - انقر بزر الماوس الأيمن في نافذة مساحة العمل وحدد إضافة > إضافة ملفات...

بالنسبة إلى WINAVR، الأمر نفسه تقريبًا، يجب إضافة sound.c فقط إلى ملف makefile:

SRC = $(TARGET).c sound.c

3. قم بتضمين ملف الرأس sound.h في الوحدة المقابلة. على سبيل المثال، في main.c

#تشمل "sound.h"

4. اضبط إعدادات الوحدة في ملف sound.h

// إذا قمت بالتعليق، فستكون مدة الملاحظات

// يتم حسابه من BPM المحدد في اللحن

// إذا تركت، فمن القيمة المحددة أدناه

//#تعريف الصوت_BPM24

// تردد الساعة μ

#define SOUND_F_CPU 16U

// إخراج وحدة التحكم الدقيقة التي سيتم إنشاء الصوت عليها

#تعريف PORT_SOUND PORTB

#تعريف PINX_SOUND 0

// عدد الألحان المحددة.

#تعريف الصوت_AMOUNT_MELODY 4

5. أضف ألحانك إلى sound.c واكتب أسماء الألحان في مصفوفة الألحان.

إضافة النغمات

اللحن عبارة عن مجموعة من الأرقام ذات 16 بت ولها البنية التالية

BPM (ربع النوتة في الدقيقة)هو ثابت يستخدم لحساب مدة النغمات وتحديد السرعة التي يتم بها عزف اللحن.

يمكن أن يتراوح BPM من 1 إلى 24، وهو ما يتوافق مع 10 و240 ربع نوتة في الدقيقة، على التوالي.

إذا تم تحديد مدة النغمات/الأصوات بالمللي ثانية، فيجب أن يكون BPM المكتوب في المصفوفة مساويًا لـ 1.

إذا تم التعليق على ثابت SOUND_BPM في ملف الرأس sound.h، فسيتم حساب مدة الملاحظات أثناء تنفيذ البرنامج وفقًا لـ BPM المحدد في المصفوفة. إذا لم يتم التعليق على SOUND_BPM، فسيتم حساب مدة النغمات في مرحلة التجميع، بناءً على قيمة هذا الثابت، وسيتم تشغيل جميع الألحان بنفس الإيقاع. وهذا يحد من الوظائف، ولكنه يوفر بضعة بايتات من التعليمات البرمجية.

عدد التكرارات.يمكن أن تأخذ القيم 1 ... 254 و LOOP (255). LOOP - يعني أن اللحن سوف يتكرر إلى ما لا نهاية حتى يتم إعطاء الأمر SOUND_STOP أو SOUND_PAUSE.

مدة الملاحظة– الوقت الذي يتم خلاله إنشاء نغمة صوت معينة أو الاحتفاظ بالتوقف المؤقت. يمكن تحديدها بالمللي ثانية، باستخدام الماكرو ms(x)، أو كقيم نوتة قياسية - النوتة الثامنة، النوتة السادسة عشرة، إلخ. فيما يلي قائمة بالمدد المدعومة. إذا كانت هناك حاجة لبعض المدد الغريبة، فيمكنك دائمًا إضافتها في ملفtone.h

n1 - ملاحظة كاملة

n2 - نصف ملاحظة

ن4 - ربع

ن8 - الثامن

n3 - الثلاثي الثامن

ن16 - السادس عشر

ن6 - سيكستول

n32 - الثانية والثلاثون

ملاحظة الملعبيتم تحديده باستخدام الثوابت الرمزية الموضحة في ملفtone.h، على سبيل المثال C2، A1، وما إلى ذلك. كما يمكن تحديد درجة النغمات بالهرتز باستخدام الماكرو f(x).

البرنامج لديه قيود على الحد الأدنى والحد الأقصى لتردد الصوت!

علامة نهاية اللحن.يجب أن تكون قيمة العنصر الأخير في المصفوفة صفرًا.

باستخدام وحدة الصوت

في بداية الأمر الرئيسي، يجب عليك استدعاء الدالة SOUND_Init(). تقوم هذه الوظيفة بتعيين طرف إخراج وحدة التحكم الدقيقة، وتكوين المؤقت T2، وتهيئة متغيرات الوحدة النمطية.

ثم تحتاج إلى تعيين علامة تمكين المقاطعة - __enable_interrupt()، لأن الوحدة تستخدم تجاوز سعة مؤقت T2 والمقاطعات المتزامنة.

بعد ذلك، يمكنك البدء في تشغيل الألحان.

على سبيل المثال، مثل هذا:

SOUND_SetSong(2);

SOUND_Com(SOUND_PLAY); // تشغيل اللحن

// اضبط المؤشر على اللحن الثاني

// وابدأ التشغيل

SOUND_PlaySong(2);

يمكن إيقاف تشغيل اللحن في أي وقت عن طريق إصدار الأمر SOUND_STOP.
يمكنك أيضًا إيقاف اللحن مؤقتًا باستخدام أمر SOUND_PAUSE. يؤدي الإصدار اللاحق لأمر SOUND_PLAY إلى استئناف تشغيل اللحن من النقطة التي توقف عندها.

من حيث المبدأ، هذه الوظيفة ليست مطلوبة بشكل خاص (لقد قمت بتكوينها للتو) وعند العمل مع الوحدة، تكون وظيفة SOUND_PlaySong(unsigned char numSong) كافية؛

ملفات

يمكنك تنزيل أمثلة على استخدام وحدة الصوت من الروابط أدناه. لم أرسم مخططًا لأن كل شيء بسيط هناك. متصلاً بالدبوس PB0، يتم توصيل زر بدء الألحان بالدبوس PD3. هناك 4 ألحان محددة في المشاريع. يؤدي الضغط على الزر إلى تشغيل نغمة جديدة في كل مرة. يتم استخدام متحكم atmega8535. في البداية كنت أرغب في الاهتمام بمشروع يحتوي على أربعة أزرار - تشغيل، وإيقاف، وإيقاف مؤقت، والتالي، ولكن بعد ذلك اعتقدت أنه غير ضروري.

ملاحظة: لم تخضع الوحدة لاختبارات مكثفة ويتم توفيرها "كما هي". إذا كانت هناك أية مقترحات عقلانية، فلنضع اللمسات الأخيرة عليها.

في هذه المقالة، سننظر في كيفية عزف النغمات ومعرفة كيفية عزف لحن أحادي الصوت.

التحضير للعمل

يعلن البرنامج عن صفيفين. مصفوفة مع الملاحظات ملحوظاتيحتوي على قائمة بسيطة من الملاحظات. تتم مطابقة هذه الملاحظات مع مدة الصوت في المصفوفة يدق. يتم تحديد المدة في الموسيقى من خلال مقسوم النغمة بالنسبة إلى النغمة بأكملها. القيمة المتخذة كملاحظة كاملة هي 255 . يتم الحصول على النصف والأرباع والأثمان بتقسيم هذا الرقم.
يرجى ملاحظة أنه لا يتم الحصول على مدة الملاحظة الأولى بقسمة 255 على قوة اثنين. هنا سيكون عليك التحول إلى نظرية الموسيقى. يمكن الاطلاع على ملاحظات اللحن الأصلي. يتم دمج هذه الملاحظات في ثلاثة توائم. عندما يتم دمجها بهذه الطريقة، فإن ثلاث نوتات ثامنة تبدو مماثلة لربع النغمة. وبالتالي فإن مدتها النسبية هي 21.
يحتاج المستخدم أيضًا إلى تحديد عدد الملاحظات بشكل صريح في التسلسل باستخدام التوجيه:

# تحديد SEQU_SIZE 19

في البرنامج الرئيسي، أولا وقبل كل شيء، يتم إعادة حساب صفائف التردد ومدتها إلى فترات الإشارات ومدة الملاحظات.
مع فترات الإشارة (صفيف signal_period) كل شيء بسيط. للحصول على مدة الفترة بالميكروثانية، ما عليك سوى تقسيم 1,000,000 على تردد الإشارة.
لحساب المدة المطلقة لصوت النوتات، من الضروري الإشارة إلى إيقاع العمل الموسيقي. ويتم ذلك عن طريق التوجيه

# تعريف الإيقاع 108

الإيقاع في الموسيقى هو عدد النوتات الربعية في الدقيقة. في النسق

# تعريف WHOLE_NOTE_DUR 240000 / TEMPO

يتم حساب مدة المذكرة بأكملها بالمللي ثانية. الآن يكفي إعادة حساب القيم النسبية من المصفوفة باستخدام الصيغة يدقإلى المصفوفة المطلقة note_duration.
في الحلقة الرئيسية، المتغير الوقت المنقضيتتم زيادتها بعد كل فترة من تشغيل الإشارة بمقدار مدة هذه الفترة حتى تتجاوز مدة النغمة. يجدر الانتباه إلى هذا الإدخال:

بينما(elapsed_time< 1000 * ((uint32_t) note_duration[ i] ) )

عامل الوقت المنقضي 32 بت، وعناصر المصفوفة note_duration 16 بت. إذا تم ضرب رقم 16 بت في 1000، فسيتم ضمان تجاوز السعة والمتغير الوقت المنقضيسيتم مقارنة القمامة. المعدل (uint32_t)تحويل عنصر المصفوفة ملاحظات_المدة[i]في عدد 32 بت لا يوجد تجاوز.
يمكنك رؤية ميزة أخرى في الحلقة الصوتية. لن يكون من الممكن استخدام الوظيفة _delay_us()، نظرًا لأن وسيطتها لا يمكن أن تكون متغيرًا.
لإنشاء مثل هذه التأخيرات، استخدم الوظيفة فارديلاي_us(). في ذلك، يتم تمرير حلقة مع تأخير قدره 1 ميكروثانية لعدد محدد من المرات.

باطلة VarDelay_us(uint32_t takt) ( بينما (takt- - ) ( _delay_us(1 ) ; ) )

عند تشغيل اللحن، يتم استخدام تأخيرين آخرين. إذا تم تشغيل النوتات بدون توقف مؤقت، فسيتم دمجها في نغمة واحدة. للقيام بذلك، يتم إدراج تأخير قدره 1 مللي ثانية بينهما، المحدد بواسطة التوجيه:

# تعريف الملاحظات_الإيقاف المؤقت 1

بعد كل دورة كاملة من تشغيل اللحن، يتوقف البرنامج مؤقتًا لمدة ثانية واحدة ويبدأ التشغيل مرة أخرى.
ونتيجة لذلك، تلقينا رمزًا يسهل من خلاله تغيير الإيقاع أو ضبط المدة أو إعادة كتابة اللحن بالكامل. للقيام بذلك، سيكون كافيًا تحويل فقط جزء البرنامج الذي يحتوي على التوجيهات والإعلانات المتغيرة.

المهام الفردية

  1. في اللحن المقترح، حاول تغيير الإيقاع والتوقف لمدة 5 ثوانٍ بين التكرارات.
  2. عناصر المصفوفة يدقتقبل فقط القيم من 0 إلى 255. قم بتغيير عرض البت لعناصر المصفوفة وانظر إلى مخرجات المترجم لترى كيف يؤثر ذلك على مقدار الذاكرة التي يشغلها البرنامج.
  3. الآن حاول تغيير اللحن بنفسك. على سبيل المثال، إليك "Imperial March" من نفس الفيلم: ملاحظات int = ( A4, R, A4, R, A4, R, F4, R, C5, R, A4, R, F4, R, C5, R, A4، R، E5، R، E5، R، E5، R، F5، R، C5، R، G5، R، F5، R، C5، R، A4، R)؛ عدد الضربات = ( 50 , 20 , 50 , 20 , 50 , 20 , 40 , 5 , 20 , 5 , 60 , 10 , 40 , 5 , 20 , 5 , 60 , 80 , 50 , 20 , 50 , 20 , 50 , 20، 40، 5، 20

    إذا لم تكن سيارتك مزودة بصافرة إنذار صوتية مثبتة، ولا تزال غير قادر على تحديد أي منها تريد شراءه وتثبيته، فهذه المقالة مخصصة لك فقط. لماذا تشتري أجهزة إنذار باهظة الثمن إذا كان بإمكانك تجميعها بنفسك بطريقة بسيطة إلى حد ما؟

    أقدم اثنين من هؤلاء دوائر بسيطةعلى وحدات التحكم الدقيقة AVR ATmega8 و Attiny2313، أو بالأحرى يتم تنفيذ نفس الدائرة ببساطة للعمل على هاتين المتحكمتين الدقيقتين. بالمناسبة، ستجد في الأرشيف إصدارين من البرامج الثابتة لوحدة التحكم الدقيقة Atmega8، حيث يصدر الأول صوتًا مشابهًا لـ جهاز إنذار السيارةوالصوت الثاني يشبه إنذار أمن المبنى (إشارة سريعة وحادة).

    يمكنك تنزيل جميع البرامج الثابتة أدناه في الأرشيف (جميعها موقعة)، وستجد في الأرشيف أيضًا محاكاة للدوائر في Proteus، مما يعني أنه بعد الاستماع إلى جميع الألحان يمكنك الاختيار من القائمة ما تفضله أكثر .

    يوجد أدناه مخطط الإشارة لـ Atmega8

    قائمة مكونات الراديو المستخدمة في دائرة Atmega8

    U1- متحكم AVR 8 بت ATmega8-16PU، الكمية. 1,
    R1- المقاوم ذو القيمة الاسمية 47 أوم، رقم. 1,
    R2، R3 - المقاوم بقيمة اسمية 270 أوم، لا. 2,
    D2، D3-LED، لا. 2,
    مكبر صوت LS1، لا. 1,
    مستشعر S1.

    وفي دائرة الإشارات على Attiny2313، تم تغيير MK فقط.
    U1- متحكم AVR 8 بت ATtiny2313-20PU، لا. 1.

    لوحة الدوائر المطبوعةلـ Atmega8 يبدو مثل هذا:

    كما ترون، الدائرة بسيطة للغاية، حيث يوجد متحكم واحد فقط، و3 مقاومات، و2 مصابيح LED، ومكبر صوت آخر. بدلا من الزر، يمكنك استخدام مفتاح القصب أو جهة اتصال أخرى.

    مبدأ التشغيل هو على النحو التالي. بمجرد توصيل الطاقة، يضيء مؤشر LED (في الدائرة D3) على الفور أو يبدأ في الوميض (اعتمادًا على البرنامج الثابت)، وإذا لم نلمس المستشعر، فسيكون المنبه صامتًا. الآن، إذا تم تشغيل المستشعر، فستعمل صفارة الإنذار أيضًا، وسيومض مؤشر LED أيضًا، ولكن D2.

    إذا كنت تريد أن تومض المصابيح الأمامية للسيارة عندما يعمل المنبه، فللقيام بذلك، تحتاج إلى توصيل طرف المتحكم الدقيق 24 PC1 بالمرحل عبر الترانزستور، والمرحل نفسه بالمصابيح الأمامية. لإيقاف تشغيل صفارات الإنذار، تحتاج إلى إيقاف تشغيل الجهاز وتشغيله مرة أخرى، أو ببساطة الضغط على الزر. لتشغيل المتحكم الدقيق، تحتاج إلى مذبذب داخلي بتردد 8 ميجاهرتز،

    إذا كنت ترغب في تحسين صوت المنبه بطريقة أو بأخرى، فيمكنك تجميع مكبر للصوت مع الترانزستورات وتوصيله بالدائرة. وهذا بالضبط ما فعلته، لكنني لم أصوره في هذا الرسم البياني.

    دعنا ننتقل إلى الدائرة الموجودة على Attiny 2313، كما قلت سابقًا، بها نفس التفاصيل ونفس مبدأ التشغيل، تم تغيير MK فقط، ونتيجة لذلك، الأطراف المتصلة، يعمل هذا المتحكم الدقيق من مذبذب داخلي بتردد 4 ميجاهرتز، على الرغم من إمكانية وميضه بسرعة 1 ميجاهرتز.

    يوجد أدناه مخطط الاتصال الموجود بالفعل على Attiny2313

    بالنسبة إلى عضو الكنيست هذا، كتبت نسخة واحدة فقط من البرنامج الثابت، وقمت بتجميع كل شيء على لوحة الدائرة، وفحصته، وكل شيء يعمل بشكل جيد.
    ويجب ضبط الصمامات كما هو موضح أدناه:





قمة