برگه های داده 2 را بخوانید: SPI در STM32. PWM، تایمرها و وقفه ها در STM8
В بخش اول من سعی کردم به مهندسان الکترونیک سرگرمی که از شلوار آردوینو بزرگ شده اند بگویم چگونه و چرا باید برگه های داده و سایر اسناد میکروکنترلرها را بخوانند. متن بزرگ بود، بنابراین قول دادم نمونه های عملی را در یک مقاله جداگانه نشان دهم. خب خودشو میگفت قارچ شیری...
امروز به شما نشان خواهم داد که چگونه از دیتاشیت ها برای حل کارهای بسیار ساده اما برای بسیاری از پروژه ها در کنترلرهای STM32 (قرص آبی) و STM8 استفاده کنید. تمام پروژه های نمایشی به LED های مورد علاقه من اختصاص داده شده است، ما آنها را در مقادیر زیادی روشن می کنیم، که برای آن باید از انواع لوازم جانبی جالب استفاده کنیم.
متن دوباره بزرگ شد، بنابراین برای راحتی، محتوا را میسازم:
سلب مسئولیت: من یک مهندس نیستم، وانمود نمی کنم که دانش عمیقی در الکترونیک دارم، مقاله برای آماتورهایی مانند من در نظر گرفته شده است. در واقع دو سال پیش خودم را مخاطب هدف می دانستم. اگر در آن زمان کسی به من می گفت که برگه های داده روی یک تراشه ناآشنا خواندن ترسناک نیست، زمان زیادی را صرف جستجوی چند قطعه کد در اینترنت و اختراع عصا با قیچی و نوار چسب نمی کردم.
تمرکز این مقاله بر روی دیتاشیت ها است، نه پروژه ها، بنابراین ممکن است کد خیلی منظم و اغلب فشرده نباشد. خود پروژه ها بسیار ساده هستند، اگرچه برای اولین آشنایی با تراشه جدید مناسب هستند.
امیدوارم مقاله من به کسی در مرحله مشابهی از غوطه ور شدن در سرگرمی کمک کند.
STM32
16 LED با DM634 و SPI
یک پروژه کوچک با استفاده از قرص آبی (STM32F103C8T6) و درایور LED DM634. با استفاده از دیتاشیت ها، درایور، پورت های STM IO را مشخص کرده و SPI را پیکربندی می کنیم.
DM634
تراشه تایوانی با 16 خروجی 16 بیتی PWM، می تواند به صورت زنجیره ای متصل شود. مدل پایین 12 بیتی از یک پروژه داخلی شناخته شده است لایت پک. در یک زمان، انتخاب بین DM63x و TLC5940 معروف، DM را به چند دلیل انتخاب کردم: 1) TLC در Aliexpress قطعا جعلی است، اما این یکی نیست. 2) DM یک PWM مستقل با ژنراتور فرکانس خود دارد. 3) به جای اینکه منتظر بسته ای از علی باشید، می توان آن را ارزان در مسکو خرید. و البته جالب بود که یاد بگیرید چگونه خودتان تراشه را کنترل کنید، نه اینکه از یک کتابخانه آماده استفاده کنید. تراشهها در حال حاضر عمدتاً در بستهبندی SSOP24 ارائه میشوند و به راحتی به آداپتور لحیم میشوند.
از آنجایی که سازنده تایوانی است، برگه داده تراشه به زبان انگلیسی چینی نوشته شده است، به این معنی که سرگرم کننده خواهد بود. ابتدا به پینوت نگاه می کنیم (اتصال پین) برای درک اینکه کدام پایه باید به چه چیزی وصل شود، و شرح پین ها (شرح پین). 16 پین:
منابع سینک DC (تخلیه باز)
فرو رفتن / خروجی تخلیه باز - زه کشی؛ منبع جریان ورودی؛ خروجی در حالت فعال به زمین متصل می شود - LED ها توسط کاتد به درایور متصل می شوند. از نظر الکتریکی، البته، این یک "زهکشی باز" نیست (زهکشی باز، اما در دیتاشیت ها این نام گذاری برای پین ها در حالت تخلیه اغلب یافت می شود.
مقاومت های خارجی بین REXT و GND برای تنظیم مقدار جریان خروجی
یک مقاومت مرجع بین پایه REXT و زمین نصب شده است که مقاومت داخلی خروجی ها را کنترل می کند، نمودار صفحه 9 دیتاشیت را ببینید. در DM634، این مقاومت را می توان با نرم افزار کنترل کرد و روشنایی کلی را تنظیم کرد (روشنایی جهانی) من در این مقاله وارد جزئیات نمی شوم، فقط یک مقاومت 2.2 - 3 کیلو اهم را در اینجا قرار می دهم.
برای درک نحوه کنترل تراشه، بیایید به توضیح رابط دستگاه نگاه کنیم:
بله، اینجاست، انگلیسی چینی با تمام شکوهش. ترجمه این مشکل ساز است، در صورت تمایل می توانید آن را درک کنید، اما راه دیگری وجود دارد - ببینید چگونه اتصال به TLC5940 مشابه عملکردی در برگه داده توضیح داده شده است:
... برای وارد کردن اطلاعات به دستگاه فقط سه پین لازم است. لبه افزایشی سیگنال SCLK داده ها را از پین SIN به ثبت داخلی منتقل می کند. پس از بارگیری همه داده ها، یک سیگنال کوتاه XLAT بالا، داده های متوالی را به رجیسترهای داخلی می چسباند. ثبات های داخلی دروازه هایی هستند که توسط سطح سیگنال XLAT راه اندازی می شوند. تمام داده ها ابتدا مهم ترین بیت منتقل می شوند.
چفت – چفت/چفت/قفل. لبه در حال افزایش - لبه جلویی نبض اول MSB – مهم ترین (سمت چپ) بیت رو به جلو. به داده های ساعت - انتقال داده ها به صورت متوالی (بیت به بیت).
کلمه چفت اغلب در اسناد مربوط به تراشه ها یافت می شود و به روش های مختلف ترجمه می شود، بنابراین برای درک بهتر به خودم اجازه می دهم
برنامه آموزشی کوچکدرایور LED در اصل یک شیفت رجیستر است. "تغییر مکان" (تغییر) در نام - حرکت بیتی داده ها در داخل دستگاه: هر بیت جدید وارد شده به داخل، کل زنجیره را در مقابل خود به جلو می راند. از آنجایی که هیچ کس نمی خواهد چشمک زدن آشفته LED ها را در طول شیفت مشاهده کند، این فرآیند در رجیسترهای بافری انجام می شود که توسط یک دمپر از ثبات های کار جدا شده اند.چفت) نوعی اتاق انتظار است که در آن بیت ها به ترتیب دلخواه چیده می شوند. وقتی همه چیز آماده شد، دریچه باز می شود و بیت ها کار می کنند و جایگزین دسته قبلی می شوند. کلمه چفت در مستندات ریز مدارها تقریباً همیشه چنین دمپری وجود دارد، مهم نیست که در چه ترکیبی از آن استفاده می شود.
بنابراین، انتقال داده به DM634 به این صورت انجام می شود: ورودی DAI را روی مقدار مهم ترین بیت LED دور تنظیم کنید، DCK را بالا و پایین بکشید. ورودی DAI را روی مقدار بیت بعدی تنظیم کنید، DCK را بکشید. و به همین ترتیب تا زمانی که همه بیت ها منتقل شوند (ساعت در) پس از آن LAT را می کشیم. این کار را می توان به صورت دستی انجام داد (بیت بنگ، اما بهتر است از یک رابط SPI که مخصوص این کار طراحی شده است استفاده کنید، زیرا در STM32 ما در دو نسخه ارائه شده است.
قرص آبی STM32F103
مقدمه: کنترلرهای STM32 بسیار پیچیده تر از Atmega328 هستند که ممکن است ترسناک به نظر برسند. علاوه بر این، به دلایل صرفه جویی در انرژی، تقریباً تمام تجهیزات جانبی در شروع خاموش می شوند و فرکانس ساعت 8 مگاهرتز از منبع داخلی است. خوشبختانه، برنامه نویسان STM کدی نوشتند که تراشه را به 72 مگاهرتز "محاسبه شده" می رساند و نویسندگان همه IDE هایی که من می شناسم آن را در روند اولیه سازی گنجانده اند، بنابراین نیازی به کلاک نداریم (اما اگر واقعاً بخواهید می توانید). اما باید لوازم جانبی را روشن کنید.
مستندات: قرص آبی به تراشه محبوب STM32F103C8T6 مجهز شده است، دو سند مفید برای آن وجود دارد:
برگه اطلاعات برای میکروکنترلرهای STM32F103x8 و STM32F103xB؛
پینآتها – پینآتهای تراشهای – در صورتی که تصمیم بگیریم خود تابلوها را بسازیم.
نقشه حافظه - نقشه حافظه برای یک تراشه خاص. کتابچه راهنمای مرجع یک نقشه برای کل خط دارد و به ثبتهایی اشاره میکند که ما آنها را ندارند.
جدول تعاریف پین – لیستی از توابع اصلی و جایگزین پین ها. برای "قرص آبی" می توانید تصاویر راحت تری را با لیستی از پین ها و عملکرد آنها در اینترنت پیدا کنید. بنابراین، ما بلافاصله پینآوت قرص آبی را در گوگل جستجو میکنیم و این تصویر را در دسترس داریم:
نکته: یک خطایی در تصویر از اینترنت وجود داشت که در نظرات ذکر شده بود، از شما متشکرم. تصویر جایگزین شده است، اما این یک درس است - بهتر است اطلاعات را نه از برگه های داده بررسی کنید.
دیتاشیت را حذف می کنیم، Reference Manual را باز می کنیم و از این به بعد فقط از آن استفاده می کنیم.
روش: ما با ورودی/خروجی استاندارد سروکار داریم، SPI را پیکربندی می کنیم، لوازم جانبی لازم را روشن می کنیم.
ورودی خروجی
در Atmega328، I/O بسیار ساده پیاده سازی می شود، به همین دلیل است که فراوانی گزینه های STM32 می تواند گیج کننده باشد. اکنون ما فقط به نتیجه گیری نیاز داریم، اما حتی اینها نیز چهار گزینه دارند:
زهکش باز، فشار کش، فشار کش جایگزین، زهکش باز جایگزین
"بکشید فشار دهید" (فشار کشش) خروجی معمولی از آردوینو است، پین می تواند مقدار HIGH یا LOW را بگیرد. اما با "زهکشی باز" وجود دارد مشکلات، اگرچه در واقع همه چیز در اینجا ساده است:
پیکربندی خروجی / هنگامی که پورت به خروجی اختصاص داده می شود: / بافر خروجی فعال است: / – حالت تخلیه باز: "0" در ثبات خروجی N-MOS را فعال می کند، "1" در رجیستر خروجی پورت را در حالت Hi-Z ترک می کند ( P-MOS فعال نیست ) / – حالت فشار کش: "0" در ثبات خروجی N-MOS را فعال می کند، "1" در رجیستر خروجی P-MOS را فعال می کند.
تمام تفاوت بین تخلیه باز (زهکشی باز) از «فشار کش» (فشار کشش) این است که در پین اول نمی تواند حالت HIGH را بپذیرد: هنگام نوشتن یک در رجیستر خروجی، به حالت مقاومت بالا می رود (امپدانس بالا, سلام-Z). هنگام نوشتن صفر، پین در هر دو حالت، چه از نظر منطقی و چه الکتریکی، یکسان عمل می کند.
در حالت خروجی معمولی، پین به سادگی محتویات رجیستر خروجی را پخش می کند. در "جایگزین" توسط تجهیزات جانبی مربوطه کنترل می شود (به 9.1.4 مراجعه کنید):
اگر یک بیت پورت به عنوان یک پایه تابع جایگزین پیکربندی شده باشد، ثبت پین غیرفعال می شود و پین به پین محیطی متصل می شود.
عملکرد جایگزین هر پین در شرح داده شده است تعاریف پین دیتاشیت روی تصویر دانلود شده است. به این سوال که اگر یک پین چندین عملکرد جایگزین داشته باشد، چه باید کرد، پاسخ با پاورقی در برگه داده داده می شود:
اگر چندین دستگاه جانبی از یک پین استفاده میکنند، برای جلوگیری از تضاد بین توابع جایگزین، فقط یک دستگاه جانبی باید در هر بار استفاده شود که با استفاده از بیت فعال ساعت محیطی (در رجیستر RCC مناسب) جابجا شود.
در نهایت، پین ها در حالت خروجی نیز دارای سرعت کلاک هستند. این یکی دیگر از ویژگی های صرفه جویی در انرژی است؛ در مورد ما، ما فقط آن را روی حداکثر تنظیم می کنیم و آن را فراموش می کنیم.
بنابراین: ما از SPI استفاده می کنیم، به این معنی که دو پین (با داده و با سیگنال ساعت) باید "عملکرد فشار کش جایگزین" و یکی دیگر (LAT) باید "فشار کش معمولی" باشد. اما قبل از تخصیص آنها، بیایید به SPI بپردازیم.
SPI
یک برنامه آموزشی کوچک دیگر
SPI یا Serial Peripheral Interface (اینترفیس جانبی سریال) یک رابط ساده و بسیار موثر برای اتصال MK با سایر MK ها و به طور کلی دنیای خارج است. اصل عملکرد آن قبلاً در بالا توضیح داده شده است ، جایی که در مورد درایور LED چینی (در کتابچه راهنمای مرجع ، به بخش 25 مراجعه کنید). SPI می تواند در حالت Master ("master") و Slave ("slave") کار کند. SPI دارای چهار کانال اصلی است که ممکن است از همه آنها استفاده نشود:
MOSI، خروجی اصلی / ورودی Slave: این پین داده ها را در حالت اصلی منتقل می کند و در حالت برده داده ها را دریافت می کند.
MISO، Master Input / Slave Output: برعکس، در master دریافت می کند و در Slave ارسال می کند.
SCK, Serial Clock: فرکانس انتقال داده را در Master تنظیم می کند یا سیگنال ساعت را در Slave دریافت می کند. اساسا ضربه زدن.
SS، Slave Select: با کمک این کانال، برده می داند که چیزی از او می خواهد. در STM32 NSS نامیده می شود، که در آن N = منفی، یعنی. اگر زمین در این کانال وجود داشته باشد، کنترلر به یک برده تبدیل می شود. به خوبی با حالت Open Drain Output ترکیب می شود، اما این داستان دیگری است.
مانند هر چیز دیگری، SPI در STM32 از نظر عملکرد غنی است که درک آن را تا حدودی دشوار می کند. به عنوان مثال، می تواند نه تنها با SPI، بلکه با یک رابط I2S نیز کار کند، و در مستندات توضیحات آنها مخلوط شده است، لازم است که مازاد بر آن به موقع قطع شود. وظیفه ما بسیار ساده است: فقط باید داده ها را با استفاده از MOSI و SCK ارسال کنیم. ما به بخش 25.3.4 (ارتباط نیمه دوبلکس، ارتباط نیمه دوبلکس) می رویم، جایی که می یابیم 1 ساعت و 1 سیم داده یک طرفه (1 سیگنال ساعت و 1 جریان داده یک طرفه):
در این حالت، برنامه از SPI در حالت فقط ارسال یا دریافت فقط استفاده می کند. / حالت فقط انتقال مشابه حالت دوطرفه است: داده ها روی پین انتقال (MOSI در حالت اصلی یا MISO در حالت برده) منتقل می شود و پایه دریافت (به ترتیب MISO یا MOSI) می تواند به عنوان یک پایه ورودی/خروجی معمولی استفاده شود. . در این مورد، برنامه فقط باید بافر Rx را نادیده بگیرد (اگر خوانده شود، هیچ داده ای منتقل نمی شود).
عالی است، پین MISO رایگان است، بیایید سیگنال LAT را به آن وصل کنیم. بیایید Slave Select را بررسی کنیم، که در STM32 می تواند به صورت برنامه ریزی شده کنترل شود، که بسیار راحت است. ما پاراگراف با همین نام را در بخش 25.3.1 SPI توضیحات کلی می خوانیم:
کنترل نرم افزار NSS (SSM = 1) / اطلاعات انتخاب برده در بیت SSI ثبت SPI_CR1 موجود است. پین خارجی NSS برای سایر نیازهای برنامه رایگان باقی می ماند.
وقت آن است که به ثبت نام ها بنویسید. تصمیم گرفتم از SPI2 استفاده کنم، آدرس پایه آن را در دیتاشیت جستجو کنم - در بخش 3.3 Memory Map:
بخش 25.3.3 را با عنوان خود توضیحی "پیکربندی SPI در حالت Master" باز کنید:
1. فرکانس ساعت سریال را با بیت های BR[2:0] در ثبات SPI_CR1 تنظیم کنید.
رجیسترها در بخش راهنمای مرجع به همین نام جمع آوری می شوند. تغییر آدرس (آفست آدرس) برای CR1 – 0x00، به طور پیش فرض همه بیت ها پاک می شوند (بازنشانی مقدار 0x0000):
بیت های BR تقسیم کننده ساعت کنترل کننده را تنظیم می کنند، بنابراین فرکانس عملکرد SPI را تعیین می کنند. فرکانس STM32 ما 72 مگاهرتز خواهد بود، درایور LED، طبق دیتاشیت آن، با فرکانس حداکثر 25 مگاهرتز کار می کند، بنابراین باید بر چهار تقسیم کنیم (BR[2:0] = 001).
2. بیت های CPOL و CPHA را برای تعریف رابطه بین انتقال داده و زمان بندی ساعت سریال تنظیم کنید (نمودار صفحه 240 را ببینید).
از آنجایی که ما در اینجا یک دیتاشیت را می خوانیم و به شماتیک ها نگاه نمی کنیم، بیایید نگاهی دقیق تر به توضیحات متن بیت های CPOL و CPHA در صفحه 704 بیندازیم (توضیحات عمومی SPI):
فاز ساعت و قطبیت
با استفاده از بیت های CPOL و CPHA رجیستر SPI_CR1، می توانید چهار رابطه زمان بندی را به صورت برنامه نویسی انتخاب کنید. بیت CPOL (قطب ساعت) وضعیت سیگنال ساعت را هنگامی که هیچ داده ای ارسال نمی شود کنترل می کند. این بیت حالت های master و slave را کنترل می کند. اگر CPOL ریست شود، پین SCK در حالت استراحت پایین است. اگر بیت CPOL تنظیم شده باشد، پین SCK در حالت استراحت بالاست.
هنگامی که بیت CPHA (فاز ساعت) تنظیم می شود، بارق تله بیت بالا لبه دوم سیگنال SCK است (اگر CPOL واضح باشد سقوط می کند، اگر CPOL تنظیم شود افزایش می یابد). داده ها با تغییر دوم در سیگنال ساعت گرفته می شود. اگر بیت CPHA واضح باشد، بارق تله بیت بالا لبه افزایشی سیگنال SCK است (لبه در حال سقوط اگر CPOL تنظیم شده باشد، لبه صعودی اگر CPOL پاک شود). داده ها در اولین تغییر در سیگنال ساعت گرفته می شود.
با جذب این دانش، به این نتیجه می رسیم که هر دو بیت باید صفر باقی بمانند، زیرا ما میخواهیم سیگنال SCK زمانی که استفاده نمیشود پایین بماند و دادهها در لبه بالارونده پالس ارسال شوند (شکل XNUMX را ببینید). لبه در حال افزایش در دیتاشیت DM634).
به هر حال، در اینجا برای اولین بار با ویژگی واژگان در دیتاشیت های ST مواجه شدیم: در آنها عبارت "تنظیم مجدد بیت به صفر" نوشته شده است. برای تنظیم مجدد کمیو نه تا کمی پاک شود، مانند، به عنوان مثال، Atmega.
3. بیت DFF را تنظیم کنید تا مشخص شود بلوک داده 8 بیتی است یا 16 بیتی
من به طور خاص یک DM16 634 بیتی گرفتم تا مانند DM12 با انتقال داده های PWM 633 بیتی خود را خسته نکنم. منطقی است که DFF را روی یک تنظیم کنید:
4. بیت LSBFIRST را در ثبات SPI_CR1 پیکربندی کنید تا قالب بلوک را تعیین کنید.
LSBFIRST، همانطور که از نامش پیداست، ابتدا انتقال را با کمترین بیت مهم پیکربندی می کند. اما DM634 می خواهد داده ها را از مهم ترین بیت دریافت کند. بنابراین، آن را تنظیم مجدد می کنیم.
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 خود را به عنوان یک Master تعیین می کنیم و آن را روشن می کنیم:
SPI پیکربندی شده است، بیایید فورا توابعی بنویسیم که بایت ها را به درایور ارسال می کنند. به خواندن 25.3.3 "پیکربندی SPI در حالت اصلی" ادامه دهید:
سفارش انتقال داده
انتقال زمانی شروع می شود که یک بایت در بافر Tx نوشته شود.
بایت داده در رجیستر شیفت بارگذاری می شود موازی حالت (از گذرگاه داخلی) در حین انتقال بیت اول، پس از آن به آن منتقل می شود متوالی حالت پین MOSI، اولین یا آخرین بیت به جلو بسته به تنظیم بیت LSBFIRST در ثبات CPI_CR1. پرچم TXE پس از انتقال داده تنظیم می شود از بافر Tx به رجیستر شیفتو همچنین اگر بیت TXEIE در ثبات CPI_CR1 تنظیم شده باشد، یک وقفه ایجاد می کند.
من چند کلمه را در ترجمه برجسته کردم تا توجه را به یکی از ویژگی های پیاده سازی SPI در کنترل کننده های STM جلب کنم. در Atmega پرچم TXE (Tx Empty، Tx خالی است و آماده دریافت داده است) تنها پس از ارسال کل بایت تنظیم می شود بیرون. و در اینجا این پرچم پس از درج بایت در ثبات داخلی شیفت تنظیم می شود. از آنجایی که با تمام بیت ها به طور همزمان (موازی) به آنجا فشار داده می شود و سپس داده ها به صورت متوالی منتقل می شوند، TXE قبل از ارسال کامل بایت تنظیم می شود. این مهم است زیرا در مورد درایور LED ما، پس از ارسال باید پین LAT را بکشیم از همه داده ها، یعنی پرچم TXE به تنهایی برای ما کافی نخواهد بود.
این بدان معناست که ما به پرچم دیگری نیاز داریم. بیایید به 25.3.7 نگاه کنیم - "پرچم های وضعیت":
<…>
پرچم مشغول
پرچم BSY توسط سخت افزار تنظیم و پاک می شود (نوشتن روی آن تاثیری ندارد). پرچم BSY وضعیت لایه ارتباطی SPI را نشان می دهد.
بازنشانی می کند:
وقتی انتقال کامل شد (به جز در حالت اصلی اگر انتقال پیوسته باشد)
وقتی SPI غیرفعال است
هنگامی که یک خطای حالت اصلی رخ می دهد (MODF=1)
اگر انتقال پیوسته نباشد، پرچم BSY بین هر انتقال داده پاک می شود
بسیار خوب، این به کار خواهد آمد. بیایید دریابیم که بافر Tx در کجا قرار دارد. برای انجام این کار، "SPI Data Register" را بخوانید:
بیت 15:0 DR [15:0] ثبت داده
داده های دریافتی یا داده هایی که قرار است منتقل شوند.
ثبت داده به دو بافر تقسیم می شود - یکی برای نوشتن (بافر انتقال) و دیگری برای خواندن (بافر دریافت). نوشتن در رجیستر داده در بافر Tx می نویسد و خواندن از ثبات داده مقدار موجود در بافر Rx را برمی گرداند.
خوب، و ثبت وضعیت، که در آن پرچم های TXE و BSY یافت می شوند:
خوب، از آنجایی که با توجه به تعداد خروجی های درایور LED باید 16 برابر دو بایت ارسال کنیم، چیزی شبیه به این:
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:
هر یک از پورت های ورودی/خروجی عمومی (GPIO) دارای دو رجیستر پیکربندی 32 بیتی (GPIOx_CRL و GPIOx_CRH)، دو رجیستر داده 32 بیتی (GPIOx_IDR و GPIOx_ODR)، یک رجیستر تنظیم/تنظیم مجدد 32 بیتی (GPIOx_BSRR)، یک رجیستر تنظیم مجدد 16 بیتی (GPIOx_32-) و یک رجیستر مسدودکننده بیت (GPIOx_LCKR).
دو رجیستر اول غیرمعمول و همچنین کاملاً ناخوشایند هستند، زیرا 16 پین پورت در قالب "چهار بیت برای هر برادر" در سراسر آنها پراکنده شده اند. آن ها پین های صفر تا هفت در CRL و بقیه در CRH هستند. در همان زمان، رجیسترهای باقیمانده با موفقیت حاوی بیتهای تمام پینهای پورت هستند - اغلب نیمه «رزرو» باقی میمانند.
برای سادگی، اجازه دهید از انتهای لیست شروع کنیم.
ما نیازی به ثبت مسدود کننده نداریم.
رجیسترهای تنظیم و تنظیم مجدد کاملاً خنده دار هستند زیرا تا حدی یکدیگر را تکرار می کنند: می توانید همه چیز را فقط در BSRR بنویسید ، جایی که 16 بیت بالاتر پین را صفر می کند و بیت های پایین تر روی 1 تنظیم می شود ، یا همچنین می توانید از BRR استفاده کنید که 16 بیت پایین آن فقط پین را بازنشانی می کند. من گزینه دوم را دوست دارم. این رجیسترها مهم هستند زیرا دسترسی اتمی به پین ها را فراهم می کنند:
تنظیم یا تنظیم مجدد اتمی
هنگام برنامه نویسی GPIOx_ODR در سطح بیت، نیازی به غیرفعال کردن وقفه ها نیست: یک یا چند بیت را می توان با یک عملیات نوشتن اتمی APB2 تغییر داد. این با نوشتن یک "1" در ثبت تنظیم/تنظیم مجدد (GPIOx_BSRR یا فقط برای بازنشانی، GPIOx_BRR) بیتی که باید تغییر کند به دست می آید. سایر بیت ها بدون تغییر باقی می مانند.
رجیسترهای داده اسامی کاملاً واضح دارند - IDR = ورودی ثبت جهت، ثبت ورودی؛ ODR = تولید ثبت جهت، ثبت خروجی. ما در پروژه فعلی به آنها نیاز نخواهیم داشت.
و در نهایت رجیسترهای کنترلی. از آنجایی که ما به دومین پین SPI، یعنی PB13، PB14 و PB15 علاقه مند هستیم، بلافاصله به CRH نگاه می کنیم:
و می بینیم که باید چیزی را در بیت های 20 تا 31 بنویسیم.
ما قبلاً متوجه شدهایم که از پینها چه چیزی میخواهیم، بنابراین در اینجا بدون اسکرین شات این کار را انجام میدهم، فقط میگویم که MODE جهت (ورودی اگر هر دو بیت روی 0 تنظیم شده باشند) و سرعت پین را مشخص میکند (به 50 مگاهرتز نیاز داریم، به عنوان مثال. هر دو پین روی "1")، و CNF حالت را تنظیم می کند: "فشار کش" معمولی - 00، "جایگزین" - 10. به طور پیش فرض، همانطور که در بالا می بینیم، همه پین ها بیت سوم را از پایین دارند (CNF0). آنها را روی حالت قرار می دهد ورودی شناور.
از آنجایی که قصد دارم کار دیگری با این تراشه انجام دهم، برای سادگی همه مقادیر ممکن MODE و CNF را برای هر دو رجیستر کنترل پایین و بالا تعریف کرده ام.
(LAT_low فقط با اینرسی، همیشه همینطور بوده، بگذارید بماند)
اکنون همه چیز عالی است، اما کار نمی کند. از آنجایی که این STM32 است، آنها در مصرف برق صرفه جویی می کنند، به این معنی که باید کلاک تجهیزات جانبی مورد نیاز را فعال کنید.
ساعت را روشن کنید
ساعت که با نام ساعت نیز شناخته می شود، وظیفه ساعت را بر عهده دارد. و ما قبلاً می توانستیم به علامت اختصاری RCC توجه کنیم. ما آن را در مستندات جستجو می کنیم: این تنظیم مجدد و کنترل ساعت است.
همانطور که در بالا گفته شد، خوشبختانه سخت ترین قسمت موضوع کلاک توسط افرادی از STM برای ما انجام شد که از آنها بسیار تشکر می کنیم (یک بار دیگر لینک می دهم وب سایت دی هالت، تا مشخص شود که چقدر گیج کننده است). ما فقط به رجیسترهایی نیاز داریم که مسئول فعال کردن ساعت محیطی هستند (Peripheral Clock Enable Registers). ابتدا، بیایید آدرس پایه RCC را پیدا کنیم، در همان ابتدای "نقشه حافظه" است:
و سپس روی پیوندی که در آن سعی میکنید چیزی در صفحه پیدا کنید کلیک کنید، یا، خیلی بهتر، توضیحات ثبتهای فعال را از بخشهای مربوط به فعال کردن رجیسترها. جایی که RCC_APB1ENR و RCC_APB2ENR را پیدا خواهیم کرد:
و بر این اساس، آنها حاوی بیت هایی هستند که شامل کلاک SPI2، IOPB (I/O Port B) و توابع جایگزین (AFIO) می شود.
اگر فرصت و تمایل به آزمایش دارید، DM634 را به این صورت وصل کنید: DAI به PB15، DCK به PB13، LAT به PB14. ما راننده را از 5 ولت تغذیه می کنیم، فراموش نکنید که پایه ها را وصل کنید.
STM8 PWM
PWM در STM8
هنگامی که من تازه این مقاله را برنامه ریزی می کردم، به عنوان مثال، تصمیم گرفتم که سعی کنم بر برخی از عملکردهای یک تراشه ناآشنا فقط با استفاده از یک دیتاشیت مسلط شوم، به طوری که در نهایت با یک کفاش بدون چکمه مواجه نشم. STM8 برای این نقش ایده آل بود: اولاً من چند تا برد چینی با STM8S103 داشتم و ثانیاً محبوبیت زیادی ندارد و بنابراین وسوسه خواندن و یافتن راه حل در اینترنت به فقدان همین راه حل ها بستگی دارد.
تراشه نیز دارد برگه داده и راهنمای مرجع RM0016، در اولی آدرس های پین اوت و ثبت نام وجود دارد، در دومی - هر چیز دیگری. STM8 در C در یک IDE وحشتناک برنامه ریزی شده است ST Visual Develop.
ساعت و I/O
به طور پیش فرض، STM8 در فرکانس 2 مگاهرتز کار می کند، این باید بلافاصله اصلاح شود.
ساعت HSI (سرعت بالا) داخلی
سیگنال ساعت HSI از یک نوسان ساز داخلی RC 16 مگاهرتز با یک تقسیم کننده قابل برنامه ریزی (1 تا 8) مشتق شده است. در ثبت تقسیم کننده ساعت (CLK_CKDIVR) تنظیم شده است.
توجه: در شروع، یک نوسان ساز HSI RC با تقسیم کننده 8 به عنوان منبع اصلی سیگنال ساعت انتخاب می شود.
آدرس رجیستر را در دیتاشیت، توضیحات در refman پیدا می کنیم و می بینیم که رجیستر باید پاک شود:
از آنجایی که میخواهیم PWM را اجرا کنیم و LEDها را وصل کنیم، بیایید به پینآوت نگاه کنیم:
تراشه کوچک است، بسیاری از عملکردها روی همان پین ها معلق هستند. آنچه در پرانتز است "عملکرد جایگزین" است، با "بایت های گزینه" تغییر می کند (بایت های گزینه) – چیزی شبیه فیوزهای Atmega. شما می توانید مقادیر آنها را به صورت برنامه ای تغییر دهید، اما لازم نیست، زیرا عملکرد جدید فقط پس از راه اندازی مجدد فعال می شود. استفاده از ST Visual Programmer (دانلود شده با Visual Develop) که می تواند این بایت ها را تغییر دهد، ساده تر است. پینآوت نشان میدهد که پینهای CH1 و CH2 اولین تایمر در براکتهای مربع پنهان شدهاند. لازم است بیت های AFR1 و AFR0 را در STVP تنظیم کنید و دومی نیز خروجی CH1 تایمر دوم را از PD4 به PC5 منتقل می کند.
بنابراین، 6 پین LED ها را کنترل می کنند: PC6، PC7 و PC3 برای تایمر اول، PC5، PD3 و PA3 برای تایمر دوم.
تنظیم پین های I/O خود در STM8 ساده تر و منطقی تر از STM32 است:
آشنا از ثبت جهت داده Atmega DDR (ثبت جهت داده ها): 1 = خروجی;
اولین رجیستر کنترلی CR1، هنگام خروجی، حالت فشار کش (1) یا تخلیه باز (0) را تنظیم می کند. از آنجایی که من LED ها را با کاتد به تراشه وصل می کنم، صفرها را در اینجا می گذارم.
رجیستر کنترل دوم CR2، هنگام خروجی، سرعت ساعت را تنظیم می کند: 1 = 10 مگاهرتز
بارگذاری مجدد خودکار، AR - مقدار قابل بارگیری خودکار که تایمر تا آن مقدار محاسبه می شود (دوره پالس).
به روز رسانی رویداد، UEV - رویدادی که زمانی رخ می دهد که تایمر تا AR شمارش کرده باشد.
چرخه وظیفه PWM - چرخه وظیفه PWM که اغلب به آن "ضریب وظیفه" می گویند.
گرفتن/مقایسه ارزش - مقدار برای ضبط/مقایسه، که تایمر به آن حساب کرده است کاری خواهد کرد (در مورد PWM، سیگنال خروجی را معکوس می کند).
مقدار پیش بارگذاری - مقدار از پیش بارگذاری شده ارزش را مقایسه کنید نمی تواند در حالی که تایمر تیک می زند تغییر کند، در غیر این صورت چرخه PWM شکسته می شود. بنابراین، مقادیر ارسالی جدید در یک بافر قرار می گیرند و زمانی که تایمر به پایان شمارش معکوس خود رسید و تنظیم مجدد شد، خارج می شوند.
تراز لبه и حالت های تراز مرکزی - تراز در امتداد مرز و در مرکز، مانند Atmel PWM سریع и PWM با فاز صحیح.
OCiREF، سیگنال مرجع مقایسه خروجی - سیگنال خروجی مرجع، در واقع همان چیزی است که روی پین مربوطه در حالت PWM ظاهر می شود.
همانطور که قبلاً از پین اوت مشخص است، دو تایمر دارای قابلیت PWM هستند - اولی و دومی. هر دو 16 بیتی هستند، اولی دارای بسیاری از ویژگی های اضافی است (به ویژه، می تواند هم بالا و هم پایین شمارش کند). ما نیاز داریم که هر دو به یک اندازه کار کنند، بنابراین تصمیم گرفتم با دومی بدیهی فقیرتر شروع کنم تا تصادفاً از چیزی که وجود ندارد استفاده نکنم. برخی از مشکلات این است که شرح عملکرد PWM همه تایمرها در کتابچه راهنمای مرجع در فصل مربوط به تایمر اول (حالت PWM 17.5.7) آمده است، بنابراین شما باید همیشه در طول سند به جلو و عقب بپرید.
PWM در STM8 یک مزیت مهم نسبت به PWM در Atmega دارد:
PWM تراز شده مرزی
پیکربندی حساب از پایین به بالا
اگر بیت DIR در رجیستر TIM_CR1 پاک شود، شمارش از پایین به بالا فعال است
مثال
مثال از اولین حالت PWM استفاده می کند. سیگنال مرجع PWM OCiREF تا زمانی که TIM1_CNT < TIM1_CCRi بالا نگه داشته می شود. در غیر این صورت سطح پایینی می گیرد. اگر مقدار مقایسه در ثبات TIM1_CCRi از مقدار بارگذاری خودکار (رجیستر TIM1_ARR) بیشتر باشد، سیگنال OCiREF روی 1 نگه داشته می شود. اگر مقدار مقایسه 0 باشد، OCiREF روی صفر نگه داشته می شود....
تایمر STM8 در طول رویداد به روز رسانی ابتدا چک می کند ارزش را مقایسه کنید، و تنها پس از آن یک سیگنال مرجع تولید می کند. تایمر Atmega ابتدا خراب می شود و سپس مقایسه می کند و در نتیجه compare value == 0 خروجی یک سوزن است که باید به نحوی با آن برخورد کرد (مثلاً با معکوس کردن منطق برنامهای).
بنابراین کاری که می خواهیم انجام دهیم: PWM 8 بیتی (AR == 255)، شمارش از پایین به بالا، تراز در امتداد مرز. از آنجایی که لامپ ها توسط کاتد به تراشه متصل می شوند، PWM باید 0 (LED روشن) را تا زمانی که ارزش را مقایسه کنید و 1 بعد از
قبلاً در مورد برخی خوانده ایم حالت PWM، بنابراین با جستجو در دفترچه راهنمای این عبارت (18.6.8 - TIMx_CCMR1) رجیستر مورد نیاز تایمر دوم را پیدا می کنیم:
110: حالت اول PWM - هنگام شمارش از پایین به بالا، اولین کانال فعال است در حالی که TIMx_CNT < TIMx_CCR1. در غیر این صورت کانال اول غیر فعال است. [در ادامه در سند یک کپی پیست اشتباه از تایمر 1 وجود دارد] 111: حالت دوم PWM - هنگام شمارش از پایین به بالا، اولین کانال غیرفعال است در حالی که TIMx_CNT < TIMx_CCR1. در غیر این صورت کانال اول فعال است.
از آنجایی که LED ها توسط کاتد به MK متصل می شوند، حالت دوم برای ما مناسب است (اولین نیز، اما ما هنوز آن را نمی دانیم).
بیت 3 OC1PE: بارگذاری اولیه پین 1 را فعال کنید
0: ثبت پیش بارگذاری در TIMx_CCR1 غیرفعال است. میتوانید در هر زمانی به TIMx_CCR1 بنویسید. مقدار جدید بلافاصله کار می کند.
1: ثبت پیش بارگذاری در TIMx_CCR1 فعال است. عملیات خواندن/نوشتن به ثبت پیش بارگذاری دسترسی دارند. مقدار از پیش بارگذاری شده TIMx_CCR1 در طی هر رویداد به روز رسانی در ثبات سایه بارگذاری می شود.
*توجه: برای اینکه حالت PWM به درستی کار کند، رجیسترهای پیش بارگذاری باید فعال باشند. این در حالت سیگنال تک ضروری نیست (بیت OPM در ثبات TIMx_CR1 تنظیم شده است).
خوب، بیایید همه چیزهایی را که برای سه کانال تایمر دوم نیاز داریم روشن کنیم:
تایمر دوم فقط می تواند از پایین به بالا شمارش کند، تراز در امتداد مرز، چیزی نیاز به تغییر ندارد. بیایید تقسیم کننده فرکانس را مثلاً روی 256 قرار دهیم. برای تایمر دوم، تقسیم کننده در ثبات TIM2_PSCR تنظیم شده است و توان دو است:
تنها چیزی که باقی می ماند این است که نتیجه گیری و خود تایمر دوم را روشن کنیم. اولین مشکل با رجیسترها حل می شود گرفتن/مقایسه کردن فعال: دو، سه کانال به طور نامتقارن در سراسر آنها پراکنده شده است. در اینجا ما همچنین می توانیم یاد بگیریم که می توان قطبیت سیگنال را تغییر داد، یعنی. در اصل، امکان استفاده از حالت PWM 1 وجود داشت. ما می نویسیم:
بیایید یک آنالوگ ساده از AnalogWrite بنویسیم، که مقادیر واقعی را برای مقایسه به تایمر منتقل می کند. رجیسترها به صورت قابل پیش بینی نامگذاری می شوند ثبت ها را ضبط/مقایسه کنید، دو عدد از آنها برای هر کانال وجود دارد: 8 بیت مرتبه پایین در TIM2_CCRxL و بیت های مرتبه بالا در TIM2_CCRxH. از آنجایی که ما یک PWM 8 بیتی ایجاد کرده ایم، کافی است فقط بیت های کم اهمیت را بنویسیم:
خواننده توجه متوجه خواهد شد که ما یک PWM کمی معیوب داریم که قادر به تولید 100% پر شدن نیست (در حداکثر مقدار 255، سیگنال برای یک چرخه تایمر معکوس می شود). برای LED ها این مهم نیست و خواننده با دقت می تواند حدس بزند که چگونه آن را تعمیر کند.
PWM روی تایمر دوم کار می کند، اجازه دهید به سراغ اولی برویم.
تایمر اول دقیقاً همان بیتها را در رجیسترهای یکسان دارد (فقط آن بیتهایی که در تایمر دوم "رزرو" باقی ماندهاند به طور فعال در اولی برای انواع چیزهای پیشرفته استفاده میشوند). بنابراین کافی است آدرس همان رجیسترها را در دیتاشیت پیدا کنید و کد را کپی کنید. خوب، مقدار تقسیم کننده فرکانس را تغییر دهید، زیرا ... تایمر اول می خواهد نه توان دو، بلکه یک مقدار دقیق 16 بیتی را در دو رجیستر دریافت کند. Prescaler High и کم. ما همه کارها را انجام می دهیم و ... تایمر اول کار نمی کند. موضوع چیه؟
مشکل فقط با نگاه کردن به کل بخش مربوط به رجیسترهای کنترلی تایمر 1 قابل حل است، جایی که ما به دنبال تایمر دوم می گردیم که ندارد. خواهد بود 17.7.30 ثبت شکست (TIM1_BKR)، جایی که این بیت وجود دارد:
سومین مینی پروژه، اتصال هشت LED RGB به تایمر دوم در حالت PWM و نشان دادن رنگ های مختلف است. این مبتنی بر مفهوم مالتی پلکس LED است، یعنی اگر LED ها را خیلی خیلی سریع روشن و خاموش کنید، به نظر می رسد که آنها دائما روشن هستند (تداوم دید، اینرسی ادراک بصری). من یک بار انجام دادم چیزی شبیه به این در آردوینو.
الگوریتم کار به شکل زیر است:
آند اولین LED RGB را وصل کرد.
آن را روشن کرد و سیگنال های لازم را به کاتدها ارسال کرد.
تا پایان چرخه PWM منتظر ماند.
آند LED RGB دوم را وصل کرد.
روشنش کرد...
خوب و غیره البته، برای عملکرد زیبا، لازم است که آند متصل شود و LED در همان زمان "اشتعال" شود. خوب، یا تقریبا. در هر صورت، باید کدی بنویسیم که مقادیر را در سه کانال از تایمر دوم خروجی بگیرد، با رسیدن به UEV آنها را تغییر دهد و در همان زمان LED RGB فعال فعلی را تغییر دهد.
از آنجایی که سوئیچینگ 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 به ستون تامین می کند، اما در این نسخه آزمایشی این امکان به طور مستقیم وجود دارد، زیرا 20 میلی آمپر می کشد، با توجه به اعتبار حداکثر مطلق در دیتاشیت از جانب برگه داده CD74HC238 ما به پین اوت ها و این برگه تقلب نیاز داریم:
H = سطح ولتاژ بالا، L = سطح ولتاژ پایین، X - مهم نیست
E2 و E1 را به زمین، E3، A0، A1 و A3 را به پین های PD5، PC3، PC4 و PC5 STM8 متصل می کنیم. از آنجایی که جدول بالا شامل سطوح پایین و بالا است، ما این پین ها را به عنوان پین های فشاری-کششی پیکربندی می کنیم.
PWM
PWM در تایمر دوم مانند داستان قبلی با دو تفاوت پیکربندی شده است:
ابتدا باید وقفه را فعال کنیم به روز رسانی رویداد (UEV) که تابعی را فراخوانی می کند که LED فعال را تغییر می دهد. این کار با تغییر بیت انجام می شود Update Interrupt Enable در یک ثبت نام با نامی گویا
تفاوت دوم مربوط به پدیده مالتی پلکس شدن است، مانند شبح - درخشش انگلی دیودها. در مورد ما، ممکن است به این دلیل به نظر برسد که تایمر، که باعث وقفه در UEV شده است، همچنان به تیک زدن ادامه می دهد، و کنترل کننده وقفه قبل از اینکه تایمر شروع به نوشتن چیزی روی پین ها کند، زمان لازم برای تغییر LED را ندارد. برای مبارزه با این، شما باید منطق را معکوس کنید (0 = حداکثر روشنایی، 255 = هیچ چیز روشن نیست) و از مقادیر شدید چرخه وظیفه اجتناب کنید. آن ها اطمینان حاصل کنید که پس از UEV LED ها برای یک دوره PWM کاملا خاموش می شوند.
از تنظیم r، g و b روی 255 خودداری کنید و به یاد داشته باشید که هنگام استفاده آنها را معکوس کنید.
قطع می کند
ماهیت وقفه این است که تحت شرایط خاصی تراشه اجرای برنامه اصلی را متوقف می کند و برخی از عملکردهای خارجی را فراخوانی می کند. وقفه ها به دلیل تأثیرات خارجی یا داخلی از جمله تایمر رخ می دهد.
هنگامی که ما برای اولین بار پروژه ای را در ST Visual Develop ایجاد کردیم، علاوه بر این main.c ما یک پنجره با یک فایل مرموز دریافت کردیم stm8_interrupt_vector.c، به طور خودکار در پروژه گنجانده شده است. در این فایل به هر وقفه یک تابع اختصاص داده شده است NonHandledInterrupt. باید تابع خود را به وقفه مورد نظر متصل کنیم.
دیتاشیت دارای جدولی از بردارهای وقفه است که در آن موارد مورد نیاز خود را پیدا می کنیم:
13 به روز رسانی/سرریز TIM2
14 TIM2 گرفتن/مقایسه
ما باید LED را در UEV تغییر دهیم، بنابراین به وقفه شماره 13 نیاز داریم.
بر این اساس اولاً در پرونده stm8_interrupt_vector.c نام پیش فرض تابع مسئول وقفه شماره 13 (IRQ13) را به نام خود تغییر دهید:
{0x82, TIM2_Overflow}, /* irq13 */
در مرحله دوم، ما باید یک فایل ایجاد کنیم main.h با محتوای زیر:
@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 - وقفه ها را خاموش می کند. آنها باید در حین نوشتن مقادیر جدید در "حافظه ویدیویی" خاموش شوند تا وقفه ایجاد شده در لحظه اشتباه آرایه را خراب نکند.