[مقدمه]
فناوری میکروکنترلر یک فناوری اصلی ضروری در اتوماسیون صنعتی مدرن، الکترونیک، مهندسی برق و اینترنت اشیا (IoT) است. همانطور که زندگی ما به طور فزاینده ای هوشمند می شود، فناوری میکروکنترلر تقریباً در تمام جنبه های زندگی روزمره ما نفوذ کرده است، مانند پلوپزهای هوشمند، بلندگوهای هوشمند و موارد دیگر.
با در نظر گرفتن این موضوع، مجموعه مقالات «یادگیری مجدد 51 میکروکنترلر» با هدف کمک به مبتدیان برای شروع کار با فناوری میکروکنترلر است. ما با سادهترین کار شروع میکنیم-روشن کردن یک LED-و به تدریج به پیادهسازی ماژولهایی مانند دکمههای کنترل، صفحه نمایش LCD1602، سنسورهای دما DS18B20 و DS1302 و ارتباط بین دو میکروکنترلر پیش میرویم. ما همچنین پروتکل های ارتباطی سخت افزاری مانند UART، I²C و SPI را پوشش خواهیم داد. با ترکیب این مفاهیم با تکنیکهای برنامهنویسی C، از پروژههای مهندسی واقعی{10}}جهان برای نشان دادن رویکردهای برنامهنویسی استفاده میکنیم و به شما امکان میدهد به طور انعطافپذیر از نشانگرها و ساختارهای C برای دستیابی به برنامهنویسی مدولار استفاده کنید.
حالا بیایید به موضوع اصلی برگردیم: استفاده از یک میکروکنترلر 51 برای کنترل LED و ایجاد یک افکت نور تنفسی.
[چراغ های تنفسی چگونه کار می کنند]
بیایید ابتدا نگاهی به نحوه عملکرد یک افکت نور تنفسی بیندازیم.
نور تنفسی به تدریج روشن می شود و سپس به تدریج کم می شود و این چرخه را به شیوه ای شبیه تنفس تکرار می کند. با این حال، از آنجایی که پایه های یک میکروکنترلر فقط می توانند 1 (روشن) یا 0 (خاموش) را تولید کنند، چگونه می توان به یک اثر گذار تدریجی دست یافت؟
این به دلیل تداوم بینایی در چشمان ما است. هنگامی که ما به چیزی نگاه می کنیم، تصویری که توسط چشمان ما تشکیل شده است به مدت 0.04 ثانیه باقی می ماند (این شکل به صورت آنلاین یافت شد).
اگر بر اساس 0.04 ثانیه محاسبه کنیم، برابر با 40 میلی ثانیه است. بنابراین، هنگامی که LED هر کدام به مدت 20 میلی ثانیه روشن و خاموش می شود، در چشم انسان به نظر می رسد که گویی دائماً روشن است.

آیا اثر روشن شدن LED به مدت 20 میلی ثانیه و خاموش شدن آن برای 20 میلی ثانیه مانند روشن ماندن دائمی آن است؟
هههه قطعا فرق داره هنگامی که نور هر 20 میلی ثانیه یکبار بین روشن و خاموش می شود، اثری که می بینیم نسبت به زمانی که به طور مداوم روشن می ماند کم نورتر است. اگر روشنایی نور پیوسته روشن را 100% فرض کنیم، روشنایی نوری که هر 20 میلیثانیه روشن و خاموش میشود 50% است. بر این اساس، ما می توانیم روشنایی LED را تنظیم کنیم.

در این مرحله، ما می توانیم روشنایی LED را تنظیم کنیم (با تنظیم مدت زمان سطح بالا در چرخه 40 میلی ثانیه). این اصل پشت-روش شناخته شده PWM (مدولاسیون عرض پالس) کنترل روشنایی است، و تنظیم مدت زمان سطح بالا معادل تنظیم چرخه وظیفه است (یعنی مدت زمان سطح بالا تقسیم بر کل چرخه: 20/40=50%).
در اینجا مهمترین عامل این چرخه وظیفه است. برای مثال، اگر دوره 20 میلیثانیه باشد، با LED متناوب بین 10 میلیثانیه روشن و 10 میلیثانیه خاموش، روشنایی درک شده همچنان 50 درصد است (یعنی چرخه کار 10/20=50 درصد است).
بعد، بیایید ببینیم که چگونه این در برنامه پیاده سازی می شود.
[اجرای برنامه]
روشن کردن یک LED
ابتدا اجازه دهید با روشن کردن یک LED شروع کنیم و سپس به تدریج یک افکت نور تنفسی را اجرا می کنیم. سخت افزاری که ما استفاده خواهیم کرد به شرح زیر است:
| هیئت توسعه | هیئت توسعه آموزش میکروکنترلر ZeroOne |
|---|---|
| مدل میکروکنترلر | STC89C52 |
| رابط LED | پین P4^4 |

از شکل شماتیک می بینیم که LED به پایه P4^4 میکروکنترلر متصل است. وقتی میکروکنترلر عدد 1 را خروجی می دهد، LED روشن می شود. وقتی عدد 0 را نشان می دهد، LED خاموش می شود. بنابراین، برنامه روشن کردن LED بسیار ساده است، همانطور که در زیر نشان داده شده است:

برنامه روشن کردن LED بسیار ساده است. من مطمئن هستم که همه می دانند چگونه این کار را انجام دهند.
تنظیم روشنایی LED
در مرحله بعد، ما تابعی را اجرا می کنیم که به ما امکان می دهد روشنایی را تنظیم کنیم (یعنی تنظیم چرخه کار)، به شرح زیر:

برای ذخیره چرخه وظیفه، یک متغیر ثابت «duty_cycle» تعریف کنید. وقتی «پرچم» 1 است، چرخه وظیفه به تدریج به 255 افزایش می یابد، سپس «پرچم» را روی 0 تنظیم کنید، و «چرخه_کار» به تدریج از 255 به 0 کاهش می یابد. این چرخه را تکرار کنید.
هاها، در این مرحله، ممکن است فکر کنید که نور تنفسی در حال حاضر کار می کند، اما اینطور نیست. اگر من را باور ندارید، کد بالا را خودتان امتحان کنید.
پس مشکل دقیقا کجاست؟
مشکل در تماس مستقیم ما با روشنایی{0}}تنظیم تابع «set_led_luminance()» است. این تابع 40 میلی ثانیه طول می کشد تا یک چرخه کامل شود، به این معنی که چرخه وظیفه را نمی توان در طول این 40 میلی ثانیه تغییر داد. در غیر این صورت، تنظیم روشنایی کار نخواهد کرد. بیایید نگاهی دیگر به تابع «breath_led» بیندازیم. پس از هر تماس با «set_led_luminance()» برای تنظیم چرخه وظیفه، بلافاصله مقدار «duty_cycle» را بدون انتظار 40 میلیثانیه تغییر میدهد.
در این مرحله، باید یک تایمر نرمافزاری اضافه کنیم تا پس از سپری شدن 40 میلیثانیه، مقدار «دویت_چرخه» را بهروزرسانی کنیم. برنامه اصلاح شده به شرح زیر است:

توجه: مدت زمان تایمر فقط باید بیشتر از 40 میلیثانیه باشد (یعنی مقدار «s_breathCounter» باید بیشتر از 255 باشد)، اما بهتر است آن را روی مضربی از چرخه تنظیم کنید. برای مثال، اگر چرخه ما 255 باشد (یعنی 256 مقدار از 0 تا 255)، میتوانیم آن را دو برابر این مقدار تنظیم کنیم: 256 * 2 - 1=511 (یعنی 512 مقدار از 0 تا 511).
و شما آن را دارید-نور تنفس ما کامل است! این ساده نیست؟ (* ̄︶ ̄)
قسمت بعدی بخش پاداش امروز است.
اگرچه ما به جلوه نور تنفسی دست یافتهایم، کد به اندازه کافی مختصر یا ظریف نیست-از تعدادی دستور if و else استفاده میکند. بیایید ببینیم که آیا می توانیم آن را بیشتر ساده کنیم.
ابتدا اجازه دهید این بخش از تابع set_led_luminance() را همانطور که در شکل زیر نشان داده شده است ساده کنیم.

قبل از اینکه این موضوع را ساده کنیم، اجازه دهید یک نکته کوتاه در مورد C را پوشش دهیم: عملیات بیتی AND.

از این رو می دانیم که چه 1 باشد و چه 0، انجام یک عمل بیتی AND با 0 به 0 منجر می شود.
خواه 1 باشد یا 0، انجام یک عملیات AND بیتی با 1 به مقدار اصلی منجر می شود.
برای راحتی، از نماد هگزادسیمال (پیشوند "0x") استفاده می کنیم. به عنوان مثال، 0xff مربوط به 255 در اعشار است. بنابراین،
هنگامی که عددی کمتر یا مساوی 0xff با 0xff AND می شود، نتیجه همان عدد است، همانطور که در زیر نشان داده شده است.

اگر یک عمل بیتی AND بین عددی بزرگتر از 0xff و 0xff انجام دهید چه اتفاقی می افتد؟

وقتی این عدد بر (0xff + 1) تقسیم شود، نتیجه باقیمانده است (یعنی نتیجه همچنان بین 0 و 0xff است).
با این عمل بیتی AND، کد بالا را می توان ساده کرد

به این ترتیب، مقدار s_Counter همیشه در محدوده 0x00 تا 0xff خواهد بود.
به طور مشابه، تایمر نرم افزار در تابع breath_led بالا نیز می تواند به صورت زیر ساده شود:

در خط 3، 0x1ff برابر با 511 در اعشار است. این شرط زمانی درست است که مقدار s_breathCounter (0x1ff+1) یا 512 باشد، زیرا 512 & 0x1ff=0. علامت تعجب قبل از آن نشاندهنده یک عملیات NOT بیتی است (بهطور دقیق، شرط زمانی برآورده میشود که مقدار `s_breathCounter` نیاز به حذف مجدد این مقدار 5 باشد. «s_breathCounter» امیدوارم این توضیح واضح باشد{18}لطفاً به آن فکر کنید. اگر شرط برآورده شود، چرخه وظیفه شروع به افزایش یا کاهش می کند.
اما آیا محدوده چرخه کاری 0 تا 255 نیست؟ چرا خط 5 نیز 0x1ff (511) می شود؟ نگران نباشید-به خط 8 نگاه کنید. ما دوباره 0xff را کم می کنیم، بنابراین محدوده چرخه کاری بین 0 تا 255 باقی می ماند.
خطوط 7 تا 10 به این معنی هستند: هنگامی که «چرخه_کار > (0xff)»، یعنی 256-511، کم کردن 0xff معادل افزایش از 1 به 255 است، بنابراین روشنایی به تدریج افزایش مییابد.
وقتی duty_cycle<= 0xff, the duty_cycle increases from 0 to 255, while the set brightness is 255 - duty_cycle. This effectively decreases the brightness from 255 to 0, causing the light to gradually dim. This achieves the breathing light effect.
هههه فکر کردی ساده سازیمون تموم شد؟
نه نه نه
در واقع، خطوط 7 تا 10 را می توان حتی بیشتر ساده کرد. اینجاست که تابع مقدار مطلق به کار می آید.
چی؟ چرا از تابع قدر مطلق استفاده می کنیم؟
به خط 10 نگاه کنید: 0xff - duty_cycle معادل duty_cycle - 0xff است و سپس مقدار مطلق را بگیرید. خوب، این کد ساده شده است:
تابع ماکرو برای گرفتن قدر مطلق به صورت زیر است
در نهایت، کل کد ساده شده را در زیر قرار داده ام

نظر شما چیست؟ ساده نیست؟ (* ̄︶ ̄)




