اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8

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

سأوضح لك اليوم كيفية استخدام أوراق البيانات لحل المهام البسيطة إلى حد ما ولكنها ضرورية للعديد من المشاريع على وحدات تحكم STM32 (Blue Pill) و STM8. جميع المشاريع التجريبية مخصصة لمصابيح LED المفضلة لدي ، وسنضيئها بكميات كبيرة ، والتي سيتعين علينا استخدام جميع أنواع الأجهزة الطرفية المثيرة للاهتمام.

اتضح مرة أخرى أن النص ضخم ، لذا من أجل الراحة ، أقوم بإنشاء المحتوى:

STM32 Blue Pill: 16 LED مع سائق DM634
STM8: إعداد ستة دبابيس PWM
STM8: 8 مصابيح RGB LED على ثلاثة دبابيس ، المقاطعات

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

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

آمل أن تساعد مقالتي شخصًا في مرحلة مماثلة من الغوص في هواية.

STM32

16 مصباح LED مع DM634 و SPI

مشروع صغير يستخدم Blue Pill (STM32F103C8T6) ومشغل DM634 LED. بمساعدة أوراق البيانات ، سنتعامل مع برنامج التشغيل ومنافذ STM IO وتكوين SPI.

DM634

الرقاقة التايوانية ذات مخرجات PWM 16 × 16 بت ، يمكن ربطها بالسلاسل. يُعرف الطراز الأصغر 12 بت من مشروع محلي حزمة خفيفة. في وقت من الأوقات ، بالاختيار بين DM63x و TLC5940 المشهور ، استقرت على DM لعدة أسباب: 1) TLC على Aliexpress مزيف بالتأكيد ، لكن هذا ليس كذلك ؛ 2) DM لديه PWM مستقل مع مولد التردد الخاص به ؛ 3) يمكن شراؤها بسعر رخيص في موسكو ، ولا تنتظر طردًا من علي. وبالطبع ، كان من المثير للاهتمام تعلم كيفية التحكم في الشريحة بنفسك ، وعدم استخدام مكتبة جاهزة. يتم الآن تقديم الرقائق بشكل أساسي في حزمة SSOP24 ، ومن السهل لحامها على المحول.

بما أن الشركة المصنعة تايوانية ، ورقة البيانات إلى الرقاقة مكتوب باللغة الإنجليزية الصينية ، مما يعني أنه سيكون ممتعًا. أول نظرة على pinoutاتصال دبوس) لفهم أي ساق لتوصيل ماذا ، ووصف الدبابيس (دبوس الوصف). 16 دبابيس:

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
مصادر بالوعة DC (استنزاف مفتوح)

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

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
المقاومات الخارجية بين REXT و GND لتعيين قيمة الإخراج الحالية

يتم تثبيت المقاوم المرجعي بين دبوس REXT والأرض ، والذي يتحكم في المقاومة الداخلية للمخرجات ، انظر الرسم البياني في الصفحة 9 من ورقة البيانات. في DM634 ، يمكن أيضًا التحكم في هذه المقاومة بواسطة البرنامج عن طريق ضبط السطوع الكلي (سطوع عالمي) ؛ لن أخوض في التفاصيل في هذا المقال ، سأضع المقاوم 2.2 - 3 kOhm هنا.

لفهم كيفية التحكم في الشريحة ، دعنا نلقي نظرة على وصف واجهة الجهاز:

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8

نعم ، ها هي الإنجليزية الصينية بكل مجدها. من الصعب ترجمة هذا ، يمكنك فهمه إذا كنت ترغب في ذلك ، ولكن هناك طريقة أخرى - للنظر في كيفية وصف الاتصال في ورقة البيانات بـ TLC5940 القريب وظيفيًا:

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
... مطلوب ثلاثة دبابيس فقط لإدخال البيانات في الجهاز. تعمل الحافة الصاعدة لإشارة SCLK على تحويل البيانات من دبوس SIN إلى السجل الداخلي. بعد تحميل جميع البيانات ، تقوم إشارة XLAT قصيرة عالية بإغلاق البيانات المنقولة تسلسليًا في السجلات الداخلية. السجلات الداخلية هي بوابات يتم تشغيلها بواسطة مستوى إشارة XLAT. يتم إرسال جميع البيانات MSB أولاً.

مزلاج - مزلاج / مزلاج / مزلاج.
ارتفاع الحافة هي الحافة الأمامية للنبض
MSB أولا - الجزء الأكثر أهمية (أقصى اليسار) للأمام.
لساعة البيانات - نقل البيانات بالتتابع (شيئا فشيئا).

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

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

لذلك ، يتم تنفيذ نقل البيانات إلى DM634 على النحو التالي: اضبط إدخال DAI على قيمة البت العالي لمؤشر LED البعيد ، واسحب DCK لأعلى ولأسفل ؛ اضبط إدخال DAI على قيمة البتة التالية ، اسحب DCK ؛ وما إلى ذلك حتى يتم إرسال جميع البتات (سجلت في) ، وبعد ذلك نسحب LAT. يمكن القيام بذلك يدويًاقليلا الانفجار) ، ولكن من الأفضل استخدام واجهة SPI المصقولة بشكل خاص لهذا الغرض ، حيث يتم تقديمها على STM32 في نسختين.

قرص أزرق STM32F103

تمهيدية: تعتبر وحدات التحكم STM32 أكثر تعقيدًا من Atmega328 مما يمكن أن تكون مخيفة. في الوقت نفسه ، لأسباب تتعلق بتوفير الطاقة ، يتم تعطيل جميع الأجهزة الطرفية تقريبًا في البداية ، ويكون تردد الساعة 8 ميجا هرتز من مصدر داخلي. لحسن الحظ ، كتب مبرمجو STM رمزًا يجلب الشريحة إلى 72 ميجا هرتز "المحسوبة" ، وقام مؤلفو جميع IDEs المعروفين بإدراجها في إجراء التهيئة ، لذلك لا نحتاج إلى تسجيل الوقت (ولكن يمكنك إذا كنت تريد حقًا). لكن عليك تشغيل الأجهزة الطرفية.

التوثيق: تم تثبيت شريحة STM32F103C8T6 الشهيرة على Blue Pill ، وهناك وثيقتان مفيدتان لها:

في ورقة البيانات ، قد نهتم بما يلي:

  • Pinouts - pinouts رقاقة - في حال قررنا صنع لوحات بأنفسنا ؛
  • خريطة الذاكرة - خريطة ذاكرة لشريحة معينة. يحتوي الدليل المرجعي على خريطة للخط بأكمله ، ويذكر السجلات غير الموجودة لدينا.
  • جدول تعريفات الدبوس - يسرد وظائف الدبوس الرئيسية والبديلة ؛ بالنسبة إلى "الحبة الزرقاء" على الإنترنت ، يمكنك العثور على صور أكثر ملاءمة مع قائمة بالدبابيس ووظائفها. لذلك ، نحن على الفور google Blue Pill pinout ونبقي هذه الصورة في متناول اليد:

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
ملحوظة: حدث خطأ في الصورة من الإنترنت لوحظ في التعليقات نشكره عليه. تم استبدال الصورة ، لكن هذا درس - من الأفضل التحقق من المعلومات وليس من أوراق البيانات.

نقوم بإزالة ورقة البيانات ، ونفتح الدليل المرجعي ، ومن الآن فصاعدًا نستخدمها فقط.
الإجراء: التعامل مع الإدخال / الإخراج القياسي ، وتكوين SPI ، وتشغيل الأجهزة الطرفية الضرورية.

إخراج الإدخال

في Atmega328 ، يكون الإدخال / الإخراج بسيطًا للغاية ، ولهذا السبب قد تكون وفرة خيارات STM32 مربكة. الآن نحتاج فقط إلى الاستنتاجات ، ولكن حتى هناك أربعة خيارات:

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
فتح مخرج الصرف ، إخراج الدفع والسحب ، بديل الدفع والسحب ، بديل الصرف المفتوح

"أسحب أدفع" (دفع سحب) - الإخراج المعتاد من Arduino ، يمكن أن يكون الدبوس إما مرتفعًا أو منخفضًا. ولكن مع ظهور "هجرة مفتوحة" تعقيد، على الرغم من أن كل شيء بسيط هنا في الواقع:

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
تكوين الإخراج / عند تعيين المنفذ للإخراج: / تمكين المخزن المؤقت للإخراج: / - وضع التصريف المفتوح: "0" في سجل الإخراج يمكّن N-MOS ، "1" في سجل الإخراج يترك المنفذ في وضع Hi-Z (P -MOS غير مفعل) / - وضع الدفع والسحب: "0" في سجل الإخراج ينشط N-MOS ، "1" في سجل الإخراج ينشط P-MOS.

كل فرق الصرف المفتوح (استنزاف مفتوح) من "push-pull" (دفع سحب) هو أنه في الدبوس الأول لا يمكن أن يأخذ الحالة HIGH: عندما تتم كتابة وحدة في سجل الإخراج ، فإنها تنتقل إلى وضع المقاومة العالية (مقاومة عالية, مرحبا- Z). عند كتابة الصفر ، يتصرف الدبوس في كلا الوضعين بنفس الطريقة ، منطقيًا وكهربائيًا.

في وضع الإخراج العادي ، يقوم الدبوس ببساطة بترجمة محتويات سجل الإخراج. في "البديل" يتم التحكم فيه من قبل الطرف المقابل (انظر 9.1.4):

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
إذا تم تكوين بت المنفذ كإخراج وظيفة بديلة ، فسيتم تعطيل سجل الإخراج ويتم توصيل الدبوس بإشارة خرج الجهاز المحيطي.

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

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
إذا كانت الأجهزة الطرفية المتعددة تستخدم نفس الدبوس ، لتجنب التعارض بين الوظائف البديلة ، يجب استخدام طرف طرفي واحد فقط في كل مرة ، والتبديل باستخدام بت تمكين الساعة الطرفية (في سجل RCC المقابل).

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

لذلك: نحن نستخدم SPI ، مما يعني أن دبابيس (مع البيانات وإشارة الساعة) يجب أن تكون "وظيفة دفع وسحب بديلة" ، ويجب أن يكون الآخر (LAT) "عادي دفع - سحب". ولكن قبل تعيينهم ، دعونا نتعامل مع SPI.

SPI

اختراق صغير آخر

واجهة SPI أو Serial Peripheral Interface (الواجهة الطرفية التسلسلية) هي واجهة بسيطة وفعالة للغاية لتواصل MK مع أعضاء MK الآخرين والعالم الخارجي بشكل عام. تم بالفعل وصف مبدأ تشغيله أعلاه ، حيث يتعلق ببرنامج تشغيل LED الصيني (انظر القسم 25 في الدليل المرجعي). يمكن أن يعمل SPI في وضعي الرئيسي ("الرئيسي") والعبد ("الرقيق"). يحتوي SPI على أربع قنوات أساسية ، قد لا تشارك جميعها:

  • MOSI ، إخراج رئيسي / إدخال تابع: يرسل هذا الدبوس البيانات في الوضع الرئيسي ، ويستقبل البيانات في وضع الرقيق ؛
  • MISO ، إدخال رئيسي / إخراج تابع: على العكس من ذلك ، في السيد يتلقى ، في العبد الذي يقدمه ؛
  • SCK ، Serial Clock: يحدد تردد إرسال البيانات في الجهاز الرئيسي أو يستقبل إشارة الساعة في التابع. في الأساس ، يدق الإيقاعات ؛
  • SS ، Slave Select: مع هذه القناة ، يعرف العبد أنهم يريدون شيئًا منه. في STM32 يطلق عليه NSS ، حيث N = سلبي ، أي يصبح المتحكم عبدا إذا كانت هذه القناة لها أرضية. إنه يتكامل بشكل جيد مع وضع Open Drain Output ، لكن هذه قصة أخرى.

مثل أي شيء آخر ، فإن SPI على STM32 غنية بالوظائف ، مما يجعل من الصعب فهمها إلى حد ما. على سبيل المثال ، يمكن أن يعمل ليس فقط مع SPI ، ولكن أيضًا مع واجهة I2S ، وأوصافها مختلطة في الوثائق ، تحتاج إلى قطع الفائض في الوقت المناسب. مهمتنا بسيطة للغاية: ما عليك سوى تقديم البيانات باستخدام MOSI و SCK فقط. نذهب إلى القسم 25.3.4 (اتصال أحادي الاتجاه ، اتصال أحادي الاتجاه) ، حيث نجد ساعة واحدة وسلك بيانات أحادي الاتجاه (ساعة واحدة ودفق بيانات واحد أحادي الاتجاه):

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
في هذا الوضع ، يستخدم التطبيق SPI إما في وضع الإرسال فقط أو وضع الاستلام فقط. / يشبه وضع الإرسال فقط الوضع المزدوج: يتم إرسال البيانات على دبوس الإرسال (MOSI في الوضع الرئيسي أو MISO في الوضع التابع) ، بينما يمكن استخدام دبوس الاستقبال (MISO أو MOSI على التوالي) كإدخال / إخراج عادي دبوس. في هذه الحالة ، يكفي أن يتجاهل التطبيق المخزن المؤقت Rx (إذا تمت قراءته ، فلن تكون هناك بيانات مرسلة).

رائع ، دبوس MISO مجاني ، دعنا نربط إشارة LAT به. دعونا نتعامل مع Slave Select ، والذي يمكن التحكم فيه برمجيًا على STM32 ، وهو أمر مريح للغاية. قرأنا الفقرة التي تحمل الاسم نفسه في القسم 25.3.1 SPI General Description:

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
التحكم في برنامج NSS (SSM = 1) / معلومات اختيار الرقيق واردة في بت SSI لسجل SPI_CR1. يتم ترك دبوس NSS الخارجي مجانًا لاحتياجات التطبيق الأخرى.

حان الوقت للكتابة إلى السجلات. قررت استخدام SPI2 ، فنحن نبحث عن عنوانه الأساسي في ورقة البيانات - في القسم 3.3 خريطة الذاكرة (خريطة الذاكرة):

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8

حسنًا ، لنبدأ:

#define _SPI2_(mem_offset) (*(volatile uint32_t *)(0x40003800 + (mem_offset)))

نفتح القسم 25.3.3 بعنوان "تكوين SPI في الوضع الرئيسي":

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8

1. اضبط ساعة الواجهة التسلسلية مع بتات BR [2: 0] في سجل SPI_CR1.

يتم جمع السجلات في قسم الدليل المرجعي الذي يحمل نفس الاسم. تحول العنوان (عنوان الإزاحة) يحتوي CR1 على 0x00 ، ويتم مسح جميع وحدات البت افتراضيًا (قيمة إعادة التعيين 0x0000):

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8

تقوم بتات BR بتعيين مقسم ساعة وحدة التحكم ، وبالتالي تحديد التردد الذي سيعمل عنده SPI. سيكون تردد STM32 72 ميجاهرتز ، يعمل مشغل LED ، وفقًا لورقة البيانات الخاصة به ، بتردد يصل إلى 25 ميجاهرتز ، لذلك نحتاج إلى القسمة على أربعة (BR [2: 0] = 001).

#define _SPI_CR1 0x00

#define BR_0        0x0008
#define BR_1        0x0010
#define BR_2        0x0020

_SPI2_ (_SPI_CR1) |= BR_0;// pclk/4

2. اضبط بتات CPOL و CPHA لتحديد العلاقة بين نقل البيانات وساعة الواجهة التسلسلية (انظر الرسم البياني في الصفحة 240)

نظرًا لأننا نقرأ ورقة بيانات هنا ، ولا ننظر إلى المخططات ، فلنلق نظرة فاحصة على الوصف النصي لبتات CPOL و CPHA في الصفحة 704 (الوصف العام SPI):

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
مرحلة الساعة والقطبية
باستخدام بتات CPOL و CPHA لسجل SPI_CR1 ، يمكنك تحديد أربعة خيارات برمجيًا لنسب التوقيت. تتحكم بت CPOL (قطبية الساعة) في حالة إشارة الساعة عند عدم إرسال أي بيانات. يتحكم هذا البت في الوضعين الرئيسي والعبد. إذا تمت إعادة تعيين CPOL ، فإن دبوس SCK يكون منخفضًا في حالة السكون. إذا تم تعيين بت CPOL ، يكون دبوس SCK مرتفعًا عند الخمول.
إذا تم ضبط بت CPHA (Clock Phase) ، فإن ستروب المصيدة MSB هي الحافة الثانية لإشارة SCK (تهبط إذا تم مسح CPOL ، أو ترتفع الحافة إذا تم ضبط CPOL). يتم إغلاق البيانات عند تغيير الساعة الثاني. إذا تم مسح بت CPHA ، فإن ستروب المصيدة عالية البت هي الحافة الصاعدة لإشارة SCK (تهبط إذا تم ضبط CPOL ، أو الحافة الصاعدة إذا كانت CPOL واضحة). يتم إغلاق البيانات عند تغيير الساعة الأول.

بعد أن تذوقنا هذه المعرفة ، توصلنا إلى استنتاج مفاده أن كلا البتتين يجب أن تظلا صفراً ، لأن نريد أن تظل إشارة SCK منخفضة عندما لا تكون قيد الاستخدام ، وأن يتم نقل البيانات على الحافة الصاعدة للنبضة (انظر الشكل. ارتفاع الحافة في ورقة البيانات DM634).

بالمناسبة ، واجهنا هنا أولاً ميزة المفردات في أوراق بيانات ST: فيها عبارة "إعادة تعيين البت إلى الصفر" مكتوبة لإعادة قليلاوليس لمسح قليلا، على سبيل المثال ، Atmega.

3. اضبط بت DFF لتحديد تنسيق كتلة البيانات 8 بت أو 16 بت

لقد أخذت على وجه التحديد DM16 634 بت حتى لا أزعج نفسي بنقل بيانات PWM 12 بت ، مثل DM633. DFF من المنطقي أن نضع الوحدة:

#define DFF         0x0800

_SPI2_ (_SPI_CR1) |= DFF; // 16-bit mode

4. قم بتكوين بتة LSBFIRST في سجل SPI_CR1 لتعريف نسق الكتلة

تقوم LSBFIRST ، كما يوحي اسمها ، بإعداد الإرسال باستخدام بتة أقل أهمية أولاً. لكن DM634 يريد تلقي البيانات MSB أولاً. لذلك ، نتركه يعاد تعيينه.

5. في وضع الأجهزة ، إذا كان الإدخال من دبوس NSS مطلوبًا ، فقم بتحريك دبوس NSS عاليًا أثناء تسلسل نقل البايت بأكمله. في وضع برنامج NSS ، اضبط بتات SSM و SSI في سجل SPI_CR1. إذا كان سيتم إخراج دبوس NSS ، فيجب تعيين بت SSOE فقط.

قم بتثبيت SSM و SSI لنسيان وضع أجهزة NSS:

#define SSI         0x0100
#define SSM         0x0200

_SPI2_ (_SPI_CR1) |= SSM | SSI; //enable software control of SS, SS high

6. يجب تعيين بتات MSTR و SPE (تبقى مضبوطة فقط إذا كانت NSS عالية)

في الواقع ، باستخدام هذه البتات ، نقوم بتعيين SPI الخاص بنا كسيد وتشغيله:

#define MSTR        0x0004
#define SPE         0x0040

_SPI2_ (_SPI_CR1) |= MSTR; //SPI master
//когда все готово, включаем SPI
_SPI2_ (_SPI_CR1) |= SPE;

تم تكوين SPI ، فلنكتب على الفور الوظائف التي ترسل البايت إلى السائق. تابع القراءة 25.3.3 "تكوين SPI في الوضع الرئيسي":

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
أمر نقل البيانات
يبدأ النقل عند كتابة البايت في المخزن المؤقت Tx.
يتم تحميل بايت البيانات في سجل الإزاحة في موازى الوضع (من الناقل الداخلي) أثناء إرسال البتة الأولى ، وبعد ذلك يتم نقلها ثابت وضع MOSI pin ، أول أو آخر بت للأمام اعتمادًا على إعداد بت LSBFIRST في سجل CPI_CR1. يتم تعيين علامة TXE بعد نقل البيانات من المخزن المؤقت Tx لتحويل التسجيل، ويتم إنشاء مقاطعة إذا تم تعيين بت TXEIE في سجل CPI_CR1.

لقد أبرزت بضع كلمات في الترجمة للفت الانتباه إلى إحدى ميزات تنفيذ SPI في وحدات تحكم STM. على Atmega ، علم TXE (Tx فارغ، Tx فارغ وجاهز لاستلام البيانات) يتم تعيينه فقط بعد إرسال البايت بأكمله خارج. وهنا يتم تعيين هذه العلامة بعد دفع البايت إلى سجل التحول الداخلي. نظرًا لأنه يتم دفعه هناك بكل وحدات البت في نفس الوقت (بالتوازي) ، ثم يتم إرسال البيانات بالتتابع ، يتم تعيين TXE قبل إرسال البايت بالكامل. هذا مهم لأن في حالة برنامج تشغيل LED الخاص بنا ، نحتاج إلى سحب دبوس LAT بعد الإرسال جميع البيانات ، أي فقط علامة TXE لن تكون كافية بالنسبة لنا.

مما يعني أننا بحاجة إلى علم آخر. لنلق نظرة على 25.3.7 - "إشارات الحالة":

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
<…>
اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
علم BUSY
يتم تعيين علامة BSY وإزالتها بواسطة الأجهزة (الكتابة إليها ليس لها أي تأثير). تشير علامة BSY إلى حالة طبقة اتصال SPI.
يعيد:
عند اكتمال النقل (باستثناء الوضع الرئيسي إذا كان النقل مستمرًا)
عندما يتم تعطيل SPI
عند حدوث خطأ في الوضع الرئيسي (MODF = 1)
إذا لم يكن الإرسال مستمرًا ، فسيتم مسح علم BSY بين كل عملية إرسال للبيانات.

حسنًا ، سيكون مفيدًا. اكتشف مكان وجود المخزن المؤقت Tx. للقيام بذلك ، اقرأ "SPI Data Register":

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
بت 15: 0 DR [15: 0] سجل بيانات
البيانات المتلقاة أو البيانات المراد نقلها.
ينقسم سجل البيانات إلى مخزنين مؤقتين ، أحدهما للكتابة (المخزن المؤقت للإرسال) والآخر للقراءة (المخزن المؤقت للاستقبال). الكتابة إلى سجل البيانات تكتب إلى المخزن المؤقت Tx ، وستؤدي القراءة من سجل البيانات إلى إرجاع القيمة الموجودة في المخزن المؤقت Rx.

حسنًا ، سجل الحالة ، حيث توجد أعلام TXE و BSY:

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8

نحن نكتب:

#define _SPI_DR  0x0C
#define _SPI_SR  0x08

#define BSY         0x0080
#define TXE         0x0002

void dm_shift16(uint16_t value)
{
    _SPI2_(_SPI_DR) = value; //send 2 bytes
    while (!(_SPI2_(_SPI_SR) & TXE)); //wait until they're sent
}

حسنًا ، نظرًا لأننا نحتاج إلى نقل 16 ضعف XNUMX بايت ، وفقًا لعدد مخرجات برنامج تشغيل LED ، شيء من هذا القبيل:

void sendLEDdata()
{
    LAT_low();
    uint8_t k = 16;
    do
    {   k--;
        dm_shift16(leds[k]);
    } while (k);

    while (_SPI2_(_SPI_SR) & BSY); // finish transmission

    LAT_pulse();
}

لكننا لا نعرف كيفية سحب دبوس LAT حتى الآن ، لذلك دعنا نعود إلى I / O.

قم بتعيين دبابيس

في STM32F1 ، تكون السجلات المسؤولة عن حالة المسامير غير عادية إلى حد ما. من الواضح أن هناك عددًا أكبر منهم من Atmega ، لكنها تختلف أيضًا عن رقائق STM الأخرى. القسم 9.1 وصف GPIO العام:

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
كل من منافذ الإدخال / الإخراج للأغراض العامة (GPIO) يحتوي على سجلي تكوين 32 بت (GPIOx_CRL و GPIOx_CRH) ، وسجلا بيانات 32 بت (GPIOx_IDR و GPIOx_ODR) ، ومسجل تعيين / إعادة تعيين 32 بت (GPIOx_BSRR) ، وسجل إعادة تعيين 16 بت (GPIOx_BRR) و 32- سجل حظر البت (GPIOx_LCKR).

غير المعتاد ، وغير المريح أيضًا ، هما أول مسجلين هنا ، لأن دبابيس المنفذ الـ 16 مبعثرة عبرها بتنسيق "أربعة بت لكل أخ". أولئك. الدبابيس من XNUMX إلى XNUMX موجودة في CRL ، والباقي في CRH. في الوقت نفسه ، تتلاءم السجلات المتبقية بنجاح مع أجزاء كل دبابيس المنافذ - غالبًا ما تبقى نصف "محجوزة".

للتبسيط ، لنبدأ في نهاية القائمة.

نحن لا نحتاج إلى سجل الحجب.

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

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
تثبيت ذري أو إعادة تعيين
لا تحتاج إلى تعطيل المقاطعات عند برمجة GPIOx_ODR على مستوى البت: يمكنك تغيير بت واحد أو أكثر باستخدام عملية كتابة ذرية واحدة لـ APB2. يتم تحقيق ذلك من خلال كتابة "1" إلى سجل الضبط / إعادة الضبط (GPIOx_BSRR أو ، لإعادة التعيين فقط ، GPIOx_BRR) من البت المراد تغييره. ستبقى وحدات البت الأخرى دون تغيير.

تحتوي سجلات البيانات على أسماء تتحدث تمامًا - IDR = إدخال سجل الاتجاه ، سجل الإدخال ؛ ODR = الناتج سجل الاتجاه ، سجل الإخراج. في المشروع الحالي لا نحتاجهم.

وأخيرًا ، يتم تسجيل عنصر التحكم. نظرًا لأننا مهتمون بدبابيس SPI الثاني ، وهي PB13 و PB14 و PB15 ، فإننا ننظر على الفور إلى CRH:

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8

ونرى أنه سيكون من الضروري كتابة شيء ما بالبتات من العشرين إلى الحادي والثلاثين.

لقد اكتشفنا بالفعل ما نريده من المسامير أعلاه ، لذلك سأفعل هنا بدون لقطة شاشة ، فقط قل أن الوضع يحدد الاتجاه (الإدخال إذا تم ضبط كلتا البتتين على 0) وسرعة الدبوس (نحتاج إلى 50 ميجا هرتز ، أي كل من الدبوس إلى "1") ، و CNF يضبط الوضع: عادي "دفع - 00" ، "بديل" - 10. بشكل افتراضي ، كما نرى أعلاه ، تحتوي جميع المسامير على البت الثالث من الأسفل ( CNF0) ، يقوم بتعيينها على الوضع إدخال عائم.

نظرًا لأنني أخطط للقيام بشيء آخر باستخدام هذه الشريحة ، من أجل البساطة ، فقد حددت بشكل عام جميع قيم MODE و CNF الممكنة لكل من سجلات التحكم الدنيا والعليا.

بطريقة ما مثل هذا

#define CNF0_0 0x00000004
#define CNF0_1 0x00000008
#define CNF1_0 0x00000040
#define CNF1_1 0x00000080
#define CNF2_0 0x00000400
#define CNF2_1 0x00000800
#define CNF3_0 0x00004000
#define CNF3_1 0x00008000
#define CNF4_0 0x00040000
#define CNF4_1 0x00080000
#define CNF5_0 0x00400000
#define CNF5_1 0x00800000
#define CNF6_0 0x04000000
#define CNF6_1 0x08000000
#define CNF7_0 0x40000000
#define CNF7_1 0x80000000
#define CNF8_0 0x00000004
#define CNF8_1 0x00000008
#define CNF9_0 0x00000040
#define CNF9_1 0x00000080
#define CNF10_0 0x00000400
#define CNF10_1 0x00000800
#define CNF11_0 0x00004000
#define CNF11_1 0x00008000
#define CNF12_0 0x00040000
#define CNF12_1 0x00080000
#define CNF13_0 0x00400000
#define CNF13_1 0x00800000
#define CNF14_0 0x04000000
#define CNF14_1 0x08000000
#define CNF15_0 0x40000000
#define CNF15_1 0x80000000

#define MODE0_0 0x00000001
#define MODE0_1 0x00000002
#define MODE1_0 0x00000010
#define MODE1_1 0x00000020
#define MODE2_0 0x00000100
#define MODE2_1 0x00000200
#define MODE3_0 0x00001000
#define MODE3_1 0x00002000
#define MODE4_0 0x00010000
#define MODE4_1 0x00020000
#define MODE5_0 0x00100000
#define MODE5_1 0x00200000
#define MODE6_0 0x01000000
#define MODE6_1 0x02000000
#define MODE7_0 0x10000000
#define MODE7_1 0x20000000
#define MODE8_0 0x00000001
#define MODE8_1 0x00000002
#define MODE9_0 0x00000010
#define MODE9_1 0x00000020
#define MODE10_0 0x00000100
#define MODE10_1 0x00000200
#define MODE11_0 0x00001000
#define MODE11_1 0x00002000
#define MODE12_0 0x00010000
#define MODE12_1 0x00020000
#define MODE13_0 0x00100000
#define MODE13_1 0x00200000
#define MODE14_0 0x01000000
#define MODE14_1 0x02000000
#define MODE15_0 0x10000000
#define MODE15_1 0x20000000

دبابيسنا موجودة على المنفذ B (العنوان الأساسي - 0x40010C00) ، الرمز:

#define _PORTB_(mem_offset) (*(volatile uint32_t *)(0x40010C00 + (mem_offset)))

#define _BRR  0x14
#define _BSRR 0x10
#define _CRL  0x00
#define _CRH  0x04

//используем стандартный SPI2: MOSI на B15, CLK на B13
//LAT пусть будет на неиспользуемом MISO – B14

//очищаем дефолтный бит, он нам точно не нужен
_PORTB_ (_CRH) &= ~(CNF15_0 | CNF14_0 | CNF13_0 | CNF12_0);

//альтернативные функции для MOSI и SCK
_PORTB_ (_CRH) |= CNF15_1 | CNF13_1;

//50 МГц, MODE = 11
_PORTB_ (_CRH) |= MODE15_1 | MODE15_0 | MODE14_1 | MODE14_0 | MODE13_1 | MODE13_0;

وبناءً على ذلك ، يمكنك كتابة تعريفات لـ LAT ، والتي ستنشل مسجلات BRR و BSRR:

/*** LAT pulse – high, then low */
#define LAT_pulse() _PORTB_(_BSRR) = (1<<14); _PORTB_(_BRR) = (1<<14)

#define LAT_low() _PORTB_(_BRR) = (1<<14)

(LAT_low فقط من خلال القصور الذاتي ، بطريقة ما كانت دائمًا ، دعها تبقى لنفسك)

الآن كل شيء رائع ، إنه لا يعمل. نظرًا لأن هذا هو STM32 ، فإنهم يوفرون الكهرباء هنا ، مما يعني أنك بحاجة إلى تشغيل تسجيل الوقت للأجهزة الطرفية الضرورية.

قم بتشغيل تسجيل الوقت

الساعة مسؤولة عن تسجيل الوقت ، وهي أيضًا ساعة. ويمكننا بالفعل ملاحظة الاختصار RCC. نحن نبحث عنه في الوثائق: هذا هو إعادة الضبط والتحكم في الساعة (إدارة إعادة التعيين وتسجيل الوقت).

كما ذكرنا أعلاه ، لحسن الحظ ، قام الأشخاص من STM بأصعب جزء في موضوع تسجيل الوقت بالنسبة لنا ، والذي شكراً جزيلاً لهم (مرة أخرى سأقدم رابطًا إلى موقع دي هالتلتوضيح مدى ارتباكها). نحتاج فقط إلى السجلات المسؤولة عن تمكين تسجيل الوقت المحيطي (تسجيلات تمكين الساعة المحيطية). أولاً ، دعنا نعثر على العنوان الأساسي لـ RCC ، فهو في بداية "بطاقة الذاكرة":

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8

#define _RCC_(mem_offset) (*(volatile uint32_t *)(0x40021000 + (mem_offset)))

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

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8

وفيها ، على التوالي ، بتات تتضمن تسجيل الوقت SPI2 و IOPB (I / O Port B) والوظائف البديلة (AFIO).

#define _APB2ENR 0x18
#define _APB1ENR 0x1C

#define IOPBEN 0x0008
#define SPI2EN 0x4000
#define AFIOEN 0x0001

//включаем тактирование порта B и альт. функций
_RCC_(_APB2ENR) |= IOPBEN | AFIOEN;

//включаем  тактирование SPI2
_RCC_(_APB1ENR) |= SPI2EN;

يمكن العثور على الكود النهائي هنا.

إذا كانت هناك فرصة ورغبة في الاختبار ، فنحن نربط DM634 على النحو التالي: DAI بـ PB15 ، و DCK إلى PB13 ، و LAT إلى PB14. نحن نطعم السائق من 5 فولت ، ولا تنسَ الجمع بين الأسباب.

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8

STM8 بوم

PWM على STM8

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

الشريحة لديها أيضا ورقة البيانات и دليل مرجعي RM0016، في أول pinout وتسجيل العناوين ، في الثانية - كل شيء آخر. برمجة STM8 بلغة C في بيئة تطوير متكاملة قبيحة ST تطوير البصرية.

تسجيل الوقت و I / O

بشكل افتراضي ، يعمل STM8 بتردد 2 ميغا هرتز ، ويجب تصحيح ذلك على الفور.

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
ساعة HSI (داخلية عالية)
ساعة HSI مشتقة من مذبذب RC داخلي 16 ميجا هرتز مع مقسم قابل للبرمجة (1 إلى 8). يتم ضبطه في سجل مقسم الساعة (CLK_CKDIVR).
ملاحظة: يتم تحديد مذبذب HSI RC مع مقسم 8 كمصدر الساعة الرئيسي عند بدء التشغيل.

