[Вступ]
Технологія мікроконтролерів є незамінною основною технологією в сучасній промисловій автоматизації, електроніці, електротехніці та Інтернеті речей (IoT). Оскільки наше життя стає все більш розумним, технологія мікроконтролерів проникла практично в усі аспекти нашого повсякденного життя, наприклад, у розумних рисоварках, розумних колонках тощо.
Зважаючи на це, серія статей «Relearning the 51 Microcontroller» має на меті допомогти початківцям розпочати роботу з технологією мікроконтролерів. Ми почнемо з найпростішого завдання-увімкнення одного світлодіода-і поступово переходимо до впровадження таких модулів, як кнопки керування, дисплей LCD1602, датчики температури DS18B20 і DS1302 і зв’язок між двома мікроконтролерами. Ми також розглянемо апаратні протоколи зв’язку, такі як UART, I²C і SPI. Поєднуючи ці концепції з технікою програмування на C, ми використовуватимемо-інженерні проекти реального світу, щоб проілюструвати підходи до програмування, дозволяючи вам гнучко застосовувати покажчики та структури C для досягнення модульного програмування.
Тепер давайте повернемося до основної теми: використання мікроконтролера 51 для керування світлодіодом і створення ефекту дихання.
[Як працюють дихальні вогні]
Давайте спочатку розглянемо, як працює світловий ефект дихання.
Дихальне світло поступово світлішає, а потім поступово тьмяніє, повторюючи цей цикл у спосіб, який нагадує дихання. Однак, оскільки контакти мікроконтролера можуть виводити лише 1 (увімкнено) або 0 (вимкнено), як можна досягти ефекту поступового переходу?
Це пов'язано з незмінністю зору в наших очах. Коли ми дивимося на щось, зображення, сформоване нашими очима, зберігається протягом 0,04 секунди (цю цифру знайшли в мережі).
Якщо обчислити на основі 0,04 секунди, це дорівнює 40 мс. Тому, коли світлодіод вмикається і вимикається протягом 20 мс кожен, людському оку здається, що він постійно горить.

Чи блимання світлодіода протягом 20 мс і вимкнення протягом 20 мс є таким самим, як і його постійне горіння?
Ха-ха, це точно інше. Коли світло вмикається та вимикається по черзі кожні 20 мілісекунд, ефект, який ми бачимо, тьмяніший, ніж коли воно горить постійно. Якщо ми припустимо, що яскравість світла, що постійно горить, дорівнює 100%, то яскравість світла, яке почергово вмикається і вимикається кожні 20 мілісекунд, дорівнює 50%. Виходячи з цього, ми можемо регулювати яскравість світлодіода.

На цьому етапі ми можемо налаштувати яскравість світлодіода (встановивши тривалість високого рівня в межах циклу 40 мс). Це принцип, який лежить в основі-відомого методу керування яскравістю ШІМ (широтно-імпульсної модуляції), а встановлення тривалості високого рівня еквівалентно налаштуванню робочого циклу (тобто тривалість високого рівня, поділена на загальний цикл: 20/40=50%).
Тут найважливішим фактором є робочий цикл. Наприклад, якщо період дорівнює 20 мс, а світлодіод чергується між 10 мс увімкненим і 10 мс вимкненим, сприймана яскравість все ще становить 50% (тобто робочий цикл становить 10/20=50%).
Далі подивимося, як це реалізовано в програмі.
[Реалізація програми]
Вмикання світлодіода
Спочатку давайте ввімкнемо світлодіод, а потім поступово реалізуємо ефект дихання. Апаратне забезпечення, яке ми будемо використовувати, таке:
| Рада розвитку | Навчальна плата розробки мікроконтролерів ZeroOne |
|---|---|
| Модель мікроконтролера | STC89C52 |
| Світлодіодний інтерфейс | Вивід P4^4 |

Зі схеми ми бачимо, що світлодіод підключений до контакту P4^4 мікроконтролера. Коли мікроконтролер видає 1, світлодіод вмикається; коли він виводить 0, світлодіод вимикається. Отже, програма для ввімкнення світлодіода досить проста, як показано нижче:

Програма для включення світлодіода досить проста; Я впевнений, що всі знають, як це зробити.
Регулювання яскравості світлодіода
Далі ми реалізуємо функцію, яка дозволяє регулювати яскравість (тобто регулювати робочий цикл), як показано нижче:

Визначте статичну змінну `duty_cycle` для збереження робочого циклу. Коли `flag` дорівнює 1, робочий цикл поступово збільшується до 255, потім встановіть `flag` на 0, а `duty_cycle` поступово зменшується від 255 до 0. Повторіть цей цикл.
Ха-ха, на даний момент ви можете подумати, що світло для дихання вже працює, але це не так. Якщо ви не вірите мені, спробуйте код вище самостійно.
Тож де саме проблема?
Проблема полягає в нашому прямому виклику-функції налаштування яскравості `set_led_luminance()`. Ця функція займає 40 мс для завершення одного циклу, тобто робочий цикл не можна змінити протягом цих 40 мс; інакше регулювання яскравості не працюватиме. Давайте ще раз подивимося на функцію `breath_led`. Після кожного виклику `set_led_luminance()` для встановлення робочого циклу він негайно змінює значення `duty_cycle`, не чекаючи 40 мс.
На цьому етапі нам потрібно додати програмний таймер для оновлення значення `duty_cycle` після 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, виконання порозрядної операції І з 0 призводить до 0.
Незалежно від того, дорівнює воно 1 чи 0, виконання порозрядної операції І з 1 призводить до вихідного значення.
Для зручності ми використовуємо шістнадцяткову систему запису (з префіксом "0x"); наприклад, 0xff відповідає 255 у десятковій системі. тому
Коли число менше або дорівнює 0xff об’єднується оператором І за допомогою 0xff, результатом є саме число, як показано нижче

Що станеться, якщо виконати порозрядну операцію І між числом, більшим за 0xff і 0xff?

Результатом є залишок від ділення цього числа на (0xff + 1) (тобто результат усе ще знаходиться між 0 і 0xff).
За допомогою цієї порозрядної операції AND наведений вище код можна спростити до

Таким чином, значення s_Counter завжди буде в діапазоні від 0x00 до 0xff.
Подібним чином програмний таймер у наведеній вище функції breath_led також можна спростити таким чином:

У рядку 3 0x1ff дорівнює 511 у десятковому вигляді. Умова є істинною, коли значення s_breathCounter дорівнює (0x1ff+1) або 512, оскільки 512 & 0x1ff=0. Знак оклику перед ним вказує на порозрядну операцію НЕ (якщо бути точним, умова виконується, коли значення `s_breathCounter` є кратним 512; це усуває необхідність скидання `s_breathCounter`, сподіваюся, це пояснення зрозуміле-подумайте). Якщо умова виконується, робочий цикл починає збільшуватися або зменшуватися.
Але хіба робочий цикл не становить від 0 до 255? Чому рядок 5 також стає 0x1ff (511)? Не хвилюйтеся-подивіться на рядок 8. Ми знову віднімаємо 0xff, тому діапазон робочого циклу залишається від 0 до 255.
Рядки 7–10 означають: коли `duty_cycle > (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, а потім приймає абсолютне значення. Гаразд, ось спрощений код:
Макрофункція для отримання абсолютного значення така
Нарешті, я включив весь спрощений код нижче

як ти думаєш Хіба це не просто? (* ̄︶ ̄)




