[מָבוֹא]
טכנולוגיית המיקרו-בקרים היא טכנולוגיית מיינסטרים הכרחית באוטומציה תעשייתית מודרנית, אלקטרוניקה, הנדסת חשמל ואינטרנט של הדברים (IoT). ככל שהחיים שלנו הופכים ליותר ויותר חכמים, טכנולוגיית המיקרו-בקרים חלחלה למעשה לכל היבט בחיי היום-יום שלנו, כמו בישולי אורז חכמים, רמקולים חכמים ועוד.
מתוך מחשבה על כך, סדרת המאמרים "למדת מחדש את 51 המיקרו-בקר" נועדה לעזור למתחילים להתחיל עם טכנולוגיית המיקרו-בקר. נתחיל במשימה הפשוטה ביותר-להדליק נורית יחידה-ונתקדם בהדרגה ליישום מודולים כגון פקדי לחצנים, תצוגת LCD1602, חיישני טמפרטורה של DS18B20 ו-DS1302 ותקשורת בין שני מיקרו-בקרים. נסקור גם פרוטוקולי תקשורת חומרה כמו UART, I²C ו-SPI. על ידי שילוב של מושגים אלה עם טכניקות תכנות C, נשתמש בפרויקטים הנדסיים{10}}אמיתיים כדי להמחיש גישות תכנות, מה שיאפשר לך ליישם בצורה גמישה מצביעי C ומבנים כדי להשיג תכנות מודולרי.
כעת, נחזור לנושא המרכזי: שימוש במיקרו-בקר 51 כדי לשלוט ב-LED וליצור אפקט אור נושם.
[איך פועלים אורות נשימה]
תחילה נסקור כיצד פועל אפקט אור נושם.
אור נושם מתבהר בהדרגה ולאחר מכן מתעמעם בהדרגה, וחוזר על מחזור זה באופן הדומה לנשימה. עם זאת, מכיוון שפינים של מיקרו-בקר יכולים להוציא רק 1 (מופעל) או 0 (כבוי), כיצד ניתן להשיג אפקט מעבר הדרגתי?
זה נובע מהתמדה של הראייה בעינינו. כאשר אנו מסתכלים על משהו, התמונה שנוצרת על ידי העיניים שלנו נמשכת במשך 0.04 שניות (נתון זה נמצא באינטרנט).
אם נחשוב על סמך 0.04 שניות, זה שווה ל-40 אלפיות השנייה. לכן, כאשר הנורית דולקת וכבויה למשך 20 אלפיות השנייה כל אחת, היא נראית לעין האנושית כאילו היא דולקת כל הזמן.

האם ההשפעה של נורית מהבהבת דולקת למשך 20 אלפיות השנייה וכבויה למשך 20 שניות זהה לזה שהיא נשארת דולקת כל הזמן?
חחח זה בהחלט שונה. כאשר האור מתחלף לסירוגין כל 20 מילישניות, האפקט שאנו רואים עמום יותר מאשר כאשר הוא נשאר דולק ברציפות. אם נניח שהבהירות של אור מואר ברציפות היא 100%, אזי הבהירות של אור שמתחלף לסירוגין כל 20 אלפיות השנייה היא 50%. בהתבסס על זה, אנו יכולים להתאים את בהירות ה-LED.

בשלב זה, אנו יכולים להתאים את בהירות ה-LED (על ידי הגדרת משך הרמה הגבוהה במחזור של 40ms). זהו העיקרון מאחורי -שיטת PWM (Pulse Width Modulation) הידועה של בקרת בהירות, והגדרת משך הרמה הגבוהה שווה ערך לכוונון מחזור העבודה (כלומר, משך הרמה הגבוהה חלקי המחזור הכולל: 20/40=50%).
כאן, הגורם החשוב ביותר הוא מחזור החובה הזה. לדוגמה, אם התקופה היא 20 אלפיות השנייה, כאשר הנורית מתחלפת בין 10 אלפיות השנייה ל-10 אלפיות השנייה כבויה, הבהירות הנתפסת היא עדיין 50% (כלומר, מחזור העבודה הוא 10/20=50%).
לאחר מכן, בואו נראה כיצד זה מיושם בתוכנית.
[יישום תוכנית]
הדלקת LED
ראשית, נתחיל בהפעלת נורית LED, ולאחר מכן ניישם בהדרגה אפקט של אור נושם. החומרה שבה נשתמש היא כדלקמן:
| מועצת פיתוח | לוח פיתוח הדרכה של מיקרו-בקר ZeroOne |
|---|---|
| דגם מיקרו-בקר | STC89C52 |
| ממשק LED | Pin P4^4 |

מהסכמטי, אנו יכולים לראות שה-LED מחובר לפין P4^4 של המיקרו-בקר. כאשר המיקרו-בקר מוציא 1, הנורית נדלקת; כאשר הוא מוציא 0, הנורית נכבית. לכן, התוכנית להפעלת LED היא די פשוטה, כפי שמוצג להלן:

התוכנית להפעלת LED היא די פשוטה; אני בטוח שכולם יודעים איך לעשות את זה.
התאמת בהירות LED
לאחר מכן, ניישם פונקציה המאפשרת לנו להתאים את הבהירות (כלומר, להתאים את מחזור העבודה), באופן הבא:

הגדר משתנה סטטי 'מחזור_עבודה' כדי לאחסן את מחזור העבודה. כאשר 'דגל' הוא 1, מחזור העבודה גדל בהדרגה ל-255, ואז הגדר את 'דגל' ל-0, ו-'מחזור העבודה' יורד בהדרגה מ-255 ל-0. חזור על מחזור זה.
חחח, בשלב הזה אולי תחשוב שאור הנשימה כבר עובד, אבל זה לא. אם אתה לא מאמין לי, נסה את הקוד מעל עצמך.
אז איפה בדיוק הבעיה?
הבעיה נעוצה בקריאה הישירה שלנו לפונקציית -הבהירות `set_led_luminance()`. פונקציה זו לוקחת 40 שניות כדי להשלים מחזור אחד, כלומר לא ניתן לשנות את מחזור העבודה במהלך 40 שניות אלה; אחרת, התאמת הבהירות לא תעבוד. בוא נסקור שוב את הפונקציה 'נשמה_מובילה'. לאחר כל קריאה אל `set_led_luminance()` כדי להגדיר את מחזור העבודה, הוא משנה מיד את ערך `מחזור העבודה` מבלי להמתין 40 אלפיות השנייה.
בשלב זה, עלינו להוסיף טיימר תוכנה כדי לעדכן את ערך 'מחזור העבודה' לאחר שחלפו 40 אלפיות השנייה. התוכנית ששונתה היא כדלקמן:

הערה: משך הטיימר צריך להיות יותר מ-40 אלפיות השנייה (כלומר הערך של `s_breathCounter` חייב להיות גדול מ-255), אבל עדיף להגדיר אותו לכפולה של המחזור. לדוגמה, אם המחזור שלנו הוא 255 (כלומר, 256 ערכים מ-0 עד 255), נוכל להגדיר אותו לערך כפול מזה: 256 * 2 - 1=511 (כלומר, 512 ערכים מ-0 עד 511).
והנה,-אור הנשימה שלנו הושלם! זה לא פשוט? (* ̄︶ ̄)
הבא הוא קטע הבונוס של היום.
למרות שהשגנו את אפקט האור לנשימה, הקוד לא מספיק תמציתי או אלגנטי-הוא משתמש בכמה הצהרות אם ואחרות. בוא נראה אם נוכל לפשט את זה עוד יותר.
ראשית, בואו נפשט את הקטע הזה של הפונקציה set_led_luminance() כפי שמוצג באיור למטה.

לפני שנפשט את זה, בואו נסקור טיפ מהיר לגבי C: פעולת AND בשיטת הסיביות.

מכאן, אנו יודעים שבין אם זה 1 או 0, ביצוע פעולת AND עם 0 גורם ל-0.
בין אם זה 1 או 0, ביצוע פעולת AND עם 1 יביא לערך המקורי.
מטעמי נוחות, אנו משתמשים בסימון הקסדצימלי (עם קידומת "0x"); לדוגמה, 0xff מתאים ל-255 בעשרוני. לָכֵן,
כאשר מספר קטן או שווה ל-0xff מסומן עם 0xff, התוצאה היא המספר עצמו, כפי שמוצג להלן

מה קורה אם תבצע פעולת 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` הוא כפולה של 512 זה מבטל את ה-512 התקווה הזה. ההסבר ברור-אנא חשוב על זה). אם התנאי מתקיים, מחזור העבודה מתחיל לעלות או לרדת.
אבל האם טווח מחזור העבודה אינו 0 עד 255? מדוע שורה 5 הופכת גם ל-0x1ff (511)? אל תדאג-תסתכל על שורה 8. אנו מפחיתים שוב את 0xff, כך שטווח מחזור העבודה יישאר בין 0 ל-255.
השורות 7–10 אומרות: כאשר `Duty_cycle > (0xff)`, כלומר 256–511, הפחתת 0xff שווה ערך להגדלה מ-1 ל-255, כך שהבהירות גדלה בהדרגה.
כאשר מחזור_חובה<= 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 ואז לוקחים את הערך המוחלט. אוקיי, הנה הקוד הפשוט:
פונקציית המאקרו ללקיחת הערך המוחלט היא כדלקמן
לבסוף, כללתי את כל הקוד הפשוט למטה

מה אתה חושב? זה לא פשוט? (* ̄︶ ̄)