نجد عنوان السجل في ورقة البيانات والوصف في المرجع ونرى أن السجل يحتاج إلى مسح:

#define CLK_CKDIVR *(volatile uint8_t *)0x0050C6

CLK_CKDIVR &= ~(0x18);

نظرًا لأننا سنقوم بتشغيل PWM وتوصيل مصابيح LED ، فلنلقِ نظرة على pinout:

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8

الرقاقة صغيرة ، العديد من الوظائف معلقة على نفس المسامير. ما هو بين قوسين معقوفين هو "وظيفة بديلة" ، يتم تبديلها بواسطة "بايت الخيار" (بايت الخيار) - شيء مثل الصمامات Atmega. يمكنك تغيير قيمهم برمجيًا ، لكن هذا ليس ضروريًا ، لأن. يتم تنشيط الوظيفة الجديدة فقط بعد إعادة التشغيل. من الأسهل استخدام ST Visual Programmer (يتم تنزيله باستخدام Visual Develop) ، والذي يمكنه تغيير هذه البايت. يظهر pinout أن مخرجات CH1 و CH2 لجهاز ضبط الوقت الأول مخفية بين أقواس مربعة ؛ من الضروري ضبط بتات AFR1 و AFR0 في STVP ، وسينقل الثاني أيضًا إخراج CH1 الخاص بالمؤقت الثاني من PD4 إلى PC5.

وبالتالي ، ستتحكم 6 دبابيس في مصابيح LED: PC6 و PC7 و PC3 للموقت الأول ، و PC5 و PD3 و PA3 للثاني.

يعد إعداد دبابيس الإدخال / الإخراج نفسها على STM8 أبسط وأكثر منطقية من STM32:

  • سجل اتجاه البيانات المألوف Atmega DDR (سجل اتجاه البيانات): 1 = الإخراج ؛
  • سجل التحكم الأول CR1 ، عند الإخراج ، يضبط وضع الدفع والسحب (1) أو الصرف المفتوح (0) ؛ منذ أن قمت بتوصيل مصابيح LED بالشريحة بالكاثودات ، أترك الأصفار هنا ؛
  • يضبط سجل التحكم الثاني CR2 سرعة الساعة عند الإخراج: 1 = 10 ميجاهرتز

#define PA_DDR     *(volatile uint8_t *)0x005002
#define PA_CR2     *(volatile uint8_t *)0x005004
#define PD_DDR     *(volatile uint8_t *)0x005011
#define PD_CR2     *(volatile uint8_t *)0x005013
#define PC_DDR     *(volatile uint8_t *)0x00500C
#define PC_CR2     *(volatile uint8_t *)0x00500E

PA_DDR = (1<<3); //output
PA_CR2 |= (1<<3); //fast
PD_DDR = (1<<3); //output
PD_CR2 |= (1<<3); //fast
PC_DDR = ((1<<3) | (1<<5) | (1<<6) | (1<<7)); //output
PC_CR2 |= ((1<<3) | (1<<5) | (1<<6) | (1<<7)); //fast

إعداد PWM

أولاً ، دعنا نحدد المصطلحات:

  • تردد بوم - التردد الذي يدق به الموقت ؛
  • إعادة التحميل التلقائي ، AR - القيمة التي يتم تحميلها تلقائيًا ، والتي سيحسب العداد إليها (فترة النبض) ؛
  • حدث التحديث ، UEV - حدث يحدث عندما يحسب عداد الوقت إلى AR ؛
  • دورة عمل PWM - دورة عمل PWM ، وغالبا ما تسمى "دورة العمل" ؛
  • التقاط / مقارنة القيمة - قيمة للالتقاط / المقارنة ، العد حتى يصل إليها الموقت سوف تفعل شيئا (في حالة PWM ، فإنه يعكس إشارة الخرج) ؛
  • قيمة التحميل المسبق - قيمة محملة مسبقا. قارن القيمة لا يمكن التغيير أثناء تكتكة المؤقت ، وإلا ستنكسر دورة PWM. لذلك ، يتم وضع القيم المرسلة الجديدة في المخزن المؤقت ويتم سحبها عندما يصل المؤقت إلى نهاية العد التنازلي ويتم إعادة تعيينه ؛
  • محاذاة الحافة и أوضاع محاذاة للوسط - المحاذاة على الحدود وفي الوسط ، مثل atmelovskie سريع PWM и المرحلة الصحيحة PWM.
  • OCiREF ، إخراج مقارنة إشارة مرجعية - إشارة الخرج المرجعية ، في الواقع ، ما يظهر على الدبوس المقابل في وضع PWM.

كما هو واضح بالفعل من pinout ، فإن مؤقتين لهما إمكانيات PWM - الأول والثاني. كلاهما 16 بت ، الأول به الكثير من الميزات الإضافية (على وجه الخصوص ، يمكنه العد لأعلى ولأسفل). نحن بحاجة إلى كليهما للعمل بنفس الطريقة ، لذلك قررت أن أبدأ بالثانية الأكثر فقرًا بشكل واضح ، حتى لا أستخدم شيئًا غير موجود فيه عن طريق الخطأ. تتمثل بعض المشاكل في أن وصف وظيفة PWM لجميع أجهزة ضبط الوقت في الدليل المرجعي موجود في الفصل الخاص بالمؤقت الأول (وضع 17.5.7 PWM) ، لذلك عليك القفز ذهابًا وإيابًا من خلال المستند طوال الوقت.

يتمتع PWM على STM8 بميزة مهمة على Atmega PWM:

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
PWM مع محاذاة الحافة
تكوين الحساب من الأسفل إلى الأعلى
يعد العد التصاعدي نشطًا إذا كانت بت DIR في سجل TIM_CR1 واضحًا
مثال
يستخدم المثال وضع PWM الأول. تظل الإشارة المرجعية لـ PWM OCiREF مرتفعة طالما TIM1_CNT <TIM1_CCRi. خلاف ذلك ، فإنه يأخذ مستوى منخفض. إذا كانت القيمة المطلوب مقارنتها في سجل TIM1_CCRi أكبر من قيمة التحميل التلقائي (سجل TIM1_ARR) ، يتم الاحتفاظ بإشارة OCiREF عند 1. إذا كانت قيمة المقارنة 0 ، يتم الاحتفاظ بـ OCiREF عند الصفر....

مؤقت STM8 أثناء حدث التحديث يتحقق أولا قارن القيمة، وعندها فقط ينتج إشارة مرجعية. في Atmega ، يرتجف المؤقت أولاً ، ثم يقارن ، نتيجة لذلك ، متى compare value == 0 الإخراج عبارة عن إبرة يجب التعامل معها بطريقة ما (على سبيل المثال ، عن طريق عكس المنطق برمجيًا).

إذن ما نريد فعله: 8 بت PWM (AR == 255) ، العد من الأسفل إلى الأعلى ، المحاذاة على طول الحدود. نظرًا لأن المصابيح متصلة بالشريحة بواسطة الكاثودات ، يجب أن يخرج PWM 0 (LED قيد التشغيل) حتى قارن القيمة و 1 بعد.

لقد قرأنا بالفعل عن البعض وضع PWM، لذلك نجد السجل المطلوب للمؤقت الثاني من خلال البحث في الدليل المرجعي عن هذه العبارة (18.6.8 - TIMx_CCMR1):

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
110: وضع PWM الأول - عند العد من الأسفل إلى الأعلى ، تكون القناة الأولى نشطة طالما TIMx_CNT <TIMx_CCR1. خلاف ذلك ، القناة الأولى غير نشطة. [مزيد في المستند ، نسخ ولصق خاطئ من المؤقت 1] 111: وضع PWM الثاني - عند العد من الأسفل إلى الأعلى ، تكون القناة الأولى غير نشطة حتى TIMx_CNT <TIMx_CCR1. خلاف ذلك ، القناة الأولى نشطة.

نظرًا لأن مصابيح LED متصلة بـ MK باستخدام الكاثودات ، فإن الوضع الثاني يناسبنا (الوضع الأول أيضًا ، لكننا لا نعرف هذا بعد).

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
Bit 3 OC1PE: تمكين إخراج التحميل المسبق 1
0: التحميل المسبق التسجيل على TIMx_CCR1 معطل. يمكنك الكتابة إلى TIMx_CCR1 في أي وقت. القيمة الجديدة تعمل على الفور.
1: تسجيل التحميل المسبق على TIMx_CCR1 ممكّن. عمليات القراءة / الكتابة الوصول إلى سجل التحميل المسبق. يتم تحميل القيمة المحملة مسبقًا لـ TIMx_CCR1 في سجل الظل أثناء كل حدث تحديث.
* ملاحظة: يجب تمكين سجلات التحميل المسبق حتى يعمل وضع PWM بشكل صحيح. هذا اختياري في وضع الإشارة الفردية (يتم ضبط بت OPM في سجل TIMx_CR1).

حسنًا ، قم بتشغيل كل ما تحتاجه للقنوات الثلاث للمؤقت الثاني:

#define TIM2_CCMR1 *(volatile uint8_t *)0x005307
#define TIM2_CCMR2 *(volatile uint8_t *)0x005308
#define TIM2_CCMR3 *(volatile uint8_t *)0x005309

#define PWM_MODE2   0x70 //PWM mode 2, 0b01110000
#define OCxPE       0x08 //preload enable

TIM2_CCMR1 = (PWM_MODE2 | OCxPE);
TIM2_CCMR2 = (PWM_MODE2 | OCxPE);
TIM2_CCMR3 = (PWM_MODE2 | OCxPE);

يتكون AR من سجلين من ثمانية بتات ، كل شيء بسيط هنا:

#define TIM2_ARRH  *(volatile uint8_t *)0x00530F
#define TIM2_ARRL  *(volatile uint8_t *)0x005310

TIM2_ARRH = 0;
TIM2_ARRL = 255;

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

#define TIM2_PSCR  *(volatile uint8_t *)0x00530E

TIM2_PSCR = 8;

يبقى لتشغيل الاستنتاجات والموقت الثاني نفسه. يتم حل المهمة الأولى عن طريق السجلات التقط / قارن تفعيل: يوجد اثنان منهم ثلاث قنوات متناثرة بشكل غير متماثل فوقهم. هنا يمكننا أيضًا معرفة أنه من الممكن تغيير قطبية الإشارة ، أي من حيث المبدأ ، يمكن أيضًا استخدام PWM Mode 1. نكتب:

#define TIM2_CCER1 *(volatile uint8_t *)0x00530A
#define TIM2_CCER2 *(volatile uint8_t *)0x00530B

#define CC1E  (1<<0) // CCER1
#define CC2E  (1<<4) // CCER1
#define CC3E  (1<<0) // CCER2

TIM2_CCER1 = (CC1E | CC2E);
TIM2_CCER2 = CC3E;

وأخيرًا ، نبدأ المؤقت في تسجيل TIMx_CR1:

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8

#define TIM2_CR1   *(volatile uint8_t *)0x005300

TIM2_CR1 |= 1;

دعنا نكتب تناظريًا بسيطًا لـ AnalogWrite () ، والذي سيمرر القيم الفعلية إلى المؤقت للمقارنة. يتم تسمية السجلات بشكل متوقع التقاط / مقارنة السجلات، يوجد اثنان منهم لكل قناة: 8 بت المنخفضة في TIM2_CCRxL والبتات العالية في TIM2_CCRxH. منذ أن بدأنا PWM 8 بت ، يكفي أن تكتب فقط البتات المنخفضة:

#define TIM2_CCR1L *(volatile uint8_t *)0x005312
#define TIM2_CCR2L *(volatile uint8_t *)0x005314
#define TIM2_CCR3L *(volatile uint8_t *)0x005316

void setRGBled(uint8_t r, uint8_t g, uint8_t b)
{
    TIM2_CCR1L = r;
    TIM2_CCR2L = g;
    TIM2_CCR3L = b;
}

سيلاحظ القارئ اليقظ أن لدينا PWM معيبًا بعض الشيء ، غير قادر على إعطاء تعبئة بنسبة 100 ٪ (عند قيمة قصوى تبلغ 255 ، يتم قلب الإشارة بواسطة دورة مؤقت واحدة). بالنسبة لمصابيح LED ، لا يلعب هذا دورًا ، والقارئ اليقظ يخمن بالفعل كيفية إصلاحه.

يعمل PWM على جهاز ضبط الوقت الثاني ، انتقل إلى الأول.

يحتوي المؤقت الأول على نفس البتات بالضبط في نفس السجلات (إنها فقط تلك البتات التي ظلت "محجوزة" في المؤقت الثاني تُستخدم بنشاط لجميع أنواع الأشياء المتقدمة في الأول). لذلك ، يكفي العثور على عناوين نفس السجلات في ورقة البيانات ونسخ الكود. حسنًا ، قم بتغيير قيمة مقسم التردد ، لأن. لا يريد الموقت الأول الحصول على قوة اثنين ، ولكن قيمة 16 بت بالضبط في سجلين Prescaler عالية и منخفض. نفعل كل شيء و ... الموقت الأول لا يعمل. ماذا جرى؟

الطريقة الوحيدة لحل المشكلة هي من خلال النظر إلى القسم الكامل حول سجلات التحكم في المؤقت 1 ، حيث نبحث عن واحد لا يحتويه العداد الثاني. سيكون هنالك 17.7.30 كسر التسجيل (TIM1_BKR)، حيث يوجد القليل من هذا القبيل:

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
تمكين الإخراج الرئيسي

#define TIM1_BKR   *(volatile uint8_t *)0x00526D

TIM1_BKR = (1<<7);

هذا كل شيء الآن ، الرمز المرجع نفسه.

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8

STM8 متعدد

مضاعفة على STM8

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

تبدو خوارزمية العمل كما يلي:

  • توصيل الأنود لأول RGB LED ؛
  • أشعلها ، مع إعطاء الإشارات اللازمة للكاثودات ؛
  • انتظر حتى نهاية دورة PWM ؛
  • توصيل الأنود الخاص بمؤشر RGB LED الثاني ؛
  • أضائها، أشعلها...

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

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

uint8_t colors[8][3];

لتغيير لون مؤشر LED معين ، يكفي كتابة القيم الضرورية في هذه المجموعة. وسيكون المتغير مسؤولاً عن رقم مؤشر LED النشط

uint8_t cnt;

ديموكس

لتعدد الإرسال الصحيح ، نحتاج ، بشكل غريب ، إلى مزيل تعدد الإرسال CD74HC238. Demultiplexer - شريحة تنفذ المشغل في الأجهزة <<. من خلال ثلاثة دبابيس إدخال (بتات 0 و 1 و 2) ، نقوم بإطعامه رقم ثلاثي بت X ، واستجابة لذلك يقوم بتنشيط رقم الإخراج (1<<X). تُستخدم المدخلات المتبقية للرقاقة لتوسيع نطاق التصميم بأكمله. نحن بحاجة إلى هذه الشريحة ليس فقط لتقليل عدد المسامير المشغولة للميكروكونترولر ، ولكن أيضًا من أجل السلامة - حتى لا يتم تشغيل المزيد من مصابيح LED بطريق الخطأ أكثر من الممكن وعدم حرق MK. تكلف الرقاقة فلسًا واحدًا ، ويجب دائمًا الاحتفاظ بها في مجموعة الإسعافات الأولية في المنزل.

سيكون CD74HC238 مسؤولاً عن إمداد الجهد الكهربائي إلى أنود LED المطلوب. في تعدد الإرسال الكامل ، ستزود العمود بالجهد من خلال P-MOSFET ، ولكن في هذا العرض التوضيحي ، يمكنك القيام بذلك مباشرة ، لأن. انها تسحب 20mA ، وفقا ل الحد الأقصى لالتقييمات المطلقة في ورقة البيانات. من CD74HC238 ورقة البيانات نحتاج إلى pinout وورقة الغش هذه:

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
H = مستوى الجهد العالي ، L = مستوى الجهد المنخفض ، X - لا تهتم

نقوم بتوصيل E2 و E1 بالأرض و E3 و A0 و A1 و A3 بالدبابيس PD5 و PC3 و PC4 و PC5 من STM8. نظرًا لأن الجدول أعلاه يحتوي على مستويات منخفضة وعالية ، فقد قمنا بإعداد هذه المسامير كدبابيس دفع وسحب.

PWM

تم تكوين PWM في المؤقت الثاني بنفس الطريقة كما في القصة السابقة ، مع اختلافين:

أولاً ، نحتاج إلى تمكين المقاطعة حدث التحديث (UEV) التي ستستدعي وظيفة لتبديل مؤشر LED النشط. يتم ذلك عن طريق تغيير الشيء تحديث المقاطعة تمكين في سجل باسم يتحدث

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
المقاطعة تمكين التسجيل

#define TIM2_IER   *(volatile uint8_t *)0x005303

//enable interrupt
TIM2_IER = 1;

يرتبط الاختلاف الثاني بظاهرة تعدد الإرسال مثل الظلال - توهج طفيلي للديودات. في حالتنا ، قد يظهر ذلك بسبب حقيقة أن المؤقت ، الذي تسبب في حدوث مقاطعة في UEV ، يستمر في التكتكة ، ولا يملك معالج المقاطعة الوقت لتبديل مؤشر LED قبل أن يبدأ المؤقت في كتابة شيء ما إلى المخرجات. لمكافحة هذا ، سيتعين عليك عكس المنطق (0 = أقصى سطوع ، 255 = لا شيء قيد التشغيل) وعدم السماح بقيم دورة العمل القصوى. أولئك. تأكد من إطفاء مصابيح LED بالكامل بعد UEV لدورة PWM واحدة.

تغيير القطبية:

//set polarity 
    TIM2_CCER1 |= (CC1P | CC2P);
    TIM2_CCER2 |= CC3P;

تجنب ضبط r و g و b على 255 وتذكر قلبها عند الاستخدام.

المقاطعات

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

عندما أنشأنا مشروعًا لأول مرة في ST Visual Develop ، بصرف النظر عن main.c لدينا نافذة بها ملف غامض stm8_interrupt_vector.cتم تضمينه تلقائيًا في المشروع. في هذا الملف ، يتم إرفاق وظيفة بكل مقاطعة NonHandledInterrupt. نحتاج إلى ربط وظيفتنا بالمقاطعة المرغوبة.

تحتوي ورقة البيانات على جدول متجهات المقاطعة ، حيث نجد ما نحتاج إليه:

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8
13 تحديث / تجاوز TIM2
14 التقاط / مقارنة TIM2

نحتاج إلى تغيير مؤشر LED في UEV ، لذا يلزم المقاطعة رقم 13.

وفقًا لذلك ، أولاً ، في الملف stm8_interrupt_vector.c قم بتغيير اسم الوظيفة المسؤولة عن رقم المقاطعة 13 (IRQ13) افتراضيًا إلى اسمنا:

{0x82, TIM2_Overflow}, /* irq13 */

ثانيًا ، سيتعين علينا إنشاء ملف main.h محتوى مثل هذا:

#ifndef __MAIN_H
#define __MAIN_H

@far @interrupt void TIM2_Overflow (void);
#endif

وأخيرًا ، اكتب هذه الوظيفة في ملفك main.c:

@far @interrupt void TIM2_Overflow (void)
{
    PD_ODR &= ~(1<<5); // вырубаем демультиплексор
    PC_ODR = (cnt<<3); // записываем в демультиплексор новое значение
    PD_ODR |= (1<<5); // включаем демультиплексор

    TIM2_SR1 = 0; // сбрасываем флаг Update Interrupt Pending

    cnt++; 
    cnt &= 7; // двигаем счетчик LED

    TIM2_CCR1L = ~colors[cnt][0]; // передаем в буфер инвертированные значения
    TIM2_CCR2L = ~colors[cnt][1]; // для следующего цикла ШИМ
    TIM2_CCR3L = ~colors[cnt][2]; // 

    return;
}

يبقى لتمكين المقاطعات. يتم ذلك بأمر المجمع. rim - سيكون عليك البحث عنه في دليل البرمجة:

//enable interrupts
_asm("rim");

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

كل الكود - على جيثب.

اقرأ أوراق البيانات 2: SPI على STM32 ؛ PWM وأجهزة ضبط الوقت والمقاطعات على STM8

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

المصدر: www.habr.com

إضافة تعليق