Текст
                    ARDUINO
Белов А.В.
ОТ АЗОВ
программирования
ДО СОЗДАНИЯ
практических
устройств
о
El
ВИРТУАЛЬНЫЙ ЛИСП содержит: инструментальные
программы, дополнительные библиотеки для ARDUINO,
видеопрезентаиии, полный набор ARDUINO-скетчей
из книги в электронном виде

Белов А.В. ARDUINO от азов программирования до создания практических устройств ^НиТ уиздательство^р Наука и Техника, Санкт-Петербург
УДК 621.314:621311.6 ББК 32.816 Белов А.В. ARDUINO: от азов программирования до создания практических устройств. - СПб.: Наука и Техника, 2018. - 480 с., илл. ISBN 978-5-94387-884-8 Читатель пройдет путь от основ цифровой логики, булевой алгебры до программирования микроконтроллеров и создания на них практических устройств. В книге подробно рас- сматриваются принципы работы микропроцессорной системы, архитектура построения микроконтроллеров семейства AVR, составляющего основу модулей Arduino. Именно на них выполнены все устройства, на базе которых идет обучение. Модуль Arduino оказался настолько удачной разработкой, что сегодня признан идеальной основой для изучения микроконтроллерной техники. Основной частью книги являются практический курс по схемотехнике и программированию, состоящий из 15 практических уроков. Для каждого урока автор специально разработал реальное устройство на основе модуля Arduino. Переходя последовательно от простого к сложному, читатель научится писать программы, а также освоит искусство схемотехники. Одновременно на тех же примерах идет изучение языка программирования Arduino. Все функции, операторы и другие элементы этого языка подробно описываются перед тем, как о них пойдёт речь при описании конкретной программы. Неоценимую помощь в изучении оказывает виртуальный диск,содержащий инструменталь- ные программы, дополнительные библиотеки для Arduino, видео презентации и полный набор Arduino-скетчей из книги в электронном виде и многое другое. Книга создана специально для начинающих конструкторов микроконтроллерной техники, студентов и всех, кто хочет досконально изучить секреты и премудрости микроэлектроники. ISBN 978-5-94387-884-8 Автор и издательство не несут ответственности за возможный ущерб, причиненный в ходе использования материалов данной книги. Контактный телефон издательства (812) 412-70-26 Официальный сайт: www.nit.com.ru @ © Белов А.В. © Наука и Техника (оригинал-макет) ООО «Наука и Техника». Лицензия № 000350 от 23 декабря 1999 года. 198097, г. Санкт-Петербург, ул. Маршала Говорова, д. 29. Подписано в печать 11.04.2018. Формат 70*100 1/16. Бумага офсетная. Печать офсетная. Объем 30 п. л. Тираж 1200 экз. Заказ № 3568. Отпечатано с готовых файлов заказчика в АО «Первая Образцовая типография» филиал «УЛЬЯНОВСКИЙ ДОМ ПЕЧАТИ» 432980, г. Ульяновск, ул. Гончарова, 14
СОДЕРЖАНИЕ От автора..................................................... 11 Часть I. ВОТ ОНА КАКАЯ - ТЕХНИКА ЦИФРОВАЯ..................... 13 Глава 1. Без микропроцессоров мир был бы скучным.............. 14 Как микропроцессор завоевал весь мир.................. 14 Микропроцессор вырос до микроконтроллера.............. 15 Процессор - сердце микропроцессорной системы.......... 16 Что помнит память..................................... 17 Порты ввода и порты вывода............................ 18 Алгоритм упраления процессора......................... 19 Все на свете можноописать цифрами..................... 20 Что же такое микропроцессор........................... 21 Постоянные запоминающие устройства.................... 22 Оперативная память или оперативное запоминающее устройство............................................ 23 ПЗУ с электрическим стиранием информации или флэш-память....................................... 24 В чем же различия между микропроцессорами и микроконтроллерами................ 25 Глава 2. Учимся считать по-другому............................ 26 Знакомая с детства десятичная система исчисления...... 26 Восьмиричная система исчисления....................... 29 Шестнадцатеричная система исчисления.................. 31 Двоичная система исчисления........................... 32 Способы обозначения чисел в разных системах исчисления.... 33 Арифметическая операция сложения...................... 35 Арифметическая операция умножения..................... 37 Глава 3. Электронные цифры для компьютера..................... 38 Представление чисел на ПК............................. 38 Двухуровневый сигнал.................................. 41 Явление триггерного эффекта........................... 42 Глава 4. Логические элементы: простые и составные............. 44 Знакомство с логическими элементами................... 44 Простой логический элемент «И»........................ 46 Простой логический элемент «ИЛИ»...................... 46 Простой логический элемент «НЕ», или инвертор......... 47 Таблица истинности.................................... 47 Составные логические элементы......................... 48 Составные логические элементы «И-НЕ» и «ИЛИ-НЕ»....... 48 Составной логический элемент «ИСКЛЮЧАЮЩЕЕ ИЛИ»........ 49 Составной логический элемент сумматор................. 50
Глава 5. Простейшие триггеры.................................. 52 Что такое триггер..................................... 52 Триггер Шмитта: четкое срабатывание................... 53 RS-триггер: схема и условное обозначение.............. 54 RS-триггер: варианты подачи сигналов.................. 55 RS-триггер: переключение триггера..................... 56 RS-триггер: переход триггера из одного устойчивого состояния в другое.................................... 56 Борьба с дребезгом контактов.......................... 58 Глава 6. Триггеры для хранения информации..................... 61 D-триггер: устройство и схемное обозначение........... 61 D-триггер: логика работы.............................. 62 Параллельный регистр.................................. 63 Параллельный регистр с расширенными возможностями..... 64 JK-триггер: устройство и работа....................... 66 Глава 7. Счетчики импульсов и делители частоты................ 67 Работа делителя частоты............................... 67 Счетчики прямого счета................................ 70 Счетчики с обратным отсчетом.......................... 72 Делители с переменным коэффициентом деления........... 74 Таймеры: формируем различные интервалы времени........ 76 Глава 8. Дешифраторы цифровых сигналов....................... 78 Устройство и принцип действия дешифратора............. 78 Селектор памяти ячеек ОЗУ............................. 80 Каскадирование дешифраторов........................... 83 Дешифратор для работы с двоично-десятичными числами... 85 Глава 9. Мультиплексоры: собираем сигнал с нескольких входов.. 86 Как собирается сигнал с нескольких источников......... 86 Разнообразие мультиплексоров.......................... 87 Цифровые и аналоговые мультиплексоры.................. 87 Часть II. ШАГАЕМ ОТ ЦИФРОВОЙ ТЕХНИКИ К МИКРОКОНТРОЛЛЕРУ....... 89 Глава 10. Типовая схема микропроцессорной системы............. 90 Структурная схема типичной микропроцессорной системы.. 90 ОЗУ и ПЗУ: в чем сходства и отличия................... 92 Динамическая память................................... 92 Развитие постоянных запоминающих устройств............ 93 Порты ввода-вывода.................................... 95 Процессор и цифровые шины............................. 96 Шина данных........................................... 97 Шина адреса........................................... 98 Шина управления.......................................100 Принцип действия микропроцессорной системы............101
Глава 11. Алгоритм работы микропроцессорной системы..........103 Возможности процессора...............................103 Программа ...........................................105 Процесс выполнения команды...........................107 Рабочие регистры.....................................108 Команды микропроцессора..............................109 Команды условного и безусловного перехода............111 Команда организации цикла............................113 Команды перехода к подпрограмме......................115 Глава 12. Специальные режимы работы микропроцессорной системы... 118 Механизм прерываний..................................118 Прямой доступ к памяти...............................121 Часть III. ЗНАКОМТЕСЬ: МИКРОКОНТРОЛЛЕРЫ AVR, ОСНОВА ПЛАТ ARDUINO .. 125 Глава 13. Возможности и особенности построения микроконтроллеров AVR........................................126 Микроконтроллеры - кто они?..........................126 Особенности новой серии микроконтроллеров............127 Семейство микроконтроллеров AVR......................128 Таблица параметров микроконтроллеров.................129 Состав серии AVR.................................... 135 Особенности серии AVR................................136 Внутренняя память....................................137 Способы программирования Flash- и EERROM-памяти......139 Порты ввода-вывода...................................140 Периферийные устройства..............................140 Дополнительные устройства............................142 Глава 14. Регистры: храним предварительные результаты вычислений .. 143 Регистры общего назначения (РОН).....................143 Регистры ввода-вывода................................145 Общие сведения.......................................147 Глава 15. Память микроконтроллера............................147 Память программ......................................148 Оперативная память микроконтроллеров AVR.............151 Область памяти, совмещенная с набором регистров общего назначения (РОН)..........153 Область памяти, совмещенная с регистрами ввода-вывода (РВВ)......................153 Область внутреннего ОЗУ..............................154 Область внешнего ОЗУ.................................154 Энергонезависимая память данных (EEPROM).............154 Глава 16. Дополнительные регистры и стековая память..........157 Счетчик команд.......................................157 Указатель стека.................................... 159 Организация стековой памяти..........................159
Глава 17. Подсистема ввода-вывода.............................162 Назначение, состав, имена.............................162 Назначение и наименование специальных регистров.......163 Принцип действия......................................164 Конфигурирование порта ввода-вывода...................165 Глава 18. Система прерываний..................................167 Назначение системы прерываний.........................167 Управление системой прерываний...................... 168 Алгоритм работы системы прерываний....................169 Таблицу векторов прерываний для микроконтроллера ATmega328P.......................171 Глава 19. Таймеры-счетчики....................................173 Классификация встроенных таймеров.....................173 Сторожевой таймер.....................................173 Таймеры общего назначения.............................174 Режимы работы таймеров................................176 Режим Normal..........................................177 Режим «Захват» (Capture)..............................177 Режим «Сброс при совпадении» (СТС)....................178 Режим «Быстродействующий ШИМ» (Fast PWM)..............180 Режим «ШИМ с точной фазой» (Phase Correct PWM)........183 Асинхронный режим.....................................184 Предделители таймеров/счетчиков.......................185 Глава 20. Встроенные периферийные устройства..................188 Аналоговый компаратор.................................188 Аналого-цифровой преобразователь......................189 Последовательный канал (UART/USART)...................192 Последовательный периферийный интерфейс (SPI) ........193 Последовательный двухпроводный интерфейс (TWI)........195 Глава 21. Программируемые переключатели режимов и ячейки защиты информации....................................196 Конфигурационные ячейки...............................196 Ячейки защиты и идентификации.........................198 Часть IV. МОДУЛЬ ARDUINO - КОНСТРУКТОР ДЛЯ ДОМОХОЗЯЕК.........199 Глава 22. Модуль Arduino - первое знакомство..................200 Почему стал популярным модуль Arduino?................200 Как будем осваивать язык Arduino......................201 Глава 23. Модуль ARDUINO: осваиваем теоретически..............202 Кто и зачем создал модуль Arduino?....................202 Как же удалось достичь такой популярности?............203 Первые варианты Arduino............................. 204 Знакомимся с модулем Arduino UNO......................207 Полезные упрощения в модуле...........................209 Группа аналоговых входов..............................210
Команда аналогового вывода............................211 Контакты питания «Power»..............................213 Поддерживаемые языки программирования.................213 Для чего нужно специальное приложение Глава 24. Среда разработки IDE................................215 «Среда разработки Arduino IDE»?.......................215 Команды и функции языка Arduino.......................216 Внутренние библиотеки.................................218 Скачиваем программный пакете сайта разработчика.......219 Варианты установочных пакетов для Windows.............220 Запуск программы..................................... 221 Основное окно среды разработки........................222 Панель инструментов...................................224 Выбор номера СОМ порта в настройках программы.........225 Выбор типа используемой платы Arduino.................226 Скетч: открытие, сохранение, загрузка.................227 Организация обмена информацией между программой на Arduino и компьютером.............228 Часть V. ПОЛЕЗНЫЕ УСТРОЙСТВА НА ARDUINO - СВОИМИ РУКАМИ.......231 Глава 25. Простейшая программа «Hello, world!»................232 Постановка задачи.....................................232 Схема .............................................. 233 Алгоритм............................................ 2ЪЬ Первый вариант программы..............................238 Второй вариант программы..............................246 Глава 26. Переключаемый светодиод.............................255 Постановка задачи.....................................255 Схема ................................................255 Алгоритм..............................................256 Первый вариант программы..............................256 Второй вариант программы..............................260 Третий вариант программы..............................262 Глава 27. Боремся с дребезгом контактов.......................265 Постановка задачи.....................................265 Схема ................................................267 Антидребезг простыми средствами.......................267 Алгоритм..............................................267 Программа.............................................268 Применение внешней библиотеки Button..................270 Метод проверки ожидания стабильного состояния сигнала.276 Метод фильтрации сигнала по среднему значению.........276 Глава 28. Мигающий светодиод..................................278 Постановка задачи.....................................278 Схема ................................................278
Алгоритм............................................ 279 Программа.............................................279 Глава 29. Бегущие огни........................................282 Постановка задачи.....................................282 Схема ................................................283 Алгоритм..............................................283 Первый вариант программы..............................285 Второй вариант - используем один универсальный цикл...291 Глава 30. Альтернативные способы формирования задержки........295 Постановка задачи................................... 295 Схема ................................................297 Алгоритм............................................ 297 Первый вариант программы..............................298 Второй вариант программы..............................301 Глава 31. Работа с прерываниями по таймеру....................308 Постановка задачи.....................................308 Схема ................................................311 Используем внешнюю библиотеку прерываний по таймеру .... 311 Алгоритм..............................................313 Программа.............................................313 Совместное использование таймера 0....................317 Глава 32. Формирование звука................................ 326 Постановка задачи.....................................326 Схема ................................................328 Алгоритм..............................................330 Программа.............................................330 Глава 33. Ввод аналоговой информации..........................335 Постановка задачи.....................................335 Схема ................................................336 Алгоритм..............................................337 Программа.............................................339 Глава 34. Вывод аналоговой информации.........................342 Широтно-импульсная модуляция..........................342 Простейший способ аналогового вывода..................345 Схема ................................................345 Алгоритм..............................;...............346 Программа.............................................347 Более сложный пример аналоговой индикации.............348 Схема ................................................349 Алгоритм..............................................349 Программа.............................................351 Глава 35. Передача данных из Ардуино на компьютер........... 357 Постановка задачи.....................................357 Схема ................................................358
Алгоритм.............................................360 Программа............................................360 Глава 36. Передача данных с компьютера на Arduino............369 Постановка задачи....................................369 Схема ...............................................370 Алгоритм.............................................371 Программа............................................372 Глава 37. Музыкальная шкатулка...............................376 Постановка задачи....................................376 Схема ...............................................382 Алгоритм........................................... 382 Программа............................................ 38 Глава 38. Электронный замок с необычной логикой работы.......397 Постановка задачи.................................. 397 Схема ...............................................401 Алгоритм.............................................403 Программа............................................405 Глава 39. Кодовый замок с музыкальным звонком................424 Постановка задачи....................................424 Схема ...............................................425 Алгоритм.............................................426 Программа............................................427 Часть VI РАСШИРЯЕМ ФУНКЦИОНАЛЬНОСТЬ ПЛАТ ARDUINO.................437 Глава 40. Платы arduino: особенности и возможности...............438 Плата Arduino Due....................................... 438 Плата Arduino Leonardo...................................439 Плата Arduino YUN........................................440 Плата Arduino Miao.......................................441 Плата Arduino UNO........................................442 Плата Arduino Ethernet...................................443 Плата Arduino Duemilanove................................444 Плата Arduino Diecimila..................................445 Плата Arduino Nano.......................................446 Плата Arduino Mega.......................................447 Плата Arduino Mega 2560................................. 448 Плата Arduino ADK........................................449 Плата Arduino LilyPad....................................450 Плата Arduino Fio........................................451 Плата Arduino Mini.......................................452 Плата Arduino Pro........................................453 Плата Arduino Pro Mini...................................454 Плата USB SerialLight адаптер............................455
Глава 41. Arduino shields или платы расширения...............456 Плата расширенияАгбшпо WiFi..........................456 Плата расширения Xbee Shield.........................457 Плата расширения Arduino Motor.......................458 Плата расширения Ethernet Shield.....................459 Часть VII. ПОЛЕЗНАЯ ИНФОРМАЦИЯ ПО СОВРЕМЕННЫМ МИКРОКОНТРОЛЛЕРАМ.............................461 Приложение 1. Основные операторы языка Arduino...............462 Главные функции......................................462 Управляющие операторы................................462 Операторы цифрового ввода/вывода.....................464 Операторы аналогового ввода/вывода...................464 Операторы времени....................................465 Расширенный ввод/вывод...............................465 Работа с последовательным портом.....................466 Приложение 2. Типы данных в Arduino IDE......................467 Приложение 3. Сводная таблица команд Ассемблера микроконтроллеров AVR........................................469 Группа команд логических операций....................469 Группа команд арифметических операций................470 Группа команд операций с разрядами...................470 Группа команд сравнения..............................471 Группа команд операций сдвига........................472 Группа команд пересылки данных.......................472 Группа команд управления системой....................474 Группа команд передачи управления (безусловная передача управления) ...................474 Группа команд передачи управления (пропуск команды по условию).........................475 Группа команд передачи управления (передача управления по условию).....................475 Подводя итоги, или о виртуальном диске.......................477 Список литературы........................................... 478 Список ссылок на ресурсы сети Интернет, используемые в книге.478
ОТ АВТОРА Эта книга не просто рассказ о популярном в наше время модуле Arduino (Ардуино). Существует немало книг и статей, при помощи которых можно быстро научиться создавать раз- личные простые конструкции и писать простейшие программы или просто взять уже готовую программу с нужной для вас функциональностью. При этом о работе микроконтроллера, который является основой модуля Arduino, начинающий кон- структор получает очень поверхностное представление. Это не позволяет эффективно использовать его в своих разработках, применять в полной степени все его возможности. Книга призвана дать читателю глубокие знания о микро- контроллерах, начиная с основ цифровой и микропроцессор- ной техники. Подробно рассмаривается архитектура и устройство микроконтроллеров семейства AVR, ведь микроконтроллеры именно этого семейства используются в Arduino. И лишь потом, начинается подробное описание самого проекта Arduino. Вы узнаете историю создания, особенности построения, причины популярности проекта. Получите общее описание разных версий модуля, приемы работы с ним, идео- логию построения и использования модуля в конкретных раз- работках. Вы получите подробные инструкции по установке и настройке инструментальных программ, которые использу- ются для разработки программ для Arduino.
12 ARDUINO: от азов программирования до создания... В основной части книги вниманию читателя предложен учебный практический курс по программированию и схемо- технике Arduino, представляющий собой набор конкретных уроков. В каждом уроке на конкретном примере показывается процесс решения какой-либо конкретной задачи по разработке некоего устройства на основе модуля Arduino. Примеры рас- положены и рассмотрены в очередности «от простого к слож- ному». Они позволяют читателю изучить все этапы разработки: постановка задачи, разработка алгоритма, создание схемы, а затем и самой программы. С уважением, Александр Белов
ЧАСТЬ I ВОТ ОНА КАКАЯ - ТЕХНИКА ЦИФРОВАЯ Приглашаем в увлекательный мир циф- ровой техники. Перед тем, как мы будем разбирать особенности построения модуля Arduino, полезно будет узнать основы современной микропроцессор- ной техники. Досконально разобравшись в основах, вы сможете полнее понять, как работает микроконтроллер и сам модуль Arduino, который на нем собран. Процесс освоения начинаем с освоения азов: изучим базовые элементы цифро- вой логики, теорию цифрового сигнала, основы Булевой алгебры, системы исчис- ления и другие важные вопросы.
ГЛАВА 1 БЕЗ МИКРОПРОЦЕССОРОВ МИР БЫЛ БЫ СКУЧНЫМ |Как микропроцессор завоевал весь мир В последнее время на помощь человеку пришла целая армия электронных помощников. Мы привыкли к ним и часто даже не подозреваем, что во многих таких устройствах рабо- тает микропроцессор. Микропроцессорные технологии очень эффективны. Одно и то же устройство, которое раньше собиралось на тра- диционных элементах, будучи собрано с применением микро- процессора становится проще, не требует регулировки и меньше по размерам. Кроме того, с применением микропроцессоров появляются практически безграничные возможности по добав- лению новых потребительских функций и возможностей. ЧТО ЕСТЬ ЧТО. В современной электронике микропроцессором называют специальную микросхему, которая предназначена для выполнения некоего набора сложных функций по управлению тем либо иным электронным устройством.
Глава 1. Без микропроцессоров мир был бы скучным 15 Микропроцессор — это сердце любого компьютера. Но не только. Те же технологии, которые применяются в компьюте- рах, с успехом применяются и в более простых электронных устройствах. Где же применяются микропроцессоры? Да просто везде! Посмотрите вокруг себя. У вас в квартире стоит (висит) совре- менный телевизор? Не сомневайтесь: в нем есть, как мини- мум, один процессор. У вас есть на руке электронные часы или «умные часы»? Современные часы строятся на основе специ- ализированного микропроцессора. Ну, а мобильные телефоны, смартфоны и «умные часы» — это вообще миниатюрные ком- пьютеры! Возможно, у вас есть игровая приставка, карманная элек- тронная игра, современная микроволновая печь, стиральная машина, проигрыватель лазерных дисков, МРЗ-плеер, каль- кулятор. Во всех этих устройствах работает микропроцессор. Современный автомобиль нашпигован микропроцессорами, как фаршированная рыба. Не говоря уже о самолетах, кораблях, поездах и т. п. В общем, всего не перечесть. Микропроцессор насчитывает достаточно долгую историю. До того, как изобрели микропроцессор (то есть процессор на одной микросхеме), существовали целые процессорные блоки в больших компьютерах. Микропроцессор вырос II до микроконтроллера II Сегодня интеграция дошла до фантастических пределов. Одна микросхема содержит не только сам процессор, но и сопутствующие ему элементы. Такая микросхема называ- ется микроконтроллером. Целый компьютер в одной микро- схеме.
16 ARDUINO: от азов программирования до создания... ЧТО ЕСТЬ ЧТО. Микроконтроллер - это небольшая микросхема, на кристалле которой собран настоящий микро- компьютер, сочетающий функции процессора, пе- риферийных устройств, содержащий ОЗУ, ПЗУ и способный выполнять поставленные ему задачи. \J Что же это за сопутствующие элементы? Это очень важ- ные составные части микропроцессорной системы. Без них не может обходиться ни один микропроцессор. Итак, мы под- ходим к первому важному вопросу — составу типовой микро- процессорной системы. Любая микропроцессорная система (рис. 1.1) состоит из следующих основных элементов: процес- сор, модуль памяти, порты ввода-вывода. Рассмотрим далее каждую из этих составляющих подробнее. Рис. 1.1. Основные составляющие компьютерной системы I Процессор - сердце микропроцессорной системы Процессор — это самая главная часть, сердце всей системы. Он предназначен для того, что бы выполнять различные опе- рации с числами. Последовательность этих операций называ- ется программой. Каждая операция кодируется в виде числа и записывается в память. Те числа, с которыми процессор выполняет свои операции, называются данными. Данные также записаны в память. По сути дела, процессор — это цифровой автомат, способный выполнять определенный набор операций с числами. Но глав- ной его особенностью является возможность запрограммиро-
Глава 1. Без микропроцессоров мир был бы скучным 17 вать любую последовательность его действий. Как происходит программирование, мы увидим далее. Шины данных. Все три части вычислительной системы связаны между собой так называемыми шинами данных. По этим шинам передаются цифровые сигналы от процессора к модулю памяти, от процессора — к портам ввода-вывода. А также и в обратном направлении: от портов ввода вывода и памяти к процессору. Какие же операции может выполнять процессор? Во-первых, все простейшие операции, которые можно про- извести над числом. Он может читать число из любой ячейки памяти, складывать, вычих^т^ сравнивать, иногда умножать и делить прочитанные числа.. Результат^ обратно в п процессор записывает Кроме арифметических действий, процессор может выпол- нять логические операции с числами (Булевы функции). Что такое логические операции, будет подробно описано ниже (см. главу 4). Что ПОМНИТ II память I Память — это специализированное электронное устрой- ство, которое представляет собой набор ячеек, в каждой из которых может храниться одно число. Причем это не совсем то число, с которым мы с вами привыкли иметь дело. Это упро- щенное компьютерное число. Обычно каждая ячейка памяти может хранить число, принимающее значения от нуля до 255.
18 ARDUINO: от азов программирования до создания... Порты ввода и порты вывода Порты ввода-вывода — это специальные микросхемы, при помощи которых микропроцессорная система может общаться с внешним миром. Причем можно говорить отдельно о портах ввода и портах вывода: ♦ через порты ввода компьютерная система получает ин- формацию извне; ♦ через порты вывода она выдает результаты своей работы и управляет внешними устройствами. ЧТО ЕСТЬ ЧТО. Порт ввода - это специальное электронное устройство, на которое извне поступают какие- либо электрические сигналы, предназначенные для управления микропроцессорным устройством. Например, сигналы, возникающие при нажатии клавиш на клавиатуре, сигналы, возникающие при срабатывании различных датчиков и т. п, ЧТО ЕСТЬ ЧТО. Порт вывода выполняет обратную функцию. В них процессор записывает различные числа, ко- торые затем поступают на внешние устрой- ства в виде электрических сигналов. Те читатели, которые знакомы с компьютерами, возможно, слы- шали термины «параллельный порт» (LPT) и «последовательный порт» (СОМ). Так вот, в данном случае речь идет совсем о другом понятии. Это просто схожие термины. Параллельный, и тем более, последовательный порты компьютера — это достаточно сложные схемы, которые, в свою очередь, управляются при помощи пор- тов ввода-вывода. Не нужно также думать, что клавиатура и мышь используют только порты ввода, а дисплей — порт вывода.
Глава 1. Без микропроцессоров мир был бы скучным 19 ПРИМЕЧАНИЕ. Только благодаря этим самым портам ввода-выво- да к компьютеру подключаются такие устройства, как клавиатура, мышь, дисководы, CD-ROM и т. д. Для управления большинством устройств компьютера используются как порты ввода, так и порты вывода микропро- цессорной системы. Возможно, вас удивляет, что я называю внешними устройствами и жесткий диск, и флоппи дисковод. Но когда мы начнем изучать типовую схему микропроцессор- ного устройства, вы убедитесь, что это именно так! ПРИМЕЧАНИЕ. Внутри компьютера скрыто еще много устройств, которые по отношению к микропроцессору являют- ся внешними, хотя находятся зачастую не только внутри компьютера, но и непосредственно на мате- ринской плате - главной плате компьютера. Набор операций, которые процессор способен выполнять с участием портов ввода-вывода, гораздо меньше, чем опера- ций с ячейками памяти. В них также можно записывать и счи- тывать информацию. Однако хранение чисел — это не главное назначение портов. Алгоритм II упраления процессора II Процессор считывает информацию в виде чисел и обраба- тывает полученные числа в соответствии с алгоритмом управ- ления.
20 ARDUINO: от азов программирования до создания... Эти сигналы используются для управления. Управлять можно любым устройством, которое допускает электрическое управление: ♦ индикаторы; ♦ дисплеи; ♦ электромагнитные реле; ♦ электромоторы; ♦ электропневмоклапаны; ♦ электрические нагреватели и т. д. Нужно только усилить управляющие сигналы до требуе- мой мощности. Кроме перечисленных выше команд в любой микропроцессор заложен набор специальных команд, спец- ифических для задач управления процессом вычислений. В дальнейшем мы остановимся подробнее на всех типах команд микропроцессора (см. главу И). Все на свете можно описать цифрами Итак, мы разобрались, что такое процессор. И вот такой простой цифровой автомат способен вытворять все те чудеса, которые мы привыкли наблюдать в исполнении современных компьютеров. Как же это возможно? Оказывается, все на свете можно описать цифрами: ♦ текст; ♦ изображение; ♦ звуки; ♦ музыку; * целые видеофильмы. Хорошо поработали ученые-математики. Они сумели разработать математические модели всех этих процессов. Остальное оказалось делом техники. Главное, чтобы процессор мог выполнять операции как можно быстрее! А современные процессоры это могут! Но обработка всех перечисленных выше процессов — это удел мощных микропроцессоров, применяемых в персональ-
Глава 1. Без микропроцессоров мир был бы скучным 21 ных компьютерах. Однако настоящая книга не ставит перед собой задачи изучения этих микропроцессоров. ПРИМЕЧАНИЕ. Предмет нашего изучения - небольшие специа- лизированные микропроцессорные схемы, предна- значенные для управления конкретными устрой- ствами автоматики, электронной и бытовой техники. Подобные устройства управления име- ют одно общее название - микропроцессорные контроллеры. Что же такое микропроцессор Теперь рассмотрим подробнее, что же такое микропроцес- сор. Как уже упоминалось, микропроцессор — это числовой автомат, который выполняет заложенные в нем операции в соответствии с заранее составленной программой. ЧТО ЕСТЬ ЧТО. Программа - это некоторая последователь- ность команд, разработанная программистом и записанная в памяти в виде чисел. Для выполнения программы в схеме микропроцессора заложен простой алгоритм. Этот алгоритм закладывается в микросхему микропроцессора при его производстве. Он состоит в том, что сразу после включения питания процессор начинает читать числа из той области памяти, которая отве- дена для хранения программ.
22 ARDUINO: от азов программирования до создания... Чтение происходит последовательно, ячейка за ячейкой, начи- ная с самой первой. Каждое число (иногда несколько чисел) — это код команды (иногда говорят «код операции»). Прочитав код команды, микропроцессор выполняет соответствующее ему дей- ствие. То есть одну из команд, о которых мы говорили выше. ВЫВОД. Вся работа микропроцессора сводится к последо- вательному чтению и выполнению команд. Этот процесс начинается при включении питания и продолжается непрерывно, вплоть до выключения. Производители микропроцессоров заботятся о том, чтобы заложить в микропроцессор достаточный набор команд для решения любых возможных задач. Используя эти команды, разработчик конкретной микропроцессорной системы может создать свою собственную программу, заставляющую микро- процессор выполнять именно те действия, какие ему нужны. Разработанная программа записывается в соответствующую область памяти и хранится там постоянно. ПРИМЕЧАНИЕ. Различают несколько разных видов памяти. Но с точ- ки зрения микропроцессора все виды памяти иден- тичны: это набор ячеек для хранения информации. Постоянные запоминающие устройства В реальном микропроцессорном устройстве применяют микросхемы памяти, изготовленные по разной технологии и
Глава 1. Без микропроцессоров мир был бы скучным 23 имеющие различные свойства и назначение. В частности, для хранения программ чаще всего используется специальный вид микросхем памяти — так называемые постоянные запомина- ющие устройства (ПЗУ). По-английски это звучит как ROM (read only memory). Они называются постоянными потому, что допускают лишь однократную запись информации. ПРИМЕЧАНИЕ. После записи информации в ПЗУ она хранится там постоянно и не может быть изменена, что исклю- чает случайную порчу или утерю программы. \____________________________________________ Запись ПЗУ — это специальный процесс, выполняемый при помощи так называемых программаторов. Существует несколько видов микросхем ПЗУ. В разных видах ПЗУ для записи информации используются разные физические прин- ципы. В любом случае, программатор изменяет структуру раз- личных областей кристалла ПЗУ таким образом, чтобы в каж- дой ячейке прописалось нужное число. После прошивки ПЗУ информация хранится в микросхеме даже после выключения питания. Микропроцессор может только читать информацию из такой памяти. Записать туда он ничего не сможет. Если же программист ошибется при состав- лении программы, составит ее таким образом, что процессор попытается записать в ПЗУ какую-либо информацию, ничего страшного не произойдет. В ПЗУ просто останется то, что там было до попытки записи. Оперативная память или оперативное II запоминающее устройство II Кроме постоянного запоминающего устройства, в любой микропроцессорной системе обязательно должна быть так
24 ARDUINO: от азов программирования до создания... называемая оперативная память, или по другому: опера- тивное запоминающее устройство (ОЗУ). По-английски такая память называется RAM. ПРИМЕЧАНИЕ. В эту память процессор может как записывать информацию, так и читать из нее. Ни одна про- грамма не обходится без некоторого количества ячеек памяти для хранения множества промежу- точных результатов и вспомогательных вели- чин. Для этих целей и служит ОЗУ. Отличительной особенностью ОЗУ является то, что при выключении питания записанная в него информация теряется. Пока современная технология не умеет создавать микросхемы, позволяющие микропроцессору с достаточно большой скоро- стью записывать информацию и читать ее, но, при этом, не теряющие эту информацию при выключении питания. ПЗУ с электрическим стиранием информации или флэш-память Отдельным видом памяти следует считать ЭСПЗУ, т.е. ПЗУ с электрическим стиранием информации. По зарубежной тер- минологии такие микросхемы называют флэш-памятью. Эти микросхемы позволяют процессору как записывать, так и счи- тывать информацию. Кроме того, записанная в микросхемы информация сохраняется при выключении питания. ПРИМЕЧАНИЕ. Однако микросхемы флэш-памяти обладают очень низким быстродействием и не пригодны для хра- нения оперативной информации. Кроме того, ал-
Глава 1. Без микропроцессоров мир был бы скучным 25 горитм записи информации в такие микросхемы более сложный, чем для предыдущих двух типов. Поэтому флэш-память применяется ограниченно. В основном для хранения некоторых редко изменяемых констант, значение которых должно сохраняться даже при выключении питания. Например, в системе управления авто- мобильной магнитолой во флэш-памяти сохраняются значе- ние, фиксированные настройки, текущий выбранный диапа- зон, текущие уровни громкости, тембра, баланса и т. п. В чем же различия между II микропроцессорами и микроконтроллерами II Обобщая сказанное в этой главе, мы можем сформулиро- вать следующее: микроконтроллер — это целая микропроцес- сорная система на одном кристалле! Одна микросхема содер- жит в себе все описанные выше составляющие: ♦ память; ♦ порты ввода-вывода; ♦ собственно процессор. Кроме того, там часто располагаются некоторые дополни- тельные устройства: ♦ таймеры; ♦ устройства прерывания; ♦ компараторы и др. Значения этих, пока что, возможно, непонятных терминов вы узнаете из последующего повествования. ВЫВОД Термины «микропроцессор» и «микроконтроллер» достаточно условны и иногда подменяют друг дру- га. Иногда для краткости микроконтроллер назы- вают процессором. И в этом нет большой ошибки.
ГЛАВА 2 УЧИМСЯ СЧ ИТАТЬ ПО-ДРУГОМУ Знакомая с детства десятичная система исчисления Если вы всерьез собрались научиться разрабатывать микро- процессорные устройства, вам просто необходимо знать, как же компьютер хранит и обрабатывает числа. ПРИМЕЧАНИЕ. К сожалению (а может, и к счастью), люди не при- думали способа записывать в виде электронных сигналов числа в том виде, как мы их привыкли видеть. Поэтому математикам сначала пришлось потрудиться, чтобы придумать более подходящий способ представления чисел. И они поработали на славу! Придуман не один, а огром- ное множество способов представления чисел.
Глава 2. Учимся считать по-другому 27 Итак, что же это за способы? Любой грамотный человек хорошо знает, по крайней мере, два таких способа: ♦ хорошо нам известные арабские цифры (они, правда, ре- ально по происхождению индийские); ♦ гораздо менее распространенные, но тоже всем известные, римские цифры. ПРИМЕР. Одно и то же число можно записать как 2 или как II, как 5 или как V, как 22 или как XXII. Очевидно, что перед нами два альтернативных способа написания чисел. Числа одинаковые, а способы написания разные. Ну а если есть два способа, почему бы не выдумать и третий, четвертый и т. д.? И математики давно нашли такие способы. И не три-четыре. Они нашли универсальный прием, позволяющий теоретически создавать бесконечное количество способов представления чисел. Эти способы назвали систе- мами исчисления. За основу взяли арабские числа. Очевидно, что этот способ представления числа гораздо более красивый, чем римский вариант, так как подчиняется строгому закону. Судите сами. В привычной для нас системе исчисления мы имеем 10 цифр: 1, 2,3,4,5,6, 7,8,9 и 0. При помощи этих цифр мы легко можем представить любое число. Если нам нужно записать число, величина которого мень- шие десяти, мы используем всего одну из вышеуказанных цифр. Для представления чисел от десяти и выше мы вводим новый разряд, который для начала мы приравниваем единице. Подставляя в младший разряд по порядку те же десять базовых цифр, мы получаем следующий десяток. Как только все цифры в младшем разряде перебраны, мы увеличиваем наш старший разряд на единицу. И так, пока не переберем все цифры вплоть до 99.
28 ARDUINO: от азов программирования до создания... Когда во втором разряде будут перебраны все возможные варианты, мы вводим третий разряд. Затем четвертый, пятый и так до бесконечности. Как видите, здесь просматривается набор четких правил, описывающих то, как при помощи десяти знаков (цифр) представить любое мыслимое число! ЧТО ЕСТЬ ЧТО. Так как количество цифр равно десяти, описанная выше система исчисления называется десятичной. \. Сформулируем набор правил, по которым строится любое число в десятичной системе исчисления. Правило 1. Для представления чисел используются десять цифр, каждая из которых обозначается своим знаком. Любое число записывается при помощи одной или нескольких рядом стоящих цифр, причем имеет значение как набор используе- мых цифр, так и их взаимное расположение. Правило 2. Для записи чисел в пределах первого десятка используется только одна цифра. Эта цифра является младшим разрядом числа. Правило 3. Для чисел следующего десятка вводится допол- нительный разряд. Это еще одна цифра (следующий раз- ряд числа), которая ставится впереди предыдущего разряда. Цифра, стоящая в этом разряде, означает количество десятков. Двухразрядные числа используются в пределах первой сотни. Правило 4. При переполнении очередного разряда вво- дится следующий разряд, и так до бесконечности. В завершении зададим себе вопрос: а почему именно десять цифр? Видимо потому, что первобытные люди, кото- рые изобретали эту систему, пользовались для счета паль- цами рук. А их всего десять.
Глава 2. Учимся считать по-другому 29 Восьмиричная система исчисления А если бы природа распорядилась так, что у человека было бы не по пять, а по четыре пальца на каждой руке? Тогда бы цифр было восемь. И мы сейчас, наверное, использовали бы восьмеричную систему исчисления! Такая система действи- тельно существует. И как же она выглядит? Она имеет только восемь цифр. Для удобства используются первые восемь знаков десятич- ной системы: 0,1,2, 3,4,5,6 и 7. Попробуем представить, как нужно записывать числа в восьмеричной системе, при усло- вии, что правила составления числа из отдельных цифр будут такими же, как в известной нам десятичной системе. Числа от нуля до семи мы, как и в десятичной системе, будем записывать при помощи одной цифры. В данном слу- чае числа, записанные в десятичной и восьмеричной системах, ничем не будут отличаться. Далее в десятичной системе идет число восемь. ПРИМЕЧАНИЕ. № (------------------------------------ I Цифры 8 в восьмеричной системе нет! Поэтому мы поступим в строгом соответствии с описан- ными выше правилами. Мы добавим новый разряд, который будет равен у нас единице. Младший же разряд будет равен нулю. При этом число 8 в восьмеричной системе исчисления будет выглядеть как 10. Для того чтобы не путаться, при записи чисел в разных системах исчисления в математике принято помечать каждое число специальной меткой, показывающей, в какой системе исчисления оно записано.
30 ARDUINO: от азов программирования до создания... ПРИМЕР. Число восемь в десятичной системе записывает- ся так - 810. А то же число в восьмеричной си- стеме записывается следующим образом -10? Рассмотрим несколько примеров записи числа в двух разных системах исчисления: 910 = 11? Ю10 = 12? 1110 = 15? И так далее. После числа 178 в восьмеричной системе следующее число 208. Эти два числа в десятичной системе равны: 178 = 1510, 208 = 16w. Аналогичным образом, в полном соответствии с опи- санными выше правилами, записываются и остальные числа в восьмеричной системе. После переполнения второго разряда появляется третий (после 778 идет 1008). После третьего — чет- вертый, и так далее. ПРИМЕР. Так записываются числа в двух разных системах исчисления: 5210 = 408 15110 = 2058 4210 = 528 125410 = 25468 54810 = ’5548 и т. д. 1U О, 1U О \_______________________________________________ ЧТО ЕСТЬ ЧТО. Количество цифр, используемых в системе исчис- ления, называют ее основанием. Десятичная си- стема исчисления имеет основание 10, а восьме- ричная - основание 8. Ну а теперь, когда мы знаем, как выглядит восьмеричная система, легко можно представить системы и с другим основа- нием. По большому счету можно выбрать любое число в качестве основания, лишь бы знаков (цифр) хватило для записи чисел.
Глава 2. Учимся считать по-другому 31 Реально же на практике нашли применение, кроме деся- тичной и восьмеричной, еще две системы исчисления: ♦ шестнадцатеричная; ♦ двоичная. ПРИМЕЧАНИЕ. Следует отметить, что двоичная система ис- числения является той самой системой пред- ставления чисел, которую инженеры без труда смогли смоделировать при помощи электронных схем. Восьмеричная и шестнадцатеричная системы исчисления очень удобны для записи компьютерных данных на бумаге и на экране компьютера. На заре развития компьютерной тех- ники широко использовали восьмеричную систему. Сейчас она почти забыта. Теперь вместо нее более употребима шестнадца- теричная. Рассмотрим подробнее две еще не описанные нами системы. Шестнадцатеричная система II исчисления II В шестнадцатеричной системе исчисления, как вы дога- дались, используются шестнадцать цифр. Обычно для обозна- чения первых десяти цифр применяют те же символы, что и для десятичной системы. А недостающие шесть цифр заме- няют буквами латинского алфавита. Вот полный набор цифр шестнадцатеричной системы: 0,1,2,3,4,5,6,7,8,9, А, В, С, D, Е и F. Одним разрядом в шестнадцатеричной системе исчисления можно записать числа от нуля до пятнадцати. Число шестнад-
32 ARDUINO: от азов программирования до создания... цать (1610) записывается, как 1016. Вот еще несколько примеров шестнадцатеричных чисел: 1710=П16 251О -1916 2610 = 1А16 2061Q= 0CEJ6 698ю = 2BAu 1235ю= 4D3i6 ВНИМАНИЕ. Применение букв может внести путаницу Если число состоит только из букв, его можно при- нять за какое-то слово. Например, за название переменной в тексте программы. Поэтому перед шестнадцатеричным числом, начинающимся с буквы, принято ставить незначащий ноль. II Двоичная II система исчисления Среди всех систем исчисления особое место занимает дво- ичная система. Она использует для записи любого числа всего две цифры. Это цифры 0 и 1. Естественно, что при помощи одного разряда в двоичной системе можно записать только два числа: 0 и 1. Число два в двоичной системе будет выглядеть как 102. Используя уже знакомые правила, запишем другие числа: Зю = Иг 41о = Ю02 5Ш = Ю12 6ю = 11^2 7ю=1112 8W= 10002ит.д.
Глава 2. Учимся считать по-другому 33 СОВЕТ. Если у вас есть компьютер, на котором уста- новлен Windows, вы сами легко можете поэк- спериментировать с переводом чисел из од- ной системы исчисления в другую. Для это- го запустите стандартный калькулятор, входящий в Windows. Обычно он запускается через меню Пуск / Стандартные / Калькулятор. Поэкспериментируйте с калькулятором для бо- лее полного усвоения материала. ч___________________________________________ Войдите в меню «Вид» калькулятора и выберите «Программист» (в Windows ХР «Инженерный»). После этого вид калькулятора изменится. Вы увидите множество новых клавиш и органов управления. И среди них дополнительные буквен- ные клавиши для набора латинских букв. Кроме того, в левой верхней части калькулятора появится переключатель систем исчисления. Он имеет четыре положения: ♦ Hex (шестнадцатеричная); ♦ Dec (десятичная); ♦ Oct (восьмеричная); ♦ Bin (двоичная). Вы можете выбрать любую из систем исчисления, набрать на калькуляторе число, а затем переключить калькулятор на другую систему. Калькулятор автоматически переведет набранное вами число в новую систему исчисления. Способы обозначения чисел II в разных системах исчисления II Теперь немного о способах обозначения чисел в разных системах исчисления. До сих пор, во всех предыдущих приме- рах, для обозначения типа используемой системы исчисления мы применяли способ, принятый в математике. Но такой спо-
34 ARDUINO: от азов программирования до создания... соб далеко не всегда можно применить. Приписывать малень- кие циферки внизу под записью числа удобно только от руки на бумаге. Ну, еще в Microsoft Word и аналогичных ему тексто- вых процессорах. ПРИМЕЧАНИЕ. При написании же текстов программ или, напри- мер, электронных писем используются редакто- ры, не отягощенные такими возможностями. Они не позволяют писать подстрочные надписи. Поэтому существуют другие способы записи та- ких чисел. Способ 1. Самый распространенный способ — добавле- ние в конце числа латинской буквы, обозначающей систему исчисления. Так, для обозначения шестнадцатеричных чисел используется латинская буква Н. Для восьмеричных — латин- ская буква О, для двоичной системы — латинская буква В. Десятичные числа при таком способе обозначений записы- ваются либо вообще без буквы, либо обозначаются латинской буквой D. ПРИМЕРЫ. Запись чисел с использованием букв: 23D то же, что и 2310 03FH то же, что и 03F16 01101В то же, что и 011012 3750 то же, что и 3758 Способ 2. Другой широко распространенный способ использует, в частности, фирма Atmel при программировании для микроконтроллеров AVR. В этом способе систему исчисле-
Глава 2. Учимся считать по-другому 35 ния определяет дополнительный ноль и буква впереди числа. Так для записи шестнадцатеричных чисел используется соче- тание «Ох», для двоичных «ОЬ», а десятичные числа не имеют специальных обозначений. Восьмиричная система исчисления в данном случае не поддерживается. ПРИМЕР. Вот варианты записи десятичного, шестнадца- тиричного и двоичного чисел. 12342 0X12C4D0 ОЬООИОЮИ Способ 3. Еще один способ, который также используется при написании программ для микроконтроллеров AVR, — использование символа «$» для обозначения шестнадцатерич- ных чисел. В системах программирования фирмы Atmel эти два способа можно использовать одновременно. ПРИМЕР. Число 0х12С4Р0 можно записать как $12С4Р0. Арифметическая || операция сложения II В любой из вышеперечисленных систем исчисления можно выполнять любые арифметические операции, к которым мы привыкли в десятичной системе. То есть сложение, вычитание, умножение, деление.
36 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. Правда, на практике никто не занимается вось- меричной и шестнадцатеричной арифметикой. Это не имеет никакого смысла. А вот арифмети- ка в двоичной системе была подробно прорабо- тана. Надо же было обучить этому электронные устройства. На самом деле правила, по которым производятся все опе- рации в любой из систем исчисления, взяты из десятичной системы. Но при вычислениях в двоичной системе это выгля- дит немного по-другому. Возьмем, например, сложение. Как и в десятичной, так и в двоичной системе два любых числа можно сложить столбиком. Только нужно помнить, что в этой системе каждый разряд может принимать лишь два значения: либо 0, либо 1. Возьмем для примера два двоичных числа. Например, 10011001110 + 11000101110. Записываем пример сложения, 10011001110 + 11000101110 101011111100 Теперь выполним сложение. Как и в десятичной системе, будем складывать числа поразрядно, начиная с младшего раз- ряда. При сложении значений каждого разряда будем учиты- вать следующие три правила. Правило 1. Ноль плюс ноль — получится, естественно, ноль. Правило 2. Один плюс ноль и ноль плюс один дадут в резуль- тате единицу. Правило 3. При сложении двух единиц мы получим ноль в текущем разряде и единицу переноса в следующий разряд. Сложив все разряды, результат запишем под чертой. Складывая значение очередного разряда, не забывайте учиты- вать перенос из предыдущего. При сложении двух единиц плюс перенос из предыдущего разряда получим единицу и перенос в следующий.
Глава 2. Учимся считать по-другому Арифметическая операция умножения Умножение в двоичной системе также делается столбиком. Но в двоичной системе есть одна особенность, которая сильно облегчает задачу. Очевидно, что любое число, умноженное на ноль, дает в результате ноль. А число, умноженное на единицу, дает в результате само себя. Вот пример умножения столбиком двух двоичных чисел: 10011001110 10011001110 + 10011001110 10011001110 11010011011010 ПРИМЕЧАНИЕ. Легко убедиться из примера, что умножение в двоичной системе исчисления сводится к сложе- нию одного и того же числа (множимого), сдвину- того относительно самого себя. Как видите, при работе с двоичными числами даже умно- жать не приходится. Достаточно уметь сдвигать разряды числа и складывать числа между собой. Это важно при построении вычислительных устройств. Простейшие микропроцессоры в составе своих команд не имеют команды умножения. Однако любой микропроцессор имеет команды сдвига и сложения. ВНИМАНИЕ. Одну команду умножения всегда можно заменить небольшим набором команд сложения и сдвига. Точно так же команду деления легко заменить сдвигом и вычитанием.
ГЛАВА 3 ЭЛЕКТРОННЫЕ ЦИФРЫ ДЛЯ КОМПЬЮТЕРА Представление чисел на ПК Изобретение двоичной системы исчисления дало возмож- ность научить компьютер работать с числами. Теперь настало время узнать, каким образом это делается. Посмотрим, как числа представляются в компьютере. Во всех современных вычислительных системах это делается следующим обра- зом. Представим себе некий узел вычислительной системы. Допустим, он должен передавать на последующие узлы числа в электронном виде. Для этой цели такой узел имеет группу выходов (обычно их количество равно или кратно восьми). Обозначим эти выходы, как это принято в вычислительных системах, DO, DI, D2, D3, D4, D5, D6 и D7 (см. рис. 3.1). Эти выходы подключаются к соответствующим вхо- дам последующего узла, как показано на рис. 3.2. Для пере- дачи числа используется вся группа выходов одновременно. Передаваемое число представляется в двоичной системе исчисления. Каждый из выходов передает один разряд двоич- ного числа и может находиться в одном из двух состояний:
Глава 3. Электронные цифры для компьютера 39 Узел 1 Узел 2 Рис. 3.1. Узел Рис. 3.2. Соединение с цифровыми выходами двух цифровых узлов ♦ состояние логического нуля — когда напряжение на выходе отсутствует; ♦ состояние логической единицы — когда на выходе присут- ствует напряжение (в этом случае оно обычно равно или близко к напряжению питания). ЧТО ЕСТЬ ЧТО. Причем схема каждого из выходов устроена та- ким образом, что исключает появление на любом из выходов промежуточных значений напряже- ния. Такая группа выходов называется цифровой шиной данных. Каждый разряд шины имеет свой «вес». Именем ЕЮ обозна- чают разряд, который имеет самый маленький «вес» — вес, равный единице. Это значит, что когда в этом разряде установ- лена логическая единица, а во всех остальных разрядах—логи- ческий ноль, то все число равно единице. Разряд D1 имеет «вес», равный двум (102). Это означает, что, если значение разряда D1 равно единице, а во всех осталь- ных разрядах ноль, то все число, передаваемое шиной, будет равно двум.
40 ARDUINO: от азов программирования до создания... Вес разряда D2 равен четырем (1002). Вес разряда D3 — восьми (10002). И так далее. Вес последнего разряда шины (D7) равен 128 (100000002). Значение числа, которое передается по шине, всегда можно найти путем сложения весов тех разрядов шины, значение которых в данный момент равно единице. ПРИМЕР. Что бы передать по шине число 25 (110012), нуж- но выставить на шине следующие значения: на трех выходах DO, D5 и D4 должен быть единич- ный сигнал, на всех остальных выходах должен быть ноль. Проверим теперь, что получится, если мы сложим веса всех выходов, находящихся в единичном состоянии. Вес разряда D0 равен 1. Вес разряда D3 равен 8. Вес D4 равен 16. Итого: 1+8+16=25. Что и требовалось доказать. Очевидно, что для передачи числа, максимального для дан- ной шины, нужно установить все разряды шины в единичное состояние. В этом случае число, передаваемое по нашей шине данных, будет равно: 1+2+4+8+16+32+64+128 = 255. ПРИМЕЧАНИЕ. По восьмиразрядной шине можно передавать чис- ла от 0 до 255 (то есть 256 разных значений). Это важно знать, так как восьмиразрядная шина является своего рода стандартом в вычисли- тельной технике. \______________________________________________. Более подробно к описанию шин мы вернемся, когда перей- дем к описанию микропроцессорной системы.
Глава 3. Электронные цифры для компьютера 41 Двухуровневый сигнал А сейчас остановимся подробнее на двухуровневом сиг- нале, имитирующем двоичный разряд числа. ПРИМЕЧАНИЕ. Каждый из этих уровней имеет свое название. Различают сигнал логического нуля (высокий логический уровень) и сигнал логической едини- цы (низкий логический уровень). Эти термины в дальнейшем будут часто встречаться в книге. Для получения сигналов логической единицы и логиче- ского нуля используются так называемые триггерные схемы, или схемы с двумя устойчивыми состояниями. Напряжения на выходе любого реального устройства неидеальны и имеют раз- брос в значениях. ПРИМЕЧАНИЕ. Сигналы для микросхем, выполненных по так на- зываемой ТТЛ-технологии (транзисторно-тран- зисторная логика), допускают следующие откло- нения (при напряжении питания 5 В): \_____________.______________________________. ♦ для логического нуля на выходе допускается присутствие напряжения до 0,4 В; ♦ для логической единицы напряжение на выходе должно быть не менее 2,4 В. По ТТЛ технологии выполнены микросхемы таких серий, как 155,555,533,1533 и др. В микросхемах других серий уровни сигнала имеют другие значения.
42 ARDUINO: от азов программирования до создания... ПРАВИЛО. Существует правило, верное для любых типов цифровых микросхем: ♦ если напряжение на выходе цифровой микросхе- мы соответствует логическому нулю (входит в соответствующий диапазон), то другая микро- схема, на которую приходит данный цифровой сигнал, надежно распознает его как ноль; ♦ если сигнал на выходе соответствует логиче- ской единице (входит в эти допустимые преде- лы), то принимающее устройство всегда рас- познает его как единицу. Это происходит благодаря наличию у цифровых входов порога срабатывания. Если входной сигнал выше этого порога, внутренний триггер устанавливается в состояние логической единицы. Если входное напряжение ниже порога, то триггер переходит в состояние логического нуля. I Явление триггерного эффекта Триггер — это как раз такое устройство, которое может находиться лишь в одном из двух состояний. Промежуточное состояние исключено. Такой подход повышает надежность работы цифровых схем. ПРИМЕЧАНИЕ. Благодаря триггерному эффекту такие явления, как тепловые шумы, дрейф нуля и электромаг- нитные помехи гораздо меньше влияют на каче- ство передачи цифрового сигнала. Вернее, они во- обще не влияют, пока уровень сигнала помехи не превысит порога.
Глава 3. Электронные цифры для компьютера 43 Правда, если помехи все же превысят порог, то наступает полный сбой. В этом случае цифровой сигнал, передаваемый по шине данных, будет полностью искажен, а полезная инфор- мация будет утеряна. Однако в том случае, когда уровень помех невысок, при передаче цифрового сигнала полностью отсутствуют типич- ные недостатки, присущие аналоговым способам передачи информации. Отсутствует постепенное ухудшение качества с увеличением дальности передачи или при большом количестве перезаписей с одного носителя на другой. Электронное представление числа, рассмотренное выше, дает возможность не только передавать эти числа от одного устройства к другому. В следующем разделе мы увидим, каким образом можно производить операции сложения с электрон- ными числами. Используя электронные числа, можно также хранить цифровую информацию, производить описанные выше арифметические операции (сложение, вычитание, умно- жение, деление) и многое другое. Но прежде нам пришла пора познакомиться с особым клас- сом электронных элементов, которые и являются основой для построения схем, выполняющих операции с числами. Они называются «Логические элементы».
ГЛАВА 4 ЛОГИЧЕСКИЕ ЭЛЕМЕНТЫ: ПРОСТЫЕ И СОСТАВНЫЕ I Знакомство с логическими элементами Многим из вас знакомо понятие ЛОГИЧЕСКИЕ ЭЛЕМЕНТЫ. Если вы хоть немного работали с цифровыми схемами, то наверняка знакомы с подобным понятием. В настоящее время логические элементы и другие цифровые компоненты можно встретить в схемах, очень далеких от микропроцессоров и вычислительной техники. Если принципы работы цифровой логики вам хорошо знакомы, можете пропустить данную главу. Для тех, кто этого не знает или желает систематизировать свои знания, начнем с самого начала. ПРИМЕЧАНИЕ. Из всего разнообразия цифровых элементов боль- шинство можно отнести к разряду составных.
Глава 4.Логические элементы: простые и составные 45 Элемент “И” Элемент “ИЛИ” Элемент “НЕ” Рис. 4.1. Простые логические элементы Составными я называю те элементы, которые можно соста- вить из других, более простых. А в основе всего разнообразия цифровых устройств лежат всего три простых логических эле- мента. На рис. 4.1 изображены эти три кита цифровой техники. Следует заметить, что логические элементы на рис. 4.1 изо- бражены в соответствии со стандартом, принятым в свое время в СССР и теперь еще широко используемым во всех странах СНГ. По этим стандартам цифровые элементы изображаются в виде прямоугольника. Все входы рисуются слева, а выходы — справа. ПРИМЕЧАНИЕ. Именно таким образом в этом стандарте мож- но отличить входы элемента от его выходов. Правда, в случае более сложных элементов это правило соблюсти не всегда возможно, так как часто бывает, что один и тот же выход служит одновременно и входом. Но для простых элемен- тов это условие всегда соблюдается. Все логические элементы работают с цифровыми сигна- лами. Это значит, что сигнал на любом из входов элемента дол- жен принимать значения: ♦ либо логического нуля; ♦ либо логической единицы. На выходе каждый элемент также обеспечивает цифро- вой сигнал, который, в зависимости от логики работы схемы, принимает значение либо логической единицы, либо логиче-
46 ARDUINO: от азов программирования до создания... ского нуля. На рис. 4.1 изображены двухвходовые варианты элемента «И» и элемента «ИЛИ». На самом деле эти элементы могут иметь любое количество входов. ПРИМЕЧАНИЕ. Теоретически количество входов может быть увеличено до бесконечности. Тип элемента опре- деляется не количеством входов, а логикой его работы. Какова же эта логика? Рассмотрим каж- дый элемент по отдельности. Простой логический элемент «И» На выходе элемента «И» сигнал логической единицы появ- ляется тогда и только тогда, когда на всех его входах будет при- сутствовать логическая единица. То есть единица должна быть и на первом, и на втором, и на третьем (если он есть), и на всех имеющихся входах. Если хотя бы на одном входе будет ноль, то и на выходе тоже будет ноль. Простой логический элемент «ИЛИ» На выходе элемента «ИЛИ» сигнал логической единицы появится тогда и только тогда, когда хотя бы на одном из его входов появится единица. То есть единица должна быть или на первом, или на втором, или на третьем — на любом из име- ющихся входов или на нескольких сразу. Логический ноль на
Глава 4. Логические элементы: простые и составные 47 выходе будет только тогда, когда на всех входах будет сигнал логического нуля. Простой логический элемент «НЕ», или инвертор У этого элемента не может быть больше одного входа. Инвертор имеет один вход и один выход. И логика его работы очень проста. Когда на входе у инвертора сигнал логического нуля, на выходе логическая единица. И наоборот, когда на входе логическая единица, на выходе логический ноль. Таблица II истинности II Для отображения логики работы того или иного элемента принято составлять так называемые таблицы истинности. ЧТО ЕСТЬ ЧТО. Таблица истинности - это такая таблица, ко- торая имеет столбцы для всех входов и выходов конкретного элемента. В строках таблицы ото- бражаются все возможные состояния элемента. Каждая строка соответствует одному из воз- можных состояний. На рис. 4.2 приведены таблицы истинности для трех основ- ных логических элементов. Для наглядности использованы трехвходовые варианты элемента «И» и элемента «ИЛИ».
48 ARDUINO: от азов программирования до создания... Х1 Х2 хз Х2--- хз — I Составные логические элементы Итак, исходный материал — три основных элемента — у нас есть. Теперь начнем составлять из них остальные. Полученные при этом новые элементы часто имеют свое самостоятельное значение, и поэтому многие элементы, представляемые нами как составные, имеют свое собственное схемное обозначение. Рассмотрим это подробнее. I Составные логические элементы «И-НЕ» и «ИЛИ-НЕ» Для начала соединим элемент «И» с инвертором так, как это показано на рис. 4.3. В результате у нас получится новый Рис. 4.3. Составной элемент «И-НЕ»
Глава 4. Логические элементы: простые и составные 49 Рис. 4.4. Условное обозначение элемента «И-НЕ» элемент. Такой элемент имеет название «И-НЕ», и на схеме его часто изображают так, как показано на рис. 4.4. Логика работы нового для нас логического элемента «И-НЕ» очевидна. Сигнал на выходе будет равен нулю в том и только в том случае, когда на всех его входах присутствует логическая единица. Точно таким же образом легко составить элемент «ИЛИ-НЕ». Составной логический элемент II «ИСКЛЮЧАЮЩЕЕ ИЛИ» II Попробуем теперь синтезировать более сложный логиче- ский элемент под названием «ИСКЛЮЧАЮЩЕЕ ИЛИ». Его тоже часто можно встретить в различных электронных схемах. Схемное обозначение элемента «ИСКЛЮЧАЮЩЕЕ ИЛИ» и его таблица истинности приведены на рис. 4.5. Как видно из таблицы, логика работы элемента соответствует его назва- нию. Это тот же элемент «ИЛИ» с одним небольшим отличием. Если значение на обоих входах равно логической единице, то на выходе элемента «ИСКЛЮЧАЮЩЕЕ ИЛИ», в отличие от эле- мента «ИЛИ», не единица, а ноль. Рис. 4.5. Элемент «Исключающее ИЛИ»
50 ARDUINO: от азов программирования до создания... Эквивалентная схема элемента «ИСКЛЮЧАЮЩЕЕ ИЛИ» изображена на рис. 4.6. Советую самостоятельно разобрать работу этой схемы. Для этого мысленно нужно подставлять на входы XI и Х2 различные варианты логических сигналов и для каждого варианта прослеживать, какими будут сигналы на выходе каждого элемента. И так поэлементно проследить, какой будет сигнал на выходе всей схемы. Х1 Х2 Рис. 4.6. Одно из возможных схемных решений элемента «Исключающее ИЛИ» Если внимательно посмотреть на таблицу истинности эле- мента «ИСКЛЮЧАЮЩЕЕ ИЛИ», то легко заметить, что логика работы элемента очень похожа на таблицу сложения двух одно- разрядных двоичных чисел. И действительно: ♦ ноль плюс ноль равняется ноль; ♦ один плюс ноль и ноль плюс один равняется один; ♦ сумма двух единиц дает ноль в этом разряде и единицу пе- реноса в следующий разряд, не хватает только переноса. II Составной логический элемент II сумматор Элемент, формирующий также и перенос, и выполняющий суммирование входных сигналов, называется сумматором. Его еще можно составить из простых логических элементов. Схемное изображение и логика работы сумматора приводятся на рис. 4.7.
Глава 4. Логические элементы: простые и составные 51 Входы Выходы ХР Х1 Х2 Y р 0 0 0 0 0 0 0 1 1 0 0 1 0 1 0 0 1 1 0 1 1 9 0 1 0 1 0 1 0 1 1 1 0 0 1 1 1 1 1 1 Рис. 4.7. Сумматор Здесь XI и Х2 — это входы складываемых разрядов. Y — выход суммы. Р — выход переноса в старший разряд. ХР — вход переноса с младшего разряда. Один сумматор производит суммирование двух однораз- рядных двоичных чисел. Для суммирования многоразрядных цифровых сигналов сумматоры соединяют каскадом. При этом сигнал с выхода Р сумматора одного разряда подается на вход ХР сумматора следующего разряда. На практике отдельные микросхемы-сумматоры почти никогда уже не применяются. Где-то внутри микропроцес- сора обязательно есть сумматор, который является его частью. Я привел здесь его описанйе лишь как пример сложного эле- мента цифровой техники. При разработке микропроцессорных систем нам чаще при- дется иметь дело с другими элементами, такими как триггеры, регистры, дешифраторы, мультиплексоры и т. д. Прямо сейчас мы этим и займемся.
ГЛАВА 5 ПРОСТЕЙШИЕ ТРИГГЕРЫ |Что такое триггер Триггер — это качественно новый составной элемент циф- ровой техники. Его уже нельзя отнести к логическим элемен- там. Триггер можно назвать элементом нового класса. Выше мы уже говорили о том, что логические входы обладают триг- герным эффектом. В случае с логическими входами мы имели дело с триггерным эффектом, работающим по уровню сигнала. Мы говорили также, что триггер — это устройство, которое может находиться в двух (и только в одном из двух) устойчи- вых состояниях. На самом деле входы логических элементов обладают слабым триггерным эффектом. ПРИМЕЧАНИЕ. Между областью входных напряжений, соответ- ствующих логическому нулю, и областью напря- жений, соответствующих логической единице, всегда существует промежуточный диапазон ло- гической неопределенности. Если напряжение на логическом входе попадает в этот диапазон, то поведение логического элемента непредсказуемо.
Глава 5. Простейшие триггеры 53 Триггер Шмитта: II четкое срабатывание II Некоторые элементы даже могут переходить в линейный режим работы (усиливают аналоговый сигнал). Более четкое сра- батывание обеспечивает так называемый триггер Шмитта. Этот триггер имеет совершенно конкретный порог срабатывания. При переходе входного напряжения через этот порог триггер Шмитта переключается из одного устойчивого состояния в другое. Второй особенностью триггера Шмитта является наличие не одного, а двух порогов срабатывания: ♦ первый порог действует, когда напряжение на входе повы- шается. При достижении порога триггер срабатывает, и на выходе появляется логическая единица; ♦ второй порог действует при понижении напряжения на входе. Когда напряжение на входе снизится ниже этого по- рога, триггер переключается снова, и на выходе устанавли- вается логический ноль. Второй порог всегда немного ниже первого. Наличие двух порогов называется гистерезисом. Гистерезис увеличивает ста- бильность работы триггера при напряжениях, близких к поро- говому. В отсутствии гистерезиса при входных напряжениях, близких к порогу срабатывания, любая помеха на входе вызо- вет многократное переключение триггера, что обычно крайне нежелательно. Триггеры Шмитта часто используются для пре- образования аналоговых колебаний в прямоугольные импульсы, которые затем уже используются в цифровой технике. ПРИМЕЧАНИЕ. Кроме триггеров, срабатывающих по уровню, су- ществует целый класс триггеров, переключение которых происходит при воздействии различных сочетаний логических сигналов. Такие триггеры имеют не менее двух цифровых входов и один или два цифровых выхода.
54 ARDUINO: от азов программирования до создания... Сигналы на таких выходах всегда имеют противоположные значения. Один из выходов называется прямым выходом триггера, а второй — инверсным выходом. Такой триггер имеет два устойчивых состояния: единичное и нулевое. В единичном состоянии на прямом выходе триггера устанавливается сигнал логической единицы, а на инверсном, соответственно, сигнал логического нуля. Если же триггер находится в нулевом состоянии, сигналы на выходах меняют свои значения: ♦ на прямом выходе появляется ноль; ♦ на инверсном выходе — единица. Переход из одного устойчивого состояния в другое проис- ходит под воздействием сигналов на входах триггера. IRS-триггер: схема и условное обозначение Для разных триггеров используется разные сочетания сиг- налов. Далее в этой главе мы подробно рассмотрим все суще- ствующие виды триггеров и логику их работы. А начнем мы с самого элементарного, простейшего триггера, так называемого RS-триггера. На рис. 5.1 показана схема такого триггера, а на рис. 5.2 — его условное обозначение. Как видно из рис. 5.1, схема RS-триггера состоит из двух элементов «И-НЕ». Триггер имеет два входа, которые называ- Рис. 5.1. RS-триггер Рис. 5.2. Условное обозначение
Глава 5. Простейшие триггеры 55 ются S и R. Вход S называют входом установки (от слова Set — установить). Вход R — это вход сброса (Reset). Два выхода триг- гера обозначаются так: Q и Q (Q и Q с чертой). Буква Q с чертой сверху читается как «не кю». Черта над именем любого выхода или входа_означает, что данный вывод (вход) инверсный. Поэтому Q и Q — это, соответственно, прямой и инверсный выходы триггера. RS-триггер: II варианты подачи сигналов II Посмотрим, как работает RS-триггер. Для правильной работы такого триггера на оба его входа необходимо подать сигналы логической единицы. Перевод триггера из одного устойчивого состояния в другое производится путем кратко- временной подачи на один из входов нулевого сигнала. При подаче нуля на вход S (Set) триггер переходит в единичное состояние. При подаче сигнала на вход R (Reset) триггер сбра- сывается в ноль. ВНИМАНИЕ. Одновременная подача двух нулей на оба входа триггера недопустима, так как в этом случае ра- бота триггера непредсказуема. В промежутке между сигналами, когда на обоих входах единица, триггер сохраняет ранее установленное состояние. Если на обоих входах присутствует единица, установлен- ное состояние триггера сохраняется все время, пока на схему подано напряжение питания. Таким образом, триггер можно использовать для хранения информации. При выключении питания информация теряется. Если питание было выключено, то в момент включения питания (до
56 ARDUINO: от азов программирования до создания... прихода первых входных импульсов) триггер устанавливается в случайное положение. Если точнее, то это положение зависит от того, какой из элементов триггера оказался более быстро- действующим. IRS-триггер: переключение триггера Рассмотрим подробнее, как происходит переключение триггера. Обратимся для этого вновь к схеме на рис. 5.1. Допустим, что после включения триггер сбросился в нулевое состояние. То есть на выходе Q триггера — логический ноль. Этот ноль поступает на соответствующий вход нижнего эле- мента триггера (см. рис. 5.1). На втором входе того же элемента, как мы помним, — логи- ческая единица. В соответствии с логикой работы элемента «И-НЕ», на его выходе так же устанавливается единица. Эта единица поступает на выход Q и на соответствующий вход верхнего по схеме элемента. На втором входе верхнего эле- мента, как мы помним, — тоже единица. Две единицы на входе «И-НЕ» и дают ноль на его выходе. Итак, круг замкнулся. Все сигналы подтверждают сами себя. На выходе Q — логический ноль, на выходе Q — логическая единица. Триггер находится в устойчивом состоянии. RS-триггер: переход триггера из одного устойчивого состояния в другое Теперь посмотрим, как происходит переход триггера из одного устойчивого состояния в другое. Для переключе- ния триггера в единичное состояние подадим на вход S сигнал логического нуля. Равновесие сразу нарушится. На входах верх- него элемента уже не две единицы, а единица и ноль. Поэтому
Глава 5. Простейшие триггеры 57 на его выходе сразу устанавливается единица. Она поступает на соответствующий вход нижнего элемента. И теперь уже на нижнем элементе две единицы на обоих входах. Он тут же выдает на выходе ноль. Теперь можно сни- мать нулевой сигнал с входа S. Триггер находится уже в новом состоянии. И это состояние тоже устойчивое. Единичный сиг- нал на входе S не переведет триггер назад в нулевое состояние, так как на нижнем входе верхнего по схеме элемента логиче- ский ноль. Переключение триггера в нулевое состояние происходит точно так же, как и переключение в единичное. Только нуле- вой сигнал для переключения в данном случае подается на вход R. Процессы, происходящие в триггере, при этом полно- стью соответствуют процессам, происходящим в предыдущем случае, только с точностью до наоборот. Если триггер уже стоит в единичном состоянии, то подача нулевого импульса на вход S ничего не изменит. Точно так же подача импульса на вход R не изменит состояния триггера, если перед этим он находился в нулевом состоянии. ВЫВОД RS-триггер можно считать простейшим устрой- ством для хранения одного бита цифровой ин- формации. Один бит — это один двоичный разряд или величина, кото- рая может принимать только два значения (0 и 1). Логично, что для хранения единицы триггер переводится в единичное состояние. Для хранения нуля — в нулевое. Обратите внимание на обозначение входов сброса и уста- новки на рис. 5.2. Оба входа снабжены кружочками, а их имена снабжены чертой. Это означает, что входы инверсные.
58 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. RS-триггер имеет не только инверсный выход, но и оба его входа также инверсные. Входы счита- ются инверсными потому, что активный сигнал для каждого из них - это низкий логический уро- вень. Такое обозначение достаточно условно. В RS- триггере допускается обозначение входов каке инверсией, так и без. Оба варианта будут верны. I Борьба с дребезгом контактов На самом деле RS-триггеры редко используются для хране- ния двоичных чисел. Для этого существуют другие, более слож- ные триггеры, о которых мы поговорим немного позже. Но, все же, RS-триггеры достаточно широко применяются в цифровой и микропроцессорной технике. В качестве примера я хотел бы остановиться на одном из таких применений. ПРИМЕЧАНИЕ. RS-триггер - идеальное устройство для борь- бы с дребезгом контактов. Возможно, вы не зна- ете, что такое дребезг контактов. Поэтому предлагаю остановиться на этом поподробнее. В цифровой и микропроцессорной технике редко удается обойтись без различных кнопок или контактов. С их помо- щью на микропроцессорное устройство подаются различные команды, реализуются, например, разнообразные датчики. Применение механических контактов приносит дополнитель- ную проблему. Как бы качественно ни был выполнен контакт, он никогда не замыкается и не размыкается мгновенно.
Глава 5. Простейшие триггеры 59 ЧТО ЕСТЬ ЧТО. В момент замыкания, когда два контакта еще только-только коснулись друг друга и еще не плотно прижаты, происходит досадное явление, называемое дребезгом. Дребезг представляет собой многократное замыкание и размыкание цепи. В результате на вход микропроцессорного устройства поступает не единичный перепад напряжения, а целая пачка импульсов. Примерная форма сигнала на таких контактах в момент замыкания показана на рис. 5.3. Цифровые микросхемы обладают настолько большим быстродействием, что для них такая пачка импульсов выгля- дит как несколько нажатий клавиши. Если бы не применя- лись антидребезговые устройства, то мы никогда бы не смогли набрать текст на клавиатуре компьютера. При нажатии на каждую клавишу выскакивала бы не одна, а несколько одинаковых букв. Существует множество схемных и программных решений, позволяющих избавиться от дребезга контактов. Одно из таких решений основано на применении RS-триггера. На рис. 5.4 показана схема антидребезгового устрой- ства на основе RS-триггера. Такая схема применяется в том Рис. 5.4. Схема антидребезга на основе RS-триггера Рис. 5.3. Дребезг контактов RS-триггера
60 ARDUINO: от азов программирования до создания... случае, когда кнопка или датчик выполнены в виде группы переключающихся контактов. Как видно из схемы, на оба входа RS-триггера через токоограничивающие резисторы подано напряжение питания. Благодаря этому, на том входе RS-триггера, который не подключен в данный момент к под- вижному контакту, присутствует сигнал логической единицы (входное сопротивление логической микросхемы обычно столь велико, что оно не влияет на величину входного напряжения). Если подвижный контакт замыкает вход на общий про- вод, то напряжение на нем падает до нуля. А это соответствует низкому логическому уровню. При нажатии и отпускании кнопки (срабатывании датчика) подвижный контакт соеди- няет с общим проводом то один, то другой вход RS-триггера. При этом триггер переключается из одного устойчивого поло- жения в другое. Допустим, подвижный контакт переходит в нижнее по схеме положение. В момент замыкания контактов происходит их дребезг. Как только на вход триггера приходит первый отрицательный импульс из пачки импульсов, обусловленных дребезгом, триг- гер переключается, и на выходе устройства устанавливается логический ноль. Остальные импульсы уже не изменят состо- яния триггера. Это состояние изменится на обратное только тогда, когда подвижный контакт сначала разомкнется с нижним по схеме контактом, преодолеет расстояние от нижнего контакта до верхнего, а затем замкнется с верхним. Как только на верхний по схеме вход RS-триггера поступит первый отрицательный импульс, наш триггер переключится, и на выходе устройства появится логическая единица. В единичном состоянии триггер будет находиться до тех пор, пока контакт опять не переклю- чится в нижнее положение.
ГЛАВА 6 ТРИГГЕРЫ ДЛЯ ХРАНЕНИЯ ИНФОРМАЦИИ D-триггер: II устройство и схемное обозначение II Из главы 5 мы узнали, что теоретически для хранения информации можно использовать даже простейший RS-триггер. В реальной цифровой и вычислительной технике для этой цели чаще используются другие, более совершенные триггеры, из которых даже составляют целые регистры. Начнем с отдельных триггеров. Пожалуй, самый распространенный вид триггера — это так называемый D-триггер. Схемное обозна- чение D-триггера приведено на рис. 6.1. Главным атрибутом D-триггера являются два новых входа: Рис. 6.1. Схемное обозначение D-триггера ♦ D-вход; ♦ С-вход. Входы R и S имеют то же самое назначение, что и у RS-триггера (для сброса и установки). ПРИМЕЧАНИЕ. Как у любого другого триггерам D-триггера име- ются два выхода: прямой и инверсный. Следует заметить, что наличие RS-входов, так же как и инверсного выхода, необязательно.
62 ARDUINO: от азов программирования до создания... Il D-триггер: II логика работы Рассмотрим логику работы D-триггера. Для начала раз- беремся с новыми для нас входами. Вход D — это вход данных (от английского DATA). В про- цессе работы на этот вход подается логический уровень, кото- рый необходимо записать в D-триггер. Вход С называется тактовым. На него поступает тактовый импульс, синхронизирующий запись данных. ПРИМЕЧАНИЕ Обратите внимание, что на условном обозначе- нии триггера тактовый вход отмечен стрелкой в виде маленького треугольника. Такой треуголь- ник означает, что данный вход импульсный. До сих пор мы имели дело с потенциальными входами. Потенциальный вход реагирует на потенциал сигнала, посту- пающего на него. Про такой вход говорят: ♦ «Срабатывает при поступлении логической единицы. Или срабатывает от логического нуля». Импульсный вход не чувствителен к уровню сигнала. Такой вход срабатывает в момент перехода от одного уровня к другому. Про такие входы говорят: ♦ «Срабатывает по переднему фронту (то есть при переходе с нуля на единицу) или срабатывает по заднему фронту (то есть при переходе от единицы к нулю)». Иногда применяют другие технические термины для опи- сания работы импульсного входа. В литературе можно прочи- тать: ♦ «Вход срабатывает по фронту сигнала»; ♦ «Вход срабатывает по спаду сигнала». Теперь рассмотрим подробнее логику работы D-триггера. Для переключения триггера в нужное нам состояние сначала
Глава 6. Триггеры для хранения информации 63 на вход D необходимо подать соответствующий логический сигнал: ♦ для записи единицы — подаем единицу; ♦ для записи нуля — подаем ноль. Затем на вход С необходимо подать тактовый импульс. По спаду этого импульса триггер установится в нужное нам состояние (сигнал на D-входе запишется в триггер). ПРИМЕЧАНИЕ. Такая логика работы D-триггера делает его очень удобным устройством для хранения одного бита цифровой информации (одного разряда дво- ичного числа). Рис. 6.2. Простейший параллельный регистр Параллельный II регистр II Для хранения двоичного числа, состоящего из большего количества раз- рядов, используют несколько парал- лельно соединенных D-триггеров. На рис. 6.2 показана схема, предназначен- ная для хранения четырехразрядного двоичного числа. Такая схема называется параллель- ным регистром. Для того чтобы сохра- нить какое-либо число в таком регистре, нужно подать это число поразрядно на входы DO—D3. Затем на вход С схемы подается импульс записи. По заднему фронту этого импульса число записы- вается в регистр. Причем каждый разряд числа записывается в свой отдельный D-триггер. Записанное в регистр число можно считывать с выходов QO—Q3.
64 ARDUINO: от азов программирования до создания... Рис. 6.3. Восьмиразрядный параллельный регистр В схеме регистра присутствует также вход сброса R. Он объединяет входы R всех тригге- ров и используется для начальной установки всех разрядов регистра в нулевое состояние. В цифровой технике это называется «началь- ная установка». В реальных микропроцессорных устрой- ствах чаще используются восьмиразряд- ные параллельные регистры. На рис. 6.3 изображено схемное обозначение одного из таких регистров. Его внутренняя структура и назначение выводов аналогичны структуре и назначению выводов регистра, изображен- ного на рис. 6.2. II Параллельный регистр II с расширенными возможностями Более сложный регистр изображен на рис. 6.4. Это регистр приспособлен для работы с параллельной шиной данных. Для этого в регистр введены два новых входа: ♦ вход выбора микросхемы (CS); ♦ вход перевода выходов в высокоим- педансное состояние (ОЕ). Разберемся подробнее с этими новыми входами и режимами работы. Вход выбора микросхемы (Chip Select) предназначен для ее включения и выключения в разные моменты вре- мени. Такие входы можно часто встре- тить у микросхем, предназначенных для микропроцессорной техники. Особенно в больших многофункцио- DO --- D1 ---D2 D3 ---D4 D5 D6 --- D7 ОЕ RG Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 нальных микросхемах. Наличие таких входов позволяет соединять несколько подобных микро- Рис. 6.4. Параллельный регистр с расширенными возможностями
Глава 6. Триггеры для хранения информации 65 схем параллельно по входам, но работать с каждой микросхе- мой по отдельности. ПРИМЕЧАНИЕ. В случае параллельного соединения одноименных входов данные будут записаны только в тот из регистров, на входе которого в момент записи будет присутствовать низкий логический уро- вень. Состояние остальных регистров останет- ся неизменным.. Вход ОЕ, напротив, используется при параллельном объ- единении нескольких регистров по их выходам. Такое объеди- нение возможно только в том случае, если в каждый момент времени будут работать выходы только одной из микросхем. Выходы остальных параллельно соединенных микросхем должны уметь автоматически отключаться от схемы. Для этой цели микросхема, изображенная на рис. 6.4, имеет специаль- ный режим. В этом режиме все выходы микросхемы отключаются и не влияют на работу остальной схемы. Такое состояние выхо- дов называется высокоимпедансным. Импеданс — это пол- ное сопротивление цепи. Если импеданс высокий, то можно считать, что соответствующий выход просто отключен. Микросхема переводит свои выходы в высокоимпедансное состояние при подаче логической единицы на вход ОЕ. Если же на вход ОЕ подать логический ноль, то выходы микросхемы перейдут обратно в рабочее состояние.
66 ARDUINO: от азов программирования до создания... IJK-триггер: устройство и работа — Q J К Рис. 6.5. JK-триггер Ну, и в заключение этого раздела хочу опять вернуться к триггерам и описать еще один вид. Это, пожалуй, самый слож- ный из триггеров. Называется он JK-триггер. Условное обо- значение такого триггера приведено на рис. 6.5. Как видно из рис. 6.5, JK-триггер сильно напоминает D-триггер. Но вместо одного D-входа такой триггер имеет два новых, пока не известных нам входа, которые имеют обозначение J и К. В общем и целом, входы ] и К частично выпол- няют те же функции, что и D-вход. Но логика работы такого триггера более сложна: ♦ если на J-вход подать сигнал логической единицы, а на К-вход — сигнал логического нуля, то по спаду тактового сигнала на входе С триггер установится в единичное состо- яние; ♦ если на J подать логический ноль, а на К — логическую еди- ницу, то по спаду тактового сигнала триггер установится в нулевое состояние; ♦ если на входы J и К одновременно подать логическую еди- ницу, то по каждому спаду тактового импульса триггер будет переключаться в противоположное состояние. То есть, с единицы в ноль и с нуля в единицу; ♦ если и на J, и на К подать логический ноль, то триггер пере- станет реагировать на тактовые импульсы, и его состояние будет оставаться неизменным. На первый взгляд логика работы триггера чересчур сложна, и область применения таких триггеров неочевидна. Однако виртуозы схемотехники умудряются при помощи JK-триггеров создавать более компактные и рациональные схемы делителей и счетчиков. А вот что такое счетчики и делители, мы узнаем из следующей главы.
ГЛАВА 7 СЧЕТЧИКИ ИМПУЛЬСОВ и ДЕЛИТЕЛИ ЧАСТОТЫ Работа II делителя частоты II что есть что. Счетчиками в цифровой технике называются специальные элементы, позволяющие подсчи- тывать число поступивших на вход импульсов. Понятие «счетчик импульсов» тесно связано с понятием «делитель частоты». По сути дела, это одно и то же устройство. Но рассмотрим все по порядку. В качестве элементар- ного делителя частоты может выступать рассмотренный в предыдущей главе JK-триггер (см. рис. 6.5). Для того чтобы этот триггер работал как делитель, нужно на оба входа J и К подать высокий логический уровень. Теперь, если на вход С подать импульсный сигнал некоторой постоянной частоты, то по спаду каждого входного импульса триггер будет переклю- чаться в противоположное состояние.
68 ARDUINO: от азов программирования до создания... Выход । Рис. 7.1. Принцип деления частоты Вход -<>s — D -tc Q о—- Выход Рис. 7.2. Простейший делитель частоты Q В результате на выходе JK-триггера мы получим дру- гой сигнал с частотой следования импульсов в два раза меньшей, чем частота импульсов на его входе. Этот процесс наглядно показан на рис. 7.1. Как видно из рис. 7.1, период сигнала на выходе дели- теля ровно в два раза больше периода входного сигнала. А частота выходного сигнала, соответственно, в два раза ниже входного. Простейший делитель частоты приведен на рис. 7.2. Он построен на основе D-триггера. Для того чтобы перевести D-триггер в счетный режим, нужно соединить инверсный выход триггера Q с его D-входом так, как это показано на рис. 7.2. Теперь, если подать сигнал на вход С, такая схема тоже будет работать как делитель. Выходной сигнал такого делителя снимается с выхода Q триггера. Рассмотрим подробнее работу этой схемы. Предположим, что после включения триггер установился в единичное состояние. Это означает, что на инверсном выходе триггера (Q) присутствует логический ноль. Этот ноль поступает на D-вход. Подадим на вход делителя некоторый цифровой сиг- нал, такой же, как мы подавали и в предыдущем случае (см. рис. 7.1). По спаду первого входного импульса D-триггер перейдет в нулевое состояние, так как на его D-входе сигнал логического нуля. После этого на инверсном выходе триггера устанавлива- ется логическая единица. Поэтому по спаду следующего вход- ного импульса триггер переключится в единичное состояние. И так далее. Результат работы делителя на D-триггере точно такой же, как и делителя на JK-триггере, и выходной сигнал нового вари- анта также полностью соответствует рис. 7.1.
Глава 7. Счетчики импульсов и делители частоты 69 ПРИМЕЧАНИЕ. Следует заметить, что в настоящее время JK- триггеры применяются довольно редко. Гораздо большее распространение благодаря своей про- стоте и универсальности получили D-триггеры. Делители широко используются в цифровой технике. Цепочка последовательно соединенных D-триггеров позволяет получить сигналы требуемой частоты путем деления импуль- сов задающего генератора. ПРИМЕЧАНИЕ. Соединенные последовательно два делителя по- зволят получить сигнал с частотой в четыре раза меньшей, чем входная. Трехкаскадный делитель (три последовательно соединенных D-триггера) дадут деление на восемь. Четыре каскада будут делить на шестнадцать. И так далее. На рис. 7.3 изображена схема четырехкаскадного дели- теля частоты на D-триггерах. Импульсы тактового генератора поступают на вход первого каскада деления. Если частота сигнала на входе равна f, то на выходах дели- теля мы получим сигналы со следующими частотами: QO-f/2; QI - f/4; Q2 - f/8; Q3 - f/16. Рис. 7.3. Четырехкаскадный делитель частоты
70 ARDUINO: от азов программирования до создания... I Счетчики прямого счета Приведенную на рис. 7.3 схему можно использовать не только в качестве делителя частоты, но и в качестве счетчика входных импульсов. Представьте, что выходы Q0—Q3 — это разряды некоторого двоичного числа. Выход Q0 — это млад- ший разряд, а выход Q3 — самый старший. Предположим, что перед началом счета все четыре триггера установлены в нулевое состояние. На вход схемы поступает некоторое количество импульсов. Входящие в схему триггеры будут переключаться согласно описанному выше алгоритму. Состояние триггеров в процессе счета показано в табл. 7.1. Как видно из табл. 7.1, после прихода первого входного импульса триггер D0 переходит в единичное состояние. После прихода второго импульса D0 возвращается в ноль, зато в еди- ничное состояние переходит D1. Дальнейшее поведение всех четырех триггеров хорошо видно из таблицы. А теперь внимательно посмотрите, что у нас получилось. Если воспринимать совокупность цифровых сигналов на выходах счетчика как четырехразрядное двоич- ное число, то мы видим перед собой последовательность чисел от 0000 до 1111. Десятичный эквивалент этих чисел показан в правой крайней колонке табл. 7.1. Итак, перед началом счета на выходе делителя — ноль. После прохождения первого импульса на выходе — единица, после второго — два, и так далее. Каждый входной импульс увеличивает значение двоичного числа на выходе счетчика на одну единицу. Поэтому в любой момент времени счетчик содержит число, равное количеству импульсов, пришедших к этому моменту на его вход. Максимальное число импульсов, которое может посчитать счетчик, схема которого изображена на рис. 7.3, — это 16. После прихода шестнадцатого импульса счетчик вернется в нулевое состояние.
Глава 7. Счетчики импульсов и делители частоты 71 Логика работы делителя Таблица 7.1 Входные импульсы Состояние выходов Десятичный эквивалент Q3 Q2 Q1 Q0 Не было ни одного 0 0 0 0 0 Один импульс 0 0 0 1 1 Два импульса 0 0 1 0 2 Три импульса 0 0 1 1 3 - 0 1 0 0 4 - 0 1 0 1 5 - 0 1 1 0 6 - 0 1 1 1 7 - 1 0 0 0 8 - 1 0 0 1 9 - 1 0 1 0 10 - 1 0 1 1 11 - 1 1 0 0 12 - 1 1 0 1 13 Четырнадцать импульсов 1 1 1 0 14 Пятнадцать импульсов 1 1 1 1 15 ПРИМЕЧАНИЕ. Счетчики широко применяются в цифровой тех- нике в том случае, когда необходимо подсчитать количество каких-либо импульсов. Причем совсем необязательно, чтобы входные импульсы посту- пали равномерно с постоянным периодом. Это могут быть одиночные импульсы. Например, им- пульсы с какого-нибудь датчика, кнопки и т. п.
72 ARDUINO: от азов программирования до создания... II Счетчики II с обратным отсчетом Кроме счетчиков прямого отсчета, к которым относится схема, изображенная на рис. 7.3, существуют счетчики с обратным отсчетом (иногда такой счетчик называют инверс- ным). В таком счетчике при поступлении каждого входного импульса содержимое уменьшается на единицу. Кроме того, бывают задачи, для которых требуются уни- версальные счетчики, которые могут считать как в прямом, так и в инверсном направлении. ПРИМЕЧАНИЕ. Если задаваться задачей построения таких счетчиков на отдельных триггерах и логических элементах, то мы получим довольно сложную схему. На практике используют специальные ми- кросхемы - счетчики импульсов. \_______________________________________ Современная промышленность предлагает большой ассор- тимент таких микросхем. На рис. 7.4 изображена микросхема К555ИЕ7. Это одна из микросхем 555 серии, которая широко выпускалась в свое время в СССР, и сейчас ее можно свободно найти в продаже на радиорынках стран СНГ. Микросхема 555ИЕ7 — это реверсивный четырехразрядный счетчик/делитель с возмож- ностью предустановки. Он имеет два счетных входа, обозначенных как «+1» и «-1». По спаду каждого импульса на входе «+1» содержимое счетчика увеличивается на единицу. По спаду каждого импульса на входе «-1» содержимое счетчика уменьшается на единицу. Счетчик имеет прямые выхода всех своих разрядов: Реверсивный QO—Q3. Вход сброса R служит для установки счетчик всех разрядов счетчика в нулевое состояние.
Глава 7. Счетчики импульсов и делители частоты 73 Еще одно полезное свойство описываемого счетчика — это наличие режима предустановки. ПРИМЕЧАНИЕ. Используя этот режим, можно в любой момент записать во все разряды счетчика любое четы- рехразрядное двоичное число. к_______________________________________________ Для этого счетчик имеет несколько дополнительных входов: ♦ входы данных DO—D3; ♦ вход предустановки РЕ ЛЕНА. С ЧЕРТОЙ СВЕРХУ. Предустановка счетчика осуществляется следующим образом. Сначала на входы DO — D3 подается код, который требуется записать в разряды счетчика. Затем на вход пода- ется сигнал низкого логического уровня. По этому сигналу код, установленный на входах DO—D3, запишется в счетчик и тут же появится на его выходах QO—Q3. Дальнейший счет импульсов будет производиться уже от этого нового значения. Выходы «>15» и «^0» — это выходы переполнения. Они используются при последовательном соединении нескольких таких счетчиков. В процессе счета уровень сигнала на обоих этих выходах равен единице. На выходе «>15» логический ноль появляется в том случае, если в процессе прямого счета содержимое счетчика достигнет своего максимального значения 11112, и на вход «+1» поступит очередной счетный импульс. Выход «<0» работает аналогично, но при обратном счете. Сигнал логического нуля появляется на этом выходе в тот момент, когда счетчик досчитает до своего нижнего предела — 00002, и на вход «-1» поступит очередной счетный импульс. При последовательном соединении двух счетчиков выходы «>15» и «^0» первого счетчика соединяются, соответственно, с входами «+1» и «-1» второго.
74 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. В результате, соединив последовательно два та- ких счетчика, мы получим восьмиразрядный ре- версивный счетчик, который также будет иметь возможность предустановки. Таким способом можно соединять последовательно любое коли- чество счетчиков 555ИЕ7. Одно из применений микросхемы 555ИЕ7 — построение делителей с переменным коэффициентом деления. Простой делитель частоты, рассмотренный в начале этой главы, дает фиксированный набор коэффициентов деления, который к тому же можно выбирать лишь из ограниченного ряда значе- ний, являющихся степенью числа 2. I Делители с переменным коэффициентом деления В цифровой и микропроцессорной технике часто требуются делители с произвольным коэффициентом деления. При этом желательно, чтобы коэффициент деления можно было опера- тивно менять. На рис. 7.5 изображена схема делителя с про- граммируемым коэффициентом деления на основе реверсив- Рис. 7.5.Делитель с переменным коэффициентом деления
Глава 7. Счетчики импульсов и делители частоты 75 ного счетчика К555ИЕ7. Для хранения коэффициента деления используется специальный четырехразрядный параллельный регистр, обозначенный на схеме как DD1. Коэффициент деле- ния такого делителя может изменяться от 1 до 15. Работа счетчика начинается с установки всех его разрядов в ноль при помощи входа R. ПРИМЕЧАНИЕ. Обратите внимание на то, что в микросхеме К555ИЕ7 используется прямой, а не инверсный вход сброса. Поэтому сброс происходит при по- даче на этот вход сигнала логической единицы. После того, как счетчик сброшен, для нормальной работы счетчика на вход R должен быть подан нулевой уровень. Входной сигнал поступает на вход «-1». Поэтому счетчик работает в режиме обратного счета. Поэтому первый же входной импульс после сброса счетчика вызовет сигнал переполнения на выходе «^0». Этот импульс поступит на вход. В результате в счет- чик будет записано двоичное число с выхода регистра DD1. Это число соответствует выбранному коэффициенту деления. ПРИМЕР. Допустим, что в регистр DD1 мы записали число 10 (10102). Тогда именно это число будет записа- но в разряды счетчика DD2. Каждый последующий входной импульс будет уменьшать содержимое счетчика на единицу. Так будет продолжаться до тех пор, пока содержимое счетчика снова не уменьшится до нуля. Для этого потребуется как раз 10 тактовых импульсов. По приходу одиннадцатого импульса на выходе «^0» снова поя-
76 ARDUINO: от азов программирования до создания... вится сигнал переполнения, и в счетчик будет опять записано число десять из регистра DD1. Описанный процесс будет повторяться все время, пока приходят входные импульсы. Период следования импульсов на выходе «^0», а, значит, и на выходе всей схемы в нашем слу- чае будет в 11 раз больше периода входных сигналов. А частота выходных импульсов будет, соответственно, в 11 раз меньше. То есть наш счетчик будет делить на 11. Записывая в регистр DD1 различные значения, можно легко менять коэффициент деления описанной схемы. Забегая впе- ред, скажу, что запись числа в регистр коэффициента деления может производить микропроцессор. В этом случае мы можем создать делитель, управляемый от микропроцессора. II Таймеры: формируем II различные интервалы времени Подобную схему можно использовать также для формиро- вания различных интервалов времени. Если на вход «-1» пода- вать тактовые импульсы фиксированной частоты, а в качестве управляющего входа использовать вход R, то на выходе мы можем получать импульс заданной длительности. И эту дли- тельность можно программировать, записывая в регистр D1 различные коэффициенты. ЧТО ЕСТЬ ЧТО. Схемы, предназначенные для формирования раз- личных интервалов времени, называются тайме- рами. Обычно одни и те же цифровые элементы при определен- ном способе включения могут с успехом выступать в любой из трех описанных выше ролей:
Глава 7. Счетчики импульсов и делители частоты 77 ♦ либо как делители; ♦ либо как счетчики; ♦ либо как таймеры. Существуют и специализированные микросхемы-тай- меры. ПРИМЕР. Микросхема К580ВИ53 - это универсальный про- граммируемый трехканальный счетчик-таймер. Такая микросхема имеет множество режимов работы, которые должны выбираться программ- ным путем при помощи микропроцессора. Современные микроконтроллеры, или, как их еще назы- вают, однокристальные микроЭВМ, обычно всегда содержат в своем составе один или несколько встроенных таймеров- счетчиков. Микроконтроллеры серии AVR имеют от одного (в микросхеме AT90S1200) до четырех (в микросхеме ATmegal28) встроенных таймеров/счетчиков. Это позволяет при формиро- вании временных интервалов обойтись без внешних таймеров.
ГЛАВА 8 ДЕШИФРАТОРЫ ЦИФРОВЫХ СИГНАЛОВ II Устройство и принцип действия II дешифратора Еще один элемент, без которого не обойтись при изучении микропроцессорной техники, — это дешифратор цифровых сигналов. Существует много разных типов дешифраторов. ЧТО ЕСТЬ ЧТО. В общем случае дешифратор - это устройство, преобразующее цифровой сигнал, представлен- ный в какой-либо одной из кодировок, в другую, не- закодированную форму. Нас в данном случае будет интересовать классический линейный дешифратор. Схемное обозначение одного из вариантов такого дешифратора приведено на рис. 8.1. Описываемый дешифратор имеет три входа данных DO, Din D2, вход выбора микросхемы, а также восемь выходов, обозна- ченных цифрами от 0 до 7.
Глава 8. Дешифраторы цифровых сигналов 79 Логика работы микросхемы такова: на входы данных микросхемы подается цифровой код. В данном случае — это любое трехразрядное двоичное число. Смысл работы такого дешифра- тора — выдать активный сигнал только на одном из своих выходов. На том выходе, номер которого соответствует двоичному коду, присутствующему на его входах DO — D2. Рис. 8.1. Простейший дешифратор ПРИМЕЧАНИЕ. В большинстве современных дешифраторов ак- тивным сигналом на выходе считается низкий логический уровень. Это значит, что при поступлении на входы DO—D1 сигнала 0002, на выходе «О» будет логический ноль, а на всех остальных выходах — единица. Состояние выходов дешифратора при дру- гих значениях входного сигнала приведено в табл. 8.1. Таблица истинности дешифратора Таблица 8.1 Входы Выходы D2 D1 DO CS 7 б 5 4 3 2 1 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 1 0 1 1 1 1 1 1 0 1 0 1 0 0 1 1 1 1 1 0 1 1 0 1 1 0 1 1 1 1 0 1 1 1 1 0 0 0 1 1 1 0 1 1 1 1 1 0 1 0 1 1 0 1 1 1 1 1 1 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 X X X 1 1 1 1 1 1 1 1 1
80 ARDUINO: от азов программирования до создания... Табл. 8.1 — это таблица истинности данного дешифра- тора. Большое значение имеет вход выбора микросхемы. Этот вход позволяет включить или выключить всю микросхему. Микросхема работает только в том случае, если на вход дешиф- ратора подан разрешающий нулевой сигнал. В противном слу- чае микросхема выключается и на всех ее выходах устанавли- вается сигнал логической единицы. Основное назначение линейного дешифратора — функ- ция выбора одного из нескольких электронных устройств. Например, выбор одной из нескольких микросхем памяти. Каждая такая микросхема должна иметь свой собствен- ный вход. К каждому выходу дешифратора подключается одна такая микросхема. Вернее, подключается ее вход. Теперь, если на входы DO—D2 дешифратора подать номер выбираемой микросхемы, она включится, а остальные семь микросхем отключатся. При выключении самого дешифратора отключаются и все подключенные к нему микросхемы. I Селектор памяти ячеек ОЗУ Хороший пример использования дешифратора — селектор ячеек памяти ОЗУ. Схема простейшего модуля ОЗУ, состоящего всего из четырех ячеек, приведена на рис. 8.2. В качестве ячеек памяти в схеме используются параллельные регистры с воз- можностью перевода в высокоимпедансное состояние. Такие регистры нам уже знакомы по главе 6 (см. рис. 6.4). Рассмотрим внимательно схему на рис. 8.2. Линии LDO—LD7 — это восьмиразрядная шина данных. Она используется как для записи чисел в память, так и для чте- ния из нее. Входы LAO, LA1 — это так называемые входы адреса. Вход UPR — вход выбора для всего устройства. Входы WRITE и READ, соответственно, — вход команды записи и вход команды чтения.
Глава 8. Дешифраторы цифровых сигналов 81 Рис. 8.2. Схема простейшего модуля ОЗУ
82 ARDUINO: от азов программирования до создания... Входы UPR, WRITE и READ — инверсные. То есть в отсут- ствии сигнала на каждом из них должен присутствовать высо- кий логический уровень. Активным сигналом для этих входов является логический ноль. Для того чтобы записать число в одну из ячеек такого ОЗУ, нужно сначала на вход UPR подать нулевой сигнал (выбрать устройство). Затем на лини LDO—LD7 от внешнего источника цифрового сигнала подать восьмиразрядное двоичное число, предназначенное для записи. Затем на линии LAO, LA1 пода- ется число, соответствующее номеру нужной ячейки памяти (адрес ячейки). Номер выбранной ячейки поступает на дешиф- ратор DD1. Предположим, что мы хотим выбрать нулевую ячейку памяти. Для этого мы подадим на входы LAO, LA1 сигнал 002. В результате на выходе Q0 дешифратора появляется нулевой сиг- нал, а на всех остальных его выходах — единичный. С выхода Q0 дешифратора нулевой сигнал поступает на вход параллель- ного регистра DD2 и включает его. Все остальные регистры остаются отключенными. Теперь для того, чтобы записать число в выбранную ячейку памяти, нужно подать короткий нулевой импульс на вход WRITE. Он поступит на входы С всех регистров. Но число запи- шется только в регистр DD2. ПРИМЕЧАНИЕ. Как видно из схемы на рис. 8.2, лини D0-D7 объ- единяют в себе не только входы регистров, но и их выходы. Однако такая схема включения не мешает работе устройства. Это достигается благодаря тому, что все регистры имеют вы- ходы с тремя состояниями. К двум обычным со- стояниям (ноль и единица) добавлено третье - высокоимпендансное. Это состояние включается при подаче на вход ОЕ любого регистра логиче- ской единицы.
Глава 8. Дешифраторы цифровых сигналов 83 В режиме чтения информации лини LDO—LD7 используются как выходы. Для того чтобы прочитать число из любой ячейки памяти, нужно сначала подать адрес ячейки на входы LAO, LA1. Это приводит к тому, что нужный нам регистр включается. Включается точно так же, как это происходило при записи. Теперь для того, чтобы прочитать число из выбранной ячейки, достаточно подать на вход READ сигнал логического нуля. В результате выходы выбранного регистра перейдут из высокоимендансного в рабочее состояние. На них появится записанное в регистр число, которое поступит на выход всей схемы. Все остальные регистры останутся отключенными, и не будут мешать процессу чтения. Каскадирование дешифраторов Прежде, чем завершить рассказ о дешифраторах, хочу рас- смотреть вопрос их каскадирования. Благодаря наличию входа, несколько дешифраторов можно объединять вместе, образуя составной дешифратор, имеющий большее число входов и выходов. Пока мы имели дело с двумя видами дешифраторов. Первый дешифратор (рис. 8.1) имел три входа и восемь выхо- дов. Дешифратор, который мы использовали в примере схемы ОЗУ (рис. 8.2), имел всего два входа и четыре выхода. Логика работы любого такого дешифратора одна и та же. Различие состоит лишь в количестве входных и выходных разрядов. Чтобы в краткой форме обозначить характеристики кон- кретного дешифратора, иногда применяют следующее обозна- чение: «Дешифратор 2X4» или «Дешифратор 3X8». На рис. 8.3 показан способ, как при помощи каскадного соединения нескольких дешифраторов создать новый дешифратор с фор- мулой «5X32». Первый каскад состоит из одного дешифратора (DD1). Этот дешифратор управляет четырьмя другими дешиф- раторами (DD2—DD5), которые составляют второй каскад.
84 ARDUINO: от азов программирования до создания... Все дешифраторы, рассмотренные нами до сих пор, отно- сятся к разряду полных дешифраторов. Поясню, что это такое. Если дешифратор имеет пять входов, то максимальное число значений, которые могут принимать эти входы, равно 32. Если при этом дешифратор имеет 32 выхода, то при подаче на его входы любого возможного числа, на одном из выходов
Глава 8. Дешифраторы цифровых сигналов 85 обязательно появится активный уровень сигнала. В некоторых случаях наличие всех возможных выходов не обязательно. Дешифратор для работы с двоично-десятичными числами ЧТО ЕСТЬ ЧТО. Двоично-десятичное число - это число, записан- ное в двоичной форме, но принимающее значение от О (0000J до 10 (1010}. При работе с такими числами используют неполный дешифратор 4X10. Такой дешифратор имеет четыре входа и всего десять выходов. При подаче на входы такого дешифра- тора двоичных чисел в диапазоне от 00002 до 10102 активизи- руются выходы «0»—«9». При этом подразумевается, что числа выше, чем 10102, на входы дешифратора подаваться не будут. Однако ничего не мешает подать на входы дешифратора эти числа. Как будет вести себя неполный дешифратор в таком случае, определя- ется его разработчиком. Чаще всего в этом случае все выходы дешифратора остаются неактивными. Промышленность выпускает несколько видов неполных дешифраторов. Например, К555ИД1, К555ИД6, К555ИД1О.
ГЛАВА 9 МУЛЬТИПЛЕКСОРЫ: СОБИРАЕМ СИГНАЛ С НЕСКОЛЬКИХ ВХОДОВ Как собирается сигнал с нескольких источников ЧТО ЕСТЬ ЧТО. Мультиплексор - это устройство, обратное простому линейному дешифратору. Вообще, тер- мин «мультиплексирование» означает собирание сигнала с нескольких разных входов. А точнее - переключение нескольких входов на один выход. Схема одного из вариантов мультиплексора изображена на рис. 9.1. Любой мультиплексор имеет: ♦ информационные входы; ♦ один информационный выход; ♦ входы выбора адреса для управления мультиплексирова- нием. Так, мультиплексор, изображенный на рис. 9.1, имеет: ♦ восемь входов данных (DO—D7); ♦ три входа адреса (АО—А2).
Глава 9. Мультиплексоры: собираем сигнал с нескольких входов 87 D7 MS D6 D5 D4 D3 D2 D1 DO АО А1 А2 На адресные входы должен подаваться цифровой код, соответствующий номеру информационного входа, сигнал с которого должен поступить на выход. ПРИМЕЧАНИЕ. Рис. 9.1. Схема мультиплексора То есть, если на входы А0-А2 подать код 000Н, то с выходом будет соединен вход DO. Если на адресные входы подать число 001Н, то с выходом соединится вход D1. И так далее. Разнообразие II мультиплексоров II Мультиплексоры могут иметь разное количество информа- ционных входов и входов адреса. Но на их количество распро- страняется тот же самый закон, который действует при опреде- лении соотношения входов и выходов дешифратора: «Число информационных входов должно быть равно макси- мально возможному количеству адресов, которые можно подать на входы адреса». При двух адресных входах должно быть четыре информа- ционных, при трех адресных — восемь информационных, при четырех — шестнадцать. И так далее. Если информационных входов окажется меньше, мультиплексор будет неполным. Цифровые и аналоговые II мультиплексоры II Описанные выше мультиплексоры называются цифро- выми. Кроме цифровых мультиплексоров, существуют анало-
88 ARDUINO: от азов программирования до создания... говые мультиплексоры. Отличие между этими двумя видами мультиплексоров в способе соединения входа и выхода. Цифровой мультиплексор может работать лишь с цифровым сигналом. Этот сигнал должен подаваться на один из входов, а сниматься с выхода. В обратную сторону сигнал не распро- страняется. Аналоговый мультиплексор работает по принципу цифро- вого ключа. Один из входов соединяется с выходом напрямую. Две разные электрические цепи объединяются в одну общую цепь. В случае использования аналогового мультиплексора в качестве информационных сигналов можно использовать как цифровые, так и аналоговые сигналы, подавать их как на вход, так и на выход мультиплексора. В последнем случае выход становится входом. Примером аналогового мультиплексора может служить микросхема К561КП2. На этом мы заканчиваем изучение основ цифровой логики и переходим к следующему этапу — микропроцессорам.
ЧАСТЬ II ШАГАЕМ ОТ ЦИФРОВОЙ ТЕХНИКИ К МИКРОКОНТРОЛЛЕРУ Итак, мы переходим к микропроцессо- рам и микроконтроллерам. В этой части книги читатель узнает, как на основе простых цифровых элементов, о кото- рых мы говорили в предыдущей части, строится типовая микропроцессор- ная система, из чего она состоит, как работает. Узнаем, что такое «система команд», какие бывают виды команд и как они выполняются в программе. Мы рассмотрим основной и дополнитель- ные режимы работы микропроцессорной системы.
ГЛАВА 10 ТИПОВАЯ СХЕМА МИКРОПРОЦЕССОРНОЙ СИСТЕМЫ I Структурная схема типичной микропроцессорной системы Основным действующим элементом современной микро- процессорной системы является микроконтроллер. Однако для того, чтобы понять основополагающие принципы работы, сначала все же необходимо остановиться на микропроцессоре. ПРИМЕЧАНИЕ. Сразу нужно сказать, что микропроцессор не ра- ботает сам по себе. Микропроцессор - это всего лишь часть той или иной микропроцессорной си- стемы. Кроме собственно микропроцессора, в состав микропроцес- сорной системы входят и другие, не менее важные элементы. На рис. 10.1 приведена обобщенная структурная схема типич- ной микропроцессорной системы. Рассмотрим детально, как она устроена. Как вы видите, названия всех элементов системы даны как в русском, так и в английском варианте.
Глава 10. Типовая схема микропроцессорной системы 91 Рис. 10.1. Структурная схема типовой микропроцессорной системы Русские названия когда-то пытались внедрить в практику в бывшем СССР. Поэтому и сейчас они иногда встречаются в литературе. Однако в настоящее время более широкое рас- пространение получили английские, а точнее — международ- ные наименования. Каждое наименование как в русском, так и в английском варианте представляет собой определенное сокращение полного названия элемента. Ниже приведена их расшифровка: ♦ CPU (Central Processing Unit) — центральное процессорное устройство (ЦПУ); ♦ RAM (Random Access Memory) — устройство с произволь- ным доступом, или оперативное запоминающее устрой- ство (ОЗУ); ♦ ROM (Read Only Memory) — память только для чтения, или постоянное запоминающее устройство (ПЗУ); ♦ Port I/O (Port Input/Output) — порт ввода-вывода. Теперь рассмотрим все эти элементы подробнее. Что такое процессор и для чего он нужен, вы уже немного знаете из ЧАСТИ I. ПРИМЕЧАНИЕ. Замечу только, что процессор не всегда был Микропроцессором. Были времена, когда процес- сор представлял собой одну или даже несколько электронных плат, набитых радиоэлементами.
92 ARDUINO: от азов программирования до создания... II ОЗУ и ПЗУ: II в чем сходства и отличия Два вида памяти (ОЗУ и ПЗУ) предназначены для хранения информации (данных и программ). Оба вида памяти представ- ляют собой набор ячеек, в каждой из которых может храниться одно двоичное число. Деление на постоянную и оперативную память достаточно условно. ПРИМЕЧАНИЕ. С точки зрения процессора, оба эти вида памя- ти практически идентичны. Однако все же между ними есть одно довольно существенное различие. <____________________________________________. После того, как информация записана в ОЗУ, она хранится там лишь до тех пор, пока подано напряжение питания. Как только питание будет отключено, информация, записан- ная в ОЗУ, тут же теряется. Об этом мы уже говорили выше. Классический пример ячейки ОЗУ — это простейший регистр, построенный на D-триггерах (см. рис. 8.2). В такой регистр можно записывать информацию и читать ее оттуда. Однако если отключить, а затем включить пита- ние, то все триггеры, из которых состоят регистры ОЗУ, уста- новятся в случайное состояние. Информация будет утеряна. Современные микросхемы памяти строятся на основе совсем других технологий. Но и по сей день не придумано достаточно быстродействующее устройство памяти, не теряющее инфор- мации при выключении питания. Динамическая память Самая распространенная на сегодняшний день техноло- гия построения ОЗУ — это так называемая динамическая
Глава 10.Типовая схема микропроцессорной системы 93 память. Хранение информации в микросхемах динамической памяти осуществляется при помощи динамически подзаряжа- емых миниатюрных емкостей (конденсаторов), выполненных интегральным способом на кристалле кремния. Каждый конденсатор хранит один бит информации. Если значение бита должно быть равно единице, то схема управле- ния заряжает конденсатор. Если в ячейке должен быть логиче- ский ноль, то конденсатор разряжается. Заряженный конденса- тор может хранить свой заряд, а, значит, и записанную в него информацию в течение всего нескольких миллисекунд. ПРИМЕЧАНИЕ. Для того чтобы информация не потерялась, ис- пользуют регенерацию памяти: специальная схе- ма периодически считывает содержимое каждой ячейки памяти и подзаряжает конденсаторы для тех битов, где записана единица. Для ускорения процесса регенерации все ячейки памяти каждой микросхемы разбиваются на строки. Считывание и обновление производится сразу для целой строки. Для нор- мальной работы динамического ОЗУ регенерации должна непрерывно работать в течение всего времени, пока включено питание. В современных ОЗУ схема регенерации встраивается внутрь самих микросхем. Развитие постоянных II запоминающих устройств II Постоянное запоминающее устройство (ПЗУ) пред- назначено для долговременного хранения информации и не теряет записанную информацию даже после выключения питания. При изготовлении микросхем ПЗУ применяются совершенно другие технологии.
94 ARDUINO: от азов программирования до создания... Этап 1. На заре микропроцессорной техники микросхемы ПЗУ осуществляли хранение информации благодаря прожига- нию внутренних микроперемычек на кристалле. ПРИМЕЧАНИЕ. Занесенная таким образом информация не мог- ла быть изменена. Если информация устаревала, микросхему просто выбрасывали и заменяли на другую. Этап 2. На смену однократно программируемым ПЗУ пришли ПЗУ с ультрафиолетовым стиранием. Такие микросхемы ПЗУ допускали многократное использование. Пережигаемые перемычки получили возможность восста- навливаться. Перед повторным использованием микросхему нужно было «стереть». То есть восстановить перемычки. Для этого кристалл микросхемы подвергался облучению свето- вым потоком ультрафиолетового диапазона, для чего микро- схемы снабжались специальным окошечком в верхней части корпуса. Количество циклов записи-стирания для таких микросхем было ограничено. Микросхемы с ультрафиолетовым стира- нием просуществовали достаточно долго. Они и сейчас рабо- тают во множестве микропроцессорных устройств, изготов- ленных на рубеже прошлого и нынешнего веков. Этап 3. Современные же микросхемы ПЗУ строятся по так называемой флэш-технологии (Flash). Такие микросхемы также основаны на применении специальных пережигае- мых перемычек с возможностью восстановления. Но стирание информации в данном случае происходит электрическим путем. Поэтому такие микросхемы еще называют ЭСПЗУ (электриче- ски стираемые ПЗУ). Весь процесс стирания осуществляется внутри микросхемы. Для запуска процесса стирания достаточно подать определенную комбинацию сигналов на ее входы.
Глава 10. Типовая схема микропроцессорной системы 95 Будучи включенными в состав микропроцессорной системы, микросхемы ОЗУ и микросхемы ПЗУ работают как единая память программ и данных. Хотя процессор и рабо- тает с обоими видами памяти одинаково, но из ПЗУ он может только читать информацию. Запись информации в ПЗУ невоз- можна. Если микропроцессор все же попытается произвести запись, то ничего страшного не произойдет. Просто в ячейке останется то, что там было до попытки записи. Порты ввода-вывода что есть что. Порты ввода-вывода - это специальные устрой- ства, при помощи которых микропроцессорная система может общаться с внешним миром. Без портов теряется весь смысл микропроцессорной системы. Она не может работать сама по себе. Микропроцессор должен чем-то управлять, а, иначе, зачем он? Через порты ввода процессор получает внешние воздействия (управляющие сиг- налы). Например, сигналы от кнопок, датчиков. При помощи портов вывода процессор управляет внешними устройствами (реле, моторами, световыми индикаторами, дисплеями). Процессор работает с портами ввода-вывода практически так же, как и с ячейками памяти. Работа с портами сводится к тому, что процессор просто читает число из порта ввода или записывает число в порт вывода. В качестве порта вывода чаще всего выступает обыкновенный параллельный регистр. Порт ввода еще проще. Это простая ключевая схема, которая по команде с центрального процессора подает внешние данные на его входы.
96 ARDUINO: от азов программирования до создания... I Процессор и цифровые шины Главным управляющим элементом всей микропроцессор- ной системы является процессор. Именно он, за исключением нескольких особых случаев, управляет и памятью, и портами ввода-вывода. ПРИМЕЧАНИЕ. Память и порты ввода-вывода являются пассив- ными устройствами и могут только отвечать на управляющие воздействия. Чтобы процессор мог управлять микропроцессорной систе- мой, он соединен со всеми ее элементами при помощи цифро- вых шин. ЧТО ЕСТЬ ЧТО. Как мы уже говорили, шина - это набор парал- лельных проводников, по которым передается цифровой сигнал. Эти проводники называются линиями шины. В каждый момент времени по шине передается одно дво- ичное число. По каждой линии передается один разряд этого числа. В любой микропроцессорной системе имеется, по крайней мере, три основных шины. Все они изображены на рис. 10.1, но даны только русскоязычные названия шин. Ниже приведена расшифровка этих названий и их англо- язычный эквивалент: ШД — шина данных (DATA bus); ША — шина адреса (ADDR bus); ШУ — шина управления (CONTROL bus).
Глава 10.Типовая схема микропроцессорной системы 97 Все вместе эти три шины образуют системную шину. Рассмотрим подробнее назначение каждой шины. Шина данных | Шина данных предназначена для передачи данных от микропроцессора к периферийным устройствам, а также в обратном направлении. Разрядность шины данных определя- ется типом применяемого процессора. В простых микропро- цессорах шина данных обычно имеет 8 разрядов. Современные процессоры могут иметь шину данных в 16, 32, 64 разрядов. Количество разрядов всегда кратно восьми. ЧТО ЕСТЬ ЧТО. Двоичное число, имеющее восемь разрядов, назы- вается байтом. В вычислительной технике байт, по сути, стал минимальной (после бита) единицей информации. Шестнадцатиразрядная шина данных может за раз передавать до двух байтов. 32-раз- рядная шина передает до четырех байт. 64-разрядная — до восьми. Какой бы ни была разрядность шины, она всегда имеет возможность при необходимости передать всего один байт. И это не случайно. Любой процессор должен иметь возможность записать информацию в одну отдельную ячейку памяти или в один отдельный порт ввода-вывода. А также прочитать инфор- мацию из одной ячейки или одного порта.
98 ARDUINO: от азов программирования до создания... Шина адреса что есть что. Как и шина данных, шина адреса представляет собой набор проводников, по которым проис- ходит передача двоичных чисел в электронной форме. Однако, в отличие от шины данных, дво- ичные числа, передаваемые по шине адреса, име- ют другой смысл и назначение. Они представляют собой адрес ячейки памяти или номер порта ввода/вывода, к которому в данный момент обращается процессор. Количество разрядов адресной шины отличается большим разнообразием. ПРИМЕР. Микропроцессор серии К580ИК80 имеет 16 раз- рядов адреса. Это можно считать минимальным количеством для микропроцессора. Процессор Intel 8086, на котором собран компьютер IBM РС-ХТ, родоначальник всех PC-совместимых персо- нальных компьютеров, имеет 20 разрядов шины адреса. Современные процессоры имеют до 52 разрядов и больше. От количества разрядов шины адреса зависит то, какое количество ячеек памяти может адресовать процессор. Процессор, имеющий шестнадцатиразрядную шину данных, может обращаться к 216 (то есть к 65536) ячейкам памяти. Это число называется объемом адресуемой памяти. Реальный объем подключенной памяти может быть меньше, но никак не больше этой величины. Если все же есть необходимость в подключении большего объема памяти, при-
Глава 10. Типовая схема микропроцессорной системы 99 меняют специальные схемные ухищрения (переключаемые банки памяти). В каждый момент времени к микропроцес- сору подключается свой банк памяти. Переключением банков управляет сам микропроцессор. Объем памяти определяется в байтах. Сколько ячеек памяти, столько и байт. Существует понятие килобайт, мега- байт, гигабайт, терабайт и т. д. Однако в вычислительной тех- нике используется необычный способ подсчета количества байт в килобайте. ВНИМАНИЕ. Один килобайт в вычислительной технике не ра- вен 1000 байтов, как этого можно было бы ожи- дать. Число 1000 не является круглым числом в двоичной системе. В двоичной системе круглы- ми числами удобнее считать степени числа 2. Например, 4, 8,16, 52, 64 и т. д. Ближайшей сте- пенью двойки для числа 1000 будет 210, то есть число 1024. Поэтому 1 килобайт равен 1024 бай- там. Точно также 1 мегабайт равен 1024 кило- байтам. А один гигабайт равен 1024 мегабайтам. Такой способ подсчета может показаться странным. Но это только на первый взгляд. На самом деле тут действуют те же закономерности, Что и в случае с дешифратором. Вспомните полный и неполный дешифраторы (глава 8). Чтобы это было более понятно, приведу один небольшой пример. ПРИМЕР. Для адресации 1024 ячеек памяти нужна шина адреса, имеющая ровно 10 разрядов. То есть к адресной шине в 10 разрядов максимально можно подключить 1024 ячейки памяти. Если бы мы под- \_______________________________________________
100 ARDUINO: от азов программирования до создания... ключили 1000 ячеек, то нам все равно пришлось бы использовать 10 разрядов адреса, которые, в этом случае, использовались бы не полностью. Поэтому вы никогда не встретите микросхему памяти, имеющую 1000 ячеек. Именно по этой причине реальный объем памяти любой микропроцессор- ной системы, даже если она меньше максимально возможной для данной разрядности шины адреса, всегда будет кратным степени двойки. Для адресации портов ввода-вывода используется та же самая шина адреса. Но микропроцессору обычно не требуется так много портов, как ячеек памяти. Поэтому чаще всего для адресации портов используется не вся шина данных, а только несколько его младших разрядов. Например, в микропроцес- соре К580ИК80 для адресации портов используется только 8 младших разрядов шины адреса. Шина управления Шина управления в строгом понимании не является цель- ной цифровой шиной. Просто для управления процессами обмена информации микропроцессорная система должна иметь некий набор линий, передающих специальные управ- ляющие сигналы. Эти линии и принято объединять в так назы- ваемую шину управления. Что же это за линии и что за сиг- налы? Ниже приведен примерный набор линий шины управ- ления: ♦ RD (Read) — сигнал чтения; ♦ WR (Write) — сигнал записи; ♦ MREQ — сигнал инициализации устройств памяти (ОЗУ или ПЗУ); ♦ IORQ — сигнал инициализации портов ввода-вывода;
Глава 10. Типовая схема микропроцессорной системы 101 Кроме того, к сигналам шины управления относятся: ♦ READY — сигнал готовности; ♦ RESET — сигнал сброса. И еще несколько специальных сигналов, о которых мы поговорим позже. Принцип действия II микропроцессорной системы II Теперь, когда мы изучили все элементы микропроцессор- ной системы, настало время разобраться, как же она работает. Обратимся вновь к рис. 2.1. Как уже говорилось выше, основным элементом системы является центральный процессор (CPU). По отношению к любым периферийным устройствам про- цессор может выполнять в каждый момент времени одну из четырех основных операций: ♦ чтение из ячейки памяти; ♦ запись в ячейку памяти; ♦ чтение из порта; ♦ запись в порт. При работе с памятью процессор активизирует сигнал на выходе MREQ. Сигнал на выходе IORQ остается неактивным. При работе с портами ввода-вывода наоборот: сигнал IORQ активный, а сигнал MREQ — неактивный. ПРИМЕЧАНИЕ. Активным уровнем обычно является логический ноль. Теперь рассмотрим подробнее, как происходят процессы записи и чтения памяти. Чтобы прочитать байт из ячейки памяти, процессор сначала выставляет на шине адреса адрес
102 ARDUINO: от азов программирования до создания... нужной ячейки. Затем процессор переводит в активное состо- яние (логический ноль) сигнал RD. Этот сигнал поступает как на устройства памяти, так и на порты ввода-вывода. Однако порты не реагируют на него, так как они отключены высоким уровнем сигнала IORQ. Устройство памяти, напротив, получив сигналы RD и MREQ, выдает на шину данных байт информации из ячейки памяти, адрес которой присутствует на шине адреса. Процесс записи данных в память происходит в следующей последовательности. Сначала, как и при чтении, центральный процессор выставляет на адресную шину адрес нужной ячейки памяти. Затем на шину данных он выставляет байт, предназна- ченный для записи в эту ячейку. После этого процессор перево- дит в ноль сигнал WR. Получив все эти сигналы, ОЗУ произво- дит запись байта в выбранную ячейку. При работе с системами памяти часто используется еще один сигнал. Это сигнал готовности. Он необходим в том слу- чае, если модули памяти имеют низкое быстродействие. Такая память может не успеть выдать информацию или произвести ее запись так же быстро, как это способен сделать центральный процессор. Для согласования работы медленных устройств памяти с быстрыми процессорами существует сигнал READY (готов- ность). Сразу после того, как процессор установит сигнал чтения или записи в активное состояние, устройство памяти выдает сигнал «не готов». То есть переводит линию READY в пассивное нулевое состояние. Сигнал READY поступает на процессор. Процессор приостанав- ливает свою работу и переходит в режим ожидания. Когда устрой- ство памяти закончит выполнение процесса чтения (записи), оно устанавливает сигнал READY в единицу (состояние «Готов»). Получив этот сигнал, процессор возобновляет свою работу. Операции чтения из порта и записи в порт происходят анало- гично операциям чтения/записи ОЗУ. Различие лишь в том, что вместо сигнала MREQ в активное состояние переходит сигнал IORQ, разрешающий работу портов. Для работы с медленными внешними устройствами также используется сигнал READY.
ГЛАВА 11 АЛГОРИТМ РАБОТЫ МИКРОПРОЦЕССОРНОЙ СИСТЕМЫ Возможности II процессора II Мы узнали, как микропроцессор осуществляет работу с периферийными устройствами — процессор читает числа из этих устройств и записывает информацию. Однако, кроме чте- ния и записи, процессор производит множество других опера- ций по обработке полученной информации. С электронными числами процессор способен производить любые виды преобразований, которые вообще возможны с числами. Может складывать числа, вычитать, сравнивать между собой. Кроме того, он способен производить сдвиг раз- рядов двоичного числа вправо или влево, поразрядные логи- ческие операции. К логическим операциям относятся: ♦ логическое умножение (операция «И»); ♦ логическое сложение (операция «ИЛИ»); ♦ инверсия (операция «НЕ»).
104 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. Некоторые процессоры умеют производить так- же умножение и деление. Однако нужно понимать, что все эти операции микропроцессор проделы- вает с простыми восьмиразрядными (иногда с шестнадцатиразрядными) двоичными числами. Все перечисленные выше операции производятся аппарат- ным образом. Для этого микропроцессор содержит ряд логи- ческих модулей, подобных тем, которые мы рассматривали в предыдущей части книги. Все они состоят из набора логиче- ских элементов, регистров и т. п. Примером может служить рассмотренный выше сумматор. ПРИМЕЧАНИЕ. Главная же особенность микропроцессора в том, что все эти операции выполняются между про- стыми двоичными числами размером в один (ино- гда два) байта. Но этого вполне достаточно. Любую более сложную задачу всегда можно разложить на более простые составляющие и свести к операциям с байтами. Например, для того, чтобы перемножить два многоразрядных десятичных числа, их можно сначала перевести в двоичный вид и записать каждое такое число в несколько ячеек памяти. Затем составить небольшую программку, которая будет перемножать эти числа байт за байтом, а результаты складывать с учетом раз- рядности. Главное — составить правильный алгоритм.
Глава 11. Алгоритм работы микропроцессорной системы 105 Программа Как же заставить процессор выполнять все эти операции в нужной нам последовательности? Для этого нужно создать программу. Каждая операция, которую способен выполнять конкретный микропроцессор, кодируется некоторым чис- лом. Это число называется кодом операции. Коды опера- ций записываются последовательно, один за другим в память микропроцессорной системы (в ОЗУ либо в ПЗУ). Процессор последовательно, байт за байтом, читает коды операций и выполняет их по мере поступления. ЧТО ЕСТЬ ЧТО. Программа - это последовательность операций, которую должен выполнять процессор. Она запи- сывается в память в виде последовательности кодов. В простых процессорах для кодирования всех команд достаточно одного байта. Одна команда — один байт. В более сложных процессорах число команд возрастает настолько, что одного байта для их кодирования не хватает. В этом случае для кодирования команд используют два, а иногда и более байтов. Причем чаще всего применяют гибкую систему кодирования. В такой системе одни команды кодируются одним байтом, дру- гие двумя и так далее. ПРИМЕЧАНИЕ. Обратите внимание, что кодировка учитывает частоту применения той или иной команды. Чем чаще команда встречается в программах, тем короче ее код.
106 ARDUINO: от азов программирования до создания... Для кодирования команд недостаточно указать код, опре- деляющий вид операции. Например, для команды сложения двух чисел процессору нужно указать: ♦ адрес ячейки, где хранится первое число; ♦ адрес второго числа; ♦ адрес, куда нужно поместить результат. Поэтому каждая команда, кроме кода операции, может содержать еще один или несколько параметров. Это не обя- зательно адреса операндов (как в приведенном примере). Параметрами могут служить константы, номера вспомогатель- ных регистров и другие специальные коды. Существуют самые разные способы кодировки команд. Иногда команда состоит из двух байт: ♦ первый байт — это код операции; ♦ второй байт — параметр. ПРИМЕЧАНИЕ. Бывает так, что вся команда вместе с параме- трами укладывается в один байт. При этом часть битов этого байта - код операции, а другая часть - параметр. Бывают и другие варианты. В микропроцессорах серии AVR для кодировки каждой команды используется одно двухбайтовое слово. Для некото- рых особо сложных команд кодировка может состоять из двух и более слов. ПРИМЕЧАНИЕ. Систему команд микропроцессоров AVR вы може- те найти в Приложении 5 в конце книги или ин- тернете по адресу http: //fusecalc.mirmk.ru/sc/sk.htm к_____________________________.______________________
Глава 11. Алгоритм работы микропроцессорной системы 107 Процесс выполнения команды Теперь рассмотрим сам процесс выполнения программы. Чтобы микропроцессор мог последовательно читать команды из памяти, внутри него имеется специальный регистр, называ- емый регистром адреса или счетчиком команд. В этом реги- стре хранится адрес текущей выполняемой команды. Работа микропроцессора всегда начинается с процедуры начального сброса. Сброс микропроцессора сводится к уста- новке всех его регистров в исходное состояние. В регистр адреса после сброса записывается адрес начала программы. Адрес начала программы зависит от модели микропроцессора и опре- деляется его разработчиком. Чаще всего этот адрес равен нулю. Сразу по окончании процесса начального сброса начина- ется выполнение программы. Для начала процессор читает число из программной памяти, т. е. из ячейки, адрес которой записан в регистр адреса. В нашем случае — из ячейки с нуле- вым адресом. Прочитанное число он воспринимает как код первой команды. Процессор анализирует код и выполняет соответствующую команду. Если команда предполагает наличие еще одного или нескольких байтов с параметрами, то перед тем, как выполнять команду, процессор читает нужное количество байт из после- дующих ячеек памяти. При этом он каждый раз увеличивает содержимое регистра адреса. После выполнения первой команды процессор снова уве- личивает значение счетчика команд на единицу и приступает к чтению и выполнению следующей команды. ПРИМЕЧАНИЕ. Этот процесс повторяется бесконечно, пока на процессор подано напряжение питания. Таким об- разом, нормально работающий процессор всегда находится в процессе выполнения программы. Правда, существуют несколько исключений.
108 ARDUINO: от азов программирования до создания... Первое исключение. В частности, в системе команд микро- процессора обычно имеется специальная команда останова. Если в процессе выполнения программы встретится такая команда, процессор останавливается. То есть прекращает выпол- нение программы. Запуск процессора в этом случае возможен лишь после системного сброса либо в результате внешнего пре- рывания. О том, что такое прерывание, мы еще поговорим. Второе исключение — режим сна. Некоторые модели микроконтроллеров способны переходить в специальный режим низкого потребления энергии, который называется режимом сна или спящим режимом. В спящем режиме выполнение про- граммы также приостанавливается. Режим сна удобен в том слу- чае, когда микропроцессорная система вынуждена долгое время находиться в состоянии ожидания. Например, ожидание нажа- тия кнопки «Пуск». Такой процессор способен в нужный момент пробудиться из режима сна и продолжить работу. Рабочие регистры Кроме регистра адреса, любой микропроцессор обяза- тельно имеет несколько рабочих регистров (так называемых регистров общего назначения). Эти регистры наряду с ячей- ками памяти предназначены для хранения промежуточных результатов вычислений. ПРИМЕЧАНИЕ. Преимущество внутренних регистров для хране- ния данных перед памятью данных - в скорости доступа. При доступе к этим регистрам не нужно указывать адрес, как в случае с доступом к ячейке памяти. Так, команда записи в память состоит минимум из двух байт: кода операции и адреса ячейки памяти.
Глава 11. Алгоритм работы микропроцессорной системы 109 Иногда для записи адреса одной ячейки не хватает. Если шина адреса процессора имеет 16 разрядов, то для адресации ячейки памяти потребуется два байта. Поэтому такая команда будет содержать не менее трех байт. Команды, работающие с внутренними регистрами микропроцессора, обычно состоят из одного байта. Сам код операции содержит информацию о номере исполь- зуемого регистра. Чтение и выполнение таких команд про- исходит гораздо быстрее. Кроме того, внешняя память часто сама имеет меньшее быстродействие, чем процессор. Наличие нескольких внутренних регистров с быстрым доступом позво- ляет оптимально использовать память. Часто используемые данные стараются помещать в рабочие регистры. ПРИМЕЧАНИЕ. Микроконтроллеры серии AVR для хранения программ используют отдельную память, каж- дая ячейка которой состоит из одного шест- надцатиразрядного слова. То есть каждая ко- манда состоит минимум из двух байт. Эти два байта содержат и код операции, и параметры. Если двух байт не хватает, то добавляется еще два байта. То есть байты всегда читают- ся парами. Команды II микропроцессора II Теперь остановимся подробнее на выполняемых командах. Весь набор команд любого микропроцессора можно разделить на несколько групп. Первая группа — это команды перемещения данных. Повинуясь этим командам, процессор копирует содержимое одной ячейки памяти в другую, копирует информацию из ячейки
110 ARDUINO: от азов программирования до создания... памяти в один из внутренних регистров либо, наоборот, копирует содержимое регистра в одну из ячеек памяти. Кроме того, данные могут копироваться из одного внутреннего регистра в другой. ПРИМЕЧАНИЕ. Следует заметить, что так называемые коман- ды перемещения, по сути, не перемещают дан- ные из ячейки в ячейку, а копируют эти данные. Операция перемещения в цифровой технике бес- смысленна. В общепринятом понимании переме- стить означает убрать из одного места и по- местить в другое. Но убрать данные из ячейки памяти невозможно! Любой бит любой ячейки памяти всегда равен либо нулю, либо единице. То есть всегда содержит какое-либо число. Поэтому команды перемещения считывают байт данных из ячейки-источника и записывают их в ячейку-приемник. При этом в ячейке-источнике данные не изменяются. Вторая группа — команды преобразования данных. Именно в эту группу входят команды сложения, вычитания, логических преобразований, сдвига разрядов и т. д. Третья группа — команды передачи управления. Вот об этом классе команд я хотел бы поговорить подробнее. Сложно представить себе программу, состоящую лишь из одной после- довательной цепочки команд. Подавляющее число алгоритмов требуют разветвления программы. Это значит, что программа должна уметь выполнять разные последовательности действий в зависимости от некоторого условия. ПРИМЕР. Допустим, что наше микропроцессорное устрой- ство имеет кнопки управления. При нажатии каждой кнопки должно выполняться свое определенное дей-
Глава 11. Алгоритм работы микропроцессорной системы 111 ствие. Например, при нажатии одной кнопки испол- нительный механизм должен повернуться влево. При нажатии другой - повернуться вправо и т.п. Чтобы это было возможно, программа периодически считы- вает состояние кнопок. Затем программа должна оценить их состояние. Если нажата первая кнопка, выполняется некая последовательность команд, вы- дающая на соответствующий порт код, приводящий к включению двигателя в прямом направлении. Если нажата вторая кнопка, то выполняется другая по- следовательность команд, выдающая в тот же порт совсем другой код. Этот код должен вызвать включе- ние двигателя в реверсном направлении. Очевидно, что для реализации данного алгоритма придется прервать последовательное выполнение команд. Чтобы про- грамма имела возможность менять алгоритм своей работы в зависимости от какого-либо условия, в системе команд любого процессора обязательно имеются команды передачи управле- ния. Рассмотрим все эти виды команд по порядку. К командам передачи управления относятся следующие виды команд: ♦ команды условного перехода; ♦ команды безусловного перехода; ♦ команды перехода к подпрограмме; * команды организации цикла. Команды условного II и безусловного перехода || Оба этих вида команд предназначены для того, чтобы пре- рывать последовательное выполнение программы и вызывать так называемый переход. Причем условный переход происхо- дит только при соблюдении какого-либо условия. Безусловный переход выполняется всегда, как только программа встретит соответствующую команду.
112 ARDUINO: от азов программирования до создания... В качестве условий перехода может выступать одно из сле- дующих логических выражений: ♦ величина А равна величине В; ♦ величина А не равна величине В; ♦ величина А меньше величины В; ♦ величина А больше величины В; ♦ величина А меньше или равна величине В; ♦ величина А больше или равна величине В. В качестве величин для сравнения может выступать содер- жимое любых внутренних регистров процессора, содержимое любых ячеек памяти или просто константы. ПРИМЕР. Рассмотрим пример применения условного и без- условного переходов. Для наглядности изобразим цепочку команд в программной памяти в виде по- следовательности графических элементов (см. рис. 11.1). Ход выполнения программы показан при помощи стрелок. Квадратиками обозначены обычные команды (команды перемещения и ко- манды преобразования данных). Кружочек с вопросом - это команда условного перехода. Скругленный элемент с восклицательным зна- ком - это безусловный переход. Такая программа имеет две ветви. В случае если ус- ловие есть ложь, выполняется ветвь номер 1. В случае если условие - истина, выполняется ветвь номер 2. Если условие Рис. 11.1. Работа операторов условного и безусловного переходов
Глава 11. Алгоритм работы микропроцессорной системы ИЗ Допустим, что условный переход производит сравнение кода нажатой клавиши с некоторой константой. Тогда действие, выполняемое условным оператором, можно записать так: «Если код нажатой клавиши равен 0, перейти к выполнению ветви номер 2». Соответственно, в случае невыполнения условия (напри- мер, считанное число равно 1), программа продолжит свою работу в обычном режиме и перейдет, таким образом, к выпол- нению ветви номер 1. В конце ветви номер 1 стоит оператор безусловного пере- хода. Он служит для того, чтобы программа не начала выпол- нять ветвь номер 2 сразу после выполнения ветви номер 1. В данном случае выполнение перехода обязательно и никакого условия не требуется. Технически переход выполняется путем записи в регистр адреса нового значения. Изменение значения регистра адреса возможно только при помощи команд передачи управления. Команда II организации цикла II Циклическое выполнение группы команд — очень эффек- тивное средство для сокращения программного кода. Иногда требуется выполнить одну и ту же группу команд несколько раз. Вместо того чтобы много раз записывать одни и те же команды, можно заставить любой участок программы выполняться мно- гократно. Для этого и служат команды организации цикла. Допустим, мы хотим создать простейшую программу, предотвращающую ложное срабатывание кнопки. Допустим, нажатая кнопка при считывании дает единицу, отпущенная — ноль. Для повышения надежности мы будем считывать состо- яние кнопки не один, а несколько раз. Все полученные таким образом числа мы сложим между собой. Затем мы легко можем определить, каких результатов было больше: нулевых либо единичных.
114 ARDUINO: от азов программирования до создания... ЧТО ЕСТЬ ЧТО. Допустим, что мы будем производить подряд 20 операций чтения-сложения. Теперь, если получен- ная сумма окажется больше десяти, то кнопку можно считать нажатой. В противном случае она считается отпущенной. Такой алгоритм на- зывается цифровой интегрирующий фильтр. Операции считывания состояния кнопки и сложения полученных результатов удобно оформить в виде цикла. На рис. 11.2 показан ход выполнения подобной программы. Как и на предыдущем рисунке, квадратиками обозначены обычные операторы. Кружком с буквой Ц обозначен оператор цикла. ПРИМЕЧАНИЕ. Часть программы, называемая телом цикла, вы- полняется нужное количество раз. Каждое такое выполнение называется проходом цикла. Важным элементом оператора цикла служит так называе- мый параметр цикла. ЧТО ЕСТЬ ЧТО. Параметр цикла - это число, которое сначала равно количеству проходов. При каждом новом проходе параметр цикла уменьшается. Обычно параметр цикла записывается в один из рабочих регистров процессора. В нашем случае параметр цикла равен 20. На рис. 11.2 показаны несколько команд, которые выполняются до начала цикла. Среди этих команд обязательно должна быть команда, записывающая в соответствующий регистр значение параме- тра цикла. Затем выполняется тело цикла.
Глава 11. Алгоритм работы микропроцессорной системы 115 Тело цикла Если исчерпан счетчик циклов Рис. 11.2. Демонстрация работы оператора цикла В нашем случае тело цикла — это команды считывания состояния клавиши и сложения полученных результатов. После выполнения тела цикла наступает очередь оператора цикла. Оператор цикла выполняет следующие действия: ♦ уменьшает параметр цикла на единицу; ♦ проверяет, не равен ли параметр после уменьшения нулю; ♦ если не равен, то оператор осуществляет переход к началу цикла; ♦ если же параметр равен нулю, переход не производится и выполнение программы продолжается в обычном режиме. ПРИМЕЧАНИЕ. В результате такой оператор вызывает много- кратное выполнение тела цикла до тех пор, пока со- держимое параметра цикла не достигнет нуля. При достижении нуля цикл заканчивается, и программа продолжает выполняться в обычном режиме. Команды перехода II к подпрограмме II что есть что. Подпрограмма - это некоторый участок про- граммы, к выполнению которого программа мо- жет возвращаться несколько раз.
116 ARDUINO: от азов программирования до создания... Такой прием применяется в том случае, если одни и те же действия нужно выполнять в разных местах программы. Для этого любую последовательность команд можно оформить в виде подпрограммы. В нужном месте основная программа вызывает подпрограмму. После выполнения подпрограммы управление передается в то место, откуда произошел ее вызов. Одна и та же подпрограмма может быть вызвана любое коли- чество раз из самых разных мест основной программы. Для организации подпрограмм любой процессор содержит как минимум две специальные команды: ♦ команду перехода к подпрограмме; ♦ команду выхода из подпрограммы. Существуют также команды перехода к подпрограмме по условию. Процесс обращения к подпрограмме показан на рис. 11.3. Слева от многоточия показана цепочка команд, составляющих основную программу. Точками обозначена та часть основной программы, которая нас сейчас не интересует. Где-то после окончания основной программы в памяти распо- ложен текст подпрограммы. Рис. 11.3. Демонстрация работы операторов организации подпрограммы Как и в предыдущих случаях, квадратиками обозначены обычные команды: ♦ элемент с буквой «П» — это команда перехода к подпро- грамме; ♦ элемент с буквой «В» — это команда возврата из подпро- граммы. По команде перехода к подпрограмме микропроцессор запоминает текущий адрес (значение счетчика программ). Затем управление передается на начало подпрограммы.
Глава 11. Алгоритм работы микропроцессорной системы 117 В конце подпрограммы обязательно должна стоять команда выхода из подпрограммы. Встретив эту команду, процессор извлекает из памяти адрес, откуда произошел вызов подпрограммы, и переходит к команде, непосредственно сле- дующей за этим адресом. После этого программа выполняется в обычном режиме. Использование подпрограмм позволяет увеличить струк- турированность вашей программы. При чтении текста незна- комой программы каждая подпрограмма воспринимается как отдельная законченная процедура. ПРИМЕЧАНИЕ. Каждая такая процедура представляет собой законченный программный блок со своими свой- ствами и назначением. Из этих блоков, как из кирпичиков, удобно строить основную программу Написанная таким образом программа становится удобнее для понимания. Поэтому иногда подпрограммы используют даже в том случае, когда в основной программе они использу- ются только один раз. Итак, мы рассмотрели основные принципы работы микро- процессорной системы. Все описанное выше относится к основному режиму работы. Однако для повышения эффектив- ности работы большинство процессоров обычно имеют еще два не менее важных режима работы. Это режим прерывания и режим прямого доступа к памяти. На структурной схеме типового микропроцессорного устройства (рис. 10.1) для простоты не показаны элементы, которые и предназначены для работы в двух дополнитель- ных режимах. Теперь настал момент познакомиться с ними. Начнем с механизма прерываний.
ГЛАВА 12 СПЕЦИАЛЬНЫЕ РЕЖИМЫ РАБОТЫ МИКРОПРОЦЕССОРНОЙ СИСТЕМЫ Механизм прерываний ЗАДАЧА. На вход некоего микропроцессорного устройства поступают некие импульсы, которые процессор должен постоянно считать. Например, импуль- сы от датчика вращения колеса автомобиля в системе электронного спидометра. Спидометр должен постоянно подсчитывать эти импульсы, чтобы получить величину пробега автомобиля. Одновременно спидометр должен заниматься измерением скорости и другими вспомогатель- ными операциями. Например, опрашивать клави- атуру, выполнять введенные с нее команды, вы- водить информацию на индикаторы.
Глава 12. Специальные режимы работы микропроцессорной системы 119 Если включить команду опроса порта, на который посту- пают данные импульсы в общую управляющую программу, то в момент поступления импульса с датчика процессор может быть занят другой операцией. В результате некоторые импульсы могут быть пропущены. Именно для таких случаев и был придуман механизм прерывания. Для этого любой процессор имеет как минимум один спе- циальный вход запроса на прерывание. Именно на этот вход Необходимо подать наши импульсы, предназначенные для подсчета. Когда очередной импульс приходит на вход запроса прерывания, включается внутренний алгоритм обработки пре- рывания, заложенный в микропроцессор. ПРИМЕЧАНИЕ. Выполнение основной программы прерывается, а управление передается на специальную процеду- ру обработки прерывания. Эта процедура явля- ется составной частью основной управляющей программы, которую разрабатывает програм- мист при создании микропроцессорной системы. Адрес начала процедуры обработки прерывания определя- ется типом микропроцессора. Процедура обработки прерыва- ния должна выполнить те действия, которые необходимы при поступлении сигнала. В нашем случае это могут быть: ♦ алгоритм цифровой фильтрации; ♦ увеличение на единицу содержимого ячейки памяти, где хранится количество поступивших импульсов. Подпрограмма обработки прерывания завершается специ- альной командой выхода из прерывания. Эта команда подобна команде выхода из подпрограммы. Поэтому после окончания процедуры обработки прерывания микропроцессор возвраща- ется к тому месту основной программы, где произошло пре- рывание.
120 ARDUINO: от азов программирования до создания... ВЫВОД. Процедура обработки прерывания и подпрограм- ма очень похожи. Отличие только в том, что пе- реход к подпрограмме происходит по специаль- ной команде, а вызов процедуры обработки пре- рывания - по приходу внешнего сигнала. Поэтому прерывание может произойти на любом этапе выполнения основной программы. В результате применения механизма прерывания мы достигаем эффекта независимости двух процессов. Получается, что основная программа выполняется как бы сама по себе, а подсчет импульсов от датчика при этом выполняется как бы отдельно. Машинное время микропроцессора распределяется между двумя этими процессами таким образом, что они оба выполняются независимо друг от друга. Механизм прерываний широко применяется как в микропроцессорной технике, так и в больших компьютерах. ПРИМЕЧАНИЕ. Хороший пример задачи, решаемой при помо- щи прерывания, - это работа манипулятора «мышь» персонального компьютера. Какую бы сложную программу ни выполнял компьютер, но указатель всегда свободно бегает по экрану, по- винуясь движениям мыши. Бывает, что программа или несколько программ «зависли». Но указатель мыши живет. Мышь обычно зависает только в самом крайнем случае при серьезном сбое системы. Все это происходит благодаря тому, что манипулятор «мышь» работает по прерыванию. Когда вы перемещаете манипулятор по столу, специальный механизм внутри мыши преобразует эти пере-
Глава 12. Специальные режимы работы микропроцессорной системы 121 мещения в электронные сигналы, которые передаются на один из входов компьютера. Специальная схема внутри компьютера принимает эти сиг- налы и вырабатывает запрос на прерывание для микропроцес- сора. Получив этот запрос, процессор прерывает выполнение основной программы и выполняет процедуру перемещения изображения мышиного курсора по экрану. При каждом прерывании курсор перемещается всего лишь на один шажок. Затем процессор возвращается к выполнению своей основной программы. В результате вы наблюдаете сво- бодное перемещение курсора мыши по экрану на фоне выпол- няющихся программ. Механизм прерывания в персональном компьютере исполь- зуется не только для мыши. Это очень распространенный прием. Любой современный процессор имеет сложную многоуровне- вую систему прерываний, позволяющую обрабатывать преры- вания одновременно от нескольких источников. По прерыва- нию работают такие устройства, как клавиатура, жесткий диск, внутренние системные часы, порт принтера и многое другое. Прямой доступ II к памяти II Второй специальный режим работы микропроцессорной системы называется режимом прямого доступа к памяти. В этом режиме нарушается основной принцип всей микро- процессорной системы. Теперь системой управляет не микро- процессор, а специальный контроллер прямого доступа к памяти (контроллер ПДП). Прямой доступ к памяти применяется для ускорения работы в том случае, когда необходимо записать в память либо прочитать из памяти большой блок информации.
122 ARDUINO: от азов программирования до создания... ПРИМЕР. Рассмотрим печать текста на скоростном принтере. Если производить печать в обычном режиме работы, то необходимо написать некую подпрограмму, которая должна побайтно чи- тать данные из памяти и выдавать их на порт принтера. Для чтения каждого байта процессор должен выполнить 5-4 команды. Если принтер скоростной, то процессор может не обеспечить требуемую скорость печати. В этом случае при- меняют прямой доступ к памяти. Для реализации этого режима микропроцессорная система должна иметь в своем составе специальное устройство — кон- троллер прямого доступа (см. рис. 12.1). Сначала всем управляет микропроцессор. Перед тем, как начать печать, он производит подготовку сеанса прямого доступа. Для этого он программирует микросхему контрол- лера. Программирование сводится к записи в управляющие регистры контроллера специальных кодов, которые и опреде- ляют в дальнейшем его работу. При помощи этих кодов про- цессор должен определить начальный и конечный адрес блока данных в памяти, подлежащих передаче и направление пере- дачи информации. Затем центральный процессор подает команду на кон- троллер, которая запускает сеанса прямого доступа. С этого момента управление системой берет на себя микроконтрол- шд ША ШУ DRQ0 DRQ1 DRQ2 DRQ3 DRQ4 Рис. 12.1. Подключение контроллера прямого доступа к памяти
Глава 12. Специальные режимы работы микропроцессорной системы 123 лер ПДП, а центральный процессор отключается. Контроллер отвечает за формирование адреса на соответствующей шине, а также именно он формирует управляющие сигналы RD, WR, MREQ и IORQ на шине управления. При помощи этих сигна- лов контроллер прямого доступа выполняет довольно простую операцию. В нашем примере он читает байт за байтом данные из зара- нее определенной области памяти и выдает их в порт прин- тера. По завершении процесса передачи контроллер подает специальный сигнал микропроцессору, тот включается и берет на себя управление системой. Кроме выдачи данных из памяти в порт, контроллер пря- мого доступа может также осуществлять считывание блока дан- ных из порта и запись его в заранее заданную область памяти. А также может осуществлять передачу данных из одной обла- сти памяти в другую. Рассмотрим подробнее схему подключе- ния контроллера ПДП (рис. 12.1). ПРИМЕЧАНИЕ. Как уже говорилось, микросхема контроллера ПДП - это программируемое устройство. В дан- ном случае понятие «программируемое» означает то, что микросхема имеет внутри специальные регистры, которые подключаются к системной шине как порты ввода-вывода. Процессор может записывать в эти порты различные коды и, тем самым, менять режимы работы микросхемы. Чтобы запустить процесс прямого доступа к памяти, цен- тральный процессор должен сначала запрограммировать кон- троллер. Затем, при помощи тех же самых программируемых регистров, процессор передает на контроллер команду запуска процесса ПДП, а сам продолжает свою работу. Получив команду запуска, контроллер ПДП ждет сигнала на одном из специаль- ных входов DRQO—DRQ4 (см. рис. 12.1).
124 ARDUINO: от азов программирования до создания... В нашем случае сигнал запроса ПДП поступает от принтера в тот момент, когда он окажется готовым к работе. Этот сиг- нал называется «сигнал запроса на ПДП». Получив запрос на ПДП, контроллер формирует запрос на захват центрального процессора (сигнал HOLD). Получив сигнал HOLD, процессор приостанавливает выполнение текущей программы и пере- ходит в пассивный режим. Все выводы процессора отключа- ются от шины данных, шины адреса и шины управления и не мешают дальнейшей работе системы. О своей готовности к работе в режиме захвата процессор сообщает контроллеру ПДП при помощи сигнала подтверж- дения захвата (HLDA). Лишь после этого начинается передача данных под управлением контроллера ПДП. По окончании процесса передачи данных контроллер ПДП отключается от системной шины и снимает с процессора сигнал HOLD. После снятия сигнала процессор возобновляет свою работу в обыч- ном режиме. ПРИМЕЧАНИЕ. В микроконтроллерах режим прямого доступа к памяти применяется очень редко. Зато в лю- бом персональном компьютере прямой доступ применяется достаточно широко. Кроме порта принтера, прямой доступ используют сетевые и звуковые карты, а также накопители на гибких и жестких дисках.
ЧАСТЬ III ^^ЗНАКОМТЕСЬ: МИКРОКОНТРОЛЛЕРЫ AVR, ОСНОВА ПЛАТ ARDUINO Оригинальные платы и устройства Arduino построены на микроконтрол- лерах AVR фирмы Atmel, например, АТтеда328, АТтеда168, АТтеда2560, ATmega32U4,ATTiny85. Поэтому в книге по ARDUINO изучаем конкретный вид микро- контроллеров - микроконтроллеры AVR. Рассмотрим состав семейства микросхем этого типа, основные характеристики, их внутреннюю архитектуру, принципы работы и взаимодействия всех встроен- ных систем. Это поможет нам в дальней- шем при создании и программировании устройств на ARDUINO.
ГЛАВА 13 ВОЗМОЖНОСТИ И ОСОБЕННОСТИ ПОСТРОЕНИЯ МИКРОКОНТРОЛЛЕРОВ AVR Микроконтроллеры - кто они? В классической микропроцессорной системе, изображен- ной на рис. 10.1, используются отдельная микросхема про- цессора, отдельные микросхемы памяти и отдельные порты ввода-вывода. Стремительное развитие микропроцессорной техники требует все большей и большей степени интеграции микросхем. Именно поэтому были разработаны микросхемы, кото- рые объединяют в себе сразу все элементы микропроцес- сорной системы. Такие микросхемы называются микрокон- троллерами. В советское время такие микросхемы называли «Однокристальные микроЭВМ». Для однокристальных микроконтроллеров понятие «цен- тральный процессор» обычно не употребляется. Так как про- цессор — это все-таки отдельное устройство. Функции процес- сора в микроконтроллере заменяет арифметико-логическое устройство (АЛУ).
Глава 13. Возможности и особенности построения микроконтроллеров AVR 127 Кроме АЛУ, микроконтроллер содержит в своем составе: ♦ тактовый генератор; ♦ память данных; ♦ память программ; ♦ порты ввода-вывода. Все эти элементы соединены между собой внутренними шинами данных и адреса. С внешним миром микроконтроллер общается при помощи портов ввода-вывода. ПРИМЕЧАНИЕ. Любой микроконтроллер всегда имеет один или несколько портов. Кроме того, современные микроконтроллеры всегда имеют встроенную систему прерываний, а также встроенные про- граммируемые таймеры, компараторы, цифроа- налоговые преобразователи и многое другое. Если речь идет не о большом компьютере, а о портативном устройстве управления, то в нем применяются именно микро- контроллеры. Конечно, любая реальная схема редко обходится без простых логических микросхем, триггеров, счетчиков и тому подобного. Но основой всегда является микроконтроллер. Чистые микропроцессоры в настоящее время применяются только в персональных компьютерах. Особенности новой серии II микроконтроллеров II Итак, в предыдущем разделе мы рассмотрели общие прин- ципы работы микропроцессорной системы. Теперь рассмо- трим, как это выглядит на примере конкретных микрокон- троллеров.
128 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. В первом моем Самоучителе по микропроцессорной технике (вышел в издательстве «Наука и Техника» в далеком 2005 году) в качестве примера был использо- ван микроконтроллер АТ89С2051. Это одна из микро- схем популярной в свое время серии АТ89 фирмы AtmeL Главным преимуществом этой серии была совмести- мость с микроконтроллерами iMCS-51 фирмы Intel, которые, в свою очередь, были очень распространены в 80-е годы прошлого (двадцатого) столетия. Однако в настоящее время все эти микросхемы устарели. На смену им пришли новые типы микроконтроллеров. Фирма Atmel тоже не стоит на месте. Самая современная разработка этой фирмы на сегодняшний день — это микроконтроллеры серии AVR. Микросхемы этой серии достаточно распростра- нены и популярны во всем мире. Поэтому в настоящей книге мы остановимся именно на этих микроконтроллерах. I Семейство микроконтроллеров AVR В пределах серии микроконтроллеры подразделяются на несколько семейств. Устаревшее семейство «Classic» в настоя- щее время уже не используется. Основу серии составляют: ♦ семейство «Tiny»; ♦ семейство «Mega». Семейство микроконтроллеров «Tiny» — это микрокон- троллеры минимальной конфигурации и, преимущественно, небольших габаритов, предназначенные для простых недоро- гих и миниатюрных электронных устройств управления. Они имеют минимальный набор возможностей и невысокую цену. Микроконтроллеры семейства «Mega», напротив, имеют развитую архитектуру и предназначены для более мощных микропроцессорных систем.
Глава 13. Возможности и особенности построения микроконтроллеров AVR 129 ПРИМЕЧАНИЕ. Кроме того, фирма Atmel выпускает еще несколь- ко видов микроконтроллеров, которые она так- же относит к серии AVR. \_____________________________________________/ Таблица параметров микроконтроллеров ПРИМЕЧАНИЕ. В данной главе мы рассмотрим основные возмож- ности и особенности построения всей серии ми- кроконтроллеров AVR. Таким образом, мы перейдем от теоретических рассуждений к практическим вопросам конкретного устройства микросхем. Все микросхемы AVR строятся по единому принципу и имеют единую систему команд, которая для разных моделей микроконтроллеров может отличаться лишь в наличии либо отсутствии нескольких непринципиальных команд. Поэтому целесообразно изучать всю серию микросхем как единое целое. К сожалению, в 2016 году фирма Atmel — разработчик и производитель микроконтроллеров семейства AVR была погло- щена фирмой Microchip. Новый владелец снял с производ- ства большинство микросхем производимых фирмой Atmel. Однако, в связи с огромной популярностью модуля Arduino, основой которых являются микроконтроллеры семейства AVR, решено было не снимать с производства именно эти микро- контроллеры. Наше цель — изучение именно модулей Arduino. Поэтому нам нужно изучить подробнее архитектуру, характе- ристики и принцы работы этих микроконтроллеров. Полный состав этой серии приведен далее в табл. 13.1.
Микроконтроллеры AVR. Список параметров Таблица 15.1 Микро- схема Объем памяти Коли- чество Максимальная тактовая частота (MHz) Напряжение питания Vcc (В) Каналы АЦП Каналы ЦАП Каналов ШИМ Аналоговых компараторов Количество таймеров Количество внешн. прерываний Каналы Самопрограммируема память Пикопотребление Такт, генератор 32 кГц Тип корпуса Flash (Кбайт) EEPROM (Байт) SRAM (Байт) Выв. Вх / Вых Количество Разрешение (бит) Скорость (ksps) Количество Разрешение {л TWI (I2C) UART Семейство Tiny без датчика температуры ATtiny28L 2 32 0 28 11 4 1.8...5.5 0 0 0 0 0 0 1 1 10 0 0 0 Нет Нет Нет MLF.PDIP.TQFP ATtiny26 2 128 128 20 16 16 2.Z..5.5 11 10 15 0 0 4 1 2 11 1 1 0 Нет Нет Нет SOIC, MLF, PDIP ATtinylS 1 64 64 8 6 20 1.8...5.5 4 10 15 0 0 2 1 1 6 0 0 0 Есть Нет Нет SOIC, SOIC, MLF, MLF, PDIP ATtiny2313 2 128 128 20 18 20 1.8...5.5 0 0 15 0 0 4 1 2 18 2 1 1 Есть Нет Нет SOIC, MLF, PDIP ATtinyl3A 1 64 64 8 6 20 1.8...5.5 4 10 15 0 0 2 1 1 6 0 0 0 Есть Есть Нет SOIC, SOIC, MLF, MLF, PDIP ATtinylO 1 32 0 6 4 12 1.8...5.5 4 8 15 0 0 2 1 1 4 0 0 0 Нет Нет Нет SOT23, UDFN / USON ATtiny4 0.5 32 0 6 4 12 1.8...5.5 0 0 0 0 0 2 1 1 4 0 0 0 Нет Нет Нет SOT23.UDFN/USON ATtiny5 0.5 32 0 6 4 12 1.8...5.5 4 8 15 0 0 2 1 1 4 0 0 0 Нет Нет Нет SOT23 6UDFN/USON8 ATtiny9 1 32 0 6 4 12 1.8...5.5 0 0 0 0 0 2 1 1 4 0 0 0 Нет Нет Нет SOT23 6UDFN/USON8 ATtiny2313A 2 128 128 20 18 20 1.8...5.5 0 0 15 0 0 4 1 2 18 2 1 1 Есть Есть Нет SOIC, MLF, VQFN, PDIP ATtiny4313 4 256 256 20 18 20 1.8...5.5 0 0 15 0 0 4 1 2 18 2 1 1 Есть Есть Нет SOIC, MLF, VQFN, PDIP Семейство Tiny (co встроенным датчиком температуры) ATtiny25 2 128 128 8 6 20 1.8...5.5 4 10 15 0 0 6 1 2 6 1 1 0 Есть Нет Нет SOIC, MLF, PDIP ATtiny85 8 512 512 8 6 20 1.8...5.5 4 10 15 0 0 6 1 2 6 1 1 0 Есть Нет Нет SOIC, MLF, PDIP ATtiny45 4 256 256 8 6 20 1.8...5.5 4 10 15 0 0 6 1 2 6 1 1 0 Есть Нет Нет SOIC, MLF, TSSOP.PDIP ATtiny24 2 128 128 14 12 20 1.8...5.5 8 10 15 0 0 4 1 2 12 1 1 0 Есть Нет Нет MLF, PDIP, SOIC ATtiny44 4 256 256 14 12 20 1.8...5.5 8 10 15 0 0 4 1 2 12 1 1 0 Есть Нет Нет MLF, PDIP, SOIC ATtiny84 8 512 512 14 12 20 1.8...5.5 8 10 15 0 0 4 1 2 12 1 1 0 Есть Нет Нет MLF, PDIP, SOIC ATtiny261 2 128 128 20 16 20 1.8...5.5 11 10 15 0 0 6 1 2 16 1 1 0 Есть Нет Нет SOIC, MLF, PDIP ATtiny461 4 256 256 20 16 20 1.8...5.5 11 10 15 0 0 6 1 2 16 1 1 0 Есть Нет Нет SOIC, MLF, PDIP ATtiny861 8 512 512 20 16 20 1.8...5.5 11 10 15 0 0 6 1 2 16 1 1 0 Есть Нет Нет SOIC, MLF, PDIP ATtiny48 4 256 64 32 28 12 1.8...5.5 8 10 15 0 0 2 1 2 28 1 1 0 Есть Есть Нет UFBGA, MLF, MLF, PDIP.TQFP AN О ARDUINO: от азов программирования до создания...
Таблица 13.1 (продолжение) Микро- схема Объем памяти Коли- чество Максимальная тактовая частота (MHz) Напряжение питания Vcc (В) Каналы АЦП Каналы ЦАП Каналов ШИМ Аналоговых компараторов Количество таймеров Количество внешн. прерываний Каналы Самопрограммируема память Пикопотребление Такт, генератор 32 кГц Тип корпуса Flash (Кбайт) EEPROM (Байт) SRAM (Байт) Выв. Вх/Вых Количество Разрешение (бит) Скорость (ksps) Количество Разрешение {л TWI (I2C) UART ATtiny88 8 512 64 32 28 12 1.8...5.5 8 10 15 0 0 2 1 2 28 1 1 0 Есть Есть Нет UFBGA, MLF, MLF, PDIP.TQFP ATtiny24A 2 128 128 14 12 20 1.8...5.5 8 10 15 0 0 4 1 2 12 1 1 0 Есть Есть Нет MLF, VQFN, UFBGA, PDIP, SOIC ATtiny44A 4 256 256 14 12 20 1.8...5.5 8 10 15 0 0 4 1 2 12 1 1 0 Есть Есть Нет MLF, VQFN, UFBGA, PDIP, SOIC ATtiny43U 4 256 64 20 16 8 0.7...5.5 4 10 15 0 0 4 1 2 16 1 1 0 Есть Есть Нет SOIC, MLF ATtiny261A 2 128 128 20 16 20 1.8...5.5 11 10 15 0 0 6 1 2 16 1 1 0 Есть Есть Нет SOIC.TSSOP, MLF, PDIP ATtiny461A 4 256 256 20 16 20 1.8...5.5 11 10 15 0 0 6 1 2 16 1 1 0 Есть Есть Нет SOIC,TSSOP, MLF, PDIP ATtiny861A 8 512 512 20 16 20 1.8...5.5 11 10 15 0 0 6 1 2 16 1 1 0 Есть Есть Нет SOIC, TSSOP, MLF, PDIP ATtinyl67 16 512 512 20 16 16 1.8...5.5 11 10 15 0 0 9 1 2 16 2 1 1 Есть Нет Есть TSSOP, SOIC, VQFN ATtiny87 8 512 512 20 16 16 1.8...5.5 11 10 15 0 0 9 1 2 16 2 1 1 Есть Нет Есть TSSOP, SOIC, VQFN ATtiny2O 2 128 0 14 12 12 1.8...5.5 8 10 15 0 0 3 1 2 12 1 1 0 Нет Нет Нет VQFN, UFBGA, SOIC, TSSOP ATtiny40 4 256 0 20 18 12 1.8...5.5 12 10 15 0 0 2 1 2 18 1 1 0 Нет Нет Нет SOIC, VQFN, TSSOP ATtiny84A 8 512 512 14 12 20 1.8...5.5 8 10 15 0 0 4 1 2 12 1 1 0 Есть Нет Нет MLF, VQFN, UFBGA, PDIP, SOIC Семейство Mega (co встроенным датчиком температуры) ATmega48P 4 512 256 32 23 20 1.8...5.5 8 10 15 0 0 6 1 3 24 2 1 1 нет есть есть MLF, MLF, PDIP.TQFP ATmega88P 8 IK 512 32 23 20 1.8...5.5 8 10 15 0 0 6 1 3 24 2 1 1 есть есть есть MLF, PDIP.TQFP ATmegal68P 16 IK 512 32 23 20 1.8...5.5 8 10 15 0 0 6 1 3 24 2 1 1 есть есть есть MLF, PDIP.TQFP ATmegal6U4 16 2K 512 44 26 16 2.7...5.5 12 10 15 0 0 8 1 4 13 2 1 1 есть нет нет VQFN.TQFP ATmega328P 32 2K 1024 32 23 20 1.8...5.5 8 10 15 0 0 6 1 3 24 2 1 1 есть есть есть MLF. PDIP.TQFP ATmega32U4 32 3K 1024 44 26 16 2.7...5.5 12 10 15 0 0 8 1 4 13 2 1 1 есть нет нет VQFN.TQFP ATmega48PA 4 512 256 32 23 20 1.8...5.5 8 10 15 0 0 6 1 3 24 2 1 1 нет есть есть UFBGA, MLF. MLF, PDIP.TQFP ATmegal68PA 16 IK 512 32 23 20 1.8...5.5 8 10 15 0 0 6 1 3 24 2 1 1 есть есть есть UFBGA. MLF, PDIP.TQFP ATmegal6Ml 16 IK 512 32 27 16 2.7...5.5 11 10 125 1 10 10 4 2 27 1 0 1 есть нет нет MLF.TQFP ATmega32Ml 32 2K 1024 32 27 16 2.7...5.5 11 10 125 1 10 10 4 2 27 1 0 1 есть нет нет MLF.TQFP ATmega328 32 2K 1024 32 23 20 1.8...5.5 8 10 15 0 0 6 1 3 24 2 1 1 есть нет есть MLF, PDIP.TQFP Глава 13. Возможности и особенности построения микроконтроллеров AVR 131
Таблица 13.1 (продолжение) Микро- схема Объем памяти Коли- чество Максимальная тактовая частота (MHz) Напряжение питания Vcc (В) Каналы АЦП Каналы ЦАП Каналов ШИМ Аналоговых компараторов Количество таймеров Количество внешн. прерываний Каналы Самопрограммируема память Пикопотребление Такт, генератор 32 кГц Тип корпуса Flash (Кбайт) EEPROM (Байт) SRAM (Байт) Выв. Вх/Вых Количество Разрешение (бит) Скорость (ksps) Количество Разрешение (л TWI (I2C) UART ATmega64Ml 64 4К 2048 32 27 16 2.Z..5.5 11 10 125 1 10 10 4 2 27 1 0 1 есть нет нет MLF.TQFP АТтеда48А 4 512 256 32 23 20 1.8...5.5 8 10 15 0 0 6 1 3 24 2 1 1 нет нет есть UFBGA, MLF, MLF, PDIP.TQFP АТтеда88А 8 1К 512 32 23 20 1.8...5.5 8 10 15 0 0 6 1 3 24 2 1 1 есть нет есть UFBGA, MLF.PDIP.TQFP АТтеда88РА 8 1К 512 32 23 20 1.8...5.5 8 10 15 0 0 6 1 3 24 2 1 1 есть есть есть UFBGA, MLF, MLF, PDIP.TQFP АТтеда168А 16 1К 512 32 23 20 1.8...5.5 8 10 15 0 0 6 1 3 24 2 1 1 есть нет есть UFBGA, MLF.PDIP.TQFP Семейство Меда (без встроенного датчика температуры) АТтеда8 8 1К 512 32 23 16 2.Z..5.5 8 10 15 0 0 3 1 3 2 1 1 1 есть нет есть MLF.PDIP.TQFP АТтеда8515 8 512 512 44 35 16 2.Z..5.5 0 0 0 0 0 3 0 2 3 1 0 1 есть нет нет MLF.PDIP.TQFP АТтеда8535 8 512 512 44 32 16 2.Z..5.5 8 10 15 0 0 4 1 3 3 1 1 1 есть нет есть MLF.PDIP.TQFP АТтеда16 16 1К 512 44 32 16 2.Z..5.5 8 10 15 0 0 4 1 3 3 1 1 1 есть нет есть MLF.PDIP.TQFP АТтеда32 32 2К 1024 44 32 16 2.Z..5.5 8 10 15 0 0 4 1 3 3 1 1 1 есть нет есть MLF.PDIP.TQFP АТтеда64 64 4К 2048 64 53 16 2.Z..5.5 8 10 15 0 0 7 1 4 8 1 1 2 есть нет есть MLF.TQFP АТтеда128 128 4К 4096 64 53 16 2.Z..5.5 8 10 15 0 0 7 1 4 8 1 1 2 есть нет есть MLF.TQFP АТтеда162 16 1К 512 44 35 16 1.8...5.5 0 0 0 0 0 6 1 4 3 1 0 2 есть нет есть MLF.PDIP.TQFP АТтеда48 4 512 256 32 23 20 1.8...5.5 8 10 15 0 0 6 1 3 24 2 1 1 нет нет есть MLF.PDIP.TQFP АТтеда88 8 1К 512 32 23 20 1.8...5.5 8 10 15 0 0 6 1 3 24 2 1 1 есть нет есть MLF.PDIP.TQFP АТтеда168 16 1К 512 32 23 20 1.8...5.5 8 10 15 0 0 6 1 3 24 2 1 1 есть нет есть MLF.PDIP.TQFP АТтеда325 32 2К 1024 64 54 16 1.8...5.5 8 10 15 0 0 4 1 3 17 2 1 1 есть нет есть MLF.TQFP АТтеда325О 32 2К 1024 100 69 16 1.8...5.5 8 10 15 0 0 4 1 3 25 2 1 1 есть нет есть TQFP АТтеда6450 64 4К 2048 100 69 16 1.8...5.5 8 10 15 0 0 4 1 3 25 2 1 1 есть нет есть TQFP АТтеда645 64 4К 2048 64 54 16 1.8...5.5 8 10 15 0 0 4 1 3 17 2 1 1 есть нет есть MLF.TQFP АТтеда329 32 2К 1024 64 54 16 1.8...5.5 8 10 15 0 0 4 1 3 17 2 1 1 есть нет есть MLF.TQFP АТтеда3290 32 2К 1024 100 69 16 1.8...5.5 8 10 15 0 0 4 1 3 32 2 1 1 есть нет есть TQFP АТтеда649 64 4К 2048 64 54 16 1.8...5.5 8 10 15 0 0 4 1 3 17 2 1 1 есть нет есть MLF.TQFP К* W KJ ARDUINO: от азов программирования до создания...
Таблица 15.1 (продолжение) Микро- схема Объем памяти Коли- чество Максимальная тактовая частота (MHz) Напряжение питания Vcc (В) Каналы АЦП Каналы ЦАП Каналов ШИМ Аналоговых компараторов Количество таймеров Количество внешн. прерываний Каналы Самопрограммируема память Пикопотребление Такт, генератор 32 кГц Тип корпуса Flash (Кбайт) EEPROM (Байт) SRAM (Байт) Выв. Вх/Вых Количество Разрешение (бит) Скорость (ksps) Количество Разрешение (л TWI (I2C) UART ATmega6490 64 4К 2048 100 69 16 1.8...5.5 8 10 15 0 0 4 1 3 32 2 1 1 есть нет есть TQFP АТтеда640 64 8К 4096 100 86 16 1.8...5.5 16 10 15 0 0 15 1 6 32 5 1 4 есть нет есть CBGA.TQFP АТтеда1281 128 8К 4096 64 54 16 1.8...5.5 8 10 15 0 0 8 1 6 17 3 1 2 есть нет есть MLF.TQFP АТтеда2561 256 8К 4096 64 54 16 1.8...5.5 8 10 15 0 0 8 1 6 17 3 1 2 есть нет есть MLF.TQFP АТтеда2560 256 8К 4096 100 86 16 1.8...5.5 16 10 15 0 0 15 1 6 32 5 1 4 есть нет есть CBGA.TQFP АТтеда1280 128 8К 4096 100 86 16 1.8...5.5 16 10 15 0 0 15 1 6 32 5 1 4 есть нет есть CBGA.TQFP АТтеда644 64 4К 2048 44 32 20 1.8...5.5 8 10 15 0 0 6 1 3 32 3 1 1 есть нет есть MLF, PDIP.TQFP АТтеда164Р 16 1К 512 44 32 20 1.8...5.5 8 10 15 0 0 6 1 3 32 3 1 2 есть есть есть MLF, PDIP.TQFP АТтеда324Р 32 2К 1024 44 32 20 1.8...5.5 8 10 15 0 0 6 1 3 32 3 1 2 есть есть есть MLF, PDIP.TQFP АТтеда165Р 16 1К 512 64 54 16 1.8...5.5 8 10 15 0 0 4 1 3 17 2 1 1 есть есть есть MLF.TQFP АТтеда169Р 16 1К 512 64 54 16 1.8...5.5 8 10 15 0 0 4 1 3 17 2 1 1 есть есть есть QFN.TQFP АТтеда644Р 64 4К 2048 44 32 20 1.8...5.5 8 10 15 0 0 6 1 3 32 3 1 2 есть есть есть MLF, PDIP.TQFP АТтеда329Р 32 2К 1024 64 54 20 1.8...5.5 8 10 15 0 0 4 1 3 17 2 1 1 есть есть есть MLF.TQFP АТтеда3290Р 32 2К 1024 100 69 20 1.8...5.5 8 10 15 0 0 4 1 3 32 2 1 1 есть есть есть TQFP АТтеда325Р 32 2К 1024 64 54 20 1.8...5.5 8 10 15 0 0 4 1 3 17 2 1 1 есть есть есть MLF.TQFP АТтеда3250Р 32 2К 1024 100 69 20 1.8...5.5 8 10 15 0 0 4 1 3 25 2 1 1 есть есть есть TQFP АТтеда1284Р 128 16К 4096 44 32 20 1.8...5.5 8 10 15 0 0 6 1 3 32 3 1 2 есть есть есть MLF, PDIP.TQFP АТтеда16А 16 1К 512 44 32 16 2.7...5.5 8 10 15 0 0 4 1 3 3 1 1 1 есть нет есть MLF, PDIP.TQFP АТтеда32А 32 2К 1024 44 32 16 2.Z..5.5 8 10 15 0 0 4 1 3 3 1 1 1 есть нет есть MLF. PDIP.TQFP АТтеда324РА 32 2К 1024 44 32 20 1.8...5.5 8 10 15 0 0 6 1 3 32 3 1 2 есть есть есть MLF, PDIP.TQFP АТтеда164РА 16 1К 512 44 32 20 1.8...5.5 8 10 15 0 0 6 1 3 32 3 1 2 есть есть есть MLF, PDIP.TQFP АТтеда64А 64 4К 2048 64 53 16 2.Z..5.5 8 10 15 0 0 7 1 4 8 1 1 2 есть нет есть MLF.TQFP АТтеда128А 128 4К 4096 64 53 16 2.Z..5.5 8 10 15 0 0 7 1 4 8 1 1 2 есть нет есть MLF.TQFP АТтеда8А 8 1К 512 32 23 16 2.Z..5.5 8 10 15 0 0 3 1 3 2 1 1 1 есть нет есть MLF. PDIP.TQFP Глава 13. Возможности и особенности построения микроконтроллеров AVR 133
| ATmega329PA | | ATmega6490P | | ATmega6490A | |ATmega649P | | ATmega3290A | | ATmega649A 1 з1 £ QJ LN > |ATmegal69A | | ATmega6450A | ATmega6450P | | ATmega645P | | ATmega645A | | ATmega3250A | |ATmega325A | | ATmegal65PA | | ATmegal284 | | ATmega644A | |ATmega324A |ATmegal64A | ATmegal69PA | | ATmega644PA |ATmega32U2 |ATmegal6U2 |ATmega8U2 Микро- схема 2 $ 2 s 2 NJ On 2 2 On 2 NJ LN On l-A 00 2 Й l-A on On 2 NJ l-A on со Flash (Кбайт) Объем памяти X x X X X £ X X X X x X NJ X NJ X X on X X l-A X l-A X X l-A X un un NJ EEPR0M (Байт) 1024 NJ I 00 s 00 о NJ l-A О un NJ о 00 2 00 2 00 2 00 О 8 un К on 2 00 о NA un l-A 2 co о Un l-A un NJ SRAM (Байт) 2 l-A о о l-A § 2 I-a § On On г о о s 2 2 8 2 2 t 2 2 2 2 2 LN LN S Выв. Коли- чество Un s s Un on \O Ln Ln Ln <* On \O un un On \O 2 un NJ LN Uj LN NJ un Й NJ NJ NJ Вх/Вых о о о I-a On о On О l-A On о О h-n On l-A On О о l-A On О О О О l-A On NJ О l-A On l-A On On Максимальная тактовая частота (MHz) l-A bo yn 1л l-A bo bn 1л bo bn bo yn bn bo yn bn 00 bn bn I-a bo bn bn l-A bo bn bn l-A bo yn bn bo yn bn l-A bo bn bn l-A bo bn l-A bo bn bn l-A bo yn bn h-n bo yn bn l-A bo bn co bn J-A bo bn un 00 bn bn bo bn bn bo un bn bn bn NJ bn bn NJ Un bn Напряжение питания Vcc (В) co 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 co co co co co о о О Количество Каналы АЦП о О о о о о l-A о l-A О l-A о l-A О l-A О l-A О l-A О l-A О о о О о о о о о о О Разрешение (бит) un i-a un Ln l-A Ln i-a Ln £ Ln Ln un un un un un un un un un l-A un l-A un l-A un un о о О Скорость (ksps) о О О О О О О О о О О О О О о о О О О О О о о о Количество Каналы ЦАП о О О О О О О О о О О О О О о о О О О О О о о о Разрешение Фа Ф Ф Ф Ф Фа Фа Фа Фа Фа Фа Фа Фа on On On On On Каналов ШИМ l-A i-a i-a i-a i-a l-A l-A l-A l-A l-A l-A l-A l-A l-A l-A l-A l-A l-A l-A l-A М 1-А 1-А Аналоговых компараторов LN LN LN LN LN LN LN LN LN LN LN LN LN LN LN LN LN LN LNZ LN LN NJ NJ NJ Количество таймеров I-a Й Й I-a Й l-A l-A l-A un NJ l-A l-A un l-A l-A LN Й LN Й l-A NJ О ЬА о Количество внешн. прерываний NJ NJ NJ NJ NJ NJ NJ NJ NJ NJ NJ NJ NJ NJ NJ LN LN LN LN NJ LN NJ NJ NJ SPI Каналы h- h- I-a I-a I-a l-A l-A l-A l-A l-A l-A l-A l-A l-A l-A l-A l-A l-A l-A l-A l-A О О о TWI (I2C) h- h- I-a I-a l-A l-A t- l-A l-A l-A l-A l-A l-A NJ NJ NJ NJ l-A NJ НА 1-А 1-А UART ("D q ("D q 3 <T> Э § £ § 3 3 £ 1 § 3 1 3 3 3 3 3 з 3 Самопрограммируема память ("D q 3 3 3 z q 3 z q 3 3 § § z q 3 z q 3 3 z q 3 3 з 3 Z q 3 3 Пикопотребление 3 ("D Э ("D q <T> q § 3 ("D Э 3 5 § 1 § 3 I 3 Z q 3 Z q Такт, генератор 32 кГц MLF.TQFP 1 -0 U MLF.TQFP | "D MLF.TQFP ] MLF.TQFP | QFN, MLF.TQFP | "D MLF.TQFP | MLF.TQFP 1 й ПП MLF.TQFP | MLF.TQFP | MLF. PDIP.TQFP | | MLF. PDIP.TQFP | | MLF. PDIP.TQFP | MLF. PDIP.TQFP | | QFN. MLF.TQFP | MLF. PDIP.TQFP | VQFN.TQFP | I VQFN.TQFP | VQFN.TQFP | Тип корпуса Таблица 13.1 (продолжение) •"BMHetfEOD otf BMHeaodMwwedJodu aoeeio :ONinGdV KT
Глава 13. Возможности и особенности построения микроконтроллеров AVR 135 Состав II серии AVR II Итак, что же представляют собой микроконтроллеры серии AVR? Семейство AVR включает в себя микроконтроллеры самой разной конфигурации, с разным объемом памяти и разным количеством встроенных портов ввода-вывода и других допол- нительных устройств. Конструктивное исполнение микроконтроллеров также очень многообразно. Применяется несколько типов корпусов (см. рис. 13.1), например: ♦ традиционные корпуса типа PDIP с количеством ножек от 8 до 40; ♦ корпуса типа SOIC с количеством выводов от 8 до 20. ПРИМЕЧАНИЕ. А вот большинство микроконтроллеров семей- ства Меда AVR выполнятся либо в сорокавывод- ных РО1Р-корпусах,либо в современных многовыво- дных корпусах типа TQFP или MLF (до 64 выводов). Рис. 13.1. Микроконтроллеры серии AVR
136 ARDUINO: от азов программирования до создания... В задачу данной книги про Arduino не входит полное опи- сание всех микросхем серии AVR. Здесь мы познакомимся лишь с общими сведениями, позволяющими понять основ- ные принципы построения микросхем. Позже, когда мы будем рассматривать примеры программ, написанных для модуля Arduino UNO, который собран на основе микроконтроллера ATmega328P, мы познакомимся подробнее с конкретными свойствами и возможностями именно этой микросхемы. СОВЕТ. Если в справочной литературе не окажется нуж- ной вам микросхемы, рекомендую скачать из Интернета оригинальное описание нужной вам микросхемы, так называемый даташит (Datasheet). Любой даташит всегда найдется на сайте произ- водителя (www.atmel.ru или www.atmel.com). К сожалению, выложенная там документация существует только на английском языке. Полный список всех микрокон- троллеров серии AVR, производимых настоящее время фирмой Atmel, и их основные характеристики были приведены выше в табл. 13.1. Особенности серии AVR Микроконтроллеры серии AVR относятся к классу восьми- разрядных микроконтроллеров. Это значит, что подавляющее большинство операций процессоры производят с восьмираз- рядными двоичными числами. По этой причине встроенная шина данных у этих контроллеров тоже восьмиразрядная. Все ячейки памяти и большинство регистров микроконтроллера также восьмиразрядные.
Глава 13. Возможности и особенности построения микроконтроллеров AVR 137 ПРИМЕЧАНИЕ. Для обработки шестнадцатиразрядных чисел некоторые внутренние регистры могут объеди- няться попарно. Каждая такая пара может рабо- тать как один шестнадцатиразрядный регистр. Исключение составляет память программ. Она целиком состоит из шестнадцатиразрядных ячеек. Микроконтроллеры AVR изготавливаются по КМОП- технологии, благодаря которой они имеют: ♦ достаточно высокое быстродействие; ♦ низкий ток потребления. Большинство команд микроконтроллера выполняется за один такт. Поэтому быстродействие контроллеров может достигать 1 миллиона операций в секунду при тактовой частоте 1 МГц. Внутренняя память Микроконтроллеры AVR имеют в своем составе три вида памяти. Первый вид памяти — это ОЗУ (оперативная память для данных). В документации фирмы Atmel эта память называется SRAM. Объем ОЗУ для разных контроллеров варьируется от полного ее отсутствия (в микросхеме AT90S1200) до 2 Кбайт. Подробнее смотрите графу «SRAM» в табл. 13.1. Второй вид памяти — это память программ. Она выпол- нена по Flash-технологии и предназначена для хранения управляющей программы. В фирменной документации она так и называется — Flash-память. Объем программной памяти в разных микросхемах этой серии составляет от 1 до 64 Кбайт. Подробнее смотрите графу «Flash» табл. 13.1. Программная
138 ARDUINO: от азов программирования до создания... память допускает стирание записанной туда информации и повторную запись. Однако количество циклов записи/стира- ния ограничено. ПРИМЕЧАНИЕ. Программная память микроконтроллеров AVR до- пускает до 1000 циклов записи/стирания. Запись информации в память программ производится при помощи специальных устройств (програм- маторов). Последние модели микроконтроллеров AVR имеют режим автоперезаписи памяти про- грамм. То есть управляющая программа самого микроконтроллера способна сама себя переписы- вать. Именно такой способ записи информации используется в модулях Arduino. Третий вид памяти — это энергонезависимая память для данных. Она также выполнена по Flash-технологии, но в технической документации она называется EEPROM. Основное назначение этого вида памяти — долговременное хранение данных. Данные, записанные в эту память, не теряются даже при выключенном источнике питания. Управляющая программа микроконтроллера может в любой момент записать данные в EEPROM или прочитать их оттуда. Память EEPROM допускает до 100000 циклов записи/ стирания. Количество циклов чтения из EEPROM неограни- чено. Объем памяти EEPROM сравнительно небольшой. Для разных микросхем он составляет от 64 байт до 2 Кбайт. Для большинства задач этого вполне достаточно. Объем EEPROM для разных микросхем вы можете узнать из соответствующей колонки табл. 13.1. Записывать информацию в EEPROM можно также при помощи программатора. Причем для записи информации в память программ и в EEPROM используется один и тот же программатор. Такой порядок доступа к памяти позволяет
Глава 13. Возможности и особенности построения микроконтроллеров AVR 139 при необходимости отказаться от программной перезаписи EEPROM и использовать эту память для хранения любых неиз- меняемых констант. Это увеличивает гибкость системы. ПРИМЕЧАНИЕ. Однако в Arduino такой способ не используется. Способы программирования Flash- и EEPROM-памяти Микроконтроллеры AVR допускают несколько способов программирования Flash- и EEPROM-памяти, например: ♦ параллельное программирование (Self-Prog); ♦ последовательное программирование с использованием SPI-интерфейса. При параллельном программировании программа- тор передает в микросхему записываемые данные побайтно, параллельным способом. То есть при помощи восьмипровод- ной шины. При последовательном программировании использу- ется специальный последовательный интерфейс, получивший название SPI. Посредством этого интерфейса данные переда- ются в микросхему последовательно, бит за битом, с использо- ванием всего трех проводников. ПРИМЕЧАНИЕ. Последовательный способ гораздо медленнее, чем параллельный. Зато он бодее универсален и допу- скает программирование микросхемы без извле- чения ИМС из схемы.
140 ARDUINO: от азов программирования до создания... В табл. 13.1 в графе «ISP (I), Self-Prog (S)» для каждой микросхемы показаны поддерживаемые способы програм- мирования. Буква I означает наличие ISP, а буква S — наличие режима Self-Prog. I Порты ввода-вывода Порты ввода-вывода — это обязательный атрибут любого микроконтроллера. Их количество для каждой конкретной микросхемы разное. Все порты микроконтроллеров AVR вось- миразрядные, но в некоторых случаях отдельные разряды не используются. Это связано с ограниченным количеством выво- дов (ножек) у микросхемы. ПРИМЕЧАНИЕ. В табл. 13.1 в графе «Кол-во выв. I/O» указано об- щее количество линий ввода-вывода. У одних портов используются все восемь его линий. У дру- гих семь, шесть или даже три. Но для процессора порты оста- ются восьмиразрядными. Процессор всегда пишет в такие порты и читает из них полноценный байт информации. Неиспользуемые биты при записи просто теряются. При чте- нии байта из порта неиспользуемые разряды равны нулю. Периферийные устройства Кроме указанных выше элементов, любой микроконтрол- лер AVR обязательно содержит набор так называемых перифе- рийных устройств.
Глава 13. Возможности и особенности построения микроконтроллеров AVR 141 ПРИМЕЧАНИЕ. Периферийные они по отношению к централь- ному процессорному устройству (ЦПУ) микро- контроллера. Но находятся они также внутри микросхемы. Ниже перечислены все возможные периферийные устрой- ства, которые могут входить в состав микроконтроллера AVR. Встроенные таймеры/счетчики. Микроконтроллеры AVR могут содержать от одного до четырех таймеров/счетчиков. Причем используются как восьми-, так и шестнадцатиразряд- ные таймеры. Их количество на один микроконтроллер может составлять от одного до шести. Подробнее смотри в графе «Таймеры 8/16-бит» в табл. 13.1. Генератор сигнала с широтно-импульсной модуля- цией (ШИМ). Генерация сигнала ШИМ — это просто один из режимов работы таймера/счетчика. Одна микросхема может иметь от 2 до 12 каналов ШИМ, а может не иметь ни одного. Подробнее смотри в соответствующей графе в табл. 13.1. Аналоговый компаратор. Входит в состав практически во всех микроконтроллеров AVR. Аналогово-цифровой преобразователь (АЦП). АЦП микроконтроллеров AVR могут иметь от четырех до шестнад- цати каналов. То есть могут преобразовывать в цифровой экви- валент до 16 входных аналоговых сигналов. На самом деле канал АЦП всегда один. Но на его входе стоит система переключения (аналоговый мультиплексор). Поэтому АЦП способен подклю- чаться к нескольким разным источникам аналогового сигнала. Последовательный интерфейс. Микросхемы AVR спо- собны поддерживать несколько разных видов последователь- ных интерфейсов. Каждый такой интерфейс реализует один или несколько известных стандартов передачи информации. Один из видов такого интерфейса поддерживает тот же стан- дарт, что и COM-порт персонального компьютера. Есть также интерфейс, поддерживающий стандарт широко известной в микроэлектронике так называемой 12С шины.
142 ARDUINO: от азов программирования до создания... Сюда же относится и SPI-интерфейс, который может использоваться как для последовательного программирования памяти программ, так и для связи нескольких микроконтрол- леров в мультипроцессорной системе. ПРИМЕЧАНИЕ. Любой последовательный интерфейс предназна- чен для передачи информации последовательным способом. Каждый байт передается последова- тельно, бит за битом. Дополнительные устройства Кроме перечисленных выше устройств, микроконтроллеры серии AVR обязательно содержат систему прерываний, охран- ный таймер, систему начального сброса, систему контроля питающего напряжения и т. д. Все описанные выше устройства управляются центральным процессором при помощи реги- стров. И вот здесь мы вплотную подходим к такому понятию, как архитектура микроконтроллеров AVR. ЧТО ЕСТЬ ЧТО. Под архитектурой понимается внутреннее строение микросхемы и взаимодействие всех ее элементов. К элементам архитектуры можно отнести объем и струк- туру всех видов памяти микроконтроллера, количество и свой- ства так называемых регистров общего назначения, устрой- ство портов ввода-вывода и методы доступа к ним, устройство системы прерываний, способы управления встроенными пери- ферийными устройствами. А начнем мы с изучения всех видов памяти.
ГЛАВА 14 РЕГИСТРЫ: ХРАНИМ ПРЕДВАРИТЕЛЬНЫЕ РЕЗУЛЬТАТЫ ВЫЧИСЛЕНИЙ Регистры II общего назначения (РОН) II Для хранения промежуточных результатов вычислений каждый микроконтроллер AVR имеет тридцать два регистра общего назначения (сокращенно — РОН). Чтобы регистры можно было использовать в программе, каждый имеет свое собственное имя. Вот эти имена: RO, Rl, R2 — R31. Все РОН составляют так называемый файл регистров общего назначения. Все команды преобразования данных (сложения, вычитания и т. д.) микроконтроллера AVR постро- ены таким образом, что обязательно используют РОН. Каждая команда в качестве операндов использует либо содержимое двух разных РОН, либо содержимое РОН и константу. Результат вычислений также помещается в один из РОН. ПРИМЕР. Команда ADD RO, R1 производит сложение содержи- мого регистров R0 и R1. Сумма помещается в R0. Команда ADD R5, #7 прибавляет к содержимому ре- гистра R5 число семь. Результат помещается в R5.
144 ARDUINO: от азов программирования до создания... Регистры общего назначения используются также и в командах перемещения данных. Перемещать данные можно из одного РОН в другой, из РОН в ячейку памяти и в обратном направлении. Перемещение данных возможно также между РОН и регистрами ввода-вывода, о которых мы поговорим в следующем разделе. ПРИМЕЧАНИЕ. Некоторые команды имеют ограничения по ис- пользованию РОН. Например, все команды об- мена информацией с регистрами ввода-выво- да не могут использовать регистры R0-R15. Существуют и другие ограничения. Подробнее это можно узнать из описания системы команд (см. Приложение 3). Все регистры общего назначения микроконтроллеров AVR восьмиразрядные. Однако шесть последних регистров (R26— R31) способны объединяться в регистровые пары. Такая пара в некоторых операциях выступает как самостоятельный шест- надцатиразрядный регистр. При этом не теряется возможность чтения каждого реги- стра пары отдельно. Регистровые пары имеют свои названия: ♦ пара, объединяющая регистры R26—R27, называется реги- стром X; ♦ пара регистров R28—R29 называется регистром Y; ♦ пара регистров R30—31 называется регистром Z. ПРИМЕЧАНИЕ. Весь набор регистров общего назначения присут- ствует в любом микроконтроллере серии AVR.
Глава 14. Регистры: храним предварительные результаты вычислений 145 Регистры ввода-вывода То, что в ЧАСТИ I мы называли портами ввода-вывода, в микроконтроллерах AVR называется регистрами ввода- вывода. ЭТО ИНТЕРЕСНО ЗНАТЬ. Смещение понятий произошло потому, что ми- кроконтроллеры AVR для обмена информацией с внешними устройствами используют доста- точно сложные электронные схемы, имеющие несколько разных режимов работы, а также воз- можность выбора программным путем направле- ния передачи данных. Именно они и получили название портов ввода-вывода. Чуть позже мы подробно рассмотрим их устройство. Простые же регистры, служащие для связи центрального процессора с периферийными устройствами, получили более подходящее в данном случае название: регистры ввода- вывода. Эти регистры позволяют обмениваться информацией лишь со встроенными периферийными устройствами самой микросхемы, такими как: ♦ таймеры; ♦ компараторы; ♦ каналы последовательной передачи информации; ♦ система прерывания; ♦ АЦП и т. д. Каждый регистр ввода-вывода имеет свой номер, то есть адрес в адресном пространстве ввода-вывода. Номера реги- стров могут иметь значение от $00 до $3F. Это означает, что максимально возможное количество РВВ равно 64. Однако реальное количество регистров любого микроконтроллера
146 ARDUINO: от азов программирования до создания... всегда меньше. Разные микроконтроллеры имеют разный набор регистров ввода-вывода. Каждый регистр ввода-вывода, помимо номера, имеет свое уникальное имя. ПРИМЕР. В микроконтроллере семейства «Tiny» регистр номер $1Е предназначен для управления EEPROM. Этот регистр имеет имя EEAR. Второй регистр управления EEPROM имеет номер $1D и имя EEDR. Для разных микроконтроллеров регистры, имеющие одинаковое назначение, обычно имеют и одинаковое имя. А вот номер регистра может и отличаться. ЧТО ЕСТЬ ЧТО. Имя регистра - это условное понятие, приду- манное лишь для удобства программистов. Сам же микроконтроллер работает исключительно с номером регистра.
ГЛАВА 15 ПАМЯТЬ МИКРОКОНТРОЛЛЕРА Общие сведения Как уже говорилось, микроконтроллеры AVR имеют,три вида памяти: ♦ память программ (Flash); ♦ оперативную память данных (SRAM); ♦ энергонезависимую память данных (EEPROM). Объем каждого вида памяти для разных микросхем вы можете видеть в табл. 13.1. Память EEPROM имеется не во всех микроконтроллерах. Кроме того, в некоторых моделях отсут- ствует оперативная память (SRAM). В таких микросхемах для оперативного хранения данных используются только регистры общего назначения. ЧТО ЕСТЬ ЧТО. Каждый из этих трех видов памяти имеет свое собственное адресное пространство, и до- ступ к разным видам памяти осуществляет- ся независимо друг от друга. Такое построение микроконтроллеров называется архитектурой Гарвардского типа.
148 ARDUINO: от азов программирования до создания... Память программ Память программ предназначена для хранения управля- ющей программы микроконтроллера. Каждая ячейка этой памяти имеет 16 разрядов, то есть хранит одно шестнадцати- разрядное двоичное число. Каждое такое число содержит как код операции, так и один или несколько параметров команды. Кроме того, в памяти программ можно хранить данные. Такие данные будут доступны только для чтения. В памяти программ обычно хранят некоторые постоянные константы, таблицы символов и другие неизменяемые вели- чины. Данные записываются в виде восьмиразрядных двоич- ных чисел (байтов). При этом каждая шестнадцатиразрядная ячейка программной памяти используется как две восьмираз- рядные. При чтении данных из программной памяти микро- контроллер может обратиться к каждой такой половинке отдельно. Мы еще поговорим об этом подробно. Для разных микроконтроллеров память программ имеет разный объем (см. табл. 13.1). ПРИМЕЧАНИЕ. Однако при любом объеме памяти она представ- ляет собой непрерывную область и начинается с ячейки, имеющей нулевой адрес. На рис. 15.1 изображено адресное пространство памяти программ в графическом виде. Такое условное Изображение адресного пространства часто применяется в технической лите- ратуре. Изображенное на рисунке адресное пространство вклю- чает в себя ячейки Flash-памяти с адресами от $000 до F_END. Условное обозначение F_END означает адрес последней ячейки памяти. Значение этого адреса будет разным для раз- ных микроконтроллеров. Например, для микроконтроллера ATmega328P адрес последней ячейки памяти будет равен $7FFF.
Глава 15. Память микроконтроллера 149 ВНИМАНИЕ. ( \ Адрес последней ячейки памя- ти всегда на единицу меньше объема этой памяти. \> Объем памяти для каждого микрокон- троллера можно узнать из табл. 13.1. Так, для микроконтроллера ATmega328P объем программной памяти равен 32 килобай- Память программ Рис. 15.1. Адресное пространство программной памяти там. То есть 32768 байт. Если записать это число в шестнадца- тиричном виде, получим $8000. Учитывая то, что адресация начинается с нулевого адреса, то для адресации такого количества ячеек мы должны исполь- зовать адреса с 0 по 32767. Или в шестнадцатиричном виде от $0000 до $7FFF. Некоторые адреса программной памяти зарезервированы. То есть используются для неких специальных целей. И первым зарезервированным адресом можно считать нулевой адрес. Он называется вектором системного сброса. Именно с этого адреса начинается выполнение программы после системного сброса микроконтроллера. Остальные зарезервированные адреса — это векторы прерываний. ЧТО ЕСТЬ ЧТО. Вектор прерывания - это адрес в программной памяти, с которого начинается выполнение про- цедуры обработки прерывания. Так как любой микроконтроллер AVR имеет несколько источников прерывания, то и векторов прерывания тоже несколько: по одному на каждый вид прерывания. Адреса век- торов прерываний находятся сразу за вектором сброса. То есть занимают ячейки с адресами $001, $002 и т. д. Количество век- торов прерываний для разных микросхем разное. Подробнее
150 ARDUINO: от азов программирования до создания... смотрите в табл. 13.1 в графе «Кол-во каналов прерывания Внут/Внешн». В этой графе отдельно показано количество внутренних и количество внешних прерываний. ЧТО ЕСТЬ ЧТО. Внутреннее прерывание - прерывание, вызванное одним из встроенных периферийных устройств самого микроконтроллера. Например, прерывание по таймеру, аналоговому ком паратору, АЦП и т. д. ЧТО ЕСТЬ ЧТО. / Л Внешнее прерывание - это прерывание по сиг- налу, поступающему от внешнего источника на специальный вход микроконтроллера. \_____________________________________________J ЧТО ЕСТЬ ЧТО. Область адресов, зарезервированных под векто- ры прерываний, называют таблицей векторов прерываний. В микроконтроллерах семейства «Tiny» эта область начи- нается с адреса $001. Для большинства микроконтроллеров семейства «Mega» таблица векторов прерываний начинается с адреса $002. При разработке программы для микроконтрол- лера программист по своему усмотрению может использовать, но может и не использовать механизм прерываний. Если прерывания не используются, то ячейки, зарезерви- рованные под вектора прерываний, можно использовать как обычные ячейки для хранения программы. Если же вы решили в своей программе использовать прерывания, то по адресу $000 необходимо записать команду безусловного перехода, которая
Глава 15. Память микроконтроллера 151 должна передавать управление на любой адрес за пределами таблицы векторов прерываний. Именно там и должна начинаться основная программа. В каждую ячейку, соответствующую тому либо иному вектору прерывания, тоже записывается команда безусловного пере- хода. Каждый такой переход передает управление на начало соответствующей процедуры обработки прерывания. Оперативная память микроконтроллеров AVR Память данных микроконтроллеров AVR представляет собой отдельное адресное пространство с адресами от $0000 до $FFFF. То есть максимальный объем адресуемой памяти составляет 64 Кбайта. Однако большинство микроконтролле- ров имеет гораздо меньшую память. В таких микроконтролле- рах часть адресов не используется. Структура же памяти всегда одинакова. В графическом виде эта структура изображена на рис. 3.3. Посмотрите внимательно на этот рисунок. Оперативная память микроконтроллеров AVR делится на три области. $0000 — $001F — область памяти, совмещенная с реги- страми общего назначения (РОН). $0020 — $005F — область памяти, совмещенная с реги- страми ввода-вывода (РВВ). $0060 — $FFFF — не совмещенная ни с чем область памяти. Эта последняя область предназначена просто для хране- ния данных. Эту область в свою очередь можно разделить на область внутреннего ОЗУ ($0060 — RAMEND) и область внеш- него ОЗУ (RAMEND+1 - $FFFF). Под RAMEND понимается адрес последней ячейки внутрен- него ОЗУ конкретного микроконтроллера. Рассмотрим каждую область памяти подробнее.
152 ARDUINO: от азов программирования до создания... Адресное пространство памяти данных Пространство регистров $0000 = R0 Регистры общего $0001 = R1 назначения $0002 = R2 $001D = R29 $001Е = R30 $001F = R31 $0020 = $00 Регистры $0021 = $01 ввода/вывода $0022 = $02 $005D = $5D $005Е = $5Е $005F = $5F ' $0060 $0061 RAMEND-1 RAMEND RAMEND+1 RAMEND+2 $FFFE $FFFF Рис. 15.2. Адресное пространство программной памяти
Глава 15. Память микроконтроллера 153 Область памяти, совмещенная с набором регистров общего назначения (РОН) Эта область существует во всех микроконтроллерах AVR. Она занимает ячейки с адресами с $0000 по S001F. Все ячейки этой области памяти одновременно являются регистрами общего назначения (смотри выше). То есть, записывая байт данных в ячейку памяти с адресом $0000, вы на самом деле записываете ее в регистр R0. И наоборот. Соответствие ячеек памяти и регистров общего назначение показано на рис. 15.2. ПРИМЕЧАНИЕ. Двойной доступ к РОН существенно увеличивает гибкость программ. Область памяти, совмещенная с регистрами ввода-вывода (РВВ) Область памяти с адреса $0020 по адрес $005F совмещена с регистрами ввода-вывода. В адресном пространстве ОЗУ это соответствует адресам $0020 — $005F. Каждому регистру ввода- вывода соответствует своя ячейка в ОЗУ. ПРИМЕЧАНИЕ. Кок уже говорилось, реальное количество реги- стров ввода-вывода почти всегда гораздо мень- ше их максимально возможного количества. Однако данная область памяти всегда использу- ется только для этой цели. Если регистр существует, то существует и соответствующая ячейка памяти. Остальные же ячейки из этой области ОЗУ про-
154 ARDUINO: от азов программирования до создания... сто отсутствуют. На рис. 15.2 показано соответствие регистров общего назначения и ячеек памяти. Из рисунка видно, что адрес ячейки памяти всегда больше номера соответствующего РВВ на постоянную величину, равную 32 ($20). Область внутреннего ОЗУ Пространство ОЗУ с адреса $0060 и выше не выполняет никаких дополнительных функций и предназначено исключи- тельно для оперативного хранения данных. Объем (а, значит, и конечный адрес) этой области ОЗУ для разных микросхем раз- ный. Именно этот объем приведен в табл. 13.1 в графе «SRAM». I Область внешнего ОЗУ Большинство микроконтроллеров AVR имеют лишь встро- енное ОЗУ. Однако в состав серии входят микросхемы, допу- скающие подключение внешних микросхем ОЗУ. В резуль- тате объем ОЗУ микроконтроллера может быть расширен до 64 Кбайт. При этом общий объем оперативной памяти может достигать значения $FFFF. Энергонезависимая память данных (EEPROM) что есть что. EEPROM - это специальная внутренняя память, выполненная по Flash-технологии и предназна- ченная для долговременного хранения данных.
Глава 15. Память микроконтроллера 155 В современных микропроцессорных устройствах часто воз- никает необходимость в хранении таких данных. Примером может служить микропроцессорная система управления авто- магнитолой. Такая система управления где-то обязательно должна хранить множество констант. У любой магнитолы есть несколько фиксированных настроек. Кроме того, принято при выключении запоминать все режимы работы магнитолы и восстанавливать их после вклю- чения. Все эти настройки в виде чисел обычно записываются в энергонезависимую память. Можно, конечно, использовать внешнюю микросхему памяти. Но встроенная память гораздо удобнее. Для подобных задач обычно не требуется больших объе- мов EEPROM-памяти. Поэтому микроконтроллеры AVR имеют объем EEPROM от 64 байт до 8 Кбайт. Конкретное значение можно узнать из табл. 13.1 (графа «EEPROM»). ПРИМЕЧАНИЕ. EEPROM - необычная помять. Поэтому к этой памяти ЦПУ микроконтроллера обращается не так, как к остальным видам памяти. Для цен- трального процессора не существует адресного пространства EEPROM. К этому виду памяти микроконтроллер обращается при помощи регистров ввода-вывода. Для микроконтроллеров с объемом EEPROM менее 256 байт таких регистров всего три: ♦ EEAR — регистр адреса EEPROM; ♦ EEDR — регистр данных EEPROM; ♦ EECR — регистр управления EEPROM. Если объем EEPROM превышает 256 байт, то вместо одного регистра адреса (EEAR) такой микроконтроллер имеет два регистра: ♦ EEARH; ♦ EEARL.
156 ARDUINO: от азов программирования до создания... Регистры доступа к EEPROM имеют следующие номера: ♦ EEAR- $1Е; ♦ EEARH - $1F; ♦ EEDR- $1D; ♦ EEARL — $1Е; ♦ EECR —$1С. ПРИМЕЧАНИЕ. Регистры адреса EEAR (или EEARH, EEARL) рабо- тают только на запись. При помощи этих реги- стров микроконтроллер выбирает ячейку, куда нужно записать или откуда нужно прочитать данные. Регистр данных (EEDR) работает как на запись, так и на чтение. Через этот регистр в EEPROM поступает записывае- мый байт. Через него же процессор получает байт при чтении из EEPROM. Регистр управления (EECR) определяет режимы работы. Именно через него подаются команды чтения и записи EEPROM. ПРИМЕЧАНИЕ. В практическом разделе книги на примере схемы и программы электронного кодового замка мы подробно рассмотрим алгоритмы чтения и запи- си в (из) EEPROM.
ГЛАВА 16 ДОПОЛНИТЕЛЬНЫЕ РЕГИСТРЫ И СТЕКОВАЯ ПАМЯТЬ Счетчик II команд II Два важных регистра, которые существуют в любом микро- процессоре или микроконтроллере, — это счетчик команд и указатель стека. ЧТО ЕСТЬ ЧТО. Счетчик команд - это специализированный вну- тренний регистр микроконтроллера, в котором хранится адрес текущей выполняемой команды. Этот регистр не доступен для программиста в том смысле, что не существует команд прямой записи или чтения его содержимого. Размер счетчика команд составляет для разных микроконтроллеров AVR от 9 до 12 разрядов. Количество раз- рядов счетчика команд зависит от размера адресуемой про- граммной памяти конкретного микроконтроллера.
158 ARDUINO: от азов программирования до создания... После сброса микроконтроллера в счетчик команд записы- вается ноль. Затем процессор переходит в режим выполнения программы. В процессе выполнения программы счетчик всегда указывает на текущую выполняемую команду. При считыва- нии кода команды значение счетчика увеличивается на один или два (в зависимости от длины команды). При выполне- нии команд безусловного и условного переходов содержимое счетчика резко меняется. В него записывается новое значение адреса. ЧТО ЕСТЬ ЧТО. Новое значение адреса называется адресом пере- хода. Кроме традиционных команд условного перехода, которые мы уже рассматривали в предыдущей главе, микроконтрол- леры серии AVR имеют еще один вид команд, который можно рассматривать как их модификацию. Это команды типа «про- верка/пропуск». В командах этого типа производится проверка некоего условия, и результат проверки влияет на выполнение следующей команды. Если условие истинно, то следующая команда игнорируется. То есть сама команда не выполняется, изменяется лишь содержимое счетчика команд. Это содержимое увеличивается либо на единицу, либо на две единицы, в зависимости от длины пропускаемой команды. Если условие ложно, то команда не пропускается, а выполняется как обычно. Теперь перейдем к указателю стека.
Глава 16. Дополнительные регистры и стековая память 159 Указатель стека что есть что. Указатель стека - это специальный регистр, ко- торый предназначен для организации так назы- ваемой стековой памяти. Стековая память ши- роко применяется в вычислительной технике. Вообще, стек - это некий буфер, состоящий из нескольких ячеек памяти, имеющий один вход, ко- торый одновременно является и выходом. \. Запись в стековую память и чтение из нее производится по принципу магазина автомата Калашникова. Патроны в такой магазин вставляются через входное отверстие один за другим. Извлекаются патроны из магазина в обратном порядке по принципу «последний зашел — первый вышел». Стековую память очень часто используют при программировании. Особенно удобно использовать стек для сохранения данных при входе в подпрограмму и восстановления их перед выхо- дом. В дальнейшем мы убедимся в этом на примерах. Организация II стековой памяти II Остановимся на методах организации стековой памяти. В микроконтроллерах серии AVR применяется широко рас- пространенный способ организации стековой памяти, когда в качестве стека используется часть ОЗУ. Для реализации прин- ципа «последний зашел — первый вышел» и служит регистр- указатель стека.
160 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. В зависимости от размеров ОЗУ, разрядность указателя стека бывает разная. В микроконтроллерах с небольшим объемом ОЗУ используется восьмиразрядный указатель стека. Он пред- ставляет собой один регистр ввода-вывода и доступен для сво- бодного считывания и записи. Называется такой регистр SPL. Для ОЗУ больших размеров к регистру SPL добавляется еще один регистр SPH. Вместе они составляют один шестнад- цатиразрядный указатель стека. Перед началом работы в указатель стека необходимо запи- сать адрес вершины стека. Это некий адрес ячейки ОЗУ, кото- рая является старшей ячейкой области памяти, выделенной под стек. Определять размер стековой памяти и адрес ее вер- шины должен сам программист. Для работы со стеком в системе команд микроконтроллера есть две специальные команды: ♦ команда записи в стек (push); ♦ команда извлечения из стека (pop). Выполняя команду push, микроконтроллер записывает содержимое одного из РОН в ОЗУ по адресу, на который указы- вает указатель стека, а затем уменьшает значение указателя на единицу. Новая команда push запишет значение другого РОН в следующую ячейку ОЗУ. А указатель передвинется еще дальше. Таким образом, происходит заполнение стека. Выполняя команду pop, микроконтроллер сначала уве- личивает содержимое указателя стека на единицу, а затем извлекает содержимое ячейки ОЗУ, на которое указывает указатель. Считанное значение помещается в один из РОН. В результате из стека считывается последнее записанное туда число. Следующая команда pop опять сначала увеличит указа- тель стека и прочитает предпоследнее записанное туда число. Благодаря регистру-указателю стека и описанному выше алго- ритму реализуется полноценная стековая память.
Глава 16. Дополнительные регистры и стековая память 161 Сразу после сброса микроконтроллера содержимое указа- теля стека равно нулю. Если оставить это содержимое без изме- нений, то все команды, связанные со стеком, работать не будут. Если вы собираетесь использовать стек в вашей программе, то в самом ее начале вам необходимо записать в регистр-указа- тель стека значение его вершины. Обычно вершину стека устанавливают равной адресу самой старшей ячейки ОЗУ. Кроме того, при составлении программы вы должны следить, чтобы она не использовала в процессе своей работы область ОЗУ, выделенную вами для стека. Одной из команд, активно использующих стековую память, является команда перехода к подпрограмме. При вызове под- программы текущий адрес из счетчика программ автоматиче- ски записывается в стек. При выходе из подпрограммы микро- контроллер извлекает адрес из стека и продолжает выполнение программы с этого адреса. Команда перехода к подпрограмме использует тот же самый стек, что и команды push и pop. ПРИМЕЧАНИЕ. Это нужно обязательно учитывать при состав- лении программы. Если записать данные в стек, а затем перейти к подпрограмме, то в теле подпрограммы прочитать эти данные из стека будет уже невозможно. Если вы все же попытае- тесь в данной ситуации извлечь данные из сте- ка, вместо записанных данных вы получите адрес возврата из подпрограммы. Мало того, что вы не получите нужные вами данные, так вы еще и сде- лаете невозможным правильный выход из под- программы, так как в стеке уже не будет адреса выхода.
ГЛАВА 17 ПОДСИСТЕМА ВВОДА-ВЫВОДА Назначение, состав, имена Микроконтроллеры серии AVR всегда имеют в своем составе от одного до семи портов ввода-вывода. Каждый разряд такого порта подсоединен к одному из выводов (контактов) микро- схемы. Порты ввода-вывода служат для обмена информацией с внешними устройствами. Как уже говорилось, порты могут быть: ♦ полными (содержат 8 разрядов); ♦ неполными (в них задействованы не все разряды). ПРИМЕЧАНИЕ. Каждый порт имеет свое имя. Они именуются латинскими буквами от А до G. Для управления каждым портом ввода-вывода использу- ется три специальных РВВ: ♦ регистр PORTx; ♦ DDRx; ♦ PINx.
Глава 17. Подсистема ввода-вывода 163 ПРИМЕЧАНИЕ. Под «х» здесь подразумевается конкретная бук- ва - имя порта. Например, для порта А имена ре- гистров управления будут такими: PORTA, DDRA и PINA. Назначение и наименование II специальных регистров II Рассмотрим теперь назначение каждого из' этих регистров: ♦ PORTx — регистр данных (используется для вывода инфор- мации); ♦ DDRx — регистр направления передачи информации; ♦ PINx — регистр ввода информации. ПРИМЕЧАНИЕ. Отдельные разряды приведенных выше реги- стров также имеют свои имена. Разряды реги- стра PORTx обычно именуются как Рхп. [де «п» - это номер разряда. К примеру, разряды регистра PORTA будут именоваться следующим образом: РА0,РА1,РА2-РА7. Разряды порта DDRx именуются как DDxn (для порта А — DDAO, DDA1-DDA7). Разряды порта PINx именуются как PINxn (для порта А — PINAO, PINA1- PINA7). Для других портов буква А заменяется соответственно на В, С, D, Е, F, G.
164 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. Любой порт ввода-вывода микроконтроллера се- рии AVR устроен таким образом, что каждый его разряд может работать как на ввод, так и на вывод. То есть он может быть входом, а может быть выходом. Для переключения режимов работы служит регистр DDRx. Каждый разряд регистра DDRx управляет своим разря- дом порта. Если в каком-либо разряде регистра DDRx записан ноль, то соответствующий разряд порта работает как вход. Если же в этом разряде единица, то разряд порта работает как выход. I Принцип действия Чтобы выдать информацию на внешний вывод микро- схемы, нужно в соответствующий разряд DDRx записать логическую единицу, а затем записать байт данных в регистр PORTx. Содержимое соответствующего бита этого байта тут же появится на внешнем выводе микросхемы и будет присутство- вать там постоянно, пока не будет заменено другим, либо пока данная линия порта не переключится на ввод. Чтобы прочитать информацию с внешнего вывода микро- контроллера, нужно сначала перевести нужный разряд порта в режим ввода. То есть записать в соответствующий разряд регистра DDRx ноль. Только после этого на данный вывод микроконтроллера можно подавать цифровой сиг- нал от внешнего устройства. Далее микроконтроллер просто читает байт из регистра PINx. Содержимое соответствующего бита прочитанного байта соответствует сигналу на внешнем выводе порта.
Глава 17. Подсистема ввода-вывода 165 Конфигурирование порта ввода-вывода Порты ввода-вывода микроконтроллеров AVR имеют еще одну полезную функцию. В режиме ввода информации они могут при необходимости подключать к каждому выводу порта внутренний нагрузочный резистор. Внутренний резистор позволяет значительно расширить возможности порта. Такой резистор создает вытекающий ток для внешних устройств, подключенных между выводом порта и общим проводом. Благодаря этому резистору упрощается подключение внеш- них контактов и кнопок. Обычно контакты требуют внешнего резистора. Теперь без внешнего резистора можно обойтись. Включением и отключением внутренних резисторов управ- ляет регистр PORTx, если порт находится в режиме ввода. Это наглядно представлено в табл. 17.1, в которой показаны все режимы работы порта.
166 ARDUINO: от азов программирования до создания... Конфигурирование порта ввода-вывода Таблица 17.1 DDxn Рхп Режим Резистор Примечание 0 0 Вход Отключен Вывод отключен от схемы 0 1 Вход Подключен Вывод является источником тока 1 0 Выход Отключен На выходе «0» 1 1 Выход Отключен На выходе «1» На рис. 17. показана упрощенная схема одного разряда порта ввода-вывода. Эта схема дает представление о работе порта. Схема, изображенная на рис. 3.4, — это лишь универсаль- ная часть схемы вывода порта. На самом деле любой вывод кроме основных функций имеет ряд дополнительных. Поэтому реальная схема сложнее. В каждую такую схему добавлены эле- менты, реализующие все дополнительные функции.
ГЛАВА 18 СИСТЕМА ПРЕРЫВАНИЙ Назначение системы II прерываний II Важным элементом микроконтроллера является система прерываний. Система прерываний присутствует в любом современном микроконтроллере. Она также есть во всех микроконтроллерах AVR. Как уже говорилось, система преры- ваний микроконтроллера обслуживает несколько источников прерываний. Количество источников прерываний для разных микроконтроллеров различно. Самое минимальное количество источников прерывания имеет микроконтроллер ATtinyll. Два внутренних источника прерываний (от таймера/счетчика и от встроенного компара- тора), одно внешнее прерывание по сигналу на входе INTO и одно прерывание по изменению сигналов на любом из входов, которое тоже считается внутренним. К источникам прерываний фирма Atmel относит также начальный сброс микроконтроллера. Вектор начального сброса обычно также включают в таблицу векторов прерываний. Так что получается, что у микроконтроллера ATtinyl 1 имеется четыре внутренних источника прерываний и один внешний. Другие микросхемы серии AVR имеют более сложные системы прерываний.
168 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. Самая развитая на сегодняшний день система прерываний - у микроконтроллера АТтеда1281. Этот микроконтроллер способен в общей слож- ности обслуживать 48 внутренних и 17 внешних источников прерываний. Вообще, источниками прерываний служат все встроенные таймеры, компараторы, АЦП, любой последовательный канал, система управления EEPROM. Конкретное количество преры- ваний можно узнать из табл. 13.1 (графа «Кол-во прерываний Внут/Внешн»). Управление системой прерываний Управление системой прерываний осуществляется при помощи специальных регистров ввода-вывода. Определяющим регистром здесь является регистр SREG (регистр состояния системы). Этот регистр предназначен для хранения флагов состояния. Каждый бит регистра — это один из флагов. Седьмой бит регистра состояния называется «флаг I». Это флаг глобаль- ного разрешения прерываний. ПРИМЕЧАНИЕ. Когда значение этого флага равно нулю, все пре- рывания в микроконтроллере запрещены. Для разрешения прерываний нужно установить этот флаг в единицу. Однако чаще всего нам не нужны все виды прерываний одновременно. Чтобы запретить одни прерывания и разре- шить другие, применяются так называемые маскирующие регистры (регистры маски).
Глава 18. Система прерываний 169 ЧТО ЕСТЬ ЧТО. Регистр маски - это обычный регистр ввода- вывода, служащий для управления отдельными источниками прерываний. Каждому биту в реги- стре маски соответствует один источник. Если бит сброшен в ноль, прерывание этого вида за- прещено. Если бит установлен в единичное со- стояние, прерывание разрешено. В микроконтроллерах AVR применяются два регистра маски. Регистр GIMSK управляет всеми видами прерываний, кроме прерываний от таймеров. В некоторых микроконтрол- лерах семейства «Mega» этот регистр называется GICR. Для управления прерываниями от таймеров имеется специальный регистр TIMSK. Кроме регистров маски для управления процессом выпол- нения прерываний существуют еще два регистра. Это реги- стры флагов прерываний. Каждый бит такого регистра — это флаг одного из видов прерываний. При поступлении запроса на прерывание флаг устанавливается в единицу. По состоянию флага программа может судить о наличии запроса. В определенных режимах после установки флага проце- дура обработки прерывания вызывается автоматически. Сразу после вызова процедуры соответствующий флаг сбрасывается. Микроконтроллеры AVR имеют два регистра флагов: ♦ регистр GIFR (обслуживает те же прерывания, что и ре- гистр GIMSK); ♦ регистр TIFR (флаги прерываний от таймеров). Алгоритм работы II системы прерываний II Общий алгоритм работы системы прерываний следую- щий. После сброса микроконтроллера все прерывания запре-
170 ARDUINO: от азов программирования до создания... щены (флаги разрешения сброшены). Если программист плани- рует использовать один из видов прерываний, он должен пред- усмотреть в своей йрограмме включение этого прерывания. ПРИМЕЧАНИЕ. Для включения прерывания программа должна установить флаг I регистра SREG в единицу и записать в регистры маски такой код, который разрешит лишь нужные в данный момент преры- вания. Разрешив, таким образом, прерывания, про- грамма приступает к выполнению своей главной задачи. При поступлении запроса на прерывание устанавливается флаг соответствующего прерывания. Флаг устанавливается даже в том случае, если прерывание запрещено. Если прерывание разрешено, то микроконтроллер приступает к его выполнению. Текущая программа временно приостанавливается, и управле- ние передается на адрес соответствующего вектора прерывания. В тот же момент флаг I автоматически сбрасывается, запре- щая обработку других прерываний. Флаг, соответствующий вызванному прерыванию, также сбрасывается, сигнализируя о том, что микроконтроллер уже приступил к его обработке. ВНИМАНИЕ. ( \ Подпрограммы обработки прерывания обяза- тельно должны оканчиваться командой возвра- та из прерывания (RETI). По этой команде управление передается в ту точку основ- ной программы, в которой прервалась ее работа. Флаг I при этом автоматически устанавливается в единицу, разрешая новые прерывания.
Глава 18. Система прерываний 171 Следует заметить, что без принятия специальных мер невоз- можны вложенные прерывания. Пока обрабатывается одно прерывание, все остальные прерывания запрещены. Однако ни одно прерывание не остается без обработки. При получе- нии запроса на прерывание соответствующий флаг обязательно будет установлен. В этом состоянии он будет находиться до тех пор, пока данное прерывание не будет обработано. После окончания обработки очередного прерывания про- исходит проверка остальных флагов, и если имеется хоть одно необработанное прерывание, микроконтроллер переходит к его обработке. Если необработанных прерываний окажется несколько, то применяется закон приоритетов. Из всех прерыва- ний выбирается то прерывание, приоритет которого выше. Чем меньше адрес вектора прерывания, тем выше его приоритет. Таблицу векторов прерываний для II микроконтроллера ATmega328P II В заключении главы, для примера приведу таблицу век- торов прерываний для микроконтроллера ATmega328P (см. табл. 18.1). Адреса векторов прерываний микроконтроллера АТтеда328Р Таблица 18.1 Источник Номер вектора Адрес вектора Описание RESET 1 $001 Внешнее от сигнала на входе сброса, при включении питания, сброс от сторожевого таймера INTO 2 $002 Внешнее прерывание 0 INTI 3 $003 Внешнее прерывание 1 PCINTO 4 $004 Прерывание 0 по изменению состояния вывода PCINT1 5 $005 Прерывание 1 по изменению состояния вывода PCINT2 6 $006 Прерывание 2 по изменению состояния вывода
172 ARDUINO: от азов программирования до создания... Таблица 18.1 (продолжение) Источник Номер вектора Адрес вектора Описание WDT 7 $007 Сторожевой таймер (если используется в качестве источника прерывания) TIMER2 СОМРА 8 $008 Прерывание по сравнению, канал А таймера/счетчика 2 TIMER2 СОМРВ 9 $009 Прерывание по сравнению, канал В таймера/счетчика 2 TIMER2 OVF 10 $00А Прерывание по переполнению таймера/счетчика 2 TIMER1 САРТ 11 $00В Прерывание таймера/счетчика 1 по захвату TIMER1 СОМРА 12 $00С Прерывание по сравнению, канал А таймера/счетчика 1 TIMER1 СОМРВ 13 $00D Прерывание по сравнению, канал В таймера/счетчика 1 TIMER1, OVF 14 $00Е Прерывание по переполнению таймера/счетчика 1 TIMERO СОМРА 15 $00F Прерывание по сравнению, канал А таймера/счетчика 0 TIMERO СОМРВ 16 $010 Прерывание по сравнению, канал В таймера/счетчика 0 TIMERO, OVF 17 $011 Прерывание по переполнению таймера/счетчика 0 SPI 18 $012 Завершение передачи по последовательному каналу SPI USART.RX 19 $013 Завершение приема по каналу USART USART UDRE 20 $014 Регистр данных USART пуст USART.TX 21 $015 Завершение передачи по каналу USART ADC 22 $016 Преобразование АЦП завершено EE_READY 23 $017 Готовность EEPROM ANALOG, COMP 24 $018 Прорывание от Аналогового компаратора TWI 25 $019 Прерывание от двухпроводного интерфейса (I2C) SPM, READY 26 $01А Прерывание по готовности SPM
ГЛАВА 19 ТАЙМЕРЫ- СЧЕТЧИКИ Классификация II встроенных таймеров II Любой микроконтроллер серии AVR содержит несколько встроенных таймеров. Причем по своему назначению их можно разделить на две категории: ♦ к первой категории относятся таймеры общего назначения; ♦ вторую категорию составляет сторожевой таймер. Сторожевой таймер Сторожевой таймер предназначен для автоматического перезапуска микроконтроллера в случае «зависания» его про- граммы. Для каждой микросхемы нужен всего один стороже- вой таймер. В любом микроконтроллере AVR такой таймер имеется. ЧТО ЕСТЬ ЧТО. Зависанием называют зацикливание программы в результате ошибки, допущенной программистом, либо в результате действия внешней помехи.
174 ARDUINO: от азов программирования до создания... I Таймеры общего назначения Таймеры общего назначения используются для форми- рования различных интервалов времени и прямоугольных импульсов заданной частоты. Кроме того, они могут работать в режиме счетчика и подсчитывать тактовые импульсы задан- ной частоты, измеряя, таким образом, длительность внешних сигналов, а также при необходимости подсчитывать количе- ство любых внешних импульсов. ПРИМЕЧАНИЕ. По этой причине данные таймеры называют «таймеры/счетчики». В микросхемах AVR применяются как восьмиразрядные, так и шестнадцатиразрядные таймеры/счетчики. Их количе- ство для разных микроконтроллеров изменяется от одного до четырех. Точное количество таймеров/счетчиков для каж- дой микросхемы серии AVR можно определить из табл. 13.1 (графа «Таймеры 8/16 бит»). Все таймеры обозначаются чис- лами от 0 до 3. ПРИМЕР. Timer/CounterO, Timer/Counterl и т.д. В русскоя- зычной литературе их чаще именуют сокращен- но ТО, Т1, Т2, ТЗ. Таймеры ТО и Т2 в большинстве микроконтроллеров - восьмиразрядные. Таймеры Т1 и ТЗ - шестнадцатиразрядные. Таймер ТО имеется в любой микросхеме AVR. Остальные до- бавляются по мере усложнения модели.
Глава 19. Таймеры-счетчики 175 Каждый восьмиразрядный таймер представляет собой один восьмиразрядный регистр, который для микроконтрол- лера является регистром ввода-вывода. Этот регистр хранит текущее значение таймера и называется счетным регистром. Шестнадцатиразрядные таймеры имеют шестнадцатиразряд- ный счетный регистр. Каждый счетный регистр имеет свое имя. ЧТО ЕСТЬ ЧТО. Счетный регистр восьмиразрядного таймера называется TCNTx, где «х» - это номер таймера. \_______________________________________________ Для таймера ТО регистр называется TCNT0. Для таймера Т2 — TCNT2. Шестнадцатиразрядные регистры именуются похожим образом. Отличие в том, что каждый шестнадцати- разрядный счетный регистр для микроконтроллера представ- ляет собой два регистра ввода-вывода: ♦ один предназначен для хранения старших битов числа; ♦ второй — для хранения младших битов. К имени регистра старших разрядов добавляется буква Н, а для регистра младших разрядов добавляется буква L. Таким образом, счетный регистр таймера Т1 — это два регистра ввода- вывода: TCNT1H и TCNT1L. Счетный регистр таймера ТЗ — это два регистра TCNT3H и TCNT3L. ПРИМЕЧАНИЕ. Микроконтроллер может записать в любой счетный регистр любое число в любой момент времени, а также в любой момент прочитать со- держимое любого счетного регистра. \___________________________________________ Когда таймер включается в режим счета, то на его вход начи- нают поступать счетные импульсы. После прихода каждого
176 ARDUINO: от азов программирования до создания... такого импульса содержимое счетного регистра увеличивается на единицу. Счетными импульсами могут служить как специ- альные тактовые импульсы, вырабатываемые внутри самого микроконтроллера, так и внешние импульсы, поступающие на специальные входы микросхемы. При переполнении счетного регистра его содержимое обнуляется, и счет начинается сначала. Любой таймер жестко завязан с системой прерываний. Вызвать прерывание может целый ряд событий, связанных с таймером. Например, существует прерывание по переполне- нию таймера, по срабатыванию специальной схемы совпадения. Отдельные прерывания может вызывать сторожевой таймер. I Режимы работы таймеров Таймеры микроконтроллеров семейства AVR могут рабо- тать в нескольких режимах. Разные микроконтроллеры имеют разные наборы режимов для своих таймеров. Для выбора режи- мов работы существуют специальные регистры — регистры управления таймерами. Для простых таймеров используется один регистр управления. Для более сложных — два регистра. ЧТО ЕСТЬ ЧТО. Регистры управления таймером называются TCCRx (где «х» - номер таймера). Например, для таймера ТО используется один регистр с именем TCCR0. Для управления таймером Т1 используется два регистра: TCCR1A и TCCR1B. При помощи регистров управле- ния производится не только выбор соответствующего режима, но и более тонкая настройка таймера. Ниже перечислены все основные режимы работы таймера и их описание.
Глава 19. Таймеры-счетчики 177 Режим Normal Это самый простой режим. В этом режиме таймер произ- водит подсчет приходящих на его вход импульсов (от такто- вого генератора или внешнего устройства) и вызывает преры- вание по переполнению. Этот режим является единственным режимом работы для восьмиразрядных таймеров большин- ства микроконтроллеров семейства «Tiny» и для части микро- контроллеров семейства «Mega». Для всех остальных восьми- разрядных и всех шестнадцатиразрядных таймеров это всего лишь один из возможных режимов. Режим «Захват» II (Capture) II Суть этого режима заключается в сохранении содержимого счетного регистра таймера в определенный момент времени. Запоминание происходит либо по сигналу, поступающему через специальный вход микроконтроллера, либо от сигнала с выхода встроенного компаратора. ПРИМЕЧАНИЕ. Этот режим удобен в том случае, когда нужно из- мерить длительность какого-либо внешнего про- цесса. Например, время, за которое напряжение на конденсаторе достигнет определенного значения. В этом случае, напряжение с конденсатора пода- ется на один из входов компаратора, а на второй его вход подается опорное напряжение. \. Микроконтроллер должен одновременно запустить два этих процесса: ♦ подать напряжение на конденсатор; ♦ запустить таймер в режиме Capture.
178 ARDUINO: от азов программирования до создания... Конденсатор начнет заряжаться, напряжение на нем при этом будет плавно расти. Одновременно счетчик таймера будет отсчитывать тактовые импульсы заданной частоты. В тот момент, когда напряжение на конденсаторе сравняется с опорным напряжением, логический уровень на выходе компа- ратора изменится на противоположный. По этому сигналу текущее значение счетного регистра запоминается в специальном регистре захвата. Имя этого регистра ICRx (для таймера ТО это будет ICR0, для Т1 — ICR1 и т. д.). Одновременно вырабатывается запрос на прерывание. СОВЕТ. Используя принцип измерения времени зарядки, удобно создавать простые схемы, работающие с различными аналоговыми датчиками (темпе- ратуры, давления и т. д.). Если принцип работы датчика состоит в изменении его внутреннего сопротивления, то такой датчик можно вклю- чить в цепь зарядки конденсатора. Емкостные датчики можно подключать напрямую. I Режим «Сброс при совпадении» (СТС) Для работы в режиме СТС используется специальный регистр — регистр совпадения. Если микроконтроллер содер- жит несколько таймеров, то для каждого из них существует свой отдельный регистр совпадения. ПРИМЕЧАНИЕ. Для восьмиразрядных таймеров регистр совпа- дения - это один восьмиразрядный регистр. Для шестнадцатиразрядных таймеров регистр со- < впадения - это два восьмиразрядных регистра.
Глава 19. Таймеры-счетчики 179 Регистры сравнения также имеют свои имена. Например, регистр совпадения таймера Т1 состоит из двух регистров: ♦ OCR1L; ♦ OCR1H. В ряде микроконтроллеров существуют два регистра совпа- дения. Так, во всех микроконтроллерах семейства «Tiny» суще- ствует два регистра совпадения для таймера Т1. Это регистры: ♦ OCR1A; ♦ OCR1B. Два регистра совпадения для таймера Т1 имеет и микро- контроллер ATmega8x. Во втором случае, как таймер, так и его регистры совпадения имеют шестнадцать разрядов. Если регистр совпадения шестнадцатиразрядный, то физи- чески он состоят из двух регистров ввода-вывода. ПРИМЕР. Два регистра совпадения таймера Т1 микросхе- мы АТтеда8х представляют собой четыре реги- стра ввода-вывода с именами OCR1AL, OCR1AH, OCR1BL, OCR1BH. Как же используются регистры совпадения? Эти регистры включаются в работу только тогда, когда выбран режим СТС. В этом режиме, как и в предыдущем, таймер производит подсчет входных импульсов. Текущее значение таймера из его счетного регистра постоянно сравнивается с содержимым регистров совпадения. Если таймер имеет два регистра совпадения, то для каждого из этих регистров производится отдельное сравнение. Когда содержимое счетного регистра совпадет с содержимым одного из регистров совпадения, произойдет вызов соответствующего прерывания. Кроме вызова прерывания, В момент совпадения может происходить одно из следующих событий: ♦ сброс таймера (верно только для регистров совпадения OCR1 и OCR1A);
180 ARDUINO: от азов программирования до создания... ♦ изменение состояния одного из выводов микроконтролле- ра (верно для всех регистров). ПРИМЕЧАНИЕ. Произойдет или не произойдет одно или обо со- бытия из вышеперечисленных, определяется при настройке таймера. I Режим «Быстродействующий ШИМ» (Fast PWM) ЧТО ЕСТЬ ЧТО. ШИМ - расшифровывается как Широтно- Импульсная Модуляция. На английском это зву- чит как «Pulse Width Modulation» (PWM). Сигнал с ШИМ часто используется в устройствах управ- ления. Сигнал с ШИМ можно, например, использовать для регули- ровки скорости вращения электродвигателя постоянного тока. Для этого вместо постоянного напряжения на двигатель пода- ется прямоугольное импульсное напряжение. Благодаря инер- ции двигателя импульсы сглаживаются, и двигатель вращается равномерно. Меняя скважность импульсов (то есть отноше- ние периода импульсов к их длительности), можно изменять среднее напряжение, приложенное к двигателю и, тем самым, менять скорость его вращения. Точно таким же образом можно управлять и другими устройствами: ♦ нагревательными элементами; ♦ осветительными приборами и т. п.
Глава 19. Таймеры-счетчики 181 ПРИМЕЧАНИЕ. Преимущество импульсного управления - ‘в вы- соком КПД. Импульсные управляющие элементы рассеивают гораздо меньше паразитной мощно- сти, чем управляющие элементы, работающие в аналоговом режиме. Для формирования сигнала ШИМ используются те же самые регистры совпадения, которые работают и в режиме СТС. Формирование сигнала ШИМ может осуществляться несколь- кими разными способами. Работа таймера в режиме Fast PWM проиллюстрирована на рис. 19.1. Сигнал с ШИМ формируется на специальном выходе микро- контроллера. На вход таймера подаются импульсы от систем- ного генератора. Таймер находится в состоянии непрерывного счета. При переполнении таймера его содержимое сбрасыва- ется в ноль, и счет начинается сначала. В режиме ШИМ пере- Большая скважность Рис. 19.1. Работа таймера в режиме Fast PWM
182 ARDUINO: от азов программирования до создания... полнение таймера не вызывает прерываний. На рис. 19.1 это показано в виде пилообразной кривой, обозначенной как TCNTn. Кривая представляет собой зависимость содержимого счетного регистра от времени. Содержимое счетного регистра непрерывно сравнивается с содержимым регистра совпадения. Пока число в регистре OCRn больше, чем число в счетном регистре таймера (TCNTn), напря- жение на выходе ШИМ равно логической единице. Когда же в процессе счета содержимое счетного регистра TCNTn станет больше содержимого OCRn, на выходе ШИМ установится нуле- вой потенциал. В результате на выходе мы получим прямоу- гольные импульсы. ПРИМЕЧАНИЕ. Скважность этих импульсов будет зависеть от содержимого регистра OCRn. Чем меньше число в OCRn, тем выше скважность выходных импульсов. На рис. 19.1 показана скважность импульсов для двух разных значений регистра OCRn. Если содержимое OCRn достигнет своего максималь- ного значения, то импульсы на выходе ШИМ исчезнут, и там постоянно будет присутствовать логическая единица. При уменьшении числа в OCRn появятся импульсы малой скваж- ности (длительность почти равна периоду). Если плавно уменьшать число в OCRn, то скважность будет плавно умень- шаться. Когда содержимое OCRn достигнет нуля, импульсы на выходе ШИМ также исчезнут, и там установится логиче- ский ноль.
Глава 19. Таймеры-счетчики 183 Режим «ШИМ с точной фазой» (Phase Correct PWM) ПРИМЕЧАНИЕ. Описанный в предыдущем разделе режим ШИМ имеет один недостаток: при изменении дли- тельности импульсов меняется и их фаза. Центр каждого импульса как бы сдвигается во времени. При управлении электродвигателем такое пове- дение фазы нежелательно. Поэтому в микроконтроллерах AVR предусмотрен еще один режим ШИМ. Это ШИМ с точной фазой. Принцип работы тай- мера в этом режиме изображен на рис. 19.2. ОСАп TCNTn ивых Малая скважность OCRn - TCNTn ивых Большая скважность Рис. 19.2. Работа таймера в режиме Phase Correct PWM
184 ARDUINO: от азов программирования до создания... Отличие режима «Phase Correct PWM» от режима «Fast PWM» заключается в режиме работы счетчика. Сначала счет- чик считает так же, как и в предыдущем режиме (от каждого входного импульса его значение увеличивается на единицу). Достигнув своего максимального значения, счетчик не сбра- сывается в ноль, а переключается в режим реверсивного счета. Теперь уже от каждого входного импульса его содержимое уменьшается на единицу. В результате пилообразная кривая, отображающая содержимое счетного регистра TCNTn, стано- вится симметричной, как показано на рис. 3.6. Система совпа- дения работает так же, как и в предыдущем случае. Благодаря симметричности сигнала на таймере, фаза выходных импульсов в процессе регулировки скважности не изменяется. Середина каждого импульса строго привязана к точке смены направления счета таймера. ПРИМЕЧАНИЕ. Недостатком режима «Phase Correct PWM» мож- но считать в два раза меньшую частоту выход- ного сигнала. Это существенно уменьшает дина- мичность регулирования. Кроме того, при использовании внешних филь- тров для преобразования импульсного сигнала ШИМ в аналоговый, схема с более низкой часто- той потребует применения комплектующих с большими габаритами и массой. к_______________________________________________. I Асинхронный режим В некоторых моделях микроконтроллеров таймер может работать в асинхронном режиме, в котором: ♦ на вход таймера подается либо частота от внутренне- го кварцевого генератора, либо от внешнего генератора.
Глава 19. Таймеры-счетчики 185 Счетчик не вырабатывает никаких прерываний и дополни- тельных сигналов; ♦ таймер работает в качестве часов реального времени. Микроконтроллер может предустанавливать содержимое счетного регистра. А затем в любой момент он может считать это содержимое, получив, таким образом, текущее значение реального времени. Предделители II таймеров/счетчиков II Как уже говорилось ранее, каждый таймер микроконтрол- лера может работать от двух разных источников тактовых импульсов: ♦ либо это внешние импульсы; ♦ либо импульсы, вырабатываемые внутренней схемой ми- кроконтроллера. Какой бы источник сигналов ни был выбран перед тем, как попасть на вход таймера, этот сигнал проходит схему пред- варительного делителя. Предварительный делитель пред- назначен для того, чтобы расширить диапазон формируемых частот и длительностей таймера. Каждая микросхема AVR имеет свою структуру предварительного делителя для тайме- ров/счетчиков. Упрощенная схема одного из вариантов предварительного делителя приведена на рис. 19.3. Как видно из схемы, частота внутреннего тактового гене- ратора CLK поступает на специальный десятиразрядный дели- тель. С выходов делителя снимаются сигналы: ♦ CLK/8; ♦ CLK/32; ♦ CLK/64; ♦ CLK/128; ♦ CLK/256; ♦ CLK/1024.
186 ARDUINO: от азов программирования до создания... ClkTn Рис. 19.3. Предделитель для таймера Все эти сигналы поступают на входы данных мультиплек- сора. На адресные входы мультиплексора поступают сигналы от трех разрядов регистра управления таймером (TCCRn). ПРИМЕЧАНИЕ. Таким образом, записывая в разряды CSnO, CSnl, CSn2 различные значения, можно выбирать один из восьми режимов роботы предделителя. В за- висимости от выбранного режима, на выход схе- мы могут поступать сигнал с одного из выходов десятиразрядного делителя, прямой сигнал с тактового генератора либо нулевой логический уровень (входа DO). В последнем случае сигнал на входе таймера будет отсутствовать, и его ра- бота приостанавливается. Схема, приведенная на рис. 19.3, не является стандартом для всех микроконтроллеров серии AVR. Она отражает лишь общий принцип построения предделителей. В разных моделях это сделано немного по-разному.
Глава 19. Таймеры-счетчики 187 На рис. 19.4 приведена еще одна схема предделителя. Эта схема, в отличие от предыдущей, предусматривает подачу на входы таймеров тактового сигнала от внешнего источника. Для этого количество сигналов, снимаемых с десятиразрядного делителя, уменьшено до четырех. CLK/32 и CLK/128 исключены. Зато в схеме появились цепи, через которые на вход таймера может поступать внешние импульсы. Эти импульсы должны подаваться на вход Tn. С этого входа импульсы поступают на формирователь, который осущест- вляет их предварительную обработку (приближает их форму к прямоугольной). Затем импульсы поступают на вход D7 дешифратора. На вход D6 поступают те же импульсы, но только в инвер- тированном виде. В результате для схемы, показанной на рис. 19.4, мы получаем следующие восемь режимов работы: ♦ режим 0 — отсутствие импульсов; ♦ режим 1 — прямой сигнал от внутреннего генератора; ♦ режимы 2...5 — один из сигналов с делителя; ♦ режим 6 — инверсный сигнал с внешнего входа; ♦ режим 7 — прямой внешний сигнал. Рис. 19.4. Предделитель с входом для внешнего сигнала
ГЛАВА 20 ВСТРОЕННЫЕ ПЕРИФЕРИЙНЫЕ УСТРОЙСТВА I Аналоговый компаратор Компаратор предназначен для сравнения напряжений на двух специальных внешних входах. Такие входы имеют назва- ния: ♦ AIN0 (неинвертирующий); ♦ AIN1 (инвертирующий). ПРИМЕЧАНИЕ. Не забываем, что каждый из этих входов совме- щен с одной из линий какого-либо порта ввода- вывода. Если напряжение на входе AINO больше, чем напряжение на входе AIN1, то на выходе ком- паратора - логическая единица. В противном случае там логический ноль. Этот результат сохраняется в одном из разрядов специаль- ного регистра ввода-вывода, предназначенного для работы с компаратором. Регистр называется ACSR. А разряд, куда выво-
Глава 20. Встроенные периферийные устройства 189 дится выходной сигнал компаратора, тоже имеет свое название. Он называется АСО. Другой разряд под названием ACD того же регистра отвечает за включение/выключение компаратора. Еще два разряда ACIS0 и ACIS1 определяют способ влияния сигнала с выхода компаратора на последующие схемы. Есть три варианта: ♦ любое изменение на выходе; ♦ изменение с единицы на ноль; ♦ изменение с ноля на единицу. Как видите, отдельные разряды некоторых регистров тоже иногда различаются не по номерам, а по названиям. Это позво- ляет в разных микроконтроллерах использовать для одной и той же цели разные разряды регистров. В этом случае имя раз- ряда остается прежним. Хотя чаще всего номера разрядов не меняются. Схема компаратора имеет специальный внутренний источ- ник опорного напряжения, который может быть подключен к неинвертирующему входу компаратора. Подключением вну- треннего источника управляет разряд ACBG регистра ACSR. Кроме того, на инвертирующий вход компаратора можно подать сигнал с любого входа АЦП. Этим переключением управляют остальные разряды регистра ACSR. Что такое АЦП, и какие АЦП применяются в микроконтроллерах серии AVR, мы рассмотрим в следующем разделе. Аналого-цифровой II преобразователь II Аналого-цифровой преобразователь (АЦП) предназна- чен для преобразования аналогового напряжения в цифровую форму. На вход АЦП поступает обычное аналоговое напряжение. Преобразователь измеряет величину этого напряжения и выдает на выходе цифровой код, соответствующий этой величине. АЦП применяются в микропроцессорных системах управ- ления, которые должны управлять различными аналоговыми
190 ARDUINO: от азов программирования до создания... процессами. Например, микропроцессорный стабилизатор напряжения, цифровой вольтметр и т. п. ПРИМЕЧАНИЕ. Встроенный АЦП имеют не все микроконтролле- ры AVR. Это и понятно. Ввод аналоговой инфор- мации нужен далеко не всегда. В микроконтроллерах AVR применяется десятиразрядное АЦП последовательного приближения. Микросхемы, имею- щие в своем составе встроенный АЦП, обязательно имеют раз- дельное питание для цифровой и для аналоговой частей схемы. Поэтому они имеют два вывода питания и два вывода общего провода. Кроме того, один из выводов зарезервирован для подачи на микросхему внешнего опорного напряжения. Опорное напря- жение используется в схеме АЦП для оценки уровня входного сигнала. От стабильности опорного напряжения зависит точ- ность измерения. Каждый АЦП снабжен многоканальным аналоговым комму- татором (мультиплексором), который позволяет измерять ана- логовое напряжение с нескольких разных входов. Количество входов АЦП у разных микросхем различное. Существуют вари- анты в 4,6,8 и 11 входов. ПРИМЕЧАНИЕ. Количество входов аналого-цифрового преобразо- вания для каждой из микросхем серии AVR можно узнать из табл. 13.1 (графа «Число Каналов АЦП»), Обычно измеряемый сигнал прикладывается между соот- ветствующим входом АЦП и аналоговым общим проводом. Такие входы называются несимметричными. В некоторых
Глава 20. Встроенные периферийные устройства 191 микроконтроллерах имеется режим, в котором входы АЦП объ- единяются попарно и образуют дифференциальные входы. Дифференциальные входы отличаются от обычных тем, что измеряемый сигнал прикладывается между двумя входами: ♦ прямым; ♦ инверсным. При этом наводимые помехи компенсируются, а полезный сигнал проходит без изменений. Такие входы называются сим- метричными. Процесс преобразования напряжения в код занимает 13 или 14 тактов. За это время происходит подбор кода методом последовательных приближений. По окончании процесса пре- образования вырабатывается запрос на прерывание. Результат преобразования записывается в пару регистров ADCH, ADCL. ПРИМЕЧАНИЕ. Из шестнадцати разрядов этой регистровой поры используются только 10. Остальные всег- да равны нулю. Причем могут использоваться либо десять старших разрядов (ADCH7 - ADCH0, ADCL7, ADCL6), либо десять младших разрядов (ADCH1, ADCHO, ADCL7 - ADCLO). Это зависит от выбранного вами режима работы. АЦП могут работать как в одиночном режиме, так и в непрерывном. В непрерывном режиме преобразования идут один за другим. В одиночном режиме процесс преобразования запускается однократно от одного из следующих событий: ♦ прерывания от аналогового компаратора; внешнего пре- рывания INTO; ♦ прерывания по событию «Совпадение» одного из таймеров; ♦ прерывания по переполнению одного из таймеров; ♦ прерывания по событию «Захват» одного из таймеров. Управление всеми режимами работы АЦП производится при помощи двух специальных регистров:
192 ARDUINO: от азов программирования до создания... ♦ ADMUX (предназначен для управления входным аналого- вым мультиплексором); ♦ ADCSR (предназначен для выбора режима работы АЦП). Процесс преобразования в АЦП синхронизируется от внутреннего генератора микроконтроллера. Тактовый сиг- нал от генератора поступает на АЦП через предваритель- ный делитель с программируемым коэффициентом деления. Коэффициент деления зависит от значения разрядов ADPS0, ADPS1 и ADPS2 регистра ADCSR и может принимать значения 2,4,8,16,32,64 и 128. СОВЕТ. Наибольшая точность преобразования дости- гается тогда, когда тактовая частота преоб- разования находится в диапазоне 50-200 кГц. Поэтому рекомендуется выбирать такой коэф- фициент деления, чтобы тактовая частота мо- дуля АЦП находилась в этом диапазоне. I Последовательный канал (UART/USART) Некоторые микроконтроллеры серии AVR имеют: ♦ встроенный универсальный последовательный асинхрон- ный приемопередатчик (UART); ♦ универсальный последовательный синхронно/асинхрон- ный приемопередатчик (USART). А у некоторых моделей сразу два таких канала. Наличие UART для разных микроконтроллеров указано в графе «UART» в табл. 13.1. Каналы UART (USART) предназначены для обмена инфор- мацией между микроконтроллером и любым внешним устрой- ством. Протокол UART (USART) — это довольно распространен- ный протокол последовательной передачи информации. Такой протокол, в частности, использует последовательный порт ком-
Глава 20. Встроенные периферийные устройства 193 пьютера (COM-порт). При помощи UART (USART) можно органи- зовывать линию связи не только между двумя микроконтролле- рами, но и между микроконтроллером и компьютером. Для обмена информацией UART (USART) использует две линии: ♦ RxD (используется для приема информации); ♦ TxD (используется для передачи информации). В модулях UART посылка может быть восьми- или девяти- разрядной. В модуле USART ее длина составляет от 5 до 9 раз- рядов. Кроме того, модули могут вырабатывать и контролиро- вать разряд четности. Скорость передачи определяется специальным внутренним программируемым делителем и частотой тактового генератора микроконтроллера. Коэффициент деления делителя может изменяться от 2 до 65536. ПРИМЕЧАНИЕ. Чтобы последовательный канал мог нормально обмениваться информацией с внешними устрой- ствами, необходимо так подобрать коэффици- ент деления и частоту тактового генератора, чтобы получить одну из стандартных скоро- стей передачи информации. Например, 2400,4800, 9600,14400,19200,28800 бит в секунду. Последовательный периферийный II интерфейс (SPI) II Это специальный последовательный интерфейс, разрабо- танный для связи микроконтроллеров между собой. Канал SPI использует для передачи информации три линии: ♦ линию MISO (Master Input / Slave Output); ♦ линию MOSI (Master Output / Slave Input); ♦ линию SCK (Тактовый сигнал).
194 ARDUINO: от азов программирования до создания... В микроконтроллерах AVR канал SPI может выполнять дво- якую функцию. Так, при помощи этого интерфейса можно не только организовать последовательный канал обмена инфор- мацией между двумя микроконтроллерами, но и между микро- контроллером и любым периферийным устройством, имею- щим SPI-интерфейс. ПРИМЕЧАНИЕ. Существует целый набор подобных устройств: цифровые потенциометры, ЦАП/АЦП, внешние Flash-ПЗУ и др., В табл. 13.1 в графе SPI приведена информация о наличии канала SPI в разных микроконтроллерах. Здесь имеется в виду полный SPI-канал, способный выполнять все вышеперечислен- ные функции. Второе предназначение канала SPI — программирование микроконтроллера. Именно через этот канал осуществляется последовательное программирование памяти программ и вну- треннего EEPROM. Такой усеченный канал SPI имеется практи- чески в каждом микроконтроллере AVR. Преимущество программирования через SPI состоит в том, что такой способ позволяет программировать микросхему, не вынимая ее из отлаживаемого устройства. Это так называемое внутрисхемное программирование. Необходимо лишь позабо- титься, чтобы другие сигналы на выводах, служащих линиями SPI интерфейса, отключались в момент программирования. Обычно в плате отлаживаемого устройства предусматри- вают специальный разъем, куда и подключается программатор. ПРИМЕЧАНИЕ. Модуль Arduino отличается кок раз тем, что не требует специального программатора. Модуль использует функцию самопрограммирования ми- кроконтроллера.
Глава 20. Встроенные периферийные устройства 195 Последовательный двухпроводный интерфейс (TWI) Этот интерфейс является полным аналогом шины 12С фирмы Philips, получившей широкое распространение в раз- личных системах управления бытовой и промышленной техни- кой. Интерфейс позволяет объединить вместе до 128 устройств, подключив их к одной двухпроводной шине. Линии шины 12С имеют следующие названия: ♦ линия SCL (линия тактового сигнала); ♦ линия SDA (линия передачи данных). Интерфейс позволяет обмениваться данными между веду- щим устройством, которым обычно является микроконтрол- лер, и любым из внешних устройств, подключенных к двухпро- водной линии. При этом ведущее устройство может как пере- давать данные на ведомое, так и принимать данные из него. Наличие интерфейса для работы с 12С шиной позволяет применять микроконтроллеры в системах управления телеви- зоров, радиоприемников и т. п. Специализированные микро- схемы для телевизионных приемников, радиоприемников, магнитол с 12С-интерфейсом в настоящее время становятся фактически стандартом. Кроме того, в настоящее время широко применяются кон- троллеры дисплеев на жидких кристаллах, микросхемы Flash- памяти и другие устройства, управляемые по 12С-шине.
ГЛАВА 21 ПРОГРАММИРУЕМЫЕ ПЕРЕКЛЮЧАТЕЛИ РЕЖИМОВ И ЯЧЕЙКИ ЗАЩИТЫ ИНФОРМАЦИИ II Конфигурационные II ячейки Все контроллеры AVR имеют множество режимов работы. Некоторые из режимов невозможно переключить программ- ным путем, используя регистры управления. Например, в боль- шинстве моделей микроконтроллеров в качестве тактового генератора можно применять встроенный параметрический генератор с подстраиваемой частотой. Два освободившихся контакта плюс контакт аппаратного сброса (Reset) можно использовать как дополнительный трехразрядный порт ввода- вывода. Естественно, что перевести в такой режим микросхему нужно еще до включения в схему. Для подобных целей фирма Atmel ввела в свои микро- контроллеры новый настроечный элемент — программиру- емые переключатели режимов. Эти переключатели выпол- нены в виде специальных ячеек, которые, по сути, являются еще одним видом перепрограммируемой энергонезависимой памяти. Все конфигурационные ячейки объединяются в байты. Различные микросхемы AVR имеют от одной до трех байтов конфигурационных ячеек.
Глава 21. Программируемые переключатели режимов и ячейки защиты... 197 ПРИМЕЧАНИЕ. Каждый конфигурационный переключатель пред- назначен для того, чтобы изменять какой-либо один параметр или режим работы микрокон- троллера. В документации каждый такой пере- ключатель имеет свое определенное имя. Некоторые биты конфигурационных ячеек объединены в группы. Например, группа из четырех битов CKSEL3 — 0 позво- ляет выбирать режимы синхронизации. Разные модели микро- контроллеров имеют различные наборы конфигурационных ячеек. По терминологии фирмы Atmel, конфигурационные ячейки называются Fuse Bits. Поэтому для удобства и кратко- сти эти ячейки часто называют «Фусами», или Fuse-ячейками. ПРИМЕЧАНИЕ. Запись и чтение конфигурационных ячеек воз- можны только при помощи программатора. Все ^запрограммированные Fuse-ячейки содержат еди- ницу. При программировании в ячейку записывается ноль. Некоторые ячейки программируются еще на заводе. Состояние всех конфигурационных ячеек для каждой конкретной микро- схемы смотрите в документации на эту микросхему. При работе с модулем Arduino вам не придется забо- титься о состоянии Fuse переключателей. Все переключатели установлены заранее при производстве модуля и не должны изменяться, так как иначе может быть нарушена логика работы платы.
198 ARDUINO: от азов программирования до создания... I Ячейки защиты и идентификации Исторически сложилось так, что даже самые первые модели микроконтроллеров имели программируемые ячейки защиты информации. Микроконтроллеры AVR также имеют такую защиту. Это специальные ячейки, подобные конфигура- ционным. Каждый микроконтроллер имеет, как минимум, две защитные ячейки LB1 и LB2. Запись и чтение этих ячеек воз- можны только в режиме программирования. При записи нуля в LB1 блокируется запись данных во Flash- и EEPROM-память. Одновременно блокируется возможность изменять конфигура- ционные ячейки. Если записать ноль еще и в LB2, то блокируется и возмож- ность чтения всех данных. После этого узнать содержимое вашей программы будет невозможно. Для повторного исполь- зования микроконтроллера нужно подать команду «Стирание микросхемы». При этом вся информация теряется, а способ- ность чтения и модификации возвращается. В микроконтроллерах семейства «Mega» имеются дополни- тельные ячейки защиты BLB02, BLB01, BLB12, BLB11. Они слу- жат для ограничения доступа к различным областям памяти программ. Еще одна группа ячеек — это ячейки идентифика- ции. Любой микроконтроллер имеет три ячейки идентифи- кации. Эти ячейки доступны только для чтения и содержат информацию о производителе и модели микроконтроллера. ПРИМЕЧАНИЕ. Подробнее о ячейках защиты и о ячейках иден- тификации можно прочитать в документации (Datasheet) но конкретный микроконтроллер.
ЧАСТЬ IV МОДУ/lbARDUiNO- КОНСТРУКТОР ДЛЯ ДОМОХОЗЯЕК Модуль ARDUINO - это небольшая плата, содержащая собственный процессор, память и множество контактов, к кото- рой можно подключать все, что рабо- тает от электричества. В процессор модуля ARDUINO можно загрузить про- грамму для управления подключенными устройствами по заданному алгоритму. Есть возможность создать бесконечное количество уникальных практических устройств, сделанных своими руками, реа- лизуя собственные идеи. Узнаем подроб- нее, что же это такое модуль Arduino и почему его называют «конструктор для домохозяек».
ГЛАВА 22 МОДУЛЬ ARDUINO - ПЕРВОЕ ЗНАКОМСТВО Почему стал популярным модуль Arduino? Модуль Arduino — это небольшая плата, собранная на микроконтроллере AVR, которая служит основой для создания любых электронных устройств управления, сигнализации и автоматики, которые могут применяться в самых разных обла- стях электронной техники. ПРИМЕЧАНИЕ. Arduino является отличной альтернативой для начинающих разработчиков благодаря тому, что в модуле использован ряд оригинальных решений упрощающих разработку как схем, так и про- грамм. Модуль не требует отдельного программатора и предостав- ляет разработчику простые средства обмена информацией с компьютером по последовательному USB каналу. Arduino ока- зался настолько удачной разработкой и получил настолько широкое распространение во всем мире, что теперь именно он считается самой удачной основой для изучения азов микро- контроллерной техники.
Глава 22. Модуль Arduino - первое знакомство 201 Как будем осваивать II язык Arduino II Как уже говорилось выше, данная книга содержит набор специально разработанных примеров, на основе которых чита- тель постепенно, от простого к сложному, учится разрабаты- вать схемы и создавать программы с использованием модуля Arduino. Каждый пример снабжен: ♦ подробным описанием решаемой проблемы; ♦ четко сформулированной постановкой задачи; ♦ описанием алгоритма; ♦ подробным описанием схемы и готовой программы. В книге вы увидите очень подробное описание каждой про- граммы. Изучение языка программирования Arduino идет в ходе разбора каждой программы. Все функции, операторы и другие элементы языка программирования подробно описываются перед тем, как начинается разбор той программы, где они используются.
ГЛАВА 23 МОДУЛЬ ARDUINO: ОСВАИВАЕМ ТЕОРЕТИЧЕСКИ |Кто и зачем создал модуль Arduino? Модуль Arduino придумали пятеро друзей из малень- кого итальянского городка Ивреа, стоящего на реке Дора Балтея. Городок знаменит своими королями-неудачниками. В 1002 году король по имени АРДУИН стал правителем страны, но через два года был свергнут королем Германии Генри II. Сегодня есть бар ди Ре Arduino, расположенный в историче- ской части этого городка. Назван бар в честь короля и стоит на том самом месте, где, по преданию, родился король. Бар явля- ется пивнушкой Массимо Банци (Massimo Banzi), итальянского соучредителя уникального проекта в сфере электроники, кото- рый был назван в честь этого места. Появился модуль в 2005 году. Создателей Arduino звали так: ♦ Дэвид Куар-тилльз (David Cuartielles); ♦ Джанлука Мартино (Gianluka Martino); ♦ Том Иго (Tom Igoe); ♦ Дэвид Мелис (David Meilis); * Массимо Банци (Massimo Banzi). Эта компания из пяти единомышленников разработала учебное пособие для студентов Института проектирования
Глава 23. Модуль ARDUINO: осваиваем теоретически 203 взаимодействий города Ивреа. При помощи этого модуля сту- денты изучали микроэлектронику. ПРИМЕЧАНИЕ. Название модуля было придумано позже по име- ни упонянутого ранее бара «Arduino», в котором любили собираться друзья и обсуждать там все свои идеи. Модуль получился настолько удачным, что моментально стал известен во всем мире! Arduino — недорогая микрокон- троллерная плата, которая позволяет даже новичку делать по-настоящему удивительные вещи. Как же удалось достичь || такой популярности? II Прежде всего, разработчики Arduino (первоначально он вообще не имел названия, но будем называть его так) решили упростить процесс прошивки программ в программную память микроконтроллера. Традиционно, для прошивки микроконтрол- леров использовались отдельные устройства—программаторы. Программатор подключается к компьютеру, а уже к про- грамматору подключается микроконтроллер. Разработчики решили избавиться от такого вспомогательного устройства, как программатор. Решение напрашивалось само собой. Большинство выпускаемых микроконтроллеров к тому вре- мени уже имело такую полезную функцию, как возможность самопрограммирования. Для этого программная память микроконтроллера раз- бивалась на две области соответствующими настрой- ками (точнее установкой его битов конфигурации FUSE- переключателями):
204 ARDUINO: от азов программирования до создания... ♦ часть памяти выделялась под область загрузчика; ♦ оставшаяся же память использовалась для размещения ту- да основной рабочей программы. ЧТО ЕСТЬ что. Область загрузчика - это защищенная область программной памяти. Программный код, записан- ный в эту область, не может быть переписан са- мопрограммированием. Такая конфигурация программной памяти позволяла про- граммисту поместить в область загрузчика программу, кото- рая в нужный момент, используя любые внешние каналы связи микроконтроллера, будет: ♦ получать извне коды нового варианта рабочей программы; ♦ прошивать эти коды в основную часть программной памяти. Программа-загрузчик обычно разрабатывается програм- мистом, и алгоритмы ее работы зависят от его квалификации и фантазии. В настоящее время технология самопрограмми- рования широко используется в самых разных электронных устройствах. Она позволяет заливать обновленные версии про- грамм, используя самые разные источники данных. Например, Интернет, компьютер и т. п. I Первые варианты Arduino Самые первые варианты Arduino представляли собой плату, на которую был установлен микроконтроллер (использова- лись микроконтроллеры AVR) и элементы самой необходимой внешней обвязки: ♦ цепи сброса; ♦ внешний кварцевый резонатор;
Глава 23, Модуль ARDUINO: осваиваем теоретически 205 ♦ стабилизатор напряжения; ♦ несколько светодиодов для индикации питания и сигналов канала связи. С компьютером первые Arduino связывались при помощи последовательного порта. В микроконтроллере для этого использовался встроенный канал UART, а в компьютере — СОМ порт. ПРИМЕЧАНИЕ. Оба этих стандарта основаны на едином прото- коле RS-252. Но UART отличается от СОМ уров- нями сигнала. Последовательный канал в микроконтроллере работает с сигналом, принимающим значения: 0 В и +5 В. В стандарте СОМ используются уровни плюс 12 В и минус 12 В. Поэтому на плате Arduino присутствовала схема преоб- разования уровней. На рис. 23.1 изображен один из первых вариантов Arduino, использующих СОМ порт для связи с компьютером. ПРИМЕЧАНИЕ. Как известно, СОМ порты в настоящее время уже полностью вытеснены таким универсаль- ным стандартом, как USB. Поэтому и Arduino пришлось приспосабливаться. На платах Arduino появились микросхемы с адаптерами USB-COM. В одном из вариантов маленький модуль с преобра- зователем USB-COM выполнялся как отдельный модуль, кото- рый после загрузки и отладки программы в основную плату снимался и мог быть использован для отладки и прошивки в других разработках.
206 ARDUINO: от азов программирования до создания... Рис. 23.1. Модуль Ардуино для СОМ порта Рис. 23.2. Модуль Arduino UNO
Глава 23. Модуль ARDUINO: осваиваем теоретически 207 В настоящее время все модели Arduino снабжены USB пор- тами. На сегодняшний день в мире разработано и произво- дится большое количество самых различных моделей Arduino. На рис. 23.2 изображена плата одного из вариантов модуля, который носит название «Arduino UNO». Это довольно удач- ная модель, которая получила довольно широкое распростра- нение по всему миру, в том числе и в России. Ее мы и будем использовать в качестве примера в нашей книге. Знакомимся с модулем II Arduino UNO II Для того чтобы понять, какие преимущества дает начи- нающему разработчику электронных устройств архитектура модуля Arduino, рассмотрим модель Arduino UNO подробнее. Существует несколько версий Arduino UNO. Они отличаются по: ♦ схеме; ♦ размещению некоторых деталей на плате; ♦ типу корпуса микросхем. Но все они полностью совместимы между собой и взаимо- заменяемы. На рис. 23.2 показан внешний вид одного из вариантов Arduino UNO. В основе этой модели модуля лежит микрокон- троллер ATmega328P. При этом существует две разновидности: ♦ вариант на микросхеме в DIP корпусе (как раз его мы ви- дим на рис. 23.2); ♦ вариант на микросхемах в SMD корпусе. Разные модели также отличаются типом преобразователя USB-COM: ♦ в одних вариантах используется специализированная ми- кросхема CH340G; ♦ в других же (как на рис. 23.2) в качестве преобразователя используется микроконтроллер Atmegal6U2 с соответству- ющей программой, зашитой в ее программную память.
208 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. Но какой бы вариант не использовался, определен- ные параметры в модуле всегда остаются неиз- менными. Во-первых, это установочные и габа- ритные размеры модуля. Во-вторых, расположение и функциональное назначение всех его выводов. Выводы Arduino UNO выполнены в виде разъемов, выстро- енных в две цепочки гнезд, расположенные по краям платы. К таким разъемам удобно подключать внешние элементы. При желании, например, светодиод можно просто вставить в нуж- ные гнезда разъема. На своих строго определенных местах установлены: ♦ разъем внешнего питания; ♦ разъем USB. Чаще всего в модулях Arduino (в том числе и в Arduino UNO) используются аппаратные USB розетки, такие же, какие используются в современных принтерах. Поэтому для подклю- чения модуля Arduino к компьютеру можно использовать USB кабель от принтера. Кроме разъемов всегда находятся на стандартных местах следующие элементы: ♦ кнопка сброса (Reset); ♦ светодиоды, предназначенные для индикации. На плате Arduino UNO имеется четыре светодиода. Светодиод индикации питания загорается всегда, когда на шине питания модуля появляется напряжение +5 В. Напряжение может поступать как от порта USB, так и от разъ- ема внешнего питания. Два светодиода подключены параллельно линиям вну- треннего СОМ порта, то есть к линиям, идущим от преобразо- вателя USB-COM к основному микроконтроллеру модуля: ♦ один из этих светодиодов индицирует процесс передачи информации от компьютера в модуль Arduino; ♦ второй светодиод индицирует процесс передачи информа- ции от микроконтроллера в компьютер.
Глава 23. Модуль ARDUINO: осваиваем теоретически 209 Четвертый светодиод подключен к выводу РВ5 порта РВ основного микроконтроллера ATmega323 и предназначен для использования программистом по своему усмотрению. Полезные упрощения II в модуле II Как уже говорилось выше, главным преимуществом про- екта Arduino является его простота в понимании и использо- вании. Для того чтобы работа с Arduino стала доступнее, авто- рами был придуман целый ряд упрощений. И одно из них — сквозная нумерация линий ввода- вывода. Так, все цифровые контакты объединены в одну общую группу и пронумерованы, как контакт 0, контакт 1 и так далее до 13 (см. рис. 23.2). ПРИМЕЧАНИЕ. На самом деле к контактам 0...7 подключены раз- ряды D0...D7 порта PD микроконтроллера, а к контактам 8...15 - разряды В0...В5 порто РВ. Однако на языке программирования, который используется для создания программ в модуле Arduino, обращение к любому цифровому контакту производится по его номеру. Например, для чтения уровня сигнала на цифровом кон- такте используется команда digitalRead (НомерКонтакта). Например: а = digitalRead(O); или b = digitalRead(13); Вывод уровней на любой цифровой контакт тоже очень прост. Для перевода контакта в режим вывода информации используется команда: pinMode (НомерКонтакта, OUTPUT);
210 ARDUINO: от азов программирования до создания... Второй параметр этой функции имеет значение OUTPUT. Служебное слово OUTPUT настраивает контакт на вывод информации. Затем, для вывода на контакт нужного цифро- вого уровня используется команда: digitalWrite (НомерКонтакта, Значение); Параметр «Значение» может принимать величину: ♦ или HIGH (высокий логический уровень); ♦ или LOW (низкий логический уровень). ПРИМЕЧАНИЕ. Также можно задавать значение и в цифровом виде: 1 или 0. I Группа аналоговых входов Кроме группы цифровых контактов («пинов») в Arduino имеется группа так называемых аналоговых входов. Это шесть контактов, расположенных на противоположном «борту» модуля. В Arduino аналоговые входы называются АО, А1,... А5 (см. рис. 23.2). ПРИМЕЧАНИЕ. На самом деле аналоговыми эти входы можно назвать условно. В качестве аналоговых входов используются разряды РС0...РС5 порта PC микро- контроллера. То есть, это обычные разряды пор- та, которые могут служить и цифровыми входа- ми, и цифровыми выходами.
Глава 23. Модуль ARDUINO: осваиваем теоретически 211 Но альтернативной функцией именно этих шести выводов микроконтроллера ATmega328P является то, что они могут слу- жить входами внутреннего АЦП. Для упрощения эти входы объявлены аналоговыми. И это в Arduino основной режим их работы. В языке программирования Arduino для того, чтобы прочи- тать уровень аналогового сигнала с любого аналогового входа, нужно всего лишь дать одну простую команду: analogRead( ); Например, следующая строка программы прочитает уро- вень аналогового сигнала с входа АО: с = analogRead (АО); Очевидно, что любой аналоговый вход всегда можно использовать как цифровой вход или выход. Это позволяет архитектура микроконтроллера. В языке Arduino учитыва- ется и эта возможность. На этот случай выводы А0...А5 имеют альтернативную нумерацию. В командах цифрового ввода и цифрового вывода к ним можно обращаться как к контактам 14... 19. Например, командой d = digitalRead(14); вы можете прочитать цифровой уровень (HIGH или LOW) с «аналогового входа» АО. Команда II аналогового вывода || Еще одной интересной находкой, упрощающей програм- мирование на языке Arduino, является команда аналогового вывода. Выглядит эта команда следующим образом: analogWrite (НомерКонтакта, Значение);
212 ARDUINO: от азов программирования до создания... Несмотря на то, что команда выводит некий уровень, назы- ваемый аналоговым, выводимый этой командой сигнал не совсем аналоговый. И выводить «аналоговый сигнал» можно как раз только на цифровые выводы, и то не на все. ПРИМЕЧАНИЕ. Дело в том, что «аналоговый» сигнал выводит- ся при помощи широтно-импульсной модуляции (ШИМ). На плате Arduino контакты, при помощи которых можно производить «аналоговый» вывод информации, обозначены значком «~». Это тоже связано с архитектурой микроконтрол- лера ATmega328P. ПРИМЕЧАНИЕ. Подобный «аналоговый» вывод возможен толь- ко на те разряды портов ввода/вывода, кото- рые поддерживают ШИМ. Поэтому параметр НомерКонтакта в модуле Arduino UNO может принимать только следующие значения 5, 5, 6, 9, 10, И. В более ранних версиях аналоговый выход был возмо- жен только на контактах 9,10,11. Параметр «Значение» может лежать в диапазоне O...255. Как уже говорилось, команда analogWrite() вызывает на выходе «НомерКонтакта» появление прямоугольных импуль- сов. Частота импульсов приблизительно равна 490 герц. Длительность зависит от параметра «Значение». Чем больше значение, тем больше длительность импульса. Если «Значение» = 0, импульсы прекращаются (импульсы нулевой длины), и на выходе устанавливается логический ноль.
Глава 23. Модуль ARDUINO: осваиваем теоретически 213 Если «Значение» = 255, то ширина импульсов становится равной их периоду. Поэтому импульсов также не будет, и на выходе установится постоянное значение логической единицы. Контакты питания «Power» Кроме вышеописанных контактов, на плате Arduino есть группа контактов под общим названием «Power» (питание). Сюда выведены: шина питания +5 В; опорное напряжение 3,3 В; контакт общего провода; сигнал сброса. Так как большинство контактов модуля Arduino напря- мую подключены каждый к своему выводу микроконтроллера ATmega328P, для каждого из контактов модуля дублируются все альтернативные функции, характерные для соответствующего вывода микроконтроллера. Поддерживаемые II языки программирования II Разработчики предусмотрели возможность при необходи- мости использовать все возможности микроконтроллера. Для этого, кроме специализированного языка программирования Arduino, модуль поддерживает и классический язык C++. Для тех, кто, например, изучал язык СИ, описанный в книге [2] или [3] (см. список литературы в конце книги), не составит труда перейти на язык C++ Arduino. Эти языки очень похожи. На рис. 23.3 изображена схема распиновки модуля Arduino UNO, где для каждого контакта указаны все поддержи- ваемые им функции. Это поможет вам разобраться с дополни- тельными функциями каждого контакта.
Внешнее питание 7...12В х О Только для R3 .. t Выводы MCATmega328 Рис. 23.3. Схема распиновки модуля Ардуино 214___________________ARDUINO: от азов программирования до создания..
ГЛАВА 24 СРЕДА РАЗРАБОТКИ IDE Для чего нужно специальное приложение «Среда разработки Arduino IDE»? Специальное приложение для компьютера, которое назы- вается «Среда разработки Arduino IDE», нужно для таких целей: ♦ составлять программы для Arduino; ♦ сохранять программы на компьютере; ♦ транслировать и загружать программы в программную па- мять модуля. ПРИМЕЧАНИЕ. Это приложение полностью бесплатно, и его можно свободно скачать с сайта разработчика (https://www.arduino.cc). Существуют версии для всех основных операционных систем (Windows, Mac X, Linux). \.___________________________________ Среда разработки включает в себя специализированный текстовый редактор, при помощи которого вы можете писать программы для Arduino. Для написания программ использу- ется специальная версия языка программирования, кото- рую мы будем называть далее «Язык Arduino».
216 ARDUINO: от азов программирования до создания... ЧТО ЕСТЬ ЧТО. Программа, написанная на этом языке в среде IDE, называется Скетч и записывается на жест- кий диск компьютера в виде файла с расширени- ем ino. \______________________________________________ Программа может состоять из нескольких файлов ino, состав- ляющих проект. Один из файлов проекта считается главным. ВНИМАНИЕ. Все файлы проекта (даже если в проекте один файл) должны размещаться в отдельной дирек- тории, имя которой должно совпадать с именем главного файла проекта. I Команды и функции языка Arduino Мы уже познакомились с несколькими командами и функ- циями языка Arduino. Простота обучения и использования Arduino в значительной степени обусловлена эффективностью его языка программирования. ПРИМЕЧАНИЕ. Список основных команд и функций языка Arduino приведен в Приложении 1. Язык Arduino является клоном языка СИ, и его синтак- сис максимально приближен к синтаксису этого популярного языка программирования.
Глава 24. Среда разработки IDE 217 СОВЕТ. В том случае, когда при программировании вам не хватает набора команд языка Arduino, вы мо- жете использовать команды языка C++. При трансляции разработанной вами программы, создан- ной в среде разработки Arduino, создается машинный код, который, кроме команд заложенных программистом, содержит ряд системных процедур. Одна из таких процедур — внутренние системные часы. При запуске на Arduino любой вашей программы параллельно запускаются эти часы. Они работают все время, пока работает ваша программа, и постоянно отсчитывают количество милли- секунд, прошедших с момента запуска программы. Для этого используется системный таймер 0 микрокон- троллера и прерывание по переполнению этого таймера. Этот таймер используется, например, для работы функций millis() или micros(), возвращающих значение счетчика вре- мени в миллисекундах и в микросекундах, соответственно. Кроме системного таймера, программа на Arduino органи- зует еще несколько вспомогательных процессов. Например, таймер 1 микроконтроллера используется для команд аналогового вывода на контакты 3,5,6, а таймер 2 для ана- логового вывода на контакты 9,10,11 и для формирования звуко- вых сигналов. Для этого таймеры переводятся в режим ШИМ. Некоторые ресурсы микроконтроллера система програм- мирования самостоятельно использует для своих системных нужд. Поэтому программист, создающий программы на языке Arduino, уже не может распоряжаться ресурсами микрокон- троллера так же свободно, как он может это делать в програм- мах на классическом языке СИ. Зато такое решение облегчает программирование для начинающих программистов. Язык Arduino позволяет не утруждать себя подробным изу- чением всех сложных режимов работы таймеров, прерываний, выбором нужных режимов, определением того, какие коды и в какие системные регистры записать для того, чтобы правильно выбрать нужный режим. Язык Arduino все это делает сам.
218 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. Главный минус подобного решения состоит в том, что это сужает гибкость готовой про- граммы. \_______________________________________________ Допуская вольное использование ресурсов нужно всегда помнить, что тем самым вы мешаете языку Arduino выполнять те либо иные команды. Например, используя самостоятельно для своих нужд тай- мер 1, вы уже не сможете осуществлять аналоговый вывод для контактов 3,5,6. I Внутренние библиотеки Набор стандартных команд Arduino можно существенно расширить применением внешних библиотек. Пакет среды разработки Arduino имеет довольно большой набор внешних библиотек для самых различных задач. ПРИМЕР. Существует Библиотека для работы с внутрен- ней долговременной памятью данных, или библи- отека для работы с последовательным каналом CPI. Есть библиотека для работы с Ethernet, Wi-Fi, GSM, внешним SD модулем памяти и многое другое. СОВЕТ. --------------------------------------------- Если нужная библиотека отсутствует в стан- ов дартном пакете среды разработки, вы можете использовать библиотеку сторонних разробот- чиков. Огромное количество таких библиотек можно свободно скачать из сети Интернет.
Глава 24. Среда разработки IDE 219 Например, существует библиотека, позволяющая исполь- зовать прерывания по таймеру. Набор внешних библиотек в проекте Arduino просто огромен. Совместными усилиями раз- работчиков и энтузиастов проекта разработаны библиотеки на все случаи жизни. После присоединения к вашей программе нужной вам библиотеки в вашем распоряжении появляется набор новых функций, которые дают вам новые нужные вам возможности. Вы можете самостоятельно разработать свою собственную библиотеку и применять ее в своих программах. Далее, по мере изучения разных примеров в нашей книге, мы будем часто использовать внешние библиотеки. Скачиваем программный пакет II с сайта разработчика II Для установки среды программирования Arduino на ваш компьютер нужно сначала скачать программный пакет с сайта разработчика (arduino.cc). Точный адрес ссылки на страницу загрузки вы можете посмотреть в списке ссылок в конце книги. Сайт англоязычный. Его удобно просматривать при помощи браузера с переводчиком. Например, в Яндекс-браузере. Находясь на сайте, выберите в главном меню пункт Software (Программное обеспечение). На открывшейся по этой ссылке странице вы увидите раздел «Download the Arduino IDE» (Скачать Arduino IDE). ПРИМЕЧАНИЕ. В момент написания книги (январь 2018 года) но- мер последней стабильной версии среды разра- ботки -1.8.5.
220 ARDUINO: от азов программирования до создания... Справа от описания последней версии в синем прямоуголь- нике вы увидите набор ссылок на разные варианты пакета для разных операционных систем. Варианты установочных пакетов для Windows Для Windows, например, на сайте имеется три варианта установочных пакетов. Вариант №1. Windows Installer — пакет с инсталлято- ром. Представляет собой исполняемую программу (с расши- рением .ехе). При запуске инсталлятора он сам автоматически устанавливает все компоненты на ваш компьютер. В том числе и драйвер USB интерфейса для платы Arduino. Вариант №2. Windows ZIP file for non admin install — пакет в виде ZIP архива. В архиве находится папка с именем «arduino-x.x.x», где х.х.х — это номер версии программного пакета. Папка содержит все файлы, составляющие пакет среды раз- работки IDE. Для установки среды вам нужно извлечь папку со всем ее содержимым из ZIP-архива и поместить в любом удоб- ном для вас месте на жестком диске вашего компьютера. После этого вам вручную придется установить драйвер USB интерфейса. Для этого вы просто подключаете модуль Arduino к USB порту компьютера. Компьютер обнаружит USB устрой- ство и попытается установить драйвер самостоятельно. Ему это не удастся, и он выведет на дисплей стандартное окно, сообща- ющее, что драйвер установить не удалось. В этом окне нужно: ♦ выбрать команду «Установить драйвер с известного устройства»; ♦ выбрать и указать файл драйвера и нажать кнопку «Уста- новить».
Глава 24. Среда разработки IDE 221 ПРИМЕЧАНИЕ. Драйвер вы найдете в папке «arduino-x.x.x>> в под- папке «drivers». Там вы увидите несколько вариан- тов драйвера. Выберите тот, который подходит для вашей системы. Программа установки «увидит» только тот вариант, кото- рый подходит для вашего случая. Вариант №3. Windows арр Get — версия для Windows 10. Эта версия также выполнена в виде ZIP-архива и устанавлива- ется аналогично предыдущей. Запуск II программы II После установки драйверов запустите программу. Если вы использовали для установки ZIP-архив, то на рабочем столе у вас будет отсутствовать иконка для запуска программы. В этом случае вы должны знать, что запускать нужно файл arduino.exe в папке arduino-x.x.x. СОВЕТ. Для удобства дальнейшей работы вам рекомен- дуется самостоятельно создать иконку для запу- ска этой программы на рабочем столе. \____________________________________________ Для этого проще всего сначала щелкнуть правой кнопкой мышки по файлу программы (arduino.exe) и выбрать пункт меню «Копировать». А затем щелкнуть правой кнопкой мыши в любом месте рабочего стола и выбрать пункт «Вставить ярлык».
222 ARDUINO: от азов программирования до создания... I Основное окно среды разработки После запуска программы откроется основное окно среды разработки (см. рис. 24.1). Основное окно имеет два встроен- ных окна: ♦ строка меню; ♦ панель инструментов. В центре основного окна программы находится окно редактора для написания текста программ. Текст программы пишется на белом фоне. Редактор имеет подсветку синтаксиса. Поэтому разные эле- менты текста автоматически раскрашиваются разными цве- тами. Например, выделяются элементы текста такими цветами: ♦ управляющие слова языка программирования — красным; ♦ зарезервированные константы — голубым; ♦ тексты примечаний — серым; ♦ основной текст программы — темно-синим. /* Примеры для книги Белова Александра Пример 1 Простейшая программа Включение и выключение светодиода (LED), подключенного к цифровому контакту 8, при нажатии на кнопку, подключенную к контакту 2. Схема: * Последовательное соединение светодиода и резистора 270 Ом подключается между выв< * Кнопка подключается между контактом 2 и общим проводом */ НЯНМИМИНМИИМИ^ИИМШ^МИ1 Рис. 24.1. Основное окно среды разработки IDE
Глава 24. Среда разработки IDE 223 Как уже говорилось, файл с текстом программы называется «скетч». Сразу под окном редактора программ находится дру- гое узкое окошко, предназначенное для вывода системных сообщений. Сюда выводятся сообщения при трансляции программы и записи ее в модуль Arduino. Сюда же выводятся все сообщения об ошибках. Сообщения в этом окне выводятся белым цветом на черном фоне. Сообщения об ошибках выделяются красным. В верхней части окна системных сообщений можно видеть поле заголовка. ПРИМЕЧАНИЕ. В обычном состоянии поле заголовка голубого цвета. В поле заголовка в процессе работы выводится сообщение о текущем режиме работы IDE (проверка, трансляция, загрузка ит.д.). ВНИМАНИЕ. Если процесс трансляции программы закончится ошибкой, то поле заголовка становится желтым. В нем появляется сообщение о том, что произо- шла ошибка, а также появится кнопка, при помо- щи которой вы можете распечатать все содержи- мое из окна системных сообщений на принтере. Содержимое окна будут содержать как сообщения, обычно выводимые при трансляции, так и все сообщения об ошибках. Полный текст сообщений значительно больше, чем то, что вы видите в окне сообщений. Весь текст вы можете просмотреть также, пролистав это окно при помощи полосы прокрутки.
224 ARDUINO: от азов программирования до создания... В самой верхней части основного окна среды разработки расположено главное меню программы. При помощи этого меню можно производить все операции управления средой IDE. I Панель инструментов Сразу под строкой основного меню расположена панель инструментов. На этой панели расположено несколько ико- нок, которые дублируют самые важные функции основного меню. При наведении курсора мыши на любую из этих ико- нок, справа сразу за последней иконкой появляется под- сказка с пояснением функции, на которую указывает мышь. В табл. 24.1 приведено назначение всех элементов панели управления. Назначение элементов панели инструментов Таблица 24.1 Иконка Название Команда меню Описание V Проверить Скетч/Проверить Проверка синтаксиса программы * Загрузить Скетч/Загрузить Загрузка программы в память модуля Arduino В Новый Файл/Новый Создание нового файла программы (новый скетч) ♦ Открыть Файл/Открыть Открыть файл программы (скетч) Сохранить Файл/Сохранить Записать файл программы (скетч) на диск £> Монитор порта Инструменты/ Монитор порта Открыть окно монитора порта
Глава 24. Среда разработки IDE 225 Выбор номера СОМ порта II в настройках программы II Прежде чем начать работу в среде разработки, нужно пра- вильно выбрать номер СОМ порта в настройках программы. ПРИМЕЧАНИЕ. Драйвер USB модуля Arduino работает в режиме эмуляции СОМ порто. При установке драйвера он создает в списке устройств компьютера вирту- альный СОМ порт. Номер создаваемого порта вы- бирается автоматически в процессе установки. В зависимости от конфигурации системы номер может быть разный. По умолчанию среда разработки настроена на порт СОМ1. Чтобы узнать правильный номер порта, нужно открыть дис- петчер устройств Windows (Компьютер/Свойства/Диспетчер устройств). Откроется окно диспетчера (см. рис. 24.2). В спи- ске устройств откройте ветку «Порты СОМ и LPT». Среди СОМ портов должен появиться порт Arduino (на рис. 24.2 мы обвели эту запись серой линией). ВНИМАНИЕ. Учтите, что порт в этом списке виден только при подключенном к компьютеру модуле Arduino. При отключении Arduino порт в окне диспетчера исчезает. Запомните номер СОМ порта. Затем зайдите в настройки среды разработки: меню «Инструменты/Порт». При выборе этого пункта меню вы увидите список всех имеющихся в вашем компьютере последовательных портов; Выберите нуж- ный порт из списка.
226 ARDUINO: от азов программирования до создания... DVD и CD-ROM дисководы IDE ATA/ATAPI контроллеры Батареи Видеоадаптеры Дисковые устройства Звуковые, видео и игровые устройства Клавиатуры Компьютер Контроллеры USB Мониторы Мыши и иные указывающие устройства . ПоииД8М,ша„ Порт принтера (LPTI) | Последовательный порт (С0М1) Процессоры Сетевые адаптеры Системные устройства Устройства обработки изображений Рис. 24.2. Порт Ардуино в окне диспетчера устройств Выбор типа используемой платы Arduino Кроме номера порта, вы должны выбрать тип вашей платы Arduino. Для этого выберите пункт меню «Инструменты/ Плата». Появится список всех поддерживаемых плат. Выберите из списка вашу плату. Например «Arduino Uno». После того как вы выберите порт и плату, в самой нижней части окна среды разработки (в строке состояния основного окна) вы увидите надпись: ♦ «Arduino/Genuino Uno на С0М1». Теперь все готово к работе. ЧТО ЕСТЬ ЧТО. Genuino - это проект, аналогичный Arduino. Он разработан другим производителем, но эти два проекта совместимы на уровне среды разработ- ки IDE.
Глава 24. Среда разработки IDE 227 Скетч: открытие, сохранение, загрузка При каждом последующем запуске среды разработки в окно редактора программ загружается последний редактиру- емый при предыдущем запуске программы скетч. Если среда разработки запускается впервые, в окне редактора программ создается новый пустой не именованный скетч. ПРИМЕЧАНИЕ. После написания или редактирования текста программы скетч можно записать на жесткий диск при помощи команды меню «Файл/Сохранить» или «Файл/Сохранить кок». Прочитать уже записанный файл можно при по- мощи команды «Файл/Открыть». Когда программа написана, ее можно оттранслировать и загрузить в память модуля Arduino. Для этого нужно просто выбрать пункт меню «Скетч/Загрузка» или щелкнуть по соот- ветствующей иконке на панели инструментов. При выборе команды «Загрузка» скетч сначала записы- вается на жесткий диск, затем начнется процесс проверки и трансляции программы. По окончании транслирования среда IDE сразу же начинает передавать оттранслированную про- грамму в модуль Arduino посредством USB интерфейса. ПРИМЕЧАНИЕ. При этом модуль Arduino должен быть подключен к компьютеру и готов к работе.
228 ARDUINO: от азов программирования до создания... Процесс трансляции идет достаточно продолжительное время. Если все пройдет нормально, то по окончании транс- ляции и загрузки в заголовке окна системных сообщений вы увидите надпись: «Загрузка окончена». А в самом окне увидите сообщение о результатах трансляции. ВНИМАНИЕ. При заливке программ из компьютера в модуль Arduino используются цепи, связанные с цифро- выми контактами 0 и 1. Поэтому в момент за- грузки на эти контакты нельзя подавать ника- кие сигналы, нельзя замыкать их или как-то по- другому мешать прохождению сигналов. СОВЕТ. Лучше всего, по возможности, вообще не исполь- зовать цифровые контакты 0 и 1. Сразу после загрузки программы в модуль Arduino она автоматически начинает выполняться. При этом выполнение программы тут же прекращается, как только вы начнете новый процесс заливки программы из компьютера в модуль. Главное не забывать, что цифровые контакты 0 и 1 модуля не должны быть заблокированы. I Организация обмена информацией между программой на Arduino и компьютером Удобной особенностью Arduino является простой способ организации обмена информацией между программой на Arduino и компьютером с использованием USB интерфейса.
Глава 24. Среда разработки IDE 229 Ряд несложных команд, описанных в Приложении 1 (раз- дел «Работа с последовательным портом»), позволяют вашей программе передавать результаты своей работы в компьютер и принимать данные из компьютера. При этом среда разра- ботки IDE имеет специальные средства для того, чтобы при- нимать и отображать информацию, поступающую по каналу USB от модуля Arduino, а также, наоборот, передавать данные в Arduino. Эти средства называются «Монитор порта» и «Плоттер по последовательному соединению». Рассмотрим работу этих двух функций среды IDE по порядку. Монитор порта. Отображает поступающие через USB порт данные в текстовом виде. Запускается монитор из меню «Инструменты/Монитор порта» или при помощи соответству- ющей иконки на панели инструментов. После запуска мони- тора открывается специальное окно. В окне два поля. Верхнее поле — узкое в одну строку. В него вы можете ввести с клавиатуры данные для передачи в модуль Arduino. В конце этого поля имеется кнопка «Отправить». При нажатии на эту кнопку все набранные данные отправляются по каналу USB. ПРИМЕЧАНИЕ. Разработанная вами программа, работающая в модуле Arduino, должна принять эти данные и об- работать так, как вы задумали. Второе большое поле в окне монитора порта сразу после запуска монитора работает на прием данных. Все посту- пившие от модуля Arduino данные сразу же отображаются на экране. Монитор порта предполагает, что передаваемые и при- нимаемые данные — это символьные строки. Плоттер по последовательному соединению. Плоттер вызывается аналогично монитору при помощи команды меню: «Инструменты/ Плоттер по последовательному соединению».
230 ARDUINO: от азов программирования до создания... Окно плоттера похоже на окно монитора, но в нем имеется только одно большое поле. И это поле отображает поступаю- щие из Arduino по USB порту данные в графическом виде. ПРИМЕЧАНИЕ. Монитор порта и Плоттер по последовательно- му соединению предназначены лишь для отладки алгоритмов передачи и приема данных. Для практического применения вам придется разработать специализированные программы для компьютера, кото- рые будут работать в паре с программами, загруженными в модуль Arduino. Это позволит, например, создавать на Arduino систему сбора информации с разных датчиков (один из вари- антов — пункт метеонаблюдения), и передавать эту информа- цию в компьютер. А компьютер сможет обрабатывать и систе- матизировать полученные данные. ПРИМЕЧАНИЕ. Правда, в среде разработок IDE вы сможете соз- дать только ту часть программного пакета, ко- торая будет работать в самом модуле Arduino. Приложение для компьютера вам придется создавать при помощи других систем программирования. Рассмотрение этого вопроса не входит в задачу данной книги.
ЧАСТЬ V SB ПОЛЕЗНЫЕ УСТРОЙСТВА НА ARDUINO - СВОИМИ РУКАМИ Приглашаю пройти учебный практи- ческий курс по программированию и схемотехнике. Он представляет собой набор конкретных уроков. В каждом из них на конкретном примере показыва- ется процесс решения какой-либо кон- кретной задачи по разработке некоего устройства на основе модуля ARDUINO. Примеры расположены и рассмотрены в очередности «От простого к сложному». Они позволяют читателю изучить все этапы разработки: постановку задачи, разработку алгоритма, создание схемы, а затем и самой программы.
ГЛАВА 25 ПРОСТЕЙШАЯ ПРОГРАММА «HELLO,WORLD!» I Постановка задачи Итак, в предыдущем разделе мы познакомились с общими принципами построения модулей Arduino и среды разработки IDE. ВНИМАНИЕ. Дальнейшая наша цель - научиться програм- мировать, изучить основные тонкости языка Arduino, узнать приемы составления программ. \. Лучший способ научиться программировать — изучать материал на конкретных примерах. Именно такой способ обу- чения языкам Ассемблера и СИ используется в книгах [2] и [3]. Поэтому и в данной книге изучение материала мы будем про- изводить на конкретных примерах. За основу набора примеров, предложенных в этой книге, взяты примеры, используемые в [2] и [3]. Примеры специально придуманы так, чтобы изучать программирование от простого к сложному. Каждый новый пример раскрывает, какой-либо новый аспект или прием программирования. Этот набор про- стейших алгоритмов хорошо зарекомендовал себя на практике.
Глава 25. Простейшая программа «Hello, world!» 233 И начнем мы с самого простого, элементарного примера. Задача, поставленная в этом примере, не имеет практического смысла. Но как первый шаг в мир программирования подходит идеально. Первый урок по программированию для компьютера обычно начинается с программы, выводящей на экран над- пись «Hello, world!». Считайте, что наша первая задача — это «Hello, world!» для микроконтроллеров. Не буквально (вывести надпись — задача не для начинающих), а в смысле задача, ана- логичная по простоте решения. ЗАДАЧА. Создать программу для модуля Arduino, которая должна управлять свечением светодиода в зави- симости от нажатия кнопки. Светодиод должен быть подключен к одному из цифровых контак- тов модуля, а кнопка - к другому цифровому кон- такту. При нажатии кнопки светодиод должен загораться, а при отпускании - гаснуть. Схема j Один из возможных вариантов схемы изображен на рис. 25.1. Для подключения кнопки мы используем цифровой кон- такт 2, а для подключения светодиода — контакт 8. ПРИМЕЧАНИЕ. Выбор именно этих двух контактов не критичен. Для подобной задачи мы могли бы выбрать любые два других цифровых контакта. Не желательно лишь использовать контакты 0 и 1 по причине, о которой говорилось в предыдущей главе книги.
234 ARDUINO: от азов программирования до создания... Рис. 25.1. Электрическая схема с кнопкой и светодиодом Для подключения кнопки выбрана схема с замыканием на общий провод и использованием внутреннего подтягивающего резистора. Такое включение кнопки требует минимума дета- лей и позволяет использовать специальные возможности вход- ных цепей микроконтроллера. Что бы понять, что это такое, мы должны вспомнить внутреннее устройство подсистемы ввода/ вывода, которое мы изучали в главе 17 нашей книги. В нашей схеме подключения кнопки будет активно использоваться свой- ства подсистемы. На рис. 25.2 изображена часть схемы внутрен- него устройства одного из разрядов порта ввода/вывода микро- контроллера AVR. Именно к такой линии подключен каждый цифровой (да и аналоговый) контакт модуля Arduino. Схема, приведенная на рис. 25.2, представляет собой лишь часть общей схемы линии порта — ту часть, которая отвечает за ввод информации в порт. Схема содержит резистор Rn (подтя- гивающий резистор). При помощи программно управляемого ключа «К» резистор может подключаться между входом линии порта и шиной питания +5 В.
Глава 25. Простейшая программа «Hello, world!» 235 Рис. 25.2. Схема работы кнопки и подтягивающего резистора ВНИМАНИЕ. В нашем случае ключ «К» должен быть постоян- но включен. \J В результате, если кнопка Skh не нажата, то благодаря рези- стору Rh, на входную линию порта поступает сигнал логиче- ской единицы. Если контакт Skh замкнуть, то вход порта будет соединен с общим проводом, а это эквивалентно подаче логи- ческого нуля. В результате этого микроконтроллер может легко считывать состояние кнопки. Если прочитанный сигнал равен единице — кнопка отпущена. Если нулю — кнопка нажата. ВНИМАНИЕ. При написании программы нужно обязательно предусмотреть команду, которая включит ключ «К» и подключит к схеме подтягивающий рези- стор. Если резистор не подключен, то при разом- кнутых контактах кнопки Skh на входе будут наводиться электромагнитные помехи, мешаю- щие роботе программы. *-------------------------------------------'
236 ARDUINO: от азов программирования до создан и я.. . Отключают подтягивающий резистор в двух случаях: ♦ когда линия порта работает на вывод информации; ♦ когда на вход подается сигнал с выхода других микросхем с четкими уровнями нуля и единицы. Свой подтягивающий резистор имеется на каждой линии каждого порта микроконтроллера, и все они включаются и выключаются независимо друг от друга. Для подключения светодиода выбран классический спо- соб (см. рис. 25.1). Светодиод подключается через токоогра- ничивающий резистор между цифровым контактом модуля и шиной питания. Для того чтобы зажечь светодиод, подклю- ченный по такой схеме, нужно установить на выходе (в данном случае на контакте 8) уровень логического нуля. В этом случае перепад потенциалов между нулем на выходе и напряжением питания составит 5 вольт. Светодиод загорится. ПРИМЕЧАНИЕ. Токоограничивающий резистор необходим для того, чтобы ток через светодиод не превысил максимально допустимого значения. Описанную выше схему удобнее всего собрать с использо- ванием универсального макетного контактного модуля, так как это показано на рис. 25.3. Алгоритм Программа должна непрерывно многократно считывать состояние кнопки, подключенной к контакту 2 модуля, и, в зависимости от считанного уровня, управлять сигналом на контакте 8 (выход светодиода).
Глава 25. Простейшая программа «Hello, world!» 237 Рис. 25.3. Пример монтажа простейшей схемы на макетной плате Если кнопка нажата (на входе 2 логический ноль), то про- грамма должна включить светодиод (подать логический ноль на выход 8). Если кнопка отпущена (на входе единица) — выключить светодиод (подать на выход единицу). Фактически, программа должна многократно в цикле считывать сигнал с входа 2 и передавать его на выход 8.
238 ARDUINO: от азов программирования до создания... Первый вариант программы Для решения поставленной выше задачи предлагается два варианта программы. Первый вариант — это решение задачи «В лоб». Программа, приведенная в листинге 25.1, реализует сформулированный нами алгоритм буквально. Разберем под- робнее синтаксис программы. ПРИМЕЧАНИЕ. Для удобства восприятия материала читателем мы пронумеровали строки программы. Так удоб- нее ссылаться но ту или иную строку в тексте описания. Хотя синтаксис языка Arduino не пред- полагает нумерации строк. Каждая команда программы отделяется от следующей сим- волом «точка с запятой». А на строки программа разбивается из соображений удобочитаемости. Так что программа — это то, что в листинге находится справа от столбца с номерами строк. Именно этот текст вы должны набрать при создании скетча в окне редактора про- грамм среды разработки. Кроме команд и операторов, составляющих собственно программу, текст программы содержит еще и комментарии. ПРИМЕЧАНИЕ. Любой язык программирования обязательно име- ет средства, которые позволяют вставлять в текст программы комментарии.
Глава 25. Простейшая программа «Hello, world 1» 239 В языке Arduino используется Си-подобный синтаксис. Поэтому комментарии в программу вставляются двумя спо- собами. Первый способ. Как комментарий воспринимается любая часть текста, ограниченная символами /* */. То есть все, что находится между парой символов /* и второй парой символов ♦/ воспринимается программой как комментарий. Второй способ позволяет добавлять комментарий в конце строки. Все, что находится после двойного слеша//до конца строки, считается комментарием. При трансляции программы комментарии игнорируются. Они предназначены для чело- века, который читает программу, для лучшего ее понимания. ПРИМЕЧАНИЕ. В листинге 25.1, как и в других листингах этой книги, пронумерованы только те строки, которые содержат команды и операторы языка. Строки, содержащие только комментарии или строки, в которых располагается продолжение команд, за- нимающих несколько строк, не нумерованы. Любая программа, написанная на языке Arduino, должна содержать две обязательные функции: setup() и 1оор(). Эти две функции обязательно должны присутствовать в каждой программе, даже если они не содержат никаких команд. Это структурные функции, определяющие два основных этапа работы любой программы для микроконтроллера. Функция setup() выполняется один раз, сразу после запу- ска программы или после нажатия кнопки сброса. В эту функ- цию нужно включить команды начальной настройки режимов всех узлов и систем микроконтроллера, и определение началь- ных значений переменных.
240 ARDUINO: от азов программирования до создания... Функция 1оор() — это основной цикл программы. Этот цикл начинает выполняться сразу после окончания функции начальных установок и выполняется многократно все время, пока работает микроконтроллер. ПРИМЕЧАНИЕ. Любая программа для микроконтроллера всегда работает по такой схеме. Сначала однократно выполняется модуль начальной инициализации, а затем начинается основной цикл программы, в котором обычно и реализуется весь основной алгоритм. В языке Arduino такая типовая организация программы заложена в структуру языка путем применения двух обяза- тельных функций setup() и 1оор(). Кроме двух обязательных функций, программист может создавать любое количество соб- ственных функций по своему усмотрению. Любая функция в языке Arduino объявляется следующим образом: тип ИмяФункции(тип Параметр!, тип Прараметр2 ... ) ( Команда!; Команда2; } Имя функции выбирается произвольно. Имя должно под- чиняться обычным требованиям для синтаксиса имен: ♦ только латинские буквы и цифры; ♦ начинается с буквы; ♦ не допускаются пробелы. Перед именем функции необходимо указать тип возвра- щаемого значения. Тип может принимать значения int, char или другой допустимый в языке Arduino.
Глава 25. Простейшая программа «Hello, world!» 241 ПРИМЕЧАНИЕ. Полный список допустимых типов значений при- веден в Приложении 2 в конце книги. В круглых скобках указывается список параметров, переда- ваемых в функцию при ее вызове. Для каждого параметра вы также должны указать его тип. Сразу за определением функ- ции в фигурных скобках указываются команды, составляю- щие тело функции. ПРИМЕЧАНИЕ. Если ваша функция в результате своей работы должна возвращать некое значение, то тело функции должно содержать хотя бы один опера- тор return, в параметре которого указывается это самое возвращаемое значение. Оператор return, в какой бы строке внутри функции он не находился, немедленно завершает выполнение функции. В языке Arduino нет правила «сначала описание функции, затем ее использование». Вы можете помещать описание функции в любое место программы (но не внутрь другой функции). Особый случай, когда функция не возвращает никакого значения. ПРИМЕЧАНИЕ. Л По-другому такие функции иногда называют процедурами. Если функция не возвращает никакого значения, то перед функцией вместо типа возвращаемого значения нужно поме- стить управляющее слово void. Функции setup() и 1оор() отно-
242 ARDUINO: от азов программирования до создания... сятся к функциям никогда не возвращающим значения. Более подробно о том, как используются функции, мы рассмотрим далее, по мере разбора конкретных примеров. Теперь, когда мы немного разобрались с некоторыми эле- ментами синтаксиса, давайте разберем по порядку программу, приведенную в листинге 25.1. В строках 1 и 2 происходит определение констант. Использование констант добавляет программе наглядности, а также упрощает в будущем изменение значений этих самых констант. Например, в нашей программе определяются значе- ния двух констант. В строке 1 определяется константа buttonPin (номер кон- такта для подключения кнопки). В строке 2 определяется константа ledPin (номер контакта для подключения светодиода). Этим константам присваива- ются значения 2 и 8, соответственно. Далее в программе эти константы используются вместо номеров этих контактов. ПРИМЕЧАНИЕ. Вместо номера контакта для подключения кноп- ки мы будем писать buttonPin, а вместо номера контакта для подключения светодиода - ledPin. Согласитесь, что это нагляднее. А если вы захотите поменять номер контакта? Например, решите подключить светодиод к контакту номер 9. Вам доста- точно будет просто поменять 8 на 9 в строке 2 программы. После этого везде, где в программе используется ledPin, про- грамма будет обращаться к контакту номер 9. Если программа большая и сложная, то в ней каждая кон- станта может использоваться десятки раз.
Глава 25. Простейшая программа «Hello, world!» 243 Листинг 25.1. Пример простой программы (вариант 1) /* Простейшая программа: Светодиод и кнопка */ // Постоянные константы. В данной программе // константы определяют номера используемых контактов: 1 2 const int buttonPin =2; // номер контакта кнопки const int ledPin =8; // номер контакта светодиода // Изменяемые переменные: 3 int buttonstate =0; // статус кнопки (нажата/не нажата) 4 void setup() { // Инициализируем контакт светодиода (как выход): 5 pinMode(ledPin, OUTPUT); // Инициализируем контакт кнопки (как вход): 6 pinMode(buttonPin, INPUT PULLUP); } 7 void loop() ( // Читаем статус кнопки и помещаем // его значение в переменную: 8 buttonstate = digitalRead(buttonPin); // Помещаем считанное значение на выход светодиода: 9 digitalWrite(ledPin, buttonstate); } ПРИМЕЧАНИЕ. Использование именованных констант гаранти- рует от ошибок при изменении параметров про- граммы и упрощает изменение значений опреде- ляемых константами параметров.
244 ARDUINO: от азов программирования до создания... Описание константы начинается с ключевого слова const. Далее указывается тип значения определяемой константы. В данном случае тип значения — int (intedger). Это означает — целое число. В строке 3 определяется переменная. Имя переменной buttonstate. ЧТО ЕСТЬ ЧТО. Переменная - это некая величина, которая мо- жет изменяться в процессе работы программы. Каждой переменной (так же, как и константе) присваивается свое уникальное имя. Далее в про- грамме обращение к переменной происходит по ее имени. \_______________________________________________ Под переменную в оперативной памяти микроконтроллера выделяется одна или несколько ячеек. Программа может: ♦ присваивать переменной различные значения; ♦ читать содержимое переменной; ♦ использовать переменную в различных математических выражениях. ПРИМЕЧАНИЕ. В нашем случае переменная buttonState использу- ется для временного хранения значения состоя- ние кнопки. В строке 4 программы начинается описание функции setup( ). В теле функции всего две команды (строки 5 и 6). В строке 5 определяется режим работы контакта ledPin (вывода для подключения светодиода). Режим работы контакта определяется как OUTPUT (вывод информации). Определение режима любого цифрового контакта в языке Arduino произво-
Глава 25. Простейшая программа «Hello, world!» 245 дится при помощи функции pinMode(). Эту функцию мы уже описывали в предыдущей главе книги. В строке 6 при помощи той же функции определяется режим работы контакта buttonPin (контакт для подключения кнопки). Этот режим определяется как INPUT_PULLUP (ввод информации с включенным подтягивающим резистором). В строке 7 программы объявляется функция 1оор() (основ- ной цикл). Функция 1оор() также содержит всего две команды (строки 8 и 9). В строке 8 происходит чтение состояния кнопки (считыва- ется значение сигнала на входе buttonPin). Для этого использу- ется функция digitalRead(). Считанное значение присваивается переменной buttonState. В строке 9 это значение выводится на выход ledPin при помощи функции digitalWrite(). Функции digitalRead() и digitalWrite() используемые для чтения и вывода информации так же были описаны в предыдущей главе. ПРИМЕЧАНИЕ. Полный список функций вы всегда можете найти в Приложении 1. В результате работы функции 1оор() программа все время считывает состояние кнопки и тут же выводит его на свето- диод. Если кнопка не нажата, то считанное состояние будет равно 1. Единица на выходе светодиода приведет к тому, что он не будет гореть. Если при очередном считывании кнопка окажется нажатой, то ее состояние станет равно нулю. Ноль тут же передастся на выход светодиода и светодиод загорится.
246 ARDUINO: от азов программирования до создания... I Второй вариант программы Недостаток программы, приведенной в листинге 25.1, состоит в том, что микроконтроллер полностью занят всего одной задачей — сканированием кнопки и передачей значения ее состояния на светодиод. В такую программу трудно встроить какие-нибудь другие задачи. Но существует простой способ, как реализовать этот же алгоритм так, чтобы он выполнялся в фоновом режиме. То есть, так, чтобы основной цикл программы был не занят. ПРИМЕЧАНИЕ. Это дает возможность использовать основной цикл для решения любых других задач. И поможет нам создать такую программу механизм преры- ваний. Механизм прерываний существует в лю- бом современном микроконтроллере. Очень под- робно все вопросы организации прерываний опи- саны в главе 12 данной книги. В нашем случае в данном конкретном примере мы будем использовать лишь один из видов прерываний, поддержива- емых микроконтроллером ATmega328. Это, так называемое, внешнее прерывание. Прерывание работает при поступлении внешнего сигнала на специальный вход микроконтроллера. При поступлении сигнала на вход прерывания выполнение текущей программы приостанавливается, и контроллер переходит к выполнению закрепленной за этим прерыванием процедуры, которая назы- вается процедурой обработки прерывания. Микроконтроллер Atmega328, а, значит, и модуль Arduino, имеет два входа внешних прерываний. Они совмещены с линиями PD2 и PD3 порта PD микроконтроллера и, соответ- ственно, с цифровыми контактами 2 и 3 модуля Arduino. В нашей схеме кнопка как раз подключена к входу 2.
Глава 25. Простейшая программа «Hello, world!» 247 ПРИМЕЧАНИЕ. Поэтому мы без изменения схемы можем исполь- зовать прерывание по этому входу для обработ- ки события: «нажатие кнопки». Теперь основной цикл программы не будет заниматься сканированием кнопки и переключением светодиода. Эту задачу мы возложим на процедуру обработки прерывания. А на основной цикл программы можно возложить любые другие придуманные вами задачи. Новая программа будет работать так. В момент нажатия кнопки: ♦ возникает прерывание; ♦ выполнение основной программы приостанавливается; ♦ запускается процедура обработки прерывания. Эта процедура однократно читает состояние кнопки с того же самого входа 2 и посылает считанное значение на выход светодиода. Затем процедура обработки прерывания заверша- ется, и выполнение основной программы продолжается. При отпускании кнопки снова будет вызвано то же самое прерывание. И снова процедура обработки прерывания передаст состояние кнопки на светодиод. Обработка прерывания происхо- дит мгновенно и практически не отражается на скорости выпол- нения основной программы. Поэтому все операции с кнопкой и светодиодом будут выполняться как бы параллельным процессом. ПРИМЕР. Подобным образом выглядит процесс управления указателем мыши на экране компьютера. Какую бы сложную программу не выполнял компьютер, курсор мышки легко бегает по экрану, подчиняясь движениям самой мыши по столу. А ведь прори- совка курсора на экране - это тоже специальная небольшая программа, которая также работает по прерыванию от сигнала мыши.
248 ARDUINO: от азов программирования до создания... Программа, реализующая задачу управления светодио- дом при помощи кнопки с использованием внешнего преры- вания, приведена в листинге 25.2. Благодаря тому, что язык Arduino имеет очень простые и удобные средства работы с этим видом прерываний, программа настолько же проста, как и программа без прерываний. Рассмотрим листинг про- граммы подробнее. Определения констант (строки 1 и 2) происходит так же, как и в предыдущем случае. В строке 3 также мы видим команду определения пере- менной buttonState. Однако теперь перед строкой определения добавлено управляющее слово: volatile. ПРИМЕЧАНИЕ. Это указание для компилятора, которое означа- ет, что изменение значения данной переменной будет производиться в теле процедуры обра- ботки прерывания, а, значит, не под контролем основной программы. То есть, в какой-то момент, когда выполнение основной программы будет приостановлено, значение переменной может из- мениться. Программа должна учитывать такую возможность. Ведь для основной программы это будет выглядеть так, как будто значе- ние неожиданно прямо в процессе вычислений вдруг измени- лось. Возможна ситуация, когда в основной программе перемен- ная используется несколько раз в сложном математическом выражении. Такое выражение вычисляется не мгновенно, а поэтапно. И может получиться так, что первая часть выраже- ния будет вычисляться с одним значением переменной, а вто- рая часть — уже с другим. Если переменная имеет тип volatile, то при трансляции в машинные коды программа строится так, что не переходит к обработке прерывания до тех пор, пока очередное выражение
Глава 25. Простейшая программа «Hello, world!» 249 не будет вычислено до конца. В нашем простом случае такая предосторожность не обязательна, но мы для порядка все же выполним это правило. Далее в теле функции setup() в строках 5,6 мы видим уже знакомые нам команды, устанавливающие режимы работы внешних контактов ledPin и buttonPin. ПРИМЕЧАНИЕ. Но кроме этого в новом варианте программы в тело функции setup() добавлены еще две, отсут- ствующие ранее команды. В строке 7 на выход светодиода подается высокий логиче- ский уровень, который принудительно гасит светоДиод. Такая команда понадобилась здесь потому, что в новой программе оценка состояния кнопки и передача значения на выход све- тодиода происходит только в момент нажатия либо отпускания кнопки. При запуске программы кнопка не нажата, а на любом выходе (в том числе и на ledPin) по умолчанию устанавливается логический ноль. ВНИМАНИЕ. Если не предусмотреть принудительное гашение светодиода, то при включении питания светоди- од загорится, и будет гореть, пока не нажмешь кнопку. В первом варианте программы, когда опрос кнопки и вывод ее состояния на светодиод начинались сразу после включения питания, и продолжались непрерывно все время работы, све- тодиод принимал значение состояния кнопки моментально и гас, не успевая загореться.
250 ARDUINO: от азов программирования до создания... Листинг 25.2. Простая программа вариант 2 (с использованием прерываний) 1 2 3 4 5 6 7 8 9 10 И 12 13 /* Простейшая программа Светодиод и кнопка с использованием прерывания */ // Определение констант: const int buttonPin =2; // номер вывода с кнопкой const int ledPin = 8; // номер вывода со светодиодом // Определение переменных: volatile int buttonstate = 0; // состояние кнопки void setup () { // Установить режим работы контакта светодиода: pinMode(ledPin, OUTPUT); // Установить режим работы контакта кнопки: pinMode(buttonPin, INPUT_PULLUP); digitalWrite(ledPin, HIGH); // Прикрепить прерывание к вектору ISR attachlnterrupt(digitalPinToInterrupt(buttonPin), pinISR, CHANGE); } // Основной цикл программы void loop() { // Здесь ничего нет! } // Обработчик прерывания void pinISR() { buttonstate = digitalRead(buttonPin); digitalWrite(ledPin, buttonstate);
Глава 25. Простейшая программа «Hello, world!» 251 Ну и последняя команда, добавленная в новой версии про- граммы в тело функции setup(), — это команда определения вектора прерывания. ПРИМЕЧАНИЕ. Выражение «определить вектор прерывания» оз- начает - закрепить за конкретным прерывани- ем процедуру его обработки. Сама процедура расположена ниже, в конце программы (строки 11,12,13). Оператор, определяющий вектор преры- вания, в чистом виде выглядит так: attachlnterrupt(interrupt, function, mode) Оператор имеет три параметра. Параметр interrupt — номер прерывания. Наш Arduino UNO, как уже говорилось выше, имеет всего два внешних прерывания. Прерывания в Arduino различаются по номеру. Нумеруются они по порядку. Разные модели Arduino отлича- ются как количеством внешних прерываний, так и номерами контактов, от которых они работают. Но в любом Arduino есть прерывание 0 и прерывание 1. Некоторые модели имеют боль- шее число прерываний. ПРИМЕР. Arduino Mega2560 имеет шесть внешних пре- рываний. Они нумеруются цифрами от 0 до 5. Модуль Arduino UNO имеет следующие два внеш- них прерывания: прерывание 0, работающее от входа 2 и прерывание 1, работающее от входа 5. Параметр function — имя функции обработки прерывания.
252 ARDUINO: от азов программирования до создания... Параметр mode — режим работы прерывания. Параметр mode может принимать следующие значения: ♦ LOW — вызывает прерывание, когда на входе прерывания установится низкий логический уровень (LOW); ♦ CHANGE — прерывание вызывается при смене значения на входе, с LOW на HIGH или наоборот; ♦ RISING — прерывание вызывается только при смене значе- ния на входе с низкого логического уровня (LOW) на высо- кий (HIGH); ♦ FALLING — прерывание вызывается только при смене зна- чения на входе с высокого уровня (HIGH) на низкий (LOW). Если мы посмотрим на строку 8 программы (листинг 25.2), то увидим, что вместо номера прерывания в функцию attachlnterrupt() подставлена другая функция: digitalPinToInterrupt(buttonPiri), в качестве параметра которой выступает номер контакта для подключения кнопки. Как легко догадаться эта специальная функция возвращает номер прерывания по номеру цифрового входа. Конечно, мы могли бы просто поставить в этом месте номер прерывания (в данном случае — это 0). Но использование специальной функ- ции делает программу более гибкой. Теперь, если вы захотите подключить кнопку не на кон- такт 2, а на контакт 3, вам нужно будет просто изменить номер контакта в строке 1 программы. СОВЕТ. В данной простейшей программе это не очень актуально, но в больших сложных программах, где прерывание вызывается много раз, такой прием очень облегчит изменение конфигурации системы. В строке 9 программы начинается основной цикл про- граммы. В теле цикла нет ни одного оператора.
Глава 25. Простейшая программа «Hello, world!» 253 Вместо комментария в строке 10 вы можете поместить в основной цикл любую сложную программу, которая будет выполнять нужные вам задачи совершенно независимо от задачи управления светодиодом при помощи кнопки. Описание функции обработки прерывания начинается в строке 11. ПРИМЕЧАНИЕ. Прежде чем приступить к разбору этой функции, опишем общие принципы построения подобных функций. Любая функция, предназначенная для обработки прерыва- ния, имеет следующие особенности: ♦ функция не должна иметь никаких входных параметров и не должна возвращать никаких значений; ♦ внутри функции обработки прерывания не работает опе- ратор delay(), а значения возвращаемые millis() не изме- няются; ♦ возможна потеря данных, передаваемых по последова- тельному соединению в момент выполнения функции об- работки прерывания; ♦ как уже говорилось выше, переменные, изменяемые в этой функции, должным быть объявлены как volatile. Такой тип функции имеет специальное название Interrupt Service Routine (обработчик прерывания). Сокращенно ISR. Именно поэтому мы назвали нашу функцию pinISR. В теле функции pinISR (строки 12,13) мы видим те же две команды, которые в первом варианте программы были разме- щены в основном цикле: ♦ первая команда (в строке 12) читает состояние кнопки; ♦ вторая команда (в строке 13) записывает его на выход све- тодиода.
254 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. Оба приведенных выше варианта программы можно упростить. Синтаксис языка СИ, который используется в Arduino, позволяет отказаться от переменной buttonstate. ПРИМЕР. Два оператора в строках 8 и 9 листинга 25.1, так же кок два аналогичных оператора в стро- ках 12 и 13 листинга 25.2 можно заменить на одну строку, в которую поместить следующее выражение: digitalWrite(ledPin,digitalRead(buttonPin)); Результат работы этого выражения точно та- кой же, как и результат работы двух строк, ис- пользующих промежуточную переменную. Так как переменная в этом случае больше не нужна, в обо- их вариантах программы можно удалить строку с ее определением. В обоих вариантах программы, это строка 5. __________________________________________________)
ГЛАВА 26 ПЕРЕКЛЮЧАЕМЫЙ СВЕТОДИОД Постановка задачи В этом примере мы немного изменим программу, не изме- няя схемы. ЗАДАЧА. Создать программу, переключающую состояние светодиода (горит / не горит) при каждом на- жатии кнопки. Если светодиод не горит, то при кратковременном нажатии и отпускании кнопки он должен загореться. При очередном кратко- временном нажатии и отпускании кнопки свето- диод должен снова погаснуть. Схема Схема устройства такая же, как в предыдущем примере (см. рис. 25.1).
256 ARDUINO: от азов программирования до создания... Алгоритм Алгоритм явственно вытекает из поставленной задачи. Есть только одна тонкость. Наша программа должна опреде- лить факт кратковременного нажатия кнопки. То есть момент, когда кнопка будет нажата, а затем отпущена. Поэтому алго- ритм будет звучать так. 1. Если кнопка не нажата, ждать нажатия кнопки. 2. Когда кнопка будет нажата, проверить состояние свето- диода. Если светодиод горит, программа должна его потушить. Если светодиод потушен — нужно его зажечь. 3. Снова проверить состояние кнопки. Если кнопка еще нажата, ждать отпускания. 4. Когда кнопка будет отпущена, перейти к пункту 1 алго- ритма. I Первый вариант программы Простейшая программа, реализующая вышеописанный алгоритм, приведена в листинге 26.1. Так как схема у нас не поменялась, светодиод и кнопка подключены к тем же контак- там, начало программы у нас полностью соответствует про- граммам из главы 25. В строках 1 и 2 определяются константы. В строках 3, 4, 5 расположена функция setup(). Она, как и раньше, определяет режимы работы используемых в про- грамме цифровых контактов ledPin и buttonPin. Оставшуюся часть (строки 6...12) занимает основной цикл программы 1оор(). Именно в основном цикле реализуется нуж- ный нам алгоритм. Разберем команды основного цикла под- робнее.
Глава 26. Переключаемый светодиод 257 В строке 7 реализован локальный цикл ожидания нажатия кнопки. Для организации этого цикла используется оператор while( ). While — это один из стандартных операторов цикла языка СИ. Формат этого оператора следующий: while (условие) { Тело цикла; } Английское слово while означает «пока». Операторы, вхо- дящие в тело цикла, выполняются многократно, пока условие в круглых скобках — истина. В нашей программе (см. строку 7) условием является digitalRead (buttonPin)==HlGH. Двойное «равно» — это операция сравнения двух вели- чин. Результат операции «истина», если сравниваемые вели- чины равны. Очевидно, что цикл будет выполняться до тех пор, пока значение, считанное с входа buttonPin, будет равно HIGH. Зарезервированное слово HIGH означает высокий логиче- ский уровень (или просто 1). В теле цикла ожидания нет ника- ких команд. Цикл должен просто ждать, пока сигнал с кнопки станет равным LOW (то есть нулю). Как только кнопка будет нажата, программа выйдет из цикла ожидания и перейдет к процедуре переключения све- тодиода (строки 8, 9,10,11). Для переключения светодиода используется оператор if. Формат оператора следующий: if (условие) Команда!; else Команда2; Слово if с английского переводится как «если», а слово else — как «иначе».
258 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. Если условие в круглых скобках - истина, то вы- полняется Команда!, иначе - Команда?. Вместо каждой команды можно поставить группу команд, заключив их в фигурные скобки. Оператор if в строке 8 программы используется для оценки состояния светодиода (горит / не горит). Для этого использу- ется следующий прием: при помощи оператора digitalRead() мы считываем информацию с контакта ledPin. ПРИМЕЧАНИЕ. Напоминаю, что контакт ledPin у нас запрограм- мирован на вывод информации! Но это не от- меняет возможность считывать информацию с этого контакта. Так устроены все информацион- ные контакты микроконтроллера. \ J Оператор if проверяет значение сигнала, считанного с выхода на светодиод. Если считанное значение равно HIGH, то выполняется команда в строке 9 программы, которая устанав- ливает на том же выходе светодиода уровень LOW. В противном случае, выполняется строка 11, и на выходе светодиода устанавливается HIGH. В строке 12 расположен цикл ожидания отпускания кнопки. Это такой же пустой цикл, как и цикл ожидания нажа- тия в строке 7 программы. Изменилось только условие. Цикл выполняется до тех пор, пока значение состояния кнопки, счи- танное с входа buttonPin, равно LOW. Когда кнопка будет отпу- щена, цикл ожидания отпускания заканчивается. Но продол- жается основной цикл 1оор(). Управление передается на его начало, то есть к строке 7, и все повторяется заново.
Глава 26. Переключаемый светодиод 259 Листинг 26.1. Первый вариант программы переключаемого светодиода 1 2 3 4 5 6 7 8 9 10 И 12 /* Программа «Переключаемый светодиод» */ // Постоянные константы. const int buttonPin = 2; // номер контакта кнопки const int ledPin =8; // номер контакта светодиода void setup() { • // инициализируем контакт светодиода на вывод: pinMode(ledPin, OUTPUT); // инициализируем контакт кнопки на ввод: pinMode(buttonPin, INPUT_PULLUP); } void loop() { // Ожидание нажатия кнопки: while (digitalRead(buttonPin)==HIGH) {}; // Переключение светодиода: if (digitalRead(ledPin)==HIGH) digitalWrite(ledPin, LOW); else digitalWrite(ledPin, HIGH); // ожидание отпускания кнопки: while (digitalRead(buttonPin)==LOW) {};
260 ARDUINO: от азов программирования до создания... I Второй вариант программы Этот вариант программы приведен для того, чтобы проде- монстрировать, как можно написать программу, не используя операцию чтения уровня сигнала с выхода на светодиод. Новый вариант программы приведен в листинге 26.2. Новая программа мало отличается от предыдущей. Рассмотрим различия. Так как в новом варианте программы мы отказыва- емся от считывания непосредственно с выхода ledPin, мы вво- дим переменную для хранения текущего состояния светоди- ода. Имя переменной ledState. Переменная будет хранить теку- щее значение состояния светодиода. При каждом нажатии кнопки это значение будет изме- няться на противоположное (с ноля на единицу, а с единицы на ноль), а затем выводить уже новое значение на контакт ledPin. В строке 3 программы не только создается эта переменная, но ей сразу присваивается начальное значение. В теле функции setup() также появилась новая команда. Она уже на стадии начальных установок выводит значение пере- менной ledState на контакт светодиода ledPin (строка 7 про- граммы). Эта команда нужна для того, чтобы начальное состо- яние светодиода (выключен), к тому времени уже записанное в переменную ledState, установилось на выходе светодиода. В цикле 1оор() новой программы также есть существенные изменения. Циклы ожидания нажатия и отпускания кнопки (строки 9 и 12) остались без изменений. А вот процедура изме- нения состояния светодиода изменилась полностью. Сразу после обнаружения факта нажатия кнопки выполня- ется инверсия значения переменной ledState. Значение пере- менной инвертируется и присваивается ей же. В языке СИ оператор «!» означает инверсию. Эта опера- ция как раз и изменяет ноль на единицу, а единицу на ноль. В строке 11 это новое, уже инвертированное значение выводится на контакт светодиода.
Глава 26. Переключаемый светодиод 261 Листинг 26.2. Второй вариант программы переключаемого светодиода /* 1 Переключаемый светодиод (с использованием переменной для хранения состояния кнопки) */ // Определение констант: const int buttonPin =2; // номер контакта кнопки 2 const int ledPin =8; // номер контакта светодиода 3 // Определение переменной: int ledState = HIGH; // состояние светодиода 4 void setup() { 5 // Установка режимов контактов pinMode(ledPin, OUTPUT); // контакт светодиода 6 pinMode(buttonPin, INPUT_PULLUP); // контакт кнопки 7 digitalWrite(ledPin, ledState); // нач. сост. светодиода 8 void 1оор() { 9 // Ожидание нажатия кнопки while (digitalRead(buttonPin)==HIGH) {}; 10 // Определение состояния светодиода ledState = !ledState; // Инвертирование И digitalWrite(ledPin, ledState); // Вывод 12 // Ожидание отпускания кнопки while (digitalRead(buttonPin)==LOW) {}; } ПРИМЕЧАНИЕ. В остальном программа работает так же, как и в предыдущем варианте.
262 ARDUINO: от азов программирования до создания... Третий вариант программы В третьем варианте программы мы покажем, как можно задачу переключаемого светодиода решить с использова- нием механизма внешнего прерывания. Такая программа приведена в листинге 26.3. Начало программы (строки с 1 по 7) полностью соответ- ствует предыдущему варианту программы (листинг 26.2). В строке 8 мы видим уже знакомое нам выражение, опре- деляющее вектор прерывания. Такое же прерывание мы использовали в главе 25. ПРИМЕЧАНИЕ. В связи с использованием прерывания основной цикл, и в этой программе оставлен пустым. Как мы уже знаем, туда вы можете поместить команды, которые будут выполнять любые другие нужные вам задачи. В строках 11,12,13 находится процедура обработки пре- рывания. ПРИМЕЧАНИЕ. В теле процедуры имеются всего две команды. Это те же самые команды, которые в программе из листинга 26.2. были расположены в основном цикле. Алгоритм работы программы (листинг 26.3) очень про- стой. После выполнения команд начальных установок в теле функции setup(), программа переходит к основному циклу 1оор().
Глава 26. Переключаемый светодиод 263 Листинг 26.3. Программа переключаемого светодиода с использованием прерывания 1 2 3 4 5 6 7 8 9 10 11 12 13 /* Переключаемый светодиод (с использованием механизма внешнего прерывания) */ // Константы const int buttonPin =2; // номер контакта кнопки const int ledPin =8; // номер контакта светодиода // Переменная volatile int ledState = HIGH; // состояние светодиода void setup() { // Установка режимов контактов pinMode(ledPin, OUTPUT); // контакт светодиода pinMode(buttonPin, INPUT_PULLUP); // конт. кнопки digitalWrite(ledPin, ledState); // нач. состояние св-диода // Прикрепление прерывания к вектору ISR: attachlnterrupt(digitalPinToInterrupt(buttonPin), pinISR, FALLING); } void loop() { // Основной цикл остается свободным! // Тут можно размещать основную программу, на // фоне которой будет выполняться переключение // светодиода в фоновом режиме // Обработчик прерывания void pinISR() { ledState = !ledState; digitalWrite(ledPin, LEDstate);
264 ARDUI NO: от азов программирования до создания... При нажатии кнопки активизируется прерывание. Выполнение основного цикла программы прерывается и вызы- вается процедура обработки прерывания. Эта процедура инвертирует значение переменной ledState (строка 12) и выводит новое ее значение на выход ledPin (строка 13). ПРИМЕЧАНИЕ. Циклы ожидания нажатия и отпускания кнопки в данном случае не требуется. Факт нажатия кнопки определяется настройками внешнего прерывания. При инициализации вектора прерывания (в строке 8) был выбран режим FALLING. В этом режиме прерывание возникает только в момент смены сигнала на входе с высокого логиче- ского уровня на низкий. А значит только в момент отпускания кнопки.
ГЛАВА 27 БОРЕМСЯ С ДРЕБЕЗГОМ КОНТАКТОВ Постановка задачи Иногда, собрав схему и опробовав программу, приведенную в предыдущей главе 26, вы можете заметить, что программа переключения светодиода работает нестабильно. Выражается это в том, что при нажатии кнопки светодиод иногда может не переключиться. Это связано с таким явлением, как дребезг контактов. ПРИМЕЧАНИЕ. Дребезг происходит в момент замыкания или размыкания любых механических контактов. Эффект дребезга состоит в том, что в момент замыкания надежное соединение не происходит моментально. Замыкание сопровождается целым рядом очень быстрых замыканий и размыканий, прежде чем установится надежный контакт. Такие же процессы сопровождают и в процесс размыкания контактов.
266 ARDUINO: от азов программирования до создания... Дребезг контактов является проблемой и мешает работе электроники. Например, в программе переключения светоди- ода при нажатии кнопки из-за дребезга происходит не одно, а несколько переключений за одно нажатие. Это известная про- блема, которая хорошо знакома разработчикам электронной аппаратуры. В инженерной практике существует множество приемов борьбы с этой проблемой. Подробно о дребезге контактов мы уже рассказывали в главе 5. Как уже говорилось, существуют аппаратные и программные методы борьбы с дребезгом. Аппаратные методы — это различные схемные ухищрения. Их мы сейчас рассматривать не будем. Мы рассмотрим несколько программных методов борьбы с дребезгом путем усовершен- ствования программы. Самый простой метод борьбы с дребезгом — введение программной задержки. Как уже говорилось, дребезг контак- тов происходит некоторое время в момент после замыкания контактов либо некоторое время сразу после размыкания. По этому методу для борьбы с дребезгом после обнаруже- ния самого первого замыкания контакта программа должна выдержать небольшую паузу. ПРИМЕЧАНИЕ. Длительность паузы должна быть такой, что- бы за время паузы закончился весь процесс дре- безга. То есть программа должна пропустить все остальные замыкания и размыкания контактов, возникающие из-за дребезга. Точно такую же задержку нужно сформировать сразу после первого же размыкания контактов. Более продвинутые про- граммные методы борьбы с дребезгом контактов: ♦ метод статистической обработки сигналов, поступающих от кнопки; ♦ метод программного интегрирования цифрового сигнала;
Глава 27. Боремся с дребезгом контактов 267 ♦ так называемый алгоритм ожидания момента стабильного состояния кнопки. Сформулируем задачу. ЗАДАЧА. Доработать программу переключения светоди- ода, описанную в главе 8, изменив ее так, чтобы она обеспечивала эффект антидребезга. Схема Схема у нас опять остается без изменений (смотри рис. 25.1). Антидребезг II простыми средствами II Простейший способ обеспечить антидребезг — вклю- чить в нужные места программы команды, обеспечивающие задержку на время дребезга. Для формирования задержки в языке Arduino имеется специальная команда delay (Период). Команда формирует программную задержку. Длительность задержки определяется параметром «Период». Длительность задается в миллисекундах. Алгоритм Алгоритм в основном остается таким же, который был описан в главе 26 для программы переключения светодиода.
268 ARDUINO: от азов программирования до создания... Отличие состоит лишь в том, что после цикла ожидания нажа- тия кнопки, а также после цикла ожидания отпускания, мы введем команду программной задержки. j Программа В листинге 27.1 приведена доработанная программа, основу которой составляет программа, приведенная в листинге 26.1, в которую введены задержки антидребезга. Для этого в блок определений констант (строка 3 листинга 27.1) введена новая константа DelayTime. Константа определяет время задержки антидребезга. Команды задержки введены в основной цикл программы: ♦ одна — в строке 9 сразу после цикла ожидания нажатия кнопки; ♦ вторая — в строке 12 сразу после цикла ожидания отпуска- ния кнопки. Кроме изменений, связанных с антидребезгом, в про- грамме на листинге 27.1 представлен еще один способ реали- зации процедуры переключения состояния светодиода. НОВАЯ ПРОЦЕДУРА. Вся процедура реализуется в виде выражения, ко- торое занимает всего одну строку Программы (строка 10). Это сложное выражение, которое при помощи оператора digitalWrite() выводит на контакт светодиода ledPin инверти- рованное значение, считанное оператором digitalRead() с того же самого контакта ledPin. В результате программа обходится и без переменной для хранения состояния светодиода и без опе- ратора if()... else.
Глава 27. Боремся с дребезгом контактов 269 Листинг 27.1. Программа переключаемого светодиода с антидребезгом 1 2 3 4 5 6 7 8 9 10 И 12 /* Программа переключаемого светодиода с функцией антидребезга */ // Определение констант. const int buttonPin =2; // номер контакта кнопки const int ledPin =8; // номер контакта светодиода const int DelayTime =20; // Задержка антидребезга void setup () { // Инициализация контактов: pinMode(ledPin, OUTPUT); pinMode(buttonPin, INPUT_PULLUP); void loop() { // Ожидание нажатия кнопки: while (digitalRead(buttonPin)==HIGH) {}; // Задержка после нажатия кнопки delay (DelayTime); // Переключение светодиода: digitalWrite(ledPin, (digitalRead(ledPin)); // Ожидание отпускания кнопки: while (digitalRead(buttonPin)==LOW) {}; // Задержка после отпускания кнопки delay (DelayTime);
270 ARDUINO: от азов программирования до создания... Применение внешней библиотеки Button Простейший способ антидребезга, примененный в пре- дыдущей версии программы (листинг 27.1), не всегда каче- ственно отрабатывает все проблемы, связанные с вводом дан- ных от внешних контактов. В сложных условиях эксплуатации, при изношенных контактах дребезг контактов может быть достаточно велик. К тому же, кроме проблем, создаваемых дребезгом контактов, на проводах, идущих от кнопки к плате, могут наводиться элек- тромагнитные помехи, особенно если их длина значительная. Помехи также мешают правильной работе. Для надежного избав- ления от всех видов помех требуются более сложные алгоритмы. И вот тут очень удобно воспользоваться внешней библио- текой функций обслуживания кнопок и контактов. ПРИМЕЧАНИЕ. Стандартный набор библиотек пакета про- грамм Arduino не содержит такой библиотеки. Но в Интернете вы можете найти множество вариантов подобных библиотек. Все они обычно доступны для свободного скачивания. Для примера возьмем библиотеку, которая называется «Button», автор Калинин Эдуард. Скачать библиотеку можно на сайте «Мир книг по электронике» (book.mirmk.ru). Библиотека представляет собой папку с именем «Button», кото- рая содержит три файла: ♦ собственно библиотека (Button.h); ♦ текст программ библиотеки на языке C++ (Button.cpp); ♦ список ключей (keywords.txt). После скачивания эту папку нужно извлечь из архива и поместить в пакет программ Arduino в папку «libraries».
Глава 27. Боремся с дребезгом контактов 271 Если вы поместили пакет программ среды разработки в корневом каталоге диска «С:», то путь к папке библиотеки Button должен стать следующим: «C:\arduino\libraries\Putton\». Теперь эту библиотеку вы можете использовать в ваших программах. ПРИМЕЧАНИЕ. Как это сделать в нашем конкретном случае, рас- смотрим на примере программы, приведенной в листинге 27.2. Для начала нужно присоединить библиотеку к нашей про- грамме. Среда разработки Arduino имеет встроенную функцию, облегчающую поиск нужной библиотеки. Выбранная библио- тека автоматически включается в программу пользователя. Для включения библиотеки в программу выберите пункт меню «Скетч/Подключить библиотеку». В открывшемся списке библиотек выберите «Button». Сразу после того, как вы щел- кните по названию выбранной библиотеки мышкой, в текст программы в верхней ее части добавится оператор ^include, а за ним в треугольных скобках — имя файла библиотеки. В листинге 27.2 этот оператор вы можете видеть в строке 1. ПРИМЕЧАНИЕ. Наличие оператора ^include в тексте програм- мы означает, что библиотека подключена. \_________________________________________________ Оператор ^include — это стандартный оператор, имею- щийся практически в любом языке программирования. Этот оператор как бы вставляет библиотечные функции в текст вашей программы в том ее месте, где этот оператор находится.
272 ARDUINO: от азов программирования до создания... Листинг 27.2. Программа переключения светодиода с использованием внешней библиотеки 1 2 3 4 5 6 7 8 9 10 И 12 13 14 /* Программа переключаемого светодиода антидребезг с использованием внешней библиотеки */ ♦include <Button.h> // Определение констант: const int buttonPin =2; // номер контакта кнопки const int ledPin =8; // номер контакта светодиода const int DelayTime =20; // Задержка антидребезга // Создание объекта «кнопка» Button buttonl (buttonPin, DelayTime); void setup() { // Инициализация контактов модуля pinMode(ledPin, OUTPUT); // конт. светодиода pinMode(buttonPin, INPUT_PULLUP); // конт. кнопки digitalWrite(ledPin, HIGH); } void loop() { // Вызов метода ожидания стабильного состояния кнопки buttonl.scanState(); if ( buttonl .flagClick == true ) { buttonl.flagClick = false; // сброс признака клика // Переключение светодиода: digitalWrite(ledPin, JdigitalRead(ledPin)); }
Глава 27. Боремся с дребезгом контактов 273 Вы можете использовать ^include для подключения своих собственных программных процедур к своей основной про- грамме. Запишите текст этих процедур в отдельный файл, а в основную программу впишите оператор ^include. В качестве параметра укажите имя вашего присоединяемого файла. СОВЕТ. Для подключения библиотеки совсем не обяза- тельно использовать команду «Подключить би- блиотеку». Вы можете просто вписать нужную строку в текст вашей программы вручную. Если вы скачаете с сайта «Мир книг по микроэлектронике» приведенный ниже пример программы в электронном виде, то там уже имеется нужная запись, а, значит, библиотека уже под- ключена. После присоединения к вашей программе библиотеки «Button» в распоряжении программиста появляется ряд новых функций, помогающих работать с кнопками и контактами. Эти функции реализуют алгоритмы, устраняющие как проблемы с дребезгом контактов, так и влияние других видов помех. ПРИМЕЧАНИЕ. В связи с тем, что библиотека «Button» написана на языке C++, все библиотечные функции работа- ют в стиле объектного программирования. Это значит, что сначала мы должны создать объект «Кнопка», при помощи которого мы и будем осуществлять доступ к нашей физической кнопке. Если бы у нас в программе было несколько кнопок, то для каждой из них мы должны были бы создать свой отдельный объект типа «Кнопка».
274 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. О том, как создается объект и как с ним нужно работать, мы узнаем в процессе построчного разбора программы, приведенной в листинге 27.2. Итак, начнем по порядку. В начале программы, в строках 2, 3,4 определяются все необходимые для работы программы константы. Эта часть программы полностью соответствует ее предыдущей версии (см. листинг 27.1). Оператор, создающий объект «Кнопка», расположен в строке 5. Формат оператора следующий: Button ИмяКнопки (НомерКонтакта, ПериодОбработки); Имя кнопки программист может выбрать по своему усмо- трению. ПРИМЕЧАНИЕ. Оно должно подчиняться стандартным требо- ваниям к синтаксису имен. Параметр «НомерКонтакта», в нашем случае, соответствует переменной buttonPin. ПериодОбработки — имеет такой же смысл, как время задержки в предыдущей версии программы. ПРИМЕЧАНИЕ. Это время должно немного превышать продол- жительность дребезга для ваших конкретных контактов. Однако оно не должно быть слишком большим. ВремяОбработки должно быть значи- тельно меньше интервала времени между двумя последовательными нажатиями кнопки. Иначе вы не сможете нажимать кнопку слишком быстро.
Глава 27. Боремся с дребезгом контактов 275 В нашей программе в строке 5 мы создаем объект «Кнопка» с именем Buttonl. В объектном программировании любой объект имеет свои «свойства» и «методы». При обращении к «методу» объекта он выполняет определенные действия. ЧТО ЕСТЬ ЧТО. «Метод» - это аналог понятию «функция» в обычной программе. Понятие «свойство» анало- гично понятию «переменная». Значение «свой- ства» объекта можно прочитать. «Свойству» можно присвоить новое значение. Объект «Кнопка» имеет два встроенных метода: ♦ метод проверки ожидания стабильного состояния сигнала; ♦ метод фильтрации сигнала по среднему значению. Например, для объекта Buttonl методы будут выглядеть следующим образом: Buttonl.scanState(); II метод проверки ожидания стабиль- ного состояния сигнала Buttonl.filterAvarage(); // метод фильтрации сигнала по среднему значению В своей программе вы можете использовать любой, но только один из этих двух методов. Но ваша программа должна обеспечить многократный вызов выбранного вами метода. ПРИМЕЧАНИЕ. Для этого вы должны либо включить его в ос- новной цикл программы (желательно в самое его начало), либо обеспечить вызов метода по пре- рыванию от таймера с максимально возможной частотой вызова. \_______________________________________________
276 ARDUINO: от азов программирования до создания... Что же делает каждый их этих методов? I Метод проверки ожидания стабильного состояния сигнала При каждом вызове производит опрос состояния закре- пленной за ним кнопки и ведет от вызова к вызову статисти- ческую обработку. По результатам этой обработки устанавли- ваются следующие свойства объекта: Button.flagPress — примет значение true при стабильно нажатой кнопке; Button.flagPress — примет значение false при стабильно отжатой кнопке; Button.flagClick — примет значение true при кратковремен- ном нажатии и отпускании кнопки. Все свойства устанавливаются только в момент достижения стабильного состояния контактов кнопки. II Метод фильтрации сигнала II по среднему значению Отличается от предыдущего метода лишь алгоритмом обработки входного сигнала. В процессе работы устанавливает следующие свойства: Button.flagPress — примет значение true когда на входе ста- бильно установится сигнал низкого уровня; Button.flagPress — примет значение false когда на входе ста- бильно установится сигнал высокого уровня; Button.flagClick — примет значение true при изменении сигнала на входе с высокого уровня на низкий.
Глава 27. Боремся с дребезгом контактов 277 ПРИМЕЧАНИЕ. Подробное описание алгоритма работы и тек- ста программ библиотеки Button вы можете найти в Интернете по адресу: http://myproctic.ru/urok-8-cifrovoyo-filtrociyo- signolov-v-programmox-dlya-arduino.html Вернемся к нашей программе и посмотрим, как методы и свойства объекта «Кнопка» используются для решения нашей задачи. Описывать функцию setup() мы не будем, так как размещенные в теле этой функции команды уже много раз описывались в предыдущих программах. Нововведения мы увидим в функции 1оор(). Первая команда функции 1оор() (строка 11) вызывает метод scanState() объекта Button 1. Метод производит заложенные в нем статистические дей- ствия, и управление переходит к строке 12. В этой строке находится оператор if, который оценивает значение свойства flagClick объекта Buttonl. Строки 13 и 14 выполняются только в том случае, если значение свойства flagClick равно true. То есть, если обнаружен факт кратковременного нажатия и отпускания кнопки. В строке 13 программа сбрасывает значение flagClick для того, чтобы избежать повторной обработки события «Нажатие кнопки». В строке 14 мы видим уже знакомое нам выражение, пере- ключающее светодиод на выходе ledPin. В результате работы описанной выше программы при каж- дом нажатии кнопки светодиод переключится в противопо- ложное состояние. При этом факт нажатия будет определен путем статистической обработки исключающей влияния дре- безга контактов и электромагнитных помех.
ГЛАВА 28 МИГАЮЩИЙ СВЕТОДИОД Постановка задачи Программу переключаемого светодиода, описанную в пре- дыдущей главе, легко превратить в программу мигающего све- тодиода. ЗАДАЧА. Создать программу, которая при нажатии кноп- ки будет вызывать мигание светодиода, а при отпускании кнопки мигание должно прекра- титься, и светодиод должен погаснуть. Схема Мы снова используем схему, которая использовалась во всех предыдущих примерах (см. рис. 25.1).
Глава 28. Мигающий светодиод 279 Алгоритм 1. Считать состояние кнопки. 2. Оценить состояние кнопки. Если кнопка нажата, перейти к процедуре мигания. Если кнопка не нажата, принудительно погасить светодиод. 3. В процедуре мигания один раз выполнить следующие дей- ствия: 3.1. зажечь светодиод; 3.2. сформировать задержку заданной длительности; 3.3. погасить светодиод; 3.4. сформировать заданную задержку. 4. Перейти к пункту 1 алгоритма. В результате работы такого алгоритма перед каждым циклом загорания и потухания светодиода происходит оценка состояния кнопки. Это позволяет прекратить мигание сразу, после того, как кнопка будет отпущена. Программа Вариант программы, реализующий описанный выше алго- ритм, приведен в листинге 28.1. Начальная часть программы (строки 1...6) пояснений, я думаю, не требуют. Они уже не раз встречались в наших пре- дыдущих программах. В строке 7 начинается основной цикл программы. Команды основного цикла последовательно выполняют все пункты при- веденного выше алгоритма. В строке 8 считывается и оценивается значение на входе buttonPin. Если это значение равно LOW (кнопка нажата), выполняются операции мигания светодиода (строки 9...12). В противном случае выполняется оператор, непосред- ственно следующий за оператором else (строка 13). Он запи-
280 ARDUINO: от азов программирования до создания... сывает на выход светодиода (ledPin) значение высокого логи- ческого уровня (тушит светодиод). Процедура мигания также очень проста. В строке 9 на выход светодиода ledPin записывается низкий логический уро- вень (светодиод зажигается). В строке 10 формируется задержка. Для этого используется команда delay(). В качестве параметра процедуры используется константа DelayBlink, заданная в начале программы (строка 3). ПРИМЕЧАНИЕ. Константа DelayBlink определяет время свече- ния светодиода, а, значит, половину периода мер- цания. В строке 11 находится команда, которая тушит светодиод. В строке 12 мы видим еще одну команду задержки. Она определяет длительность нахождения светодиода в погашен- ном состоянии. Эта длительность также равна DelayBlink. Если учесть, что значение константы DelayBlink равно 200, то период мигания нашего светодиода будет равен 400 миллисекундам, то есть 0,4 секунды. ПРИМЕЧАНИЕ. Временем выполнения остальных операций (чте- ния состояния кнопки, оценки этого состояния и вывода значений на светодиод) можно прене- бречь. Поэтому частота мигания светодиода будет равна: 1/0,4 = 2,5 Гц (два с половиной герца). Главным недостатком программы, приведенной в листинге 28.1, можно считать то, что при своей работе она полностью забирает все ресурсы микроконтроллера. Эта про- блема легко решается применением механизма прерываний.
Глава 28. Мигающий светодиод 281 Листинг 28.1. Программа мигающего светодиода /* Программа «Мигающий светодиод» */ 1 // Определение констант const int buttonPin =2; // номер контакта кнопки 2 const int ledPin =8; // номер контакта 3 светодиода const int DelayBlink = 200; // Задержка мигания 4 void setup() { 5 // Инициализиация контактов модуля: pinMode(ledPin, OUTPUT); // конт. светодиод 6 pinMode(buttonPin, INPUT_PULLUP); // конт. кнопки 7 void 1оор() ( 8 // Если кнопка нажата: if (digitalRead(buttonPin)==LOW) { 9 digitalWrite(ledPin, LOW); // Зажигаем светодиод 10 delay (DelayBlink); // Задержка 11 digitalWrite(ledPin, HIGH); // Тушим светодиод 12 delay (DelayBlink); // Задержка 13 } else digitalWrite(ledPin, HIGH); // Тушим светодиод } ПРИМЕЧАНИЕ. Прерывания по таймеру мы рассмотрим в гла- ве 31. А в следующей главе, мы добавим к нашей схеме еще несколько дополнительных светодио- дов, вспомним новогодний праздник и заставим «бежать огни».
ГЛАВА 29 БЕГУЩИЕ ОГНИ Постановка задачи В настоящее время тема бегущих огней потеряла свою актуальность. В продаже имеется такое огромное количество всяческих гирлянд, у которых вся схема управления запрятана прямо в вилке или в малюсенькой коробочке, висящей на про- воде. Все уже забыли те времена, когда созданием и сборкой различных схем бегущих огней в канун нового года занима- лись тысячи радиолюбителей нашей страны. Но мы в данной главе все-таки используем эту задачу в качестве примера. ЗАДАЧА. Создать схему и программу, реализующую эф- фект «бегущих огней». Программа «бегущих ог- ней» должна управлять цепочкой из восьми све- тодиодов (в дальнейшем вместо каждого свето- диода можно будет подключить целую гирлянду). В каждом цикле «пробегания» огня светодиоды должны зажигаться по очереди, начиная с перво- го и заканчивая последним. В каждый момент времени должен гореть один из восьми свето-
Глава 29. Бегущие огни 283 диодов. Разрабатываемое устройство также должно иметь кнопку управления. Назначение кнопки- реверс направления движения огней. При отжатой кнопке огни должны бежать слева направо, а при нажатой кнопке - справа налево. Схема Один из вариантов возможной схемы бегущих огней при- веден на рис. 29.1. Собрать такую схему можно на универсальном монтаж- ном контактном поле (см. рис.29.2). Такое поле позволяет создавать несложные устройства без использования пайки. Подобные монтажные контактные модули, соединительные кабели с разъемами и другие комплектующие, используемые в нашем примере, можно купить в магазине радиодеталей, на радиорынке или в Интернете. Алгоритм | 1. Проверить состояние кнопки. 2. Если кнопка отпущена, запустить процесс однократного пробегания огня слева направо (один раз по очереди заго- раются все восемь светодиодов). 3. Если кнопка отпущена, запустить процесс пробегания огня справа налево. 4. По окончанию процесса однократного пробегания, про- должить выполнение алгоритма сначала. То есть, перейти к пункту 1 данного алгоритма.
284 ARDUINO: от азов программирования до создания... Рис. 29.2. Внешний вид «бегущих огней» на монтажной плате
Глава 29. Бегущие огни 285 ПРИМЕЧАНИЕ. Особенность донного алгоритма в том, что про- верка состояния кнопки происходит один раз за один цикл пробегания (8 шагов). Поэтому, если на- жать кнопку в тот момент, когда огонь еще не «добежал» до конца, он сначала закончит свой «бег», о уже потом «побежит» в обратную сторону Первый вариант программы, реализующей описанный выше алгоритм, приведен в листинге 29.1. Первый вариант программы Начинается программа, как обычно, с определения кон- стант и переменных. В данной программе мы определяем зна- чение всего двух констант. В строке 1 определяется номер контакта для подключения кнопки. В строке 2 задается величина задержки одного шага «бега» огней. В строках 3...6 расположена функция начальных установок setup(). В теле функции происходит установка режимов работы всех используемых в программе информационных контактов модуля Arduino. ПРИМЕЧАНИЕ. Для задания режимов работы группы контактов, предназначенных для подключения светодиодов, организован программный цикл.
286 ARDUINO: от азов программирования до создания... Для организации цикла в данном случае мы будем исполь- зовать оператор for. Этот оператор применяется и в других местах данного программного примера (см. листинг 29.1). Например, в строках 4,10,15. Формат оператора for следующий: for (НачЗнач, Условие, Инкремент); { Команды тела цикла; } Оператор имеет три параметра. Параметр «НачЗнач» — это команда, присваивающая начальное значение переменной, которая называется «счет- чик цикла». Значение счетчика цикла изменяется в процессе его работы. В строке 4 программы в качестве счетчика цикла используется переменная this Pin. Параметр «Условие» — это логическое выражение. Цикл выполняется до тех пор, пока результат этого выражения — TRUE (Истина). Обычно в этом выражении сравнивается зна- чение счетчика цикла и его предельное значение. Но допу- стимо и любое другое логическое выражение. Параметр «Инкремент» — представляет собой выраже- ние, которое увеличивает значение счетчика цикла при каж- дом проходе (итерации). Чаще всего за один проход значение счетчика цикла увеличивается на единицу. ПРИМЕЧАНИЕ. Но никаких ограничений тут нет. Увеличивать счетчик цикла, при необходимости, можно на лю- бую величину, а также Инкремент можно менять на Декремент. То есть с каждой итерацией не увеличивать, а уменьшать значение счетчика. Здесь уместно сказать, что в языке СИ именно для Инкрементации и Декрементации различных величин часто
Глава 29. Бегущие огни 287 используются два оператора, характерных именно для этого языка программирования: ♦ двойной плюс «++»; ♦ двойной минус «- -». Каждый из этих операторов используется двумя разными способами. Например, для переменной X применение этих операторов будет выглядеть так: ♦ Х++ — увеличение значения переменной на единицу после ее использования; ♦ ++Х — увеличение значения переменной на единицу перед ее использованием; ♦ X-----уменьшение значения переменной на единицу по- сле ее использования; ♦ - -X — уменьшение значения переменной на единицу пе- ред ее использованием. В табл. 29.1 работа операторов инкрементации и декре- ментации описана на примерах. Значение, которое мы решили присвоить переменной X перед началом операции, взято про- сто для примера. Под операцией мы понимаем процесс вычис- ления Выражения. Логика работы операторов инкременации и декременации Таблица 29.1 Выражение Значение X до операции Значение Y после операции Значение X после операции У = Х++ 5 5 6 Y =++Х 5 6 6 Y = X-- 5 5 4 Y = --X 5 4 4 Но вернемся к описанию программы. В строке 4 программы организован цикл, который пере- бирает цифровые контакты модуля Arduino со второго по девятый, и настраивает режим работы каждого из этих кон- тактов. Эти контакты используются для подключения свето- диодов.
288 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. Как уже говорилось, в качестве счетчика цикла используется переменная thisPin. Первый параметр цикла присваивает счетчику значение 2. В качестве условия используется выражение thisPin<10. В тре- тьем параметре значение счетчика цикла увеличивается на единицу. Такие параметры обеспечивают перебор значений переменной thisPin от 2 до 9. В теле цикла всего два оператора: ♦ первый (строка 5) настраивает контакт с номером thisPin на вывод информации; ♦ второй (строка 6) устанавливает на выводе номер thisPin высокий логический уровень. вывоя Таким образом, цикл настраивает по очереди режим работы всей группы контактов, исполь- зуемых для подключения светодиодов, и тушит каждый светодиод, подавая на выход логическую единицу Основной цикл программы 1оор() начинается с команды, считывающей и оценивающей состояние кнопки (строка 9). Если состояние кнопки равно HIGH (кнопка отпущена) выпол- няется цикл однократного «пробегания огня» в прямом направлении (строки 10, И, 12 и 13). В противном случае выполняется цикл «пробегания огня» в обратном направлении (строки 15,16,17 и 18).
Глава 29. Бегущие огни 289 Листинг 29.1. Программа «Бегущие огни» 1 2 3 4 5 6 7 8 9 10 И 12 13 14 15 16 17 18 /* Простая программа «Бегущие огни» */ const int buttonPin =13; // номер контакта кнопки const int LoopTime =200; // задержка шага бег. огня void setup() { // Цикл инициализации контактов светодиодов: for (int thisPin = 2; thisPin < 10; thisPin++) { pinMode(thisPin, OUTPUT); digitalWrite(thisPin, HIGH); // Инициализация контакта кнопки: pinMode(buttonPin, INPUT); void loop() { if (digitalRead(buttonPin)==HIGH) { // Цикл одного пробега в прямом направлении: for (int thisPin = 2; thisPin < 10; thisPin++) { // Включение текущего светодиода: digitalWrite(thisPin, LOW); delay(LoopTime); // Задержка // Выключение текущего светодиода: digitalWrite(thisPin, HIGH); } else { // Цикл одного пробега в обратном направлении: for (int thisPin = 9; thisPin > 1;-thisPin—) { digitalWrite(thisPin, LOW); delay(LoopTime); // Задержка digitalWrite(thisPin, HIGH); } } }
290 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. Оба цикла (прямой и обратный) практически одинаковы. Разница только в том, что перемен- ная счетчика цикла в одном случае с каждой ите- рацией цикла увеличивается на единицу, а во вто- ром случае - уменьшается. Обратимся сначала к прямому циклу, который начина- ется в строке 10 программы. Все параметры этого цикла ана- логичны уже рассмотренному нами циклу, который находится в строке 4. Поэтому цикл в строке 10 тоже перебирает все зна- чения счетчика цикла thisPin от 2 до 9. Для каждого значения thisPin программа выполняет три последовательных операции: ♦ в строке 11 программа зажигает текущий светодиод, под- ключенный к выходу thisPin; ♦ в строке 12 формирует задержку длительностью LoopTime; ♦ в строке 13 затем тушит текущий светодиод. ПРИМЕЧАНИЕ. В результате за восемь итераций (шагов) цикла загораются по очереди все 8 светодиодов. Цикл обратного «пробегания» расположен в строках 15,16,17 и 18. Обратный цикл работает также, как и прямой цикл, но перебирает контакты светодиодов в обратной после- довательности (с девятого по второй). По этой причине обратный цикл от прямого отличается лишь значениями своих параметров. Теперь в качестве началь- ного значения счетчику цикла thisPin присваивается значе- ние 9. В качестве условия продолжения цикла используется выражение thisPin>l.
Глава 29. Бегущие огни 291 А вместо команды инкрементации используется команда декрементации (thisPin—). В результате мы получим эффект обратного перебора значений. Набор команд в теле обратного цикла ничем не отличается от таких же команд цикла прямого. Второй вариант - используем один универсальный цикл ПРИМЕЧАНИЕ. Если вы посмотрите на текст предыдущей про- граммы (листинг 29.1), вы легко заметите, что цикл прямого и цикл обратного «пробега» от- личаются только параметрами. Это дает воз- можность использовать вместо двух циклов один универсальный цикл. В листинге 29.2 показано, как это сделать. Программа, приведенная в листинге 29.2, представляет собой доработан- ную программу из листинга 29.1. Поэтому опишем только изменения. Для начала в программу мы введем три переменных (строки 3,4 и 5). В этих переменных будут храниться и в нуж- ный момент изменяться параметры цикла, именно: ♦ значение начала цикла; ♦ значение конца цикла; ♦ значение шага (+1 или -1). Функция setup() не имеет никаких изменений. А вот в теле функции 1оор() все становится немного по-другому. Оператор if в строке 12 считывает и оценивает состояние клавиатуры. В зависимости от этого состояния он присваивает трем нашим новым переменным соответствующие значения. Если кнопка нажата, то переменным присваиваются значе- ния параметров цикла для пробега вперед (строка 13). Если кнопка отпущена, то переменным присваиваются параметры цикла «пробега назад» (строка 15).
292 ARDUINO: от азов программирования до создания... Листинг 29.2. Программа «Бегущие огни» с общим универсальным циклом 1 2 3 4 5 6 7 8 9 10 И 12 13 14 15 16 17 18 19 /* Программа «Бегущие огни» с общим универсальным циклом */ const int buttonPin = 13; // Номер контакта кнопки const int LoopTime = 200; // Задержка шага бег. огня int loopStart =2; // Начало цикла бега int loopstop =10; // Конец цикла бега int loopStep = 1; // Шаг цикла бега void setup () { // Цикл инициализации контактов светодиодов: for (int thisPin = 2; thisPin < 10; thisPin++) { pinMode(thisPin, OUTPUT); digitalWrite(thisPin, HIGH); } // Инициализация контакта кнопки: pinMode(buttonPin, INPUT); void loop() { if (digitalRead(buttonPin)==HIGH) { loopStart = 2; loopStop = 10; loopStep =1; } else { loopStart = 9; loopStop = 1; loopStep = -1; } // Цикл одного пробега бегущего огня: for (int thisPin = loopStart; thisPin != loopStop; thisPin+=loopStep) { // Включение текущего светодиода: digitalWrite(thisPin, LOW); delay(LoopTime); // Задержка // Выключение текущего светодиода: digitalWrite(thisPin, HIGH);
Глава 29. Бегущие огни 293 Сам универсальный цикл пробега находится в строках 16...19. Строки 17, 18 и 19 составляют тело цикла и полностью соответствуют командам, которые мы видели в теле цикла в предыдущем примере. Ну, а параметры цикла определяются следующим образом. В качестве начального значения для переменной thisPin присваивается значение переменной loopStart. В качестве условия работы цикла используется логическое выражение thisPin != loopStop. Оператор «!=» — в языке СИ представляет собой логиче- ский оператор, выполняющий проверку условия «не равно». Представленное выражение возвращает значение TRUE («Истина») в том случае, если значения переменных thisPin и loopStop не равны между собой. То есть, цикл будет длиться до тех пор, пока значение счетчика цикла thisPin будет не равно его предельному значению, хранящемуся в переменной loopStop. Ну, а третий параметр нашего универсального цикла выглядит следующим образом: thisPin += loopStep; Составной оператор «+=» означает: присвоить перемен- ной в левой части выражения значение суммы значений из левой и правой части. То есть, вышеприведенное выражение полностью эквивалентно выражению thisPin = thisPin + loopStep; Если кнопка не была нажата, значение переменной loopStep равно единице, и при каждой итерации значение thisPin увели- чивается на единицу. Если кнопка нажата, значение loopStep равно минус один. А это значит, что при каждой итерации счетчик цикла thisPin будет уменьшаться на единицу. Это приведет к тому, что при нажатой и при отпущенной кнопке цикл будет: ♦ в первом случае — прямым; ♦ во втором случае — обратным. И в том, и в другом случае цикл будет начинаться со зна- чения loopStart и заканчиваться значением loopStop. Но при
294 ARDUINO: от азов программирования до создания... прямом и при обратном направлении перебора значения, при- своенные переменным loopStart и loopStop, будут разные (см. строки 13 и 15). Для того чтобы превратить схему, у которой лишь 8 свето- диодов на выходе, в настоящие бегущие огни нужно подклю- чить на выходы Arduino вместо каждого из светодиодов сило- вой ключ. К каждому ключу нужно подключить гирлянду лам- почек или светодиодов. ПРИМЕЧАНИЕ. Светодиоды в каждой гирлянде могут быть вклю- чены как последовательно, так и параллельно. \.__________________J Нужно только рассчитать питающее напряжение. При последовательном соединении придется подавать достаточно большое напряжение. Оно будет вычисляться по формуле: U =U sxN ^гирл wpa6 х^св где игирл — напряжение на гирлянде; — рабочее напряжение одной лампочки (светодиода); NCB — количество светодиодов. Все восемь гирлянд нужно сложить таким образом, чтобы светодиоды от разных гирлянд перемежались по порядку. Сначала светодиод первой гирлянды, затем светодиод второй, затем третьей и т. д. до светодиода восьмой. После этого все должно повторяться: светодиод первой гирлянды, второй и т. д. Мы не будем приводить подробную схему полной гир- лянды, так как это не является целью данной книги. Схема и программа «бегущих огней» является просто хорошим учеб- ным примером в конструировании и составлении программ. СОВЕТ. При желании, схему силового ключа можно легко найти в Интернете.
ГЛАВА 30 АЛЬТЕРНАТИВНЫЕ СПОСОБЫ ФОРМИРОВАНИЯ ЗАДЕРЖКИ Постановка задачи Во всех предыдущих программах, приведенных в этой книге, в которых нужно было сформировать задержку по вре- мени, мы это делали при помощи функции delay(). ПРИМЕЧАНИЕ. Однако у этой функции есть большой недоста- ток: в процессе своей работы она полностью за- нимает все ресурсы микроконтроллера. Если программа вызывает команду delay(), то до тех пор, пока эта команда не закончит свою работу, никакая другая команда выполниться не может. То же самое касается и еще одной функции, которая также используется для формирова- ния программной задержки в языке Arduino.
296 ARDUINO: от азов программирования до создания... Функция называется delayMicroseconds() и от функции delay() отличается тем, что формирует задержку, которая зада- ется в микросекундах. Специально для тех случаев, когда в момент формирования задержки необходимо выполнять еще какие-либо действия, в языке Arduino имеется другой механизм формирования интер- валов времени. В основе этого механизма лежат встроенные системные часы. Их, как мы знаем, транслятор автоматически создает при трансляции вашей программы. Системные часы посто- янно отсчитывают время, прошедшее с момента запуска про- граммы. Для чтения текущего времени системных часов в наборе команд языка Arduino имеются две специальные функ- ции: millis() — возвращает количество миллисекунд micros() — возвращает количество микросекунд Используются эти функции следующим образом. Перед тем, как сформировать задержку, программа должна при помощи одной из вышеприведенных функций считать текущее значе- ние системного таймера, и сохранить считанное значение в одной из переменных. ПРИМЕЧАНИЕ. Момент времени, когда мы запомнили значение системных часов, и будет считаться началом пе- риода формирования задержки. Затем программа может выполнять любые другие необ- ходимые действия, но периодически она должна проверять текущее время. Для этого она должна периодически считывать значение системного таймера и вычислять разность между текущим и ранее сохраненным значениями времени. Момент, когда эта разница превысит заданное время задержки, счита- ется моментом ее окончания.
Глава 30. Альтернативные способы формирования задержки 297 ЗАДАЧА. Доработать одну из программ бегущих огней, из главы 29, исключив из нее операторы delayf), и ис- пользуя для формирования задержки системные часы и функцию millsf ).Для начала возьмем за ос- нову программу, приведенную в листинге 29.1. Схема I Разумеется, схема бегущих огней останется прежней (см. рис. 29.1). Алгоритм | 1. Проверить состояние кнопки. 2. Если кнопка отпущена, запустить процесс однократного пробегания огня слева направо (один раз по очереди заго- раются все восемь светодиодов). 3. Если кнопка отпущена, запустить процесс пробегания огня справа налево. 4. По окончанию процесса однократного пробегания, про- должить выполнение алгоритма сначала. То есть, перейти к пункту 1 данного алгоритма. ПРИМЕЧАНИЕ. По большому счету, алгоритм программы не из- меняется. Меняется лишь способ формирования задержки.
298 ARDUINO: от азов программирования до создания... Подробнее о том, как это делается, рассмотрим в процессе детального разбора каждой из двух версий представленных ниже программ. II Первый вариант II программы Самый простой способ решения вышеописанной задачи — заменить команду delay() другой, специально созданной про- граммой задержки, которая, в свою очередь, будет использо- вать системный таймер и функцию mills(). Программа, реализующая данный способ формирования задержки, приведена в листинге 30.1. Если сравнить эту про- грамму с оригиналом (см. листинг 30.1), то изменения в новой версии программы минимальны. В программу добавлена новая переменная lastTime (строка 3 программы). В этой переменной мы будем хранить значение системного таймера на момент начала периода фор- мирования задержки. ПРИМЕЧАНИЕ. Обратите внимание на тип этой переменной. Она имеет тип: unsigned long. Переменная, ко- торая должна хранить значение системного счетчика времени, должна иметь именно такой тип, так как размерность системного счетчика времени - четыре байта. Такую же размерность должна иметь и переменная! Следующее изменение новой программы по сравнению со старой — своя собственная специально созданная проце- дура задержки. Процедуру мы назвали ndelay() и поместили в конце программы в строках 20,21 и 22.
Глава 30. Альтернативные способы формирования задержки 299 Листинг 30.1. Бегущие огни с альтернативной процедурой задержки 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 /* Бегущие огни. Без использования функции delay() */ const int buttonPin = 13; // Номер контакта кнопки const int LoopTime = 200; // Задержка шага бег. огня unsigned long lastTime; // Переменная текущ. время void setup() { // Цикл инициализации контактов светодиодов: for (int thisPin = 2; thisPin < 10; thisPin++) { pinMode(thisPin, OUTPUT); digitalWrite(thisPin, HIGH); } // Инициализация контакта кнопки: pinMode(buttonPin, INPUT); } void loop() { if (digitalRead(buttonPin)==HIGH) { // Цикл одного пробега в прямом направлении: for (int thisPin = 2; thisPin < 10; thisPin++) { //Включение текущего светодиода: digitalWrite(thisPin, LOW); ndelay(LoopTime); // Задержка // Выключение текущего светодиода: digitalWrite(thisPin, HIGH); ' } } else { // Цикл одного пробега в прямом направлении: for (int thisPin = 9; thisPin > 1; thisPin—) { digitalWrite(thisPin, LOW); ndelay(LoopTime); // Задержка
300 ARDUINO: от азов программирования до создания... 19 20 21 22 23 digitalWrite(thisPin, HIGH); } void ndelay (int delayTime) { lastTime = millis(); while (millis() - lastTime < delayTime) { // тут можно вставить любые команды // } Процедура имеет один входной параметр delayTime (см. строку 20). При помощи этого параметра в процедуру пере- дается длительность задержки. Функция ndelay() работает следующим образом. В строке 21 считывается текущее значение системного тай- мера. Считанное значение помещается в переменную lastTime. Далее в строке 22 начинается цикл ожидания. Это уже знакомый нам цикл while (цикл пока...). Условием выполнения цикла является выражение, которое читает значение систем- ного таймера и вычисляет время, прошедшее с момента начала задержки. То есть, вычисляет разность ) - lastTime. ПРИМЕЧАНИЕ. Пока эта разность не превышает значение пере- менной delayTime, цикл продолжается. В против- ном случае цикл завершается. В результате за- вершается^ Функция ndelay() используется везде в программе там, где раньше использовалась функция delay(). Мы можем видеть вызов нашей новой функции в строках 13 и 18 программы.
Глава 30. Альтернативные способы формирования задержки 301 Применение функции ndelay() дает нам возможность в момент формирования задержки выполнять еще какие-либо дополнительные действия. Команды, выполняющие эти дей- ствия, мы должны разместить вместо комментариев в строках, обозначенных в листинге номером 23. Второй вариант II программы || Как легко заметить из описания предыдущей версии про- граммы (листинг 30.1), она действительно позволяет выпол- нять дополнительные действия в момент формирования задержки, но для очень узкого спектра применений. ПРИМЕЧАНИЕ. Тот факт, что добавлять дополнительные ко- манды придется не в основной цикл, а в отдель- ную процедуру, очень сужает возможности этих дополнительных операций. Однако, искусство программирования позволяет скомпоновать про- грамму таким образом, чтобы место, куда можно будет вставить дополнительные команды, оказа- лось в самом центре основного цикла программы. Для решения этой задачи мы возьмем в качестве исходной другую версию программы из главы 29. А именно, программу, приведенную в листинге 29.2. Этот вариант программы использует единый универсальный цикл для прямого и обратного «бега» «огней». Это облегчает нам поставленную выше задачу. В листинге 30.2 представлен вариант программы, в которой в один общий цикл объединены все входящие в нее циклы.
302 ARDUINO: от азов программирования до создания... Это, во-первых, универсальный реверсивный цикл «пробе- гания огня». Во-вторых, цикл формирования задержки. И все это заключено в главный цикл программы 1оор(). Начальная часть программы (строки 1...11) полностью соответствует программе-оригиналу. Лишь в конце функции setup() добавлены две строки, в которых определяются началь- ные значения двух важных переменных. В строке 12 указателю текущего выхода thisPin присваи- вается начальное значение. А именно, номер самого первого из выходов на светодиод (loopStart). В данном случае первым является выход, с которого будет начинаться «бег вперед». Затем в строке 13 обнуляется переменная lastTime. ПРИМЕЧАНИЕ. Как говорилось выше, переменная lastTime пред- назначена для хранения текущего значения си- стемного таймера. Это значение считывается и помещается в переменную в момент начала формирования периода задержки. Нулевое же значение присваивается этой переменной в том случае, когда программа еще не начала формирование задержки. В результате переменная lastTime используется в этой программе двояко: ♦ для хранения мгновенного значения системного времени; ♦ и еще в одном качестве — в качестве флага. ЧТО ЕСТЬ ЧТО. Флагом в программировании называют перемен- ную или ячейку памяти, которая в процессе ра- боты программы принимает два значения (флаг установлен, флаг сброшен) и служит для регули- рования хода выполнения программы. \____________________________________________>
Глава 30. Альтернативные способы формирования задержки 303 Где-то в одном месте программы, исходя из каких-либо условий, устанавливается или сбрасывается флаг. А затем в других местах, в зависимости от значения флага, меняется ход выполнения программы. Под значением «Флаг установлен» и «Флаг сброшен» можно понимать любые допустимые значения переменной. В нашем случае будет считаться, что флаг сброшен, если значение пере- менной lastTime равно нулю. Когда lastTime больше нуля, то мы будем считать, что флаг установлен. То есть, значение времени, которое будет записано в переменную в процессе работы и будет означать, что «флаг установлен». Значение системного времени в процессе работы про- граммы постоянно меняется. ПРИМЕЧАНИЕ. Приблизительно через 50 дней непрерывной ра- боты системных часов, счетчик системных часов переполнится, и в течение одной миллисекунды его значение будет равно нулю. Но вероятность того, что именно это значение будет запи- сано в переменную lastTime, ничтожно мала. Поэтому исполь- зование этой переменной в качестве флага вполне оправдано. В данном конкретном случае наш флаг, будучи сброшен- ным (равным нулю), индицирует тот факт, что формирование задержки еще не началось. Если же переменная lastTime содер- жит значение текущего времени (отличное от нуля), это озна- чает, что флаг установлен и программа находится в режиме формирования задержки. Итак, в программе существует один универсальный цикл. И этим циклом служит основной цикл программы 1оор(). В начале и в конце основного цикла 1оор() находятся два про- граммных модуля, каждый из которых выполняется только при определенных условиях (далее мы узнаем, при каких).
304 ARDUINO: от азов программирования до создания... Начальный модуль цикла располагается в строках 15, 16 и 17. А конечный модуль расположен в строках 19...26. Условия, при которых выполняется каждый из модулей, опре- делены соответствующими операторами if (в строке 15 и в строке 19, соответственно). Посредине между этими двумя модулями располагается область, куда программист может включить небольшую про- грамму, выполняющую дополнительные действия. Рассмотрим работу основного цикла 1оор() программы подробнее. В строке 15 происходит оценка значения переменной lastTime. Остальные команды начального блока (строки 16 и 17) выпол- няются только в том случае, если lastTime равно нулю, то есть в том случае, если формирование задержки еще не началось. Если усло- вие выполнено, то сначала в строке 16 соответствующая команда включает текущий светодиод (подавая LOW на выход thisPin). А в строке 17 считывается и запоминается текущее значе- ние системного времени. После этого значение lastTime уже не равно нулю, а, значит, программа переходит в режим форми- рования задержки. С этого момента начальный блок команд (строки 16 и 17) не выполняется до момента окончания задержки. При этом зажженный в строке 16 светодиод на все время задержки про- должает гореть. За окончание периода задержки отвечает конечный блок основного цикла (строки 19...26). В строке 19 размещено выражение, при помощи которого программа читает текущее значение системного времени, вычисляет время, прошедшее с начала периода ожидания и сравнивает с заданным в пере- менной LoopTime контрольным значением времени задержки. Если время окончания периода задержки еще не наступило, то остальные команды этого блока (строки 20...26) не выпол- няются, и управление передается на начало основного цикла (т. е. к строке 15 программы). Не выполняются также и команды начального блока (строки 16 и 17), так как lastTime не равно нулю.
30. Альтернативные способы формирования задержки 305 30.2. Бегущие огни с одним общим циклом 1 2 3 4 5 6 7 8 9 10 И 12 13 14 15 16 17 18 19 20 21 22 /* Бегущие огни без использования функции delay() с одним универсальным общим циклом */ // Определение констант: const int buttonPin =13; // номер контакта кнопки const int LoopTime = 200; // задержка шага бегущ. огня // Определение переменных int loopStart = 2; // начало цикла бега int loopStop = 10; // конец цикла бега int loopStep =1; // шаг цикла бега int thisPin; // текущий контакт unsigned long lastTime; // текущее время void setup () { // Цикл инициализации контактов светодиодов: for (int thisPin = 2; thisPin < 10; thisPin++) { pinMode(thisPin, OUTPUT); digitalWrite(thisPin, HIGH); // Инициализация контакта кнопки: pinMode(buttonPin, INPUT); thisPin = loopStart; lastTime =0; void loop() { if (lastTime == 0) { digitalWrite(thisPin, LOW); lastTime = millis(); // Тут можно выполнять другие действия // ............ // ............ if (millis() - lastTime > LoopTime) { digitalWrite(thisPin, HIGH); thisPin += loopStep; if (thisPin == loopStop) {
306 ARDUINO: от азов программирования до создания... 23 24 25 26 if (digitalRead(buttonPin)==HIGH) { loopStart = 2; loopStop = 10; loopStep =1; } else { loopStart = 9; loopStop = 1; loopStep = -1; thisPin = loopStart; } lastTime = 0; ПРИМЕЧАНИЕ. Поэтому весь основной цикл какое-то время, пока программа находится в режиме формирования задержки, крутится вхолостую. Выполняются лишь дополнительные команды, если вы их вклю- чили вместо комментариев в строке 18. Длительность периода задержки в нашей программе выбрана равной 200 миллисекундам (см. строку 2). Этого времени хватит, чтобы дополнительные команды выполнили достаточно сложный круг задач. Так продолжается до тех пор, пока системное время достигнет такого значения, когда условие оператора if в строке 19 станет равно TRUE (конец задержки). В этом случае выполняется последняя группа операторов, расположенная в строках 20...26. Сначала оператор в строке 20 гасит текущий светодиод. Затем в строке 21 производится Инкремент (или Декремент в режиме реверса) значения переменной thisPin. То есть изменя- ется номер текущего выхода на светодиод. В строке 22 проверяется, не достигла ли переменная thisPin своего предельного значения. Если достигла, это означает, что «огонь» добежал до конца линейки светодиодов и «бег» нужно начинать сначала. Для этого нужно присвоить переменной thisPin ее начальное значение.
Глава 30. Альтернативные способы формирования задержки 507 Но сначала в строках 23 и 24 считывается и проверяется состояние кнопки. Это делается для того, чтобы при измене- нии состояния кнопки можно было бы изменить направление «бега» огней. По результатам оценки состояния кнопки переменным, loopStart, loopStop и loopStep присваиваются значения, соответ- ствующие выбранному направлению «бега» огней: ♦ если кнопка отпущена, то переменным присваиваются значения для «бега вперед»; ♦ если кнопка нажата, то значения для «бега назад». После того, как параметры бега определены, в строке 25 переменной thisPin присваивается начальное значение уже с учетом выбранного направления. В завершении, в строке 26 обнуляется переменная lastTime. Нулевое значение переменной lastTime укажет программе, что формирование периода задержки закончено, и можно начи- нать новую задержку. На этом завершающий блок команд цикла и сам основной цикл заканчиваются, и управление снова передается в начало (то есть к строке 15). Теперь lastTime равно нулю, поэтому начальный блок команд основного цикла на этот раз выпол- няется. В результате зажигается уже новый светодиод, начина- ется новый период задержки, и все повторяется сначала.
ГЛАВА 31 РАБОТА С ПРЕРЫВАНИЯМИ ПО ТАЙМЕРУ I Постановка задачи В предыдущих двух главах мы рассмотрели два способа формирования задержки в программе бегущих огней. Способ, описанный в главе 30, в котором для формирования задержки использовались системные часы и функция mills(), позволил нам параллельно с задачей бегущих огней дополнительно выполнять вспомогательные задачи. ПРИМЕЧАНИЕ. Однако самый эффективный способ формиро- вания временных интервалов - использование механизма прерываний. При этом используется новый для нас вид прерывания - прерывание по таймеру. В главе 25 мы использовали другой вид прерываний — внешнее прерывание (прерывание, вызываемое при посту- плении внешнего сигнала). Для вызова прерывания по таймеру используется один из системных таймеров микроконтроллера.
Глава 31. Работа с прерываниями по таймеру 309 Микроконтроллер ATmega328 имеет на борту три тай- мера: ♦ таймер 0 (8-ми разрядный); ♦ таймер 1 (16-ти разрядный); ♦ таймер 2 (так же 8-ми разрядный). Каждый из таймеров имеет множество режимов работы, которые могут выбираться программным путем. Для форми- рования интервалов времени обычно используют режим под- счета импульсов от внутреннего тактового генератора. С каждым таймером связано несколько видов прерываний. Чаще всего для формирования временных интервалов исполь- зуется так называемое прерывание по переполнению. Как работает прерывание по переполнению? Счетчик таймера подсчитывает тактовые импульсы. Каждый такой импульс увеличивает значение счетного регистра таймера на единицу. Когда оно достигнет максимального значения, возникает переполнение таймера. Таймер обнуляется, и счет продолжается с нуля. В момент переполнения вырабатывается сигнал преры- вания. При вызове прерывания, как мы знаем, приостанавли- вается выполнение основной программы, и микроконтроллер переходит к выполнению процедуры обработки прерывания. Частота импульсов на входе таймера выбирается таким образом, чтобы переполнение происходило с нужным нам периодом. ПРИМЕР. Таймер 0 модуля Arduino, как мы знаем, исполь- зуется как системные часы. Частота такто- вых импульсов, поступающая на его вход, выбра- на так, что переполнение таймера происходит один раз за одну миллисекунду. Процедура обработки этого прерывания просто добавляет единицу к значению, хранящемуся в составном 32-х разрядном
310 ARDUINO: от азов программирования до создания... регистре системного времени, составленном из четырех ячеек, зарезервированных в ОЗУ микроконтроллера. ПРИМЕЧАНИЕ. Используя прерывание по таймеру, легко создать программу, в которой некие действия, происходя- щие в строго фиксированные моменты времени, будут выполняться исключительно в процедуре обработки прерывания. А основной цикл програм- мы останется свободным и может быть исполь- зован для решения любых дополнительных задач. \___________________________________________J При использовании прерываний по таймеру в модуле Arduino возникают определенные коллизии. Как уже говори- лось выше, все таймеры модуля уже используются системой. Напомним: ♦ таймер 0 используется в качестве системных часов, отве- чает за ШИМ на цифровых выходах 5 и 6, а также обслужи- вает функции millis(), micros(), delay(); ♦ таймер 1, формирует ШИМ на цифровых выходах 9 и 10; ♦ таймер 2 формирует ШИМ на выводах 3 и 11 и использует- ся при формировании звукового сигнала при помощи ко- манды tone(). Если мы будем использовать один из таймеров для органи- зации прерывания, то закрепленными за ним функциями нам, возможно, придется пожертвовать. Далее, в этой главе мы опишем два способа организации прерывания для работы программы «бегущие огни». ЗАДАЧА. Создать программу «Бегущие огни», в которой для создания временных интервалов будет ис- пользоваться прерывание по таймеру.
Глава 31. Работа с прерываниями по таймеру 311 Схема Схема и на этот раз остается прежней. Она приведена на рис. 29.1. Используем внешнюю библиотеку II прерываний по таймеру II Чтобы в своих программах на Arduino вы могли использо- вать прерывание по таймеру, проще всего применить соответ- ствующую внешнюю библиотеку. В стандартном пакете такая библиотека отсутствует. Поэтому нужно использовать библио- теку стороннего разработчика. В нашем первом примере мы будем использовать библио- теку MsTimer2. ПРИМЕЧАНИЕ. Описание этой библиотеки приведено на сайте «Уроки программирования Arduino» (mypractic.ru). Скачать zip-архив, содержащий все файлы библи- отечного пакета можно на сайте «Мир книг по микроэлектронике» (book.mirmk.ru). Подключить библиотеку MsTimer2 к нашей программе так же просто, как библиотеку Button, которую мы учились под- ключать в главе 27. Библиотека MsTimer2 — это специализиро- ванная библиотека для работы с самым последним таймером модуля Arduino: таймером 2. После присоединения библиотеки к программе, в распо- ряжении программиста появляются три новые функции. Все три функции являются методами класса MsTitner, поэтому для обращения к каждой из функций используется синтаксис
312 ARDUINO: от азов программирования до создания... вызова метода языка C++. Ниже приводится описание всех этих трех функций. MsTimer2: :set(TimeInt, fnamelnt); Функция инициализации прерывания. Параметр Timelnt — это период вызова прерывания по таймеру. Период задается в миллисекундах. Переменная Timelnt должна иметь тип unsigned long. Параметр fnamelnt — это имя функции обработки преры- вания. Функцию вы должны создать самостоятельно. Эта функ- ция должна удовлетворять требованиям, предъявляемым к ISR функциям (Interrupt Service Routine). ПРИМЕЧАНИЕ. Подробно эти требования описаны в главе 25. MsTimer2::start( ) Запускает процесс периодического вызова прерыва- ния по таймеру, определенный оператором MsTimer2::set(). Прерывание вызывается многократно с периодом, который был задан параметром Timelnt. MsTimer2::stop() Останавливает процесс вызова прерывания по Таймеру. Исходя из вышеописанного набора функций, мы можем составить алгоритм нашей будущей программы. ПРИМЕЧАНИЕ. Определимся сразу: весь алгоритм «бегущих ог- ней» должен выполняться исключительно в про- цедуре обработки прерывания. Основной цикл про- граммы должен остаться абсолютно свободным.
Глава 31. Работа с прерываниями по таймеру 313 Для определенности при описании алгоритма введем два вспомогательных понятия: ♦ «текущий зажженный светодиод»; ♦ «предыдущий зажженный светодиод». Алгоритм у 1. Организовать прерывание по таймеру. Установить период вызова прерывания равным времени одного шага «бегу- щего огня» (в предыдущих программах эта величина опре- делялась временем задержки). 2. После вызова процедуры обработки прерывания выпол- нить следующие действия: 2.1. потушить предыдущий зажженный светодиод. Если он и так не горит, то команда лишь подтверждает это его состояние; 2.2. считать состояние кнопки и определить направление «бега» в зависимости от того, нажата она или отпущена; 2.3. перейти к следующему по порядку светодиоду. Если кнопка отпущена, то к следующему в прямом направле- нии, если нажата — к следующему в обратном направ- лении; 2.4. зажечь новый текущий светодиод. 3. Выйти из процедуры обработки прерывания и продолжить выполнение основной программы вплоть до очередного вызова прерывания. Программа | Вариант программы «Бегущих огней», работающий по пре- рыванию от таймера и использующий библиотеку MsTimer2, приведен в листинге 31.1. Рассмотрим программу по порядку.
314 ARDUINO: от азов программирования до создания... Листинг 31.1. Использование внешней библиотеки прерывания по таймеру /* Пример 7. (вариант 1) Бегущие огни с использованием прерываний по таймеру */ 1 ♦include <MsTimer2.h> // Определение констант: 2 const int buttonPin =13; // номер контакта кнопки 3 const int LoopTime = 200; // задержки шага бегущ. огня 4 const int loopStart =2; // начало цикла бега 5 const int 'loopStop =9; // конец цикла бега // Определение переменных: 6 volatile int thisPin; // текущий разряд светодиодов 7 void setup () { 8 // Цикл инициализации контактов светодиодов: 9 for (int thisPin = loopStart; thisPin < = loopStop; thisPin++) { 10 pinMode(thisPin, OUTPUT); 11 digitalWrite (thisPin, HIGH); 1 J // Инициализация контакта кнопки: 12 pinMode(buttonPin, INPUT); 13 thisPin = loopStart; // уст. нач. значения указателя // Инициализация таймера и привязка к прерыванию 14 MsTimer2::set(LoopTime, timerlnterupt); // уст. периода 15 MsTimer2::start(); // разрешаем прерывание 16 void 1оор() {
Глава 31. Работа с прерываниями по таймеру 315 17 18 19 20 21 22 23 24 25 26 // Основной цикл остается свободным // Сюда можно поместить основную программу // на ее фоне будет работать программа бегут, огней } // Обработчик прерывания void timerInterupt() { digitalWrite(thisPin, HIGH); // гасим тек. св.диод if (digitalRead(buttonPin)==HIGH) { // Один шаг бегущ. огня в прямом направлении: thisPin++; if (thisPin > loopStop) thisPin = loopStart; } else { // Один шаг бегут, огня в обрати, направлении: thisPin—; if (thisPin < loopStart) thisPin = loopStop; } digitalWrite(thisPin, LOW); // зажечь следуют, св.диод } В строке 1 к тексту программы присоединяется библиотека MsTimer2. В строках 2...5 определяются все необходимые константы программы. Константы buttonPin и LoopTime нам хорошо зна- комы. Так как в данной программе значения начала и конца цикла «пробега огней» (loopStart и loopStop) не изменяются, они оформлены в виде констант, а не переменных. В строке 6 определяется переменная thisPin, которая указывает на текущий обрабатываемый выход светодиода. Изменение значения этой переменной будет производиться в процедуре обработки прерывания, поэтому она объявляется как volatile. Строки 8... 12 функции setup() нам хорошо знакомы из предыдущих программ. Они настраивают все входы и выходы модуля.
316 ARDUINO: от азов программирования до создания... В строке 13 присваивается начальное значение указателю текущего светодиода thisPin. В последних строках функции setup() мы видим две команды, связанные с настройкой пре- рывания. В строке 14 определяются режимы прерывания. Период вызова прерывания устанавливается равным LoopTime. В каче- стве процедуры обработки прерывания указывается процедура с именем timerlnterupt. В строке 15 дается старт процессу вызова прерывания. ПРИМЕЧАНИЕ. Как видите, основной цикл нашей программы остается абсолютно свободным. Вместо строк, помеченных номером 17, можно вставить прак- тически любую программу, выполняющую любые дополнительные функции. Как мы и обещали, весь алгоритм «бегущих огней» выпол- няется в теле процедуры обработки прерывания. Процедура расположена в конце программы и начинается в строке 18. Сначала, в строке 19 программа гасит текущий светодиод. Этот светодиод обычно горит еще с предыдущего вызова про- цедуры обработки прерывания. Между двумя вызовами пре- рывания всегда горит один из светодиодов. ПРИМЕЧАНИЕ. Период вызова прерываний определяет длитель- ность горения очередного светодиода (то есть длительность одного шага «бега» «огней»). Далее программа должна определить, какой светодиод дол- жен загореться следующим. Определяется это так: в строке 20 программа читает и оценивает состояние кнопки.
Глава 31. Работа с прерываниями по таймеру 317 Если кнопка отпущена, перемещаем «огонь» на шаг в пря- мом направлении (строки 21 и 22). Если кнопка нажата, делаем один шаг назад (строки 24 и 25). Шаг вперед и шаг назад очень похожи. Для продвижения в прямом направлении сначала в строке 21 производится инкремент указателя текущего светодиода thisPin. В строке 22 производится оценка нового значения указа- теля. Если это значение превысит верхний предел, то указа- телю присваивается значение нижнего предела («движение» «огня» начинается сначала). При обратном шаге производятся обратные действия. В строке 24 производится декремент указателя светодиода. В строке 25 проверяется, не оказался ли указатель ниже нижнего предела. Если оказался, то ему присваивается зна- чение верхнего предела. В результате номер нового текущего светодиода будет определен. Затем в строке 26 новый текущий светодиод зажигается. И на этом процедура обработки прерывания заканчивается. Микроконтроллер возвращается к выполнению основной программы, а текущий светодиод продолжает гореть до следу- ющего вызова прерывания. Совместное использование II таймера ОII На сайте «Роботоша» (robotosha.ru) я нашел очень остро- умное решение, как организовать прерывание по таймеру для своих целей и при этом не нарушить ни одной из стандартных функций языка Arduino, связанных с использованием тайме- ров. Фокус состоит в том, что все настройки всех трех таймеров, устанавливаемые транслятором среды разработки, остаются в неприкосновенности. Но при этом активизируется еще один вид прерываний, который язык Arduino не использует. Этот вид прерываний,
318 ARDUINO: от азов программирования до создания... который предлагается использовать называется «прерывание по совпадению». Прерывание по совпадению также связано с тайме- ром. Например, таймер 0 поддерживает два прерывания по совпадению. Для этого в составе таймера имеется специ- альный регистр, который называется регистр совпадения. Программным способом в этот регистр можно записать некое число — порог совпадения. ПРИМЕЧАНИЕ. Прерывание по совпадению возникает в тот мо- мент, когда содержимое основного счетного ре- гистра таймера окажется равным содержимому регистра совпадения. Меняя содержимое реги- стра совпадения, можно менять момент возник- новения прерывания. Идея, предложенная на сайте «Роботоша», состоит в том, чтобы двояко использовать таймер 0. Как мы уже не одно- кратно говорили, таймер 0 в любой программе, написанной, на языке Arduino, работает в режиме генерации миллисекундных импульсов. За одну миллисекунду таймер успевает просчитать от 0 до своего максимального значения — 255 и затем вызвать прерывание по переполнению. При помощи этого прерывания происходит подсчет системного времени. А вот прерывание по совпадению система Arduino не использует. Это прерывание мы и будем использо- вать для наших нужд, не меняя никаких других параметров таймера.
Глава 31. Работа с прерываниями по таймеру 319 ПРИМЕЧАНИЕ. Если в регистр совпадения поместить число, при- мерно равное половине максимального значения счетного регистра таймера, и активизировать прерывание по совпадению, то такое прерывание будет вызываться также 1 раз каждую миллисе- кунду, но со сдвигом во времени от основного пре- рывания. '---------------------------------------------7 Сдвиг по времени будет очень полезен для того, чтобы процедуры обработки прерываний не мешали друг другу. У таймера 0 микроконтроллера ATmega323 имеется два реги- стра совпадения. Имя первого из них OCROA. Его мы и будем использовать для вызова нашего прерывания. Но как же быть с периодом вызова прерывания? Ведь нам нужно, чтобы процедура обработки прерывания в про- грамме «бегущих огней» вызывалась один раз за 200 миллисе- кунд? Да очень просто! В нашей новой программе прерывание будет вызываться каждую миллисекунду, но выполнять нужные нам действия только один раз за 200 вызовов. Как это сделать, сейчас увидим. Для этого разберем подробно текст нового программного примера, приведенный в листинге 31.2. За основу программы в листинге 31.2 взят первый вариант программы, приведенный в листинге 31.1. В новом варианте реализован описанный выше способ формирования преры- вания по таймеру. Нам пришлось сделать совсем небольшие изменения. Разберем по порядку все эти изменения. Для начала из программы исключен оператор ^include, так как нам теперь не нужна внешняя библиотека. Полностью изменены команды инициализации прерывания. Новые команды инициализации вы можете видеть в стро- ках 13 и 14 листинга 31.2.
320 ARDUINO: от азов программирования до создания... Листинг 31.2. Использование прерывания по таймеру О 1 2 3 4 5 6 7 8 9 10 И 12 13 14 15 16 /* Бегущие огни, использование прерываний по таймеру О (минимум вмешательства в настройки Ардуино) */ // Определение констант: const int buttonPin =13; // номер контакта кнопки // Опреление переменных: int loopStart =2; // начало цикла бега int loopStop =9; // конец цикла бега int LoopTime = 200; // время задержки шага бегущ. огня volatile int TimeCore =0; // Счетчик таймера volatile int thisPin; // Текущий разряд светодиодов void setup () { // Цикл инициализации контактов светодиодов: for (int thisPin = 2; thisPin < 10; thisPin++) { pinMode(thisPin, OUTPUT); digitalWrite(thisPin, HIGH); } // Инициализация контакта кнопки: pinMode(buttonPin, INPUT); thisPin = loopStart; // начальн. знач. указателю св.диода // Инициализация таймера (режим совпадения) OCR0A = ОхАО; // значение регистра совпадения TIMSK0 |= (1 « OCIE0A); // разрешение прерывания } void loop() { // Основной цикл остается свободным // Сюда вы можете поместить основную программу // на ее фоне будет выполняться программа бегущ. огней }
Глава 31. Работа с прерываниями по таймеру 321 // Обработчик прерывания 17 SIGNAL(TIMERO_COMPA_vect) { 18 TimeCore++; 19 if (TimeCore>LoopTime) { 20 TimeCore=0; 21 digitalWrite(thisPin, HIGH); // погасить текущ. св.диод 22 if (digitalRead(buttonPin)==HIGH) { // Один шаг бегущ. огня в прямом направлении: 23 thisPin++; 24 if (thisPin > loopStop) thisPin - loopStart; 25 digitalWrite(thisPin, LOW); // зажечь следуют, св.диод i 26 J else { // Один шаг бегут, огня в обратном направлении: 27 thisPin—; 28 if (thisPin < loopStart) thisPin = loopStop; 29 digitalWrite(thisPin, LOW); // Зажечь следующий светодиод } } ПРИМЕЧАНИЕ. Так как для инициализации прерывания мы ис- пользуем нестандартный прием, приходится программировать на уровне регистров. Так, в строке 13 записывается значение в регистр совпаде- ния OCROA. Как уже говорилось, это значение находится где-то посредине между минимальным и максимальным значениями таймера.
322 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. Автор идеи предложил величину OxAF (записано в шестнадцатеричном формате). В десятичном формате OxAF соответствует 175. Я выбрал ве- личину поближе к середине диапазона: ОхАО (то есть 160). При выборе значения, записываемого в регистр совпаде- ния, разумнее всего учитывать соотношение времени выпол- нения обеих процедур обработки прерывания (по переполне- нию и по совпадению). В строке 14 определяется значение разряд OCIEOA в реги- стре маски TIMSK0. Регистр маски TIMSK0 микроконтроллера управляет включением и выключением всех видов поддержи- ваемых им прерываний по таймеру 0. Для каждого таймера есть свой регистр маски прерываний. Каждый разряд регистра включает или выключает (маскирует) свой вид прерывания. Если какой-либо разряд равен нулю, соответствующее ему прерывание не разрешено. Чтобы разрешить прерывание, нужно установить соответствующий разряд в единицу. Каждый разряд регистра имеет свое собственное имя. ЧТО ЕСТЬ ЧТО. Разряд, который отвечает за прерывание по совпадению, называется OCIEOA. Выражение в строке 14 программы устанавливает в единицу разряд с номером OCIEOA. Если вы желаете досконально изучить синтаксис логиче- ских выражений языка СИ, рекомендую обратиться к книге [1]. Но если говорить кратко, то выражение: TIMSK0 |= (1 «OCIEOA) выполняет два действия. Составной оператор «|=» выполняет операцию побитового ИЛИ между значением переменной TIMSK0 и результатом выражения в
Глава 31. Работа с прерываниями по таймеру 323 скобках (1«ОС1ЕОА), а результат этой операции присваивается переменной TIMSK0. Операция побитового ИЛИ используется во многих язы- ках программирования для установки в единицу одного или нескольких двоичных разрядов числа, оставляя при этом все остальные двоичные разряды без изменений. ЧТО ЕСТЬ ЧТО. Значение в правой части от оператора «\=» на- зывается маской. Маска должна иметь единицы во всех двоичных разрядах, которые в исходном числе (в данном случае - в TIMSK0) необходимо установить в единицу. А те разряды, которые из- менять в исходном числе не нужно, в маске долж- ны быть равны нулю. Смысл выражения в скобках — получить маску с единицей в разряде номер OCIEOA. Для получения такой маски берется число 1 (в двоичном представлении это число, у которого во всех старших разрядах нули и единица в младшем разряде — 00000001). Двоичные разряды этого числа сдвигаются побитно влево. Число сдвигов равно OCIEOA. Следующее изменение программы, приведенной в листинге 31.2 по сравнению с программой из листинга 31.1, — это имя функции обработки прерывания. ПРИМЕЧАНИЕ. Как вы могли заметить, при инициализации пре- рывания мы не определяли имени этой функции. По законам программирования на уровне регистров кон- троллера у такой процедуры имеется фиксированное систем-
324 ARDUINO: от азов программирования до создания... ное имя. Все функции обработки прерываний всегда имеют имя SIGNAL(), а параметр функции — это системное имя выбранного нами прерывания. В нашем случае имя прерыва- ния TIMERO_COMPA_vect. Достаточно создать в своей программе функцию с таким именем и таким параметром, и вектор прерывания окажется определен. В листинге 31.2 описание этой функции начина- ется в строке 17. Тело функции расположено в строках 18...29. В строке 18 производится инкрементация значения пере- менной TimeCore. Эта переменная используется в качестве счетчика миллисекунд. ПРИМЕЧАНИЕ. Как уже говорилось, процедура SIGNAL() будет вызываться каждую миллисекунду, и каждый раз значение счетчика будет увеличиваться на еди- ницу В строке 19 оператор if сравнивает значение счетчика TimeCore с заданным в начале программы периодом шага «бегущих огней» — LoopTime, которое как раз и равно 200. Операторы в фигурных скобках (строки 20...29) выпол- няются только тогда, когда значение счетчика миллисекунд достигнет значения LoopTime. Пока значение не достигнуто, никаких действий не выполняется, и процедура обработки прерывания заканчивается без последствий. Когда значение счетчика миллисекунд TimeCore достиг- нет нужного значения (окажется равным LoopTime), пер- вой же командой (строка 20) счетчик TimeCore обнуляется и выполняются команды, реализующие один шаг «бега огней» (строки 21...29).
Глава 31. Работа с прерываниями по таймеру 325 ПРИМЕЧАНИЕ. Эти команды полностью аналогичны таким же командам из листинга 31.1. После этого процедура обработки прерываний также завер- шается. Следующий раз при вызове процедуры обработки прерывания подсчет миллисекунд начнется сначала. Таким образом, основная часть процедуры обработки прерывания будет выполняться один раз за время, заданное в переменной LoopTime, точно так же как это происходило в первом варианте программы (листинг 31.1).
ГЛАВА 32 ФОРМИРОВАНИЕ ЗВУКА | Постановка задачи В языке Arduino извлечение звука — достаточно неслож- ная задача. Для этого используется простая и удобная функция tone(). Формат этой функции следующий: Гопе(Контакт, ВысотаТона, Длительность); Параметр «Контакт» — это номер контакта модуля Arduino, на котором будет генерироваться звуковой сигнал. Параметр «ВысотаТона» — это частота генерируемого сигнала в герцах. Тип значения этого параметра — unsigned int. Параметр «Длительность» — не обязательный. Если он есть, то определяет длительность генерируемого звукового сигнала в миллисекундах. Тип значения — unsigned long. ПРИМЕЧАНИЕ. Если параметр «Длительность» отсутствует, то звуковой сигнал генерируется непрерывно до тех пор, пока не придет команда поТопе(). ч___________________________'_______________>
Глава 32. Формирование звука 327 По команде tone() на выбранном контакте вырабаты- вается цифровой сигнал, представляющий собой меандр (т. е. сигнал у которого длительность импульса равна половине периода). Для формирования сигнала используется таймер 2 микро- контроллера. В каждый момент времени может генериро- ваться только один звуковой сигнал заданной частоты только на одном из контактов. ПРИМЕЧАНИЕ. Если сигнал уже генерируется на каком-либо кон- такте, то повторное использование функции tone() для этого контакта просто приведет к изменению частоты тона (если конечно пара- метр «ВысотаТона» новой команды изменился). В то же время вызов функции tone() для любого другого контакта не будет иметь никакого эффекта. Сначала нужно выключить звук командой поТопе(), и только после этого можно применить tone() для нового контакта. ЗАДАЧА. Разработать схему и программу устройства на основе модуля Arduino, позволяющего издавать различные звуки. При нажатии на одну из деся- ти кнопок, подключенных к этому устройству на выходе, к которому подключен звукоизлучатель, должен генерироваться звуковой сигнал. Для раз- ных кнопок звук должен иметь разную высоту тона. Когда все кнопки отпущены, звук должен прекратиться.
328 ARDUINO: от азов программирования до создания... Схема Вариант схемы для реализации выше описанной задачи приведен на рис. 32.1. Рис. 32.1. Схема устройства генерации звуковых сигналов На этой схеме впервые задействованы цифровые контакты О и 1 модуля Arduino. ПРИМЕЧАНИЕ. Во всех предыдущих схемах мы не использова- ли цифровые контакты 0 и 1, чтобы не мешать процессу обмена информацией по последователь- ному каналу между модулем и компьютером. Но с увеличением количества контактов, необходи- мых для решения поставленных задач, нам все равно придеться когда-то их использовать.
Глава 32. Формирование звука 329 Использование этих контактов для подключения кнопок — одно из самых безопасных решений. Если кнопка не нажата, то она никак не влияет на подключенные к ней цепи. ВНИМАНИЕ. Главное помнить - в момент обмена данными с компьютером ни в коем случае нельзя нажимать на кнопки, подключенные к контактам 0 и 1. В качестве звукоизлучателя в схеме используется любой маломощный динамик. Он прекрасно работает, если его под- ключить через конденсатор емкостью 3...5 микрофарад. Вариант готовой конструкции, собранной на универсальной монтажной плате, приведен на рис. 32.2. Рис. 32.2. Внешний вид устройства генерации звуковых сигналов
330 ARDUINO: от азов программирования до создания... Алгоритм 1. Организовать цикл опроса кнопок. В цикле кнопки должны опрашиваться по возрастанию, начиная с кнопки номер 0 и заканчивая кнопкой номер 9. 2. При обнаружении в процессе опроса первой же нажатой кнопки программа должна прекратить опрос и запустить процесс генерации звука на выходе, куда подключен звуко- излучатель. Высота тона должна быть взята из таблицы. Для каждой кнопки своя нота. При этом перебор кнопок должен быть начат сначала (с кнопки номер 0). 3. Если в результате сканирования всех десяти кнопок ни одна из них не оказалась нажатой, программа должна принуди- тельно прекратить генерацию звука. 4. В любом случае (нажата кнопка или нет) после завершения операций, описанных в пунктах 2 или 3, управление пере- дается к пункту 1 данного алгоритма. В результате выполнения описанного выше алгоритма про- грамма будет постоянно опрашивать все кнопки, при обна- ружении нажатия начнется генерация звука, а опрос кнопок начнется сначала. Если в процессе очередного перебора про- грамма обнаружит нажатие той же кнопки, какая была нажата при предыдущем переборе, то новая команда вызова звукового сигнала только подтвердит прежний режим генерации звука. Если номер нажатой кнопки окажется другим, то тон звуко- вого сигнала изменится. Если же после перебора всех кнопок окажется, что ни одна кнопка не нажата, то генерация звука прекратится. I Программа Вариант программы простейшего звукового устрой- ства, реализующий описанный выше алгоритм, приведен в
Глава 32. Формирование звука 331 листинге 32.1. Далее мы будем детально изучать используе- мые в программе приемы программирования, рассматривая ее построчно. В строке 1 определяется константа SoundPin — номер кон- такта, к которому подключается звукоизлучатель. В строке 2 определяется переменная ButtonPin (номер теку- щей кнопки). При помощи этой переменной программа будет осуществлять перебор кнопок. Интерес для нас представляет строка 3 программы. В этой строке описывается массив. ЧТО ЕСТЬ ЧТО. Массив - это набор однотипных переменных или констант используемых как единый набор дан- ных. Каждый массив имеет свое имя. В данном случае имя массива tabFreq (массив хранит таблицу частот). В квадратных скобках указывается размер массива. В нашем случае размер массива равен 10. Это значит, что массив может хранить десять разных значений. Все значения нашего конкретного массива присваиваются тут же, в строке 3. Значения перечисляются в фигурных скоб- ках, следующих сразу за определением массива после символа «=» (равно). Значения в списке разделяются запятой. Обращение в программе к любому значению из массива происходит по его номеру в формате ИмяМассива[НомерЭлементаМассива]. ПРИМЕЧАНИЕ. Элементы массива нумеруются, начиная с эле- мента номер ноль. Это значит, что массив раз- мерностью 10 состоит из элементов с номерами от 0 до 9.
332 ARDUINO: от азов программирования до создания... Листинг 32.1. Программа «Десять кнопок - десять нот» 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 /* Сигнализатор звука «десять нот» */ // Определение констант: const int SoundPin =12; // номер контакта звукоизлучателя // Определение переменных: int ButtonPin; // указатель номера контакта текут. кнопки // Определение массива констант (частоты нот) const int tabFreq[10] = { 1046, 987, 932, 880, 831, 784, 740, 698, 659, 622 }; void setup () { // инициализируем контакт звука: pinMode(SoundPin, OUTPUT); // инициализируем контакты кнопок: for (ButtonPin=0; ButtonPin<=9; ButtonPin++) { pinMode(ButtonPin, INPUT_PULLUP); } void loop() { boolean btFree = true; // сброс флага «кнопки отпущены» // Сканирование кнопок и воспроизведение звука: for (ButtonPin=0; ButtonPin<=9; ButtonPin++) { if (digitalRead(ButtonPin)==LOW) { tone (SoundPin, tabFreq[ButtonPin]); btFree = false; break; } if (btFree) noTone(SoundPin); }
Глава 32. Формирование звука 333 После блока команд определения констант и переменных начинается функция начальных установок setup(). В теле функ- ции setup() производится настройка режимов всех контактов модуля. В, строке 5 контакт звукоизлучателя переводится в режим OUTPUT. В строках 6 и 7 мы видим цикл, который перебирает все входы от кнопок с 0 по 9 и каждый из них переводит в режим INPUT_PULLUP (режим входа с включенным подтягивающим резистором). Далее в программе начинается ее основной цикл 1оор(). В теле функции 1оор() реализуется основной алгоритм про- граммы. В строке 9 определяется локальная переменная btFree. ЧТО ЕСТЬ ЧТО. Локальная переменная - это переменная опре- деленная внутри какой-либо функции. Действие локальной переменной распространяется только на ту функцию, в которой она была определена. Вне этой функции локальная переменная не су- ществует. Переменная btFree имеет тип boolean, то есть принимает значения true или false. В данной программе эта переменная служит флагом «Все кнопки отпущены». В строке 9 сразу после определения флаг устанавливается в true. Далее в строке 10 организуется цикл, который перебирает по очереди входы кнопок и проверяет, не нажата ли одна из них. Как только программа обнаружит нажатую кнопку, флаг сбрасы- вается в false (что сигнализирует в дальнейшем для программы, что не все кнопки отпущены). Если же в конце цикла перебора значение переменной btFree все еще равно true, то это значит, что ни одна кнопка не нажата, и нужно выключать звук.
334 ARDUINO: от азов программирования до создания... В качестве счетчика цикла перебора кнопок используется переменная ButtonPin (см. строку 10). Ее начальное значение равно нулю, а цикл выполняется пока ButtonPin меньше или равен девяти. В строке 11 считывается и оценивается состояние текущей кнопки с номером ButtonPin. Если значение состояния кнопки равно LOW (кнопка нажата), то выполняются строки 12,13 и 14. В строке 12 вызывается функция генерации звука на выходе SoundPin. ЧТО ЕСТЬ ЧТО. Частота звука - это значение элемента масси- ва tabFreq с номером, равным значению перемен- ной ButtonPin. В строке 13 сбрасывается переменная btFree («Все кнопки отпущены»), потому что обнаружилась нажатая кнопка. В строке 14 мы видим оператор break. Оператор break досрочно завершает текущий цикл опроса, и оставшиеся кнопки не опрашиваются. Это нужно для того, что бы выполня- лось правило — программа реагирует только на самую первую из нажатых кнопок. Строка 15 программы выполняется уже после цикла пере- бора кнопок. Это оператор if, который проверяет значение флага btFree. Если флаг установлен (его значение равно true), то выполняется оператор поТопе(), и звук прекращается. Так как переменная btFree имеет логический тип, то составлять из нее логическое выражение не нужно. Ее значение уже само явля- ется условием для оператора if (имеет значение true или false). На этом заканчивается тело основного цикла программы, и управление передается на его начало. Многократно сканируя все кнопки, программа реагирует на их нажатие, издавая раз- личные звуки.
ГЛАВА 33 ВВОД АНАЛОГОВОЙ ИНФОРМАЦИИ Постановка задачи Конструкция модуля Arduino, а также синтаксис его языка программирования, разработаны таким образом, чтобы макси- мально облегчить работу с аналоговым сигналом. Для ввода аналогового сигнала, как уже говорилось выше, используются специальные аналоговые входы. Если говорить о модуле Arduino UNO, то он имеет шесть таких входов. Для чтения уровня сигнала на любом из этих вхо- дов в языке Arduino имеется специальный оператор analogRead(HoMepBxoda). Параметр НомерВхода может прини- мать следующие значения: АО, Al, А2, АЗ, А4, А5. Функция analogRead() возвращает уровень сигнала на выбранном входе в относительных единицах. Допустимый диапазон напряжений на любом аналоговом входе от 0 до +5 вольт. При изменении напряжения на входе в этих пределах возвращаемое значение изменяется от 0 до 1024. То есть, если напряжение на входе равно нулю, функция возвращает 0. Если же на входе +5 вольт, то функция возвращает 1024. Как видите, сама задача чтения аналоговых данных проста до примитивности. Поэтому рассмотрим пример, в котором эта задача будет дополнена задачей создания светодиодного индикатора уровня аналогового сигнала.
336 ARDUINO: от азов программирования до создания... ЗАДАЧА. Создать на основе модуля Arduino устройство, которое будет считывать напряжение с движка переменного резистора и наглядно отображать считанное напряжение при помощи линейного индикатора, выполненного в виде цепочки свето- диодов. Светодиоды должны загораться в виде светящегося столбика. Чем больше напряжение на входе модуля, тем больше длина столбика. Схема Схема устройства, позволяющая реализовать поставленную выше задачу, приведена на рис. 33.1. Переменный резистор R1 включен по схеме потенциометра между цепью питания (+5 В) и общим проводом. Напряжение с движка потенциометра поступает на вход АО модуля. Рис. 33.1. Схема устройства чтения и индикации аналогового сигнала
Глава ЪЪ. Ввод аналоговой информации 337 Рис. 33.2. Внешний вид устройства чтения и индикации аналогового сигнала Светодиоды индикатора подключаются к контактам 2...9 точно так же, как в схеме бегущих огней. Внешний вид уже собран- ного устройства показан на рис. 33.2. Алгоритм Программа должна представлять бесконечный цикл, в котором будет выполняться следующая последовательность действий. 1. Прочитать напряжение с аналогового входа. Далее мы будем оперировать понятием «считанное значение».
338 ARDUINO: от азов программирования до создания... 2. Подготовить программу к выполнению цикла вывода считанного значения на индикатор. Далее в цикле будет использоваться понятие «плавающего порога». 3. Присвоить плавающему порогу начальное значение равное нулю. 4. В цикле по очереди перебирать все выходы на светодиоды. 5. С каждым шагом перебора увеличивать значение пла- вающего порога на значение, которое мы назовем «шаг порога». Таким образом, с каждым шагом «плавающий порог» будет расти. Шаг порога должен быть выбран таким образом, чтобы за 8 шагов цикла порог изменился бы от О до 1024 (что перекроет весь диапазон считанного значения сигнала). 6. На каждом шаге сравнить считанное значение со значе- нием плавающего порога. 7. Если считанное значение больше плавающего порога, теку- щий светодиод зажечь. 8. В противном случае светодиод потушить. 9. Продолжить перебор до тех пор, пока не будут перебраны все восемь светодиодов. 10. После перебора всех восьми светодиодов перейти к пункту 1 данного алгоритма. В результате выполнения описанного выше алгоритма пла- вающий порог за восемь шагов перебора светодиодов изме- нится от нуля до максимума. Вначале перебора порог будет ниже считанного значения, и светодиоды на каждом шаге будут зажигаться. В какой-то момент плавающий порог пре- высит считанное значение. С этого момента на каждом шаге перебора программа будет тушить текущий светодиод. Чем выше считанное с аналого- вого входа напряжение, тем больше светодиодов загорится. Напряжение на аналоговом входе вы можете менять, повора- чивая вал переменного резистора. При этом длина столбика светящихся светодиодов будет меняться от минимума, когда ни один светодиод не горит, и до максимума, когда горят все светодиоды.
Глава 33. Ввод аналоговой информации 339 Программа Программа, реализующая описанный выше алгоритм, при- ведена в листинге 33.1. Начинается программа с определения всех необходимых констант. В строке 1 определяется имя аналогового входа, к которому подключен движок потенциометра. В строке 2 мы определяем величину шага изменения пла- вающего порога. Так как за восемь шагов порог должен изме- ниться от 0 до 1024, то шаг порога вычисляется так: 1024/8=128. В строках 3 и 4 определяются константы максимального и минимального номера контакта в группе контактов для под- ключения светодиодов. Эти константы используются для орга- низации цикла перебора светодиодов. В теле функции setup() находится цикл, определяющий режимы работы всех выводов для подключения светодиодов. ПРИМЕЧАНИЕ. Все контакты настраиваются на вывод инфор- мации, и на каждом выходе устанавливается вы- сокий логический уровень. То есть, все светодио- ды в начале работы программы оказываются вы- ключенными. Основной цикл программы (функция 1оор()) выпол- няет периодическое считывание сигнала с аналогового входа и вывод считанного значения на светодиодный индикатор. Для начала в строке 11 обнуляется значение плавающего порога iVol. В строке 12 программа считывает уровень входного сиг- нала с аналогового входа analogPin и присваивает считанное значение переменной AnalogVbl.
340 ARDUINO: от азов программирования до создания... Листинг 33.1. Программа ввода и индикации аналогового сигнала /* Ввод и индикация аналогового сигнала */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // Определение констант: const int analogPin = AO; // имя аналогового входа const int StepVol = 128; // шаг разрешения индикатора const int loopStart =2; // начало цикла бега const int loopStop =9; // конец цикла бега // Определения переменных: int thisPin; // текущий разряд светодиодов void setup() { // Цикл инициализации контактов светодиодов: for (thisPin = loopStart; thisPin <= loopStop; thisPin++) { pinMode(thisPin, OUTPUT); digitalWrite(thisPin, HIGH); } } void loop() { int iVol = 0; int AnalogVol = analogRead(analogPin); for (thisPin = IdopStart; thisPin <= loopStop; thisPin++) { if (iVoKAnalogVol) digitalWrite (thisPin, LOW); else digitalWrite(thisPin,HIGH); iVol += StepVol; } В строках 13...16 находится цикл вывода полученного зна- чения на светодиодный индикатор. В строке 13 этот цикл объявляется. В качестве счетчика цикла используется переменная thisPin. В процессе работы
Глава ЪЪ. Ввод аналоговой информации 341 цикла значение этой переменной изменяется от loopStart до loopStop, перебирая, таким образом, все контакты, к которым подключены светодиоды. В теле цикла происходит следующее. В строке 14 идет сравнение считанного аналогового значения (переменная AnalogVot) и текущего значения плавающего порога (перемен- ная i Vol). ПРИМЕЧАНИЕ. Если значение iVol окажется меньше чем значе- ние AnalogVol, то на текущий светодиод (кон- такт thisPin) подается низкий логический уро- вень (LOW) и соответствующий светодиод заго- рается. В противном случае выполняется оператор, следующий за управляющим словом else (строка 15). Этот оператор подает на контакт thisPin высокий логический уровень (HIGH), и соот- ветствующий светодиод гаснет. В строке 16 значение плавающего порога iVol увеличива- ется на величину шага порога Step Vol. Теперь при следующей итерации цикла считанное значение будет уже сравниваться с новым значением плавающего порога. Итак, в этой главе мы научились вводить значение анало- гового сигнала. Дополнительно мы узнали, как простыми про- граммными средствами можно индицировать уровень анало- гового сигнала при помощи команд цифрового вывода. В следующей главе мы узнаем, как в модуле Arduino реа- лизован удобный способ аналогового вывода.
ГЛАВА 34 ВЫВОД АНАЛОГОВОЙ ИНФОРМАЦИИ I Широтно-импульсная модуляция Язык программирования Arduino имеет команду вывода аналогового сигнала analogWrite(), очень похожую по синтак- сису на команду цифрового вывода digitalWrite(). Однако, как уже говорилось, при аналоговом выводе на выход поступает сигнал, представляющий из себя прямоугольные импульсы логических уровней (сам импульс имеет высокий логический уровень, в паузе — логический ноль). Частота этих импульсов примерно равна 490 Гц. ЧТО ЕСТЬ ЧТО. Аналоговая составляющая заложена в ширине импульсов, а вернее в соотношении импульса и паузы. Такой метод, как отмечалось ранее, назы- вается «Широтно-импульсной модуляцией» или ШИМ. В английской транскрипции это звучит так: «Pulse-width modulation» (PWM). Функция analogWrite() имеет всего один параметр — число в диапазоне от 0 до 255. Чем больше значение параметра, тем шире импульс сигнала ШИМ. При значении, равном 255, импульсы сливаются в постоянный единичный логический уровень. При уменьшении значения входного параметра
Глава 34. Вывод аналоговой информации 343 ширина импульсов уменьшается. Когда параметр окажется равным нулю, импульсы прекращаются, и на выходе устанав- ливается постоянный уровень логического нуля. ПРИМЕЧАНИЕ. Такой способ формирования аналогового уровня при определенных условиях вполне может заме- нить обычный способ формирования аналогового напряжения. Например, любые инерционные при- боры (лампочки, моторчики, светодиоды, нагрева- тельные элементы), будучи подключенными через силовой ключ к такому выходу, прекрасно рабо- тают от сигнала с ШИМ. Даже лучше, чем с вы- ходом, на котором плавно меняется аналоговое напряжение. \___________________________________________) Дело в том, что ШИМ работает в ключевом режиме, и сило- вой ключ, через который на нагрузку подается основная мощ- ность, в таком случае имеет максимальный КПД. Это происхо- дит потому, что в процессе работы силовой ключ: ♦ либо закрыт, и ток через него равен нулю; ♦ либо полностью открыт, и падение напряжения на ключе минимально. ПРИМЕЧАНИЕ. В обоих случаях рассеиваемая на ключе мощность незначительна.А это значит, что такая схема не потребует громоздкого радиатора, а возможно и вообще удастся обойтись без какого либо охлаж- дения. При этом, чем шире импульсы, тем сильнее светится лампочка, больше греется нагреватель, быстрее крутится моторчик (это должен быть мотор постоянного тока).
344 ARDUINO: от азов программирования до создания... Если же подключаемая нагрузка не предназначена для пита- ния импульсным сигналом, то импульсный сигнал с выхода ШИМ можно пропустить через интегрирующий фильтр, кото- рый превратит импульсный сигнал в аналоговый. Уровень такого сигнала тоже будет зависеть от ширины импульсов. Для вывода сигнала в режиме ШИМ используются аппа- ратные возможности основного микроконтроллера модуля Arduino. В связи с этим при использовании команды analogWrite() имеется ряд ограничений. ПРИМЕЧАНИЕ. Следует отметить, что аналоговый вывод про- исходит не на аналоговые, а на цифровые кон- такты микроконтроллера. Причем не на все, а только на некоторые. На плате Arduino контакты, которые поддерживают вывод сигнала в режиме ШИМ, обозначены символом «~». Перед использованием контакта для аналогового вывода не требуется настраивать режим его работы, как это было необхо- димо сделать прежде, чем производить ввод или вывод цифро- вых сигналов при помощи тех же самых контактов. Команда analogWrite() сама автоматически настроит кон- такт в режим ШИМ, и на контакте появятся импульсы заданной длительности. Эти импульсы будут присутствовать на выходе до тех пор, пока: ♦ не поступит другая команда analogWrite(); ♦ на тот же контакт не будет произведен вывод цифрового сигнала при помощи команды diginaIWrite(). В модуле Arduino UNO аналоговый вывод возможен на кон- такты 3,5,6,9,10 и И.
Глава 34. Вывод аналоговой информации 345 Простейший способ аналогового вывода Самый простой способ использования аналогового вывода — создать программу, аналогичную простейшей про- грамме цифрового ввода и вывода, приведенной в главе 25 нашей книги (см. листинг 25.1). Достаточно просто заменить команды digitalRead() и digitalWrite() в той первой программе на команды analogRead() и analogWrite(). А так же следует выбрать другие входной и выходной контакты. Новая программа будет считывать уро- вень напряжения с аналогового входа и передавать его на ана- логовый выход. ЗАДАЧА. Создать схему и программу устройства, которое будет считывать напряжение с переменного ре- зистора, включенного по схеме потенциометра, и передавать считанный уровень командой ана- логового вывода на светодиод. При нулевом на- пряжении на входе светодиод должен полностью погаснуть. При максимальном напряжении на входе - светодиод должен гореть в полную силу. Схема Схема устройства приведена на рис. 34.1. В качестве аналогового входа используется вход АО, а в качестве выхода — цифровой контакт 9.
346 ARDUINO: от азов программирования до создания... Рис. 34.1. Схема простейшего устройства аналогового ввода-вывода Алгоритм В основном цикле программы многократно выполнять сле- дующие действия: 1. Прочитать аналоговый уровень с входа. 2. Привести значение считанного аналогового уровня в диа- пазоне команды аналогового вывода, учитывая, что диа- пазон аналогового ввода 0...1024, диапазон аналогового вывода O...255. 3. Вывести приведенный уровень аналогового сигнала на ана- логовый выход. 4. Перейти к пункту 1 данного алгоритма.
Глава 34. Вывод аналоговой информации 347 Листинг 34.1. Простейшая программа ввода и вывода аналогового сигнала 1 2 3 4 5 6 7 /* Простейшая программа аналогового ввода и вывода */ const int analogPin - АО; // номер аналогового входа const int ledPin =9; // номер контакта светодиода int analogVol; // текущий аналоговый уровень void setup() {} void 1оор() { // Читаем значение сигнала с аналогового входа: analogVol = analogRead(analogPin); // Выводим аналоговое значение на выход светодиода analogWrite(ledPin, analogVol/4); } Программа | Простейшая программа аналогового ввода-вывода приве- дена в листинге 34.1. Как видите, эта программа даже проще своего цифрового аналога. В строках 1...3 уже знакомым вам образом определяются две константы и одна глобальная переменная. Константы содержат номера контактов аналогового входа (analogPin) и аналогового выхода (ledPin).
348 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. Переменная analogVol предназначена для времен- ного хранения считанного аналогового значения. Так как режимы аналоговых входа и выхода на- страивать не нужно, функция setup() (строка 3) не содержит никаких команд. В строке 4 программа читает уровень сигнала на входе analogPin и помещает его значение в переменную analogVol. В строке 7 считанное значение делится на 4 (приведение диапазонов) и результат от деления записывается на выход ledPin. I Более сложный пример аналоговой индикации В качестве более сложного примера использования анало- гового выхода предлагаю взять за основу схему из предыду- щего раздела (см. рис. 34.1) и усовершенствовать ее работу, применив плавное зажигание и потухание светодиодов. ПРИМЕЧАНИЕ. Правда, для этого нам придется сократить ко- личество светодиодов до шести и подключить их только к тем выходам, которые работают с ШИМ.
Глава 34. Вывод аналоговой информации 349 ЗАДАЧА. Создать схему и программу устройства, считы- вающего напряжение с движка переменного ре- зистора, включенного по схеме потенциометра и выводящего считанное аналоговое значение на светодиодный индикатор, состоящий из 6 свето- диодов. Индикатор должен выводить уровень сиг- нала в виде светящегося столбика разной длины. Чем больше напряжение на входе, тем больше длина светящегося столбика светодиодов. Если напряжение на входе равно нулю, все светодиоды должны потухнуть. При максимальном напря- жении на входе все светодиоды должны гореть. Отображая все изменения длины светящегося столбика, светодиоды должны загораться и по- тухать, плавно изменяя свою яркость, используя для этого аналоговый вывод. Схема у Схема устройства, реализующая поставленную задачу, изо- бражена на рис. 34.2. Алгоритм Многократно повторять основной цикл, в котором про- грамма должна выполнять два основных действия: 1. считать уровень входного сигнала на аналоговом входе; 2. выполнить цикл вывода считанного уровня на индикатор, состоящий из шести светодиодов.
350 ARDUINO: от азов программирования до создания... Рис. 34.2. Схема усложненного устройства аналогового ввода-вывода В свою очередь, алгоритм работы светодиодного индика- тора должен выглядеть следующим образом. 1. Для вывода считанного уровня аналогового сигнала должен производиться перебор всех шести светодиодов индика- тора, по порядку с первого по шестой. 2. Для каждого светодиода определяется яркость его свече- ния. Для этого используется специальное вспомогательное значение — плавающий порог. В процессе перебора све- тодиодов плавающий порог должен изменяться от нуля до максимального значения. 3. На каждом шаге перебора светодиодов считанное значение сравнивается со значением плавающего порога. Разность между этими двумя значениями корректируется (масшта- бируется, смещается по уровню) и выводится на текущий светодиод командой аналогового вывода. Корректировка уровня, выводимого на светодиоды должна обеспечивать такую работу всего индикатора, чтобы с увеличением вход- ного напряжения от нуля до максимума плавно должны
Глава 34. Вывод аналоговой информации 351 зажигаться сначала младший светодиод, затем по очереди более старшие. Когда входное считанное напряжение окажется в середине диапазона, свечение всех светодиодов должно быть таково, чтобы самый младший светодиод светился максимально. При дальнейшем увеличении входного напряжения по очереди к своему максимуму должны приближаться более старшие свето- диоды. При достижении входного напряжения верхнего предела диапазона все шесть светодиодов должны гореть по максимуму. Программа Программа, реализующая описанный выше алгоритм, при- ведена в листинге 34.2. Несмотря на более сложный алгоритм работы, программа также получилась достаточно простая. В строке 1 определяется константа, означающая имя используемого в данной программе аналогового входа. В строке 2 определяется шаг изменения плавающего порога. Значение шага определяется по формуле 255/6. То есть, диапазон входного значения команды analogWrite() делится на количество шагов перебора светодиодов. Результат деления мы округляем до целого, для того, чтобы не усложнять задачу про- цессору работой с десятичными дробями В строке 3 определяется массив констант, представляющий собой таблицу номеров контактов, поддерживающих режим аналогового вывода. Именно к этим контактам подключены наши светодиоды. Таблица нам понадобится для того, чтобы по номеру светодиода находить номер контакта, к которому он подключен. В строке 4 определяется переменная, в которой будет хра- ниться номер текущего светодиода. Как и в первой версии про- граммы, функция setup() остается пустой. В строках 6...9 расположен основной цикл программы. Первая же команда в теле основного цикла (строка 7) читает
352 ARDUINO: от азов программирования до создания... уровень входного аналогового сигнала с входа analogPin. Считанное значение делится на два и помещается в перемен- ную AnalogVol. ПРИМЕЧАНИЕ. Уменьшение считанного сигнала вдвое делается для того, что бы привести его диапазон к требу- емому диапазону для вывода на светодиоды. Вы спросите: почему делим на два? Ведь, как мы говорили выше, диапазон считанного аналогового сигнала 0...1024, а диапазон выходного — 0...255. Диапазоны отличаются в 4 раза! Двойной диапазон нам нужен потому, что при повышении напряжения от нуля до половины максимального значения, младший светодиод должен плавно изменить яркость от пол- ностью потушенного до полностью горящего. При этом самый старший светодиод должен только-только загореться. Еще пол- диапазона нам понадобится, чтобы старший светодиод плавно загорелся до максимума. Итак, в строке 8 начинается цикл перебора светодиодов. Переменная thisLed меняется от 0 до 5, перебирая все 6 свето- диодов. В строке 9 находится оператор аналогового вывода. Он выводит на контакт текущего светодиода с номером thisLed значение сигнала, которое определяется при помощи специ- ально разработанной функции приведения уровня rangeVol(). Номер контакта, куда подключен текущий светодиод, опреде- ляется при помощи массива AnalogPin[]. В качестве указателя массива подставляется номер текущего светодиода thisLed. Аргументом функции rangeVol() выступает выражение: AnalogVol+StepVol*thisLed.
Глава 34. Вывод аналоговой информации 353 Листинг 34.2. Индикация столбиком светодиодов с плавным гашением /* Ввод и вывод аналогового сигнала Плавная индикация */ 1 const int analogPin = АО; // номер аналогового входа 2 const int StepVol =42; // шаг разрешения индикатора 3 const int AnalogPin[] = {3,5,6,9,10,11}; // аналог, выходы 4 int thisLed; // текущий разряд светодиодов 5 void setup () {} 6 void 1оор() { 7 int AnalogVol = analogRead(analogPin)/2; 8 for (thisLed = 0; thisLed < 6; thisLed++) { 9 analogWrite(AnalogPin[thisLed], rangeVol(AnalogVol+StepVol*thisLed)); } i 10 int rangeVol (int InpVol) { 11 int OutpVol = InpVol - 256; 12 if (OutpVol>255) OutpVol= 255; 13 if (OutpVoKO) OutpVol= 0; 14 return 255 - OutpVol; } В этом выражении к уровню считанного с аналогового входа сигнала добавляется текущий уровень плавающего порога. В свою очередь, уровень плавающего порога вычис- ляется путем перемножения номера текущего светодиода на величину шага плавающего порога. Таким образом, на каждом шаге плавающий порог будет выше, а, значит, каждый следую- щий светодиод будет гореть сильнее.
354 ARDUINO: от азов программирования до создания... Программа приведения уровней расположена в строках 10...14. Она выполняет следующие три важных преобразова- ния. Преобразование 1. Смещение полученного входного значе- ния вниз для того, чтобы при нулевом уровне AnalogVol ни один светодиод не горел. Так как для последнего светодиода уровень плавающего порога будет равен 42*6=252, то при нулевом зна- чении AnalogVol входное значение функции и будет равно 252. ПРИМЕЧАНИЕ. Значит, именно на эту величину нужно сместить вниз входной сигнал. \, Данное действие происходит в строке 11 программы. Только вместо 252 там используется число 256. Почему? А вспомните, как мы получили величину шага плавающего порога 42. Мы округлили до целого (отбросили дробную часть). Чтобы точнее попасть в центр нужного нам диапазона, мы должны добавить несколько единиц к величине смещения. Полученное значение помещается в переменную OutpVol. Преобразование 2. Ограничение диапазона сверху и снизу. Все предыдущие преобразования уровней приведут к тому, что значение переменной OutpVol будет изменяться в диапазоне, выходящем за пределы стандартного (от 0 до 255). Поэтому сначала (в строке 12) производится ограничение этой вели- чины сверху. Оператор if проверяет уровень значения OutpVol. Если OutpVol выше 255, ему присваивается значение 255. Точно также в строке 13 ограничивается уровень снизу. Если содержимое переменной OutpVol после предыдущих преобразований ока- жется меньше нуля, то ему присваивается значение ноль. Преобразование 3. Инвертирование выходного значения. Наши светодиоды подключены таким образом, что загораются при уровне ноль на выходе, а гаснут при единичном уровне.
Глава 34. Вывод аналоговой информации 355 Наш же сигнал тем выше, чем выше сигнал на входе. Это зна- чит, что при повышении сигнала на входе интенсивность све- чения светодиода будет не увеличиваться, а уменьшаться. Операция инвертирования исправляет этот недостаток. Инвертирующее выражение включено в команду завершения функции. В строке 14 вы можете видеть команду return (возврат). Этот оператор завершает функцию и возвращает результат ее работы. Возвращаемое значение указывается как параметр команды return. В данном случае оно вычисляется при помощи выражения 255 - OutpVol. Такое выражение переворачивает диапазон значений. При изменении значения OutpVol от 0 до 255, возвращаемое значение будет изменяться от 255 до нуля. В результате работы данной программы при изменении напряжения на входе устройства, на светодиодном индика- торе отображается светящийся столбик переменной длины. Чем больше напряжение, тем длиннее столбик. Причем свето- диоды, составляющие этот столбик, будут плавно загораться с каждым шагом. При уменьшении напряжения на входе длина светящегося столбика будет уменьшаться. При этом с каждым шагом свето- диоды будут тухнуть по очереди, но также плавно. В табл.34.1 приведены значения, подаваемые на свето- диоды при помощи команды аналогового вывода при разных значениях входного сигнала. ПРИМЕЧАНИЕ. Для наглядности в табл. 34.1 указаны неинвер- тированные значения сигнала (то есть вместо 255 - OutpVol указаны значения OutpVol). По сути, цифры в таблице отражают интенсивность свечения светодиодов: 0 - светодиод потушен, 255 - полностью зажжен. Не забывайте, что на самом деле в программе цифры обратные (вме- сто 0 подается 255, а вместо 255 подается 0).
356 ARDUINO: от азов программирования до создания... Значения, подаваемые на светодиоды при разных входных уровнях Таблица 34.1 Номер светодиода Порог Значение сигнала на входе 0 100 200 300 400 500 600 700 800 900 1000 Светодиод 1 0 0 0 0 0 0 0 44 94 144 194 244 Светодиод 2 42 0 0 0 0 0 36 86 136 186 236 255 Светодиод 3 84 0 0 0 0 28 78 128 178 228 255 255 Светодиод 4 126 0 0 0 20 70 120 170 220 255 255 255 Светодиод 5 168 0 0 12 62 112 162 212 255 255 255 255 Светодиод 6 210 0 4 54 104 154 204 254 255 255 255 255
ГЛАВА 35 ПЕРЕДАЧА ДАННЫХ ИЗАРДУИНО НА КОМПЬЮТЕР Постановка задачи Еще одна функция, которая легко выполняется при про- граммировании для Arduino по сравнению с программирова- нием на других языках для микроконтроллеров, — это органи- зация канала передачи данных из модуля Arduino в компьютер по последовательному каналу. Программист легко может воспользоваться тем самым каналом, через который происходит загрузка оттранслирован- ной программы в модуль. Среда разработчика Arduino уже имеет свои встроенные средства, способные как принять данные от модуля Arduino, так и передать информацию на модуль. Поэтому мы можем смело поставить следующую простую и достаточно интерес- ную задачу.
358 ARDUINO: от азов программирования до создания... ЗАДАЧА. Разработать схему и программу устройства, которое должно иметь десять кнопок для вво- да цифр (помеченные как «1», «2», и т.д. до «9»), плюс еще одну кнопку «Ввод». При нажатии циф- ровых кнопок в последовательный канал долж- ны передаваться коды соответствующих цифр, а при нажатии на кнопку «Ввод» на компьютер должна передаваться команда перевода строки. Передаваемые цифры мы будем наблюдать при помощи инструмента «Монитор порта», входя- щего в состав среды разработки Arduino. Схема Вариант схемы, которую мы будем использовать для реали- зации вышеописанной задачи, приведен на рис. 35.1. Рис. 55.1. Схема устройства для передачи цифр в последовательный порт
Глава 35. Передача данных из Ардуино на компьютер • 359 ПРИМЕЧАНИЕ. В связи с тем, что наша программа использует последовательный канал, мы не стали исполь- зовать контакты 0 и 1 для подключения кнопок. Кнопки ввода цифр подключены к контактам Кнопка «Ввод» подключена к контакту 12. Такая схема подключения клавиатуры позволяет программе перебирать все И кнопок одним цик- лом перебора. Перед тем, как приступить к формулированию алгоритма, следует отметить, что последовательный USB канал модуля Arduino работает в режиме эмуляции СОМ порта. Как уже говорилось выше, получать и просматривать переданные из Arduino данные мы собираемся при помощи Монитора порта, встроенного в среду разработки Arduino. Монитор порта, как и любая программа «монитор», работает исключительно с кодами символов в ASCII кодировке. Монитор отображает символы, коды которых поступают по последовательному каналу. Поэтому при нажатии цифровых кнопок наш модуль Arduino должен передавать в последова- тельный канал ASCII коды символов цифр (см. табл. 35.1). А при нажатии кнопки «Ввод» в последовательный порт должны передаться два символа: ♦ символ возврата каретки (код 13); ♦ символ перевода строки (код 10). ASCII коды символов цифр Таблица 55.1 Символ «0» «1» «2» «3» «4» «5» «6» «7» «8» «9» Возврат каретки Перевод строки Код 48 49 50 51 32 53 54 55 56 57 13 10
360 ARDUINO: от азов программирования до создания... Алгоритм 1. Начать бесконечный цикл перебора всех 11 кнопок. 2. При обнаружении первой же нажатой кнопки перейти к процессу вывода кода, соответствующего этой кнопке через последовательный канал в компьютер. Для этого: 2.1. выполнить задержку антидребезга контактов; 2.2. выполнить цикл ожидания отпускания кнопки (осу- ществлять процесс передачи данных на компьютер лучше всего в момент отпускания кнопки); 2.3. сформировать небольшую защитную задержку на время дребезга при отпускании кнопки, и затем пере- дать код в последовательный порт; 2.3.1. Если была нажата одна из цифровых кнопок, передать код кнопки. 2.3.2. Если нажатой оказалась кнопка «Ввод», передать коды перевода строки и возврата каретки. 2.4. сформировать защитную задержку на время передачи информации по последовательному порту; 2.5. продолжить цикл перебора кнопок сначала, передав управление на пункт 1 данного алгоритма. Программа Вариант программы, реализующий описанный выше алго- ритм, приведен в листинге 35.1. Рассмотрим программу по порядку.
Глава 35. Передача данных из Ардуино на компьютер 361 Листинг 35.1. Программа «Цифры на Монитор» 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 /* Передача данных на компьютер по USB каналу */ // Константы const int nPinMin =2; // Первый из контактов кнопок const int nPinMax = 12; // Последний из контактов кнопок // Переменные: byte NumberPin; // Номер контакта текущей кнопки void setup () { // инициализируем контакты кнопок на ввод: for (NumberPin=nPinMin; NumberPin<=nPinMax; NumberPin++) { pinMode(NumberPin, INPUT_PULLUP); } Serial.begin(9600); // Инициализация послед, канала } void loop () { // Сканирование кнопок и воспроизведение звука: for (NumberPin=nPinMin; NumberPin<=nPinMax; NumberPin++) { if (digitalRead(NumberPin)==LOW) { delay(20); while (digitalRead(NumberPin)==LOW) (}; delay(20); if (NumberPin!=12) Serial.print(NumberPin-2,DEC); else Serial.printin(' '); delay(20); break; } }
Ъ62 ARDUINO: от азов программирования до создания... В строках 1 и 2 происходит определение двух констант: ♦ номера первого контакта из группы контактов для под- ключения кнопок; ♦ номера последнего контакта из группы контактов для под- ключения кнопок. В строке 3 определяется переменная NumberPin, в которой мы будем хранить указатель на текущий контакт при переборе кнопок. В функции setup() в строках 5 и 6 расположен цикл, задаю- щий режимы работы для всех контактов кнопок. Новая для нас команда расположена в строке 7. Эта команда инициализирует последовательный канал. Все команды работы с последовательным каналом являются производными от набора команд Serial. Команда Serial.begin(CKopocmb) подготав- ливает последовательный порт для его использования в вашей программе. В момент инициализации задается скорость, с которой будет работать последовательный порт. ПРИМЕЧАНИЕ. Скорость порта в компьютере и в модуле Arduino должны быть одинаковы. Вы должны зайти в на- стройки порта в компьютере и узнать, какая скорость порта там установлена. В программе на Arduino нужно установить такое же зна- чение скорости. Скорость может принимать одно значение из стандартного набора: 110; 150; 300; 600; 1200; 2400; 4800; 9600;
Глава 35. Передача данных из Ардуино на компьютер 363 14400; 19200; 38400; 57600; 115200. ПРИМЕЧАНИЕ. Но чаще всего в современных компьютерах по умолчанию порт настроен на 9600. к____________________'_______________________. После setupf) начинается основной цикл программы 1оор(). В теле функции 1оор() в строке 9 инициализируется цикл пере- бора кнопок. Фактически, цикл занимает все тело функции 1оор(). Цикл перебирает контакты со 2 по 12, к которым под- ключены кнопки с «0» по «9» и кнопка «Ввод». Первая команда в теле цикла (строка 10) — это чтенйе и оценка состояния кнопки, подключенной к текущему входу. ПРИМЕЧАНИЕ. Строки 11...17 выполняются только в том слу- чае, если кнопка окажется нажатой. В строке 11 вызывается задержка антидребезга. В строке 12 расположен цикл ожидания отпускания кнопки. В строке 13 — первая защитная задержка. В строке 14 производится оценка текущего номера кон- такта. Номер контакта проверяется на условие «не равно 12». К контакту номер 12 подключена кнопка «Ввод». Если условие выполнено (нажатой оказалась не кнопка «Ввод»), то в последовательный порт передается код кнопки (команда Serial.print(NumberPin-2,DEC) в строке 14). В против-
364 ARDUINO: от азов программирования до создания... ном случае в последовательный порт передается пустое значе- ние с командой перевода строки и возврата каретки (строка 15). ПРИМЕЧАНИЕ. Как видно из программы, передача данных в по- следовательный порт производится при помощи двух разных команд. Это аналоги команды print() и println(), которые имеются в любой версии языка СИ. Формат команд следующий: ♦ Serial.print(3Ha4eHne, Формат); ♦ 8епа1.рпп11п(3начение,Формат); . ♦ Параметр «Значение» может быть любого из стандартных типов (см. Приложение 2), но данные любого типа преоб- разовываются и передаются в виде текста. ПРИМЕР. Число 52.43 передается как строка «32.45». В ка- честве значения также можно передавать стро- ку символов, например, «Hello word». ВНИМАНИЕ. Недостаток транслятора Arduino в том, что строки, написаные кириллицей, передаются не- правильно. Переданные по последовательному каналу строки, записанные русскими буквами, при отображении в мониторе будут выглядеть как набор иероглифов. При необходимости, вы все же можете передать кириллический текст, но вам придется самостоятельно правильно опреде- лять и передавать в порт код каждой буквы.
Глава 35. Передача данных из Ардуино на компьютер 365 Параметр «Формат» в функциях Serial.print() и Serial. println() не обязательный. Он предназначен для изменения способа отображения данных. Допустимые значения, BIN (дво- ичный), ОСТ (восьмеричный), DEC (десятеричный), HEX (шест- надцатеричный). Для вещественных (дробных) чисел параметр «Формат» задает количество знаков после запятой. ПРИМЕР. Serial.print(78, BIN) выводит «1001110» Serial.print(78, ОСТ) выводит «116» Serial.print(78, DEC) выводит «78» Serial.print(78, HEX) выводит «4Е» Serial.print(1.23456,0) выводит «1» Serial.print(1.23456,2) выводит «1.23» Serial.print(1.23456,4) выводит «1.2346» В строке 14 программы команда Serial.print() передает в последовательный порт номер нажатой кнопки в виде деся- тичного числа. Номер нажатой кнопки вычисляется из номера текущего контакта путем уменьшения его на 2. Если номер текущего контакта равен 12, то выполняется команда Serial. println() в строке 15. Команда Serial.println() аналогична команде Serial.print(), но отличается тем, что печать содержимого параметра «Значение» завершает передачей символов возврата каретки и перевода строки. ПРИМЕЧАНИЕ. Так как в нашем случае ничего, кроме возвра- та каретки, передавать не нужно, параметр «Значение» содержит один символ пробела.
366 ARDUINO: от азов программирования до создания... ВНИМАНИЕ. Функция Serial.println() не позволяет печатать пустую строку. Поэтому параметр «Значение» должен содержать хотя бы один любой символ! В нашем случае это пробел. После передачи данных в последовательный порт наша программа переходит к строке 16. В этой строке находится команда формирования защитной задержки. Далее, в строке 17 мы видим команду break. По этой команде программа досрочно выходит из цикла перебора кнопок. То есть, текущий цикл перебора кнопок прерывается. Однако функция 1оор() продолжает выполняться. Поэтому весь процесс повторяется. То есть управление передается на строку 9 программы и перебор кнопок начинается сначала. ПРИМЕЧАНИЕ. В результате работы программы при каждом об- наружении нажатой кнопки ее код передается в последовательный порт. Повторной передачи кода уже нажатой кнопки удается избежать благодаря циклу ожидания отпускания кнопки. Пока кнопка на- жата, сканирование кнопок приостановлено. Для того чтобы увидеть поступающие из модуля Arduino данные на компьютере, нужно, находясь в среде разработки Arduino, запустить Монитор порта. Это можно сделать: ♦ либо при помощи меню: Инструменты/Монитор порта; ♦ либо при помощи иконки в панели инструментов (в пра- вом верхнем углу окна программы). В открывшемся окне монитора при нажатии на цифро- вые кнопки, подключенные к модулю Arduino, в поле приема данных будут появляться цифры, соответствующие нажатым кнопкам. Цифры выстроятся в число.
Глава 35. Передача данных из Ардуино на компьютер 367 D123456789 0627825 Рис. 35.2. Окно Монитора порта с результатами работы программы После нажатия на кнопку «Ввод» произойдет перевод строки, и следующие цифры будут выводиться уже в новой строке. Как это выглядит на экране, показано на рис. 35.2. ПРИМЕЧАНИЕ. В заключение, приведем несколько полезных заме- чаний по поводу использования контактов 0 и 1. Возможна ситуация, когда для решаемой вами задачи может потребоваться больше, чем 11 кнопок. С некоторыми ограничениями и оговорками вы все же сможете использовать два этих контакта для подключения кнопок. ПРИМЕЧАНИЕ. Контакт номер 0 в нашем случае использовать проще всего. Этот контакт связан с цепью, ко- торая используется для передачи данных от компьютера в модуль Arduino.
368 ARDUINO: от азов программирования до создания... Конфликт может возникать, только если случайно нажать на кнопку в момент загрузки программы в модуль. При работе программы данные от компьютера в модуль не передаются, поэтому кнопка будет работать без проблем. ПРИМЕЧАНИЕ. Контакт номер 1 можно использовать только в крайнем случае. В нашей программе это воз- можно. Передача данных в компьютер у нас происходит после отпускания кнопки. В программе даже предусмотрена защит- ная задержка. То есть, в момент передачи данных контакты кнопки гарантированно будут не замкнуты. Данные будут переданы без искажений. Но само нажатие кнопки воспринимается последователь- ным каналом как передача пустого значения (символа про- бела). Если в нашей программе для подключения одной из кнопок использовать контакт 1, то при нажатии на эту кнопку в окне монитора порта перед символом номера кнопки будет выводиться лишний пробел. В некоторых программах, для некоторых задач это вполне допустимо. Тем более, что такая ситуация может быть легко обработана программно.
ГЛАВА 56 ПЕРЕДАЧА ДАННЫХ С КОМПЬЮТЕРА HAARDUINO Постановка задачи В главе 35 мы передавали информацию от модуля Arduino на компьютер. В этой главе мы будем решать обратную задачу. ПРИМЕЧАНИЕ. Процесс приема данных из последовательно- го канала отличается от процесса передачи. Последовательный канал микроконтроллера сра- зу после его инициализации переходит в режим ожидания данных от компьютера. Как только придет байт данных, электроника последова- тельного канала записывает этот байт в специальный буфер обмена. Все процессы по приему байтов в буфер обмена выполняются в фоновом режиме с использованием прерыва- ния, параллельно и не зависимо от основной программы. И программисту ничего, кроме инициализации порта, для этого
370 ARDUINO: от азов программирования до создания... делать не нужно. Буфер обмена может хранить до 64 байт. Для чтения и использования данных из буфера в языке Arduino имеются две функции: Serial.available() — возвращает количество принятых бай- тов в буфере. Serial. read() — читает один байт из буфера. Возвращает -1 (минус один), если байты закончились. Попробуем создать программу, которая будет получать команды от компьютера по последнему порту и выполнять в зависимости от принятых данных те либо иные действия. Проще всего управлять генерацией звука. И так, ставим задачу! ЗАДАЧА. Создать программу, которая должна получать из компьютера сигналы в виде кодов нот (от 0 до 9). Получив код ноты, программа должна сфор- мировать звуковой сигнал с высотой тона, соот- ветствующего номеру ноты. При этом длитель- ность каждого звука должна иметь некую фикси- рованную длину. Схема Исходя из условий поставленной задачи, наша схема должна состоять всего лишь из одного звукоизлучателя, под- ключенного к одному из цифровых контактов модуля Arduino. Подключим его точно так же, как в схеме музыкальной шка- тулки. В результате схема нашего устройства будет выглядеть так, как показано на рис. 36.1.
Глава 36. Передача данных с компьютера на Arduino 371 VF1 4.7мкф Рис. 36.1. Схема устройства, управления звуком с компьютера Алгоритм | 1. Проверить, есть ли данные в буфере данных. 2. Если буфер не пуст, извлечь очередной байт данных из буфера. 3. Используя принятый код, вычислить номер ноты. 4. Воспроизвести звуковой сигнал с высотой тона, взятой из таблицы частот, используя номер ноты. При вызове звука задать фиксированную длительность. 5. Одновременно с формированием звука сформировать задержку с длительностью в полтора раза большей, чем длительность ноты (чтобы между соседними звуками была пауза). 6. Продолжить выполнения алгоритма сначала, перейдя к строке 1 данного алгоритма.
372 ARDUINO: от азов программирования до создания... | Программа Ниже приведена программа, реализующая вышеописанный алгоритм (см. листинг 36.1). Как видите, это одна из самых простых программ, приведенных в данной книге. В строке 1 программы определяется константа, указываю- щая на номер контакта звукоизлучателя. В строке 2 описан массив, содержащий таблицу частот десяти основных нот. Далее, в строке 3 начинается описание основного цикла setup(). В теле основного цикла всего две команды. Команда в строке 4 устанавливает режим работы контакта звукоизлучателя. В строке 5 расположена уже знакомая нам команда иници- ализации последовательного канала. В строке 6 начинается описание основного цикла про- граммы — функции 1оор(). Тело функции содержит два вложен- ных оператора if. Первый из них (строка 7) считывает количество приня- тых байтов в буфере обмена и проверяет это количество. Если в буфере есть хотя бы один байт, выполняются операторы в строках 8,9,10,11. В строке 8 находится выражение, которое извлекает оче- редной символ из буфера, вычисляет код ноты и помещает этот код в переменную InpCod. Для извлечения кода используется функция Serial.read(). Для вычисления номера ноты из кода вычитается число 48. ПРИМЕЧАНИЕ. Дело в том, что данные из компьютера в модуль Arduino, также, как и данные из Arduino в компью- тер, передаются в виде кодов символов в кодиров- ке ASCII. Если из ASCII кода цифр (см. табл. 36.1) вычесть 48, мы получим число, равное самой этой цифре (0,1,2 и т. д.). Это же значение будет со- ответствовать и номеру ноты.
Глава 36. Передача данных с компьютера на Arduino 373 Листинг 36.1. Программа «Звук по команде с компьютера» /* Получение команд с компьютера */ // Определение констант: 1 const int SoundPin =12; // контакт звукоизлучателя //частоты нот 2 const int tabFreq[10] = { 1046, 987, 932, 880, 831, 784, 740, 698, 659, 622 }; 3 void setup() { 4 pinMode(SoundPin, OUTPUT); // режим контакта звука 5 Serial.begin(9600); } 6 void loop() { 7 if (Serial.available()>0) { 8 int InpCod = Serial.read()-48; 9 if ((InpCod>=0)&(InpCod<=9)) { 10 tone(SoundPin,tabFreq[InpCod],200); И delay(300); } } } В результате, полученный номер ноты окажется записан- ным в переменную InpCod. Далее, в строке 9 проверяется, попадает ли вычисленный код в диапазон от 0 до 9. Это нужно для того, чтобы программа не реагировала на другие, не цифровые символы. В круглых скобках оператора if находится выражение, которое реализует сложное условие. Выражение состоит из двух отдельных выражений, каждое из которых заключено в свои круглые скобки:
374 ARDUINO: от азов программирования до создания... ♦ первое выражение проверяет переменную на соответствие нижней границе диапазона (InpCod должно быть больше или равно нулю); ♦ второе выражение точно так же проверяет верхнюю грани- цу (InpCod должно быть меньше или равно 9). Оператор & (И) объединяет эти два условия. Благодаря нему все выражение истинно, если истинны оба входящих в него условия в круглых скобках. Если номер ноты удовлетво- ряет всем этим условиям (то есть попадает в нужный диапа- зон), то выполняются строки 10 и 11. В строке 10 находится команда формирования звука. Высота тона берется из таблицы tabFreq[ ], знакомой нам по программе «Десять нот». В качестве указателя массива исполь- зуется значение переменной InpCod. Длительность звукового сигнала выбрана равной 200 миллисекундам. В строке 11 формируется задержка в 300 миллисекунд. ПРИМЕЧАНИЕ. Дело в том, что в то время, когда Arduino форми- рует звук, программа продолжает свою работу Для того чтобы программа не запустила фор- мирование нового звукового сигнала в то время, пока еще не закончилось формирование текущего, нужно выдержать паузу. Эта пауза в нашем слу- чае выбрана на 100 миллисекунд больше, чем дли- тельность звука. Это гарантирует паузу между двумя последовательными звуковыми сигналами в 100 миллисекунд. Основной цикл программы 1оор() выполняется бес- конечно, при этом каждый раз проверяя содержимое буфера обмена и воспроизводя звуки согласно считанным из буфера кодам. Что бы проверить работу приведенной выше программы нужно:
Глава 36. Передача данных с компьютера на Arduino 375 Рис. 36.2. Передача данных из окна монитора порта ♦ подключить модуль Arduino к компьютеру; ♦ запустить среду разработки IDE; ♦ открыть окно монитора порта, как описано в главе 35; ♦ набрать в верхней строке окна монитора команду (то есть вписать туда цифру от 0 до 9); ♦ нажать кнопку «Отправить» в верхнем правом углу окна. ПРИМЕЧАНИЕ. Можно также просто после набора цифры на- жать клавишу «Enter». Строка отправки кода очистится, и код отправится по последователь- ному каналу. Получив код ноты, модуль Arduino издает звуковой сиг- нал выбранного музыкального тона. Вы можете написать целую строку цифр (как показано на рис. 36.2) и послать их в модуль за один раз (одно нажатие кнопки «Отправить» или клавиши «Enter»). Arduino воспроизведет все введенные ноты по порядку, разделяя их паузой в 100 миллисекунд.
ГЛАВА 37 МУЗЫКАЛЬНАЯ ШКАТУЛКА | Постановка задачи В главе 30 мы познакомились с оператором tone() и узнали, что при помощи этого оператора мы легко можем сформиро- вать на любом из выходов звуковой сигнал любой частоты в звуковом диапазоне и с заранее заданной длительностью. Из этого следует, что для того, чтобы Arduino воспроизвел мелодию, нужно просто сформировать последовательность звуков (нот) нужной частоты (высоты тона) и длительности. Частоты всех звуков, составляющих мелодию можно поместить в массив (что такое массив мы уже знаем). В другой массив можно поместить все длительности звуков. И это будет самый простой способ извлечения мелодий. ПРИМЕЧАНИЕ. И действительно, такой способ довольно часто применяется для простых программ, воспроизво- дящих одну мелодию. Мы же предлагаем вам рас- смотреть более сложную задачу Предложенный выше способ хранения нот мелодии очень расточителен. Для хранения частоты звукового сигнала нужна переменная или даже массив переменных с типом значения
Глава 37. Музыкальная шкатулка 377 unsigned int. Этот тип значения занимает в памяти два байта. Кроме того один байт потребуется для хранения значения дли- тельности. ПРИМЕЧАНИЕ. Автор этих строк еще в своем первом самоучи- теле по программированию [4] предложил и ре- ализовал способ кодировки нот мелодии, при ко- тором для хранения одной ноты программа ис- пользует всего один байт. И сейчас, вашему вниманию предлагается программа, которая реализует тот же самый способ кодирования нот, но уже средствами языка Arduino. Для начала опишем суть предлагаемого способа коди- рования. Во-первых, вместо частоты звукового сигнала нужно использовать просто номер ноты. Как известно, для большинства простых мелодий достаточно двух, в крайнем случае, трех октав. Одна октава содержит семь основных и пять дополнитель- ных нот. То есть, для простых задач будет вполне достаточно, если мы будем использовать чуть больше тридцати нот. ПРИМЕЧАНИЕ. Поэтому предлагается из всего нотного стана выбрать 32 ноты самого популярного диапазона и пронумеровать их по порядку. Тогда, для хране- ния в памяти мелодий мы можем использовать лишь номера нот, и нам потребуется значитель- но меньше памяти. На рис. 37.1 изображен фрагмент музыкальной клавиатуры (первая и вторая октава) с указанием кодов нот, которые мы будем использовать далее в нашей музыкальной программе.
378 ARDUINO: от азов программирования до создания... На рис. 37.2 показано, как выгля- дит та же кодировка на нотном стане. Для простоты на рис. 37.2 показаны только основные ноты (ноты белых клавиш). Дополнительные ноты (черные клавиши) на нотном стане изображаются с использованием диезов или бемолей. Присвоенные им коды вы легко можете увидеть на рис. 37.1, на котором принцип кодировки нот выглядит гораздо нагляднее. Все ноты (основные и дополнительные) нумеруются по порядку. ВНИМАНИЕ. Под номером ноты в приведенных выше рассуж- дениях подразумевается номер высоты тона ноты. Такая же ситуация наблюдается в вопросе кодирования длительности звучания ноты. 24 Си 22 Ля 20 Соль 18 Фа 17 Ми 15 Ра 13 До 12 Си 10 Ля 8 Соль 6 Фа S Ми 3 Ре 1 До Рис. 37.2. Коды нот на нотном стане
Глава 37. Музыкальная шкатулка 379 ПРИМЕЧАНИЕ. В музыке не используется произвольная длитель- ность. Величина длительности музыкальных звуков подчиняется строгим законам гармонии. В музыке конкретное значение длительности не так важно. Длительность меняется в зависимости от темпа исполнения. Решающее значение имеет соотноше- ние между величинами разных длительностей. В музыке существуют следующие термины, определяющие длительность звуков (и пауз): ♦ целая; ♦ половинная; ♦ четверть; ♦ восьмая; ♦ шестнадцатая и т. д. Достаточно пронумеровать каждую их этих типов длитель- ности и использовать в кодировке мелодий код длительности ноты, а не ее значение. В табл. 37.1 приведены коды всех воз- можных длительностей, которые мы будем использовать далее в программе. ПРИМЕЧАНИЕ. Обратное направление нумерации вызвано жела- нием использовать уже готовые таблицы кодов мелодий из программы-первоисточника, которые были разработаны для моего первого самоучите- ля в 2005 году. А там большей длительности со- ответствовал больший номер. Для того чтобы облегчить задачу кодировки длительностей ваших мелодий, на рис. 37.3 показано, как обозначается дли- тельность ноты в нотной грамоте. Ноты разной длительности отличаются хвостиками.
380 ARDUINO: от азов программирования до создания... Кодировка длительностей Таблица 37.1 Код Длительность Величина в миллисекундах 7 1 (целая) 2560 6 1/2 (половинная) 1280 5 1/4 (четверть) 640 4 1/8 (восьмая) 320 3 1/16 (шестнадцатая) 160 2 1/32 (тридцать вторая) 80 1 1/64 (шестьдесят четвертая) 40 0 1/128 (сто двадцать восьмая) 20 JJ я 7 6 5 4 3 Рис. 37.3. Кодировка длительностей Предложенный выше способ коди- ровки высоты тона и длительности ноты позволяют закодировать любую ноту всего одним байтом. Как известно, один байт состоит из восьми единичных раз- рядов (битов). Три старших бита мы будем исполь- зовать для хранения кода длительности ноты, а пять оставшихся битов — для хранения кода высоты тона. Вот как будет выглядеть двоичное число, в котором закодирована нота с кодом длительности 6 (половинная дли- тельность) и кодом высоты тона 9 (соль диез первой октавы). 11001001=201 Z^-Код ноты (9) Код длительности (6) В десятичном представлений значение вышеприведенного кода равно 201. Используя описанный выше способ, можно закодировать все ноты любой мелодии. Однако кроме нот, любая мелодия содержит еще и паузы. Длительность пауз в музыке подчиняется тем же правилам, что и длительность звуков.
Глава 37. Музыкальная шкатулка 381 ПРИМЕЧАНИЕ. Поэтому при кодировке мелодий мы будем пред- ставлять паузу, как ноту без звука. Логично и удобно присвоить такой ноте-паузе код, равный нулю. \J Вот как будет выглядеть полный код паузы с четвертной длительностью (код длительности 5). 10100000=160 Z^-Код ноты (0) Код длительности (5) Теперь для того, чтобы закодировать какую-либо мело- дию, нужно составить цепочку кодов. В цепочку должны вхо- дить коды каждой ноты и каждой паузы кодируемой мелодии. Полученные коды нужно записать в массив. ПРИМЕЧАНИЕ. Массив может иметь тип значений - byte. Таким образом, каждый элемент такого массива займет в памяти всего один байт. Теперь, когда мы определились со способом кодировки мелодий, мы можем сформулировать задачу. ЗАДАЧА. Доработать программу «Десять нот», пред- ставленную в главе 32 этой книги (листинг 32.1) таким образом, чтобы при нажатии любой кноп- ки звучала мелодия. Для каждой кнопки мелодия должны быть разная. Назовем такую программу «Музыкальная шкатулка».
382 ARDUINO: от азов программирования до создания... Схема Как следует из поставленной выше задачи, схема должна оставаться прежняя, предложенная в главе 32 (см. рис. 32.1). Алгоритм 1. Просканировать клавиатуру и определить номер самой первой нажатой кнопки. 2. По номеру нажатой кнопки найти в памяти таблицу закре- пленной за этой кнопкой мелодии. 3. Начать цикл воспроизведения мелодии. Этот цикл дол- жен перебирать по порядку коды нот из таблицы мелодии, выбранной в пункте 2 алгоритма. 4. Каждый извлеченный из таблицы код ноты разложить на код тона и код длительности в соответствии с правилами кодирования, описанными в начале этой главы. 5. Если код тона не равен нулю, сформировать звуковой сиг- нал с высотой тона, соответствующей коду тона и длитель- ностью, соответствующей коду длительности. Код тона и код длительности использовать те, которые были получены в пункте 4 данного алгоритма. 6. Если код тона равен нулю, сформировать паузу длительно- стью, соответствующей коду длительности, полученному в пункте 4 данного алгоритма. 7. Повторять пункты 2—6 настоящего алгоритма много- кратно, до тех пор, пока нажата кнопка, выбранная в пункте 1 алгоритма. 8. После того, как перебор кодов нот в таблице мелодии закончен, перейти к началу алгоритма, то есть к пункту 1 и начать новое сканирование кнопок.
Глава 37. Музыкальная шкатулка 383 9. Если при сканировании кнопок окажется, что ни одна кнопка не нажата, запретить формирование звука и так же перейти к началу алгоритма. Программа Программа, реализующая поставленную задачу и описан- ный выше алгоритм, приведена в листинге 37.1. За основу этой программы взята программа «Десять нот» (См. листинг 32.1). ПРИМЕЧАНИЕ. Та часть программы, которая занималась скани- рованием кнопок, оставлена без изменений. Но теперь, после определения номера нажатой кнопки программа вызывает добавленную в конец программы про- цедуру воспроизведения мелодии. Кроме того, в начало новой программы (в область определения констант и переменных) добавлен набор массивов констант. Эти массивы представляют собой таблицы мелодий (10 таблиц по одной на каждую мело- дию), и несколько вспомогательных таблиц, назначение кото- рых мы узнаем по мере рассмотрения текста программы. В строке 1 программы определяется константа — номер контакта для подключения звукоизлучателя. В строках 2 и 3 определяются две глобальные переменные. И константа и переменные нам уже знакомы по программе «Десять нот». А вот дальше начинаются определения таблиц. В строке 4 определяется таблица длительностей нот. Как видите, таблица выполнена в виде массива, в который помеща- ются значения всех используемых в программе задержек. Это те самые значения, которые мы уже приводили в табл. 21.1,
384 ARDUINO: от азов программирования до создания... в графе «Величина в миллисекундах». Значение задержки с кодом 0 помещается в элемент массива номер ноль, значение задержки с кодом 1, в элемент номер 1 и так далее. Теперь, для того чтобы, например, получить величину задержки с кодом 4 нужно просто обратиться к элементу массива номер 4 (вот так: tabz[4]). В строке 5 определяется таблица частот. При помощи этой таблицы программа может быстро определить частоту (высоту тона) любой ноты. Например, частота ноты 10 определяется как tabFreq[10]. В строках 6... 15 размещены таблицы мелодий. Таблицы с именами mell[], те12[]т.д. содержат коды нот разных мело- дий. Каждый такой код ноты в таблице содержит номер дли- тельности и номер ноты, закодированные способом, описан- ным выше в начале этой главы. В конце каждой таблицы мело- дий стоит код 255. Этот код служит признаком конца мелодии. ПРИМЕЧАНИЕ. Все мелодии имеют разную длину, поэтому без специального маркера, индицирующего окончание каждой конкретной мелодии, не обойтись. В строке 16 мы видим определение еще одной таблицы. Она определена как *tabm[ ]. Это таблица ссылок на таблицы мелодий. Она помогает программе обратиться к нужной мело- дии по ее номеру. Элементами таблицы *tabm[] имеют новые для нас типы значения — значение типа «ссылка». Механизм ссылок — это тоже фирменная особенность языка СИ. До сих пор мы имели дело с переменными и массивами, имеющими стандартные типы значения: ♦ число; ♦ символ; ♦ булево; ♦ логическое и т. п.
Глава 37. Музыкальная шкатулка 385 Ссылочная переменная работает с ссылками на другие переменные, функции, массивы и т. д. ПРИМЕР. Элемент номер 0 массива *tabm[] содержит ссылку на таблицу mell. Элемент номер 1 со- держит ссылку на таблицу те12, элемент номер 2 содержит ссылку на таблицу те13 и т. д. Вы легко увидите это, взглянув на строку 16 программы. В каждой таблице, на которую ссылается соответствующая ссылка, содержится набор кодов одной из мелодий. Так, напри- мер, в таблице те13 записаны коды мелодии, которая должна воспроизводиться при нажатии кнопки номер 3. Используя таблицу ссылок, можно обраться к любой таблице мелодий. И даже к любому элементу любой таблицы мелодий. ПРИМЕР. Получить значение любого элемента табли- цы мелодий те13[] можно следующим образом: tabm[2][HoмepЭлeмeнma]. Результат выражение tabm[2] — это ссылка на таблицу те14[]. Поэтому вместо те14[НомерЭлемента] можно написать: 1аЬт[2][НомерЭлемента]. Допустим, мы хотим обратиться к элементу 5 таблицы мелодий те14[ ]. Как видно из строки 9 программы, значение этого элемента равно 143 (не забывайте, что нумерация эле- ментов начинается с нуля). А, значит, что мы можем приров- нять следующие три выражения: tabm[2][S] = mel4[5] = 143.
386 ARDUINO: от азов программирования до создания... Существует и другой способ работы со значениями типа «ссылка». Ссылка на массив одновременно является ссылкой на его первый элемент (элемент номер ноль). Значение типа «ссылка» можно присвоить какой-нибудь переменной. Но эта переменная должна и сама иметь ссылочный тип. То есть нам нужна переменная типа «ссылка». Например, в нашей программе мы присваиваем значе- ния различных элементов массива tabm[] переменной nota. Предположим, что нам нужно присвоить переменной значение элемента номер 2. Для этого просто запишем nota = tabm[2]. Теперь, при помощи переменной nota, можно обращаться к любому элементу массива, на который указывает эта ссылка (массива те15[ ]). ПРИМЕЧАНИЕ. Как говорилось выше, сразу после присвоения зна- чения ссылка, записанная в переменную nota, ука- зывает на элемент массива номер ноль (те13[0]). Для того чтобы получить значение элемента, на который указывает ссылка, используется оператор «*» (звездочка). В нашем случае выражение *nota будет равно 132 (*nota = 152, см. строку 8 программы). Если теперь увеличить значение ссылки на единицу, то ссылка укажет на следующий элемент массива. Увеличить зна- чение ссылки можно, просто прибавив к нему единицу или применив команду инкрементации: nota++. Теперь выражение *nota будет возвращать значение 141 (*nota = 141). Так, увеличивая значение ссылочной переменной, можно перебрать все элементы таблицы мелодии.
Глава 37. Музыкальная шкатулка 387 Листинг 37.1. Программа «Музыкальная шкатулка» /* Музыкальная шкатулка */ 1 // Определение констант const int SoundPin = 12; // номер контакта звукоизлучателя 2 , // Определение глобальных переменных int ButtonPin; // указатель текущего входа от кнопки 3 boolean btFree; // флаг «все кнопки отпущены» 4 // Таблица длительностей нот const unsigned int tabz[] = {20,40,80,160,320,640,1280,2560}; 5 // Таблица - частоты нот const unsigned int tabFreq[]={0,587,622,659,698,740,784, 6 831,880,932,988,1047,1109,1175,1245,1319,1397,1480, 1568,1661,1760,1865,1976,2093,2217,2349,2489,2637, 2794,2960,3136,3322,3520}; // Таблицы мелодий //В траве сидел кузнечик byte mell[] = {109,104,109,104,109,108,108,96,108,104, 7 108,104,108,109,109,96,109,104,109,104,109,108,108,96, 108, 104,108,104,108,141,96,109,111,79,79,111,111,112, 80,80,112,112,112,111,109,108,109,109,96,109,111,79,79, 111, 111,112,80,80,112,112,112,111,109,108,141,128,96,255}; // Песенка крокодила Гены byte mel2[] = {109,110,141,102,104,105,102,109,110,141, 104,105,107,104,109,110,141,104,105,139,109,110,173,96, 114,115,146,109,110,112,109,114,115,146,107,109, 110, 114,112,110,146,109,105,136,107,105,134,128,128,102,105, 137,136,128,104,107,139,137,128,105,109,141,139,128,110, 109,176,112,108,109,112,144,142,128,107,110,142,141,128, 105,109,139,128,173,134,128,128,109,112,144,142,128,107, 110,142,141,128,105,109,139,128,173,146,128,255};
388 ARDUINO: от азов программирования до создания... 8 // В лесу родилась елочка byte mel3[] = {132,141,141,139,141,137,132,132,132,141, 141,142,139,176,128,144,146,146,154,154,153,151,149,144 153,153,151,153,181,128,96,255}; 9 // Happy births day to you byte mel4[] = {107,107,141,139,144,143,128,107,107,141, 139,146,144,128,107,107,151,148,146,112,111,149,117,117 148,144,146,144,128,255}; 10 11 12 //С чего начинается родина byte mel5[] = {99,175,109,107,106,102,99,144,111,175,96 99,107,107,107,107,102,104,170,96,99,109,109,109,109, 107,106,143,109,141,99,109,109,109,109,104,106,171,96, 99,111,109,107,106,102,99,144,111,143,104,114,114,114, 114,109, 111,176, 96,104,116,112,109,107,106,64,73,143 107,131,99,144,80,80,112,111,64,75,173,128,255}; //Из кинофильма «Веселые ребята» byte mel6[] = {105,109,112,149,116,64,80,148,114,64,78, 146,112,96,105,105,109,144,111,64,80,145,112,64,81,178 96,117,117,117,149,116,64,82,146,112,64,79,146,144,96, 105,105,107,141,108,109,112,110,102,104,137,128,96,105 105,105,137,102,64,73,142,105,107,109,64,75,137,96,105 105,105,137,102,105,142,112,64,82,180,96,116,116,116, 148,114,112,142,109,64,78,146,144,96,105,105,107,141, 108,109,112,110,102,104,169,96,96,255}; // Улыбка byte mel7[] = {136,133,170,168,131,134,133,131,193,160, 133,136,138,138,138,140,143,141,140,138,173,200,138, 140,173,128,140,138,133,136,134,202,160,140,138,141,136, 140,138, 138,136,131,133,163,161,160,129,132,136,136, 136,136,168,141,129,132,131,131,131,163,131,132,136, 134,136,137,136,134,136,137,173,171,160,141,136,139, 137,137,137,169,141,134,137,136,136,136,168,141,132, 131,132,134,137,136,134,132,134,169,168,160,141,136, 139,137,137,137,169,141,134,137,136,136,136,168,141, 132,131,132,134,137,136,134,132,134,168,193,160,255};
Глава 37. Музыкальная шкатулка 389 14 15 16 17 18 19 20 21 22 // Гимн России byte mel8[] = {136,173,136,96,106,172,133,96,101,170, 136,96,102,168,129,96,97,163,131,96,101,166,134,96,104, 170,140,141,175,136,177,143,96,109,175,140,136,173,140, 96,106,172,133,96,101,170,136,96,102,168,129,96,97,173, 140,138,168,224,255}; // Спят усталые игрушки byte mel9[] = {168,128,133,168,128,133,168,168,166,165, 163,165,200,143,145,143,145,212,168,128,131,168,128, 131,168,166,165,163,161,165,200,145,148,145,148,214, 168,168,170,168,177,177,170,168,161,161,166,168,170, 170,168,166, 165,165, 166, 165,232,198,195, 193,160,224,255} ; // Гамма byte mellO[] = {129,130,131,132,133,134,135,136,137,138, 139,140,141,142,143,144,145,146,147,148,149,150,151, 152,153, 154,155,156,157,158,159,128,159,158,157,156, 155,154,153,152,150,149,148,147,146,145,144,143,142, 141,140,139,138,137,136,135,134,133,132,131,130,129, 128,255}; // Таблица начал всех мелодий byte *tabm[] = {mell, mel2, mel3, mel4, mel5, mel6, mel7, mel8, mel9, mellO}; void setup() { // Установка режимов контактов: pinMode(SoundPin, OUTPUT); // контакт звука // цикл установки для контактов кнопок: for (ButtonPin=0; ButtonPin<=9; ButtonPin++) { pinMode(ButtonPin, INPUT_PULLUP); } } void loop() { // Сканирование кнопок и воспроизведение звука: btFree = true; // флаг «все кнопки отпущены»
390 ARDUINO: от азов программирования до создания... 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 for (ButtonPin=0; ButtonPin<=9; ButtonPin++) { if (digitalRead(ButtonPin)==L0W) ( playMelody (ButtonPin); btFree = false; break; } } if (btFree) noTone(SoundPin); } // Функция воспроизведения мелодии void playMelody (int numberMelody) { byte fnota; // код тона ноты byte dnota; // код длительности ноты byte *nota; // ссылка на текущую ноту nota = tabm[numberMelody]; StartMelody: if (digitalRead(ButtonPin)==HIGH) return; // если кнопка отпущена, закончить if (*nota==0xFF) return; // проверка на конец мелодии fnota = (*nota)&0xlF; // определяем код тона dnota = ((*nota)»5)&0х07; // опред. код длительности if (fnota!=0) { tone (SoundPin, tabFreq[fnota],tabz[dnota]); delay (tabz[dnota]+10); } else { noTone (SoundPin); // если пауза выкл. звук delay (tabz[dnota]); } nota++; goto StartMelody;
Глава 37. Музыкальная шкатулка 391 ПРИМЕЧАНИЕ. Далее в программе мы будем использовать имен- но этот, последний, метод работы со ссылками. Функция setup() занимает строки 17...20 и не отличается от аналогичной функции из программы «Десять нот». Функция 1оор() (строки 21...28) также является копией аналогичной функции из программы «Десять нот», но с одним небольшим отличием. ПРИМЕЧАНИЕ. В строке 25 вместо вызова команды tone() те- перь производится вызов функции воспроизве- дения мелодии playMelody(). В качестве параме- тра в эту функцию передается номер нажатой кнопки. Функция playMelody() расположена в строках 29...46 про- граммы. Функция начинается с определения локальных пере- менных (строки 30...32). Переменная fnota предназначена для временного хранения кода высоты тона ноты, переменная dnota будет хранить код длительности ноты. Обратите внимание на описание переменной в строке 32. В этой строке описывается переменная nota. Она будет исполь- зоваться для хранения ссылки на текущий элемент таблицы, выбранной для воспроизведения мелодии. ПРИМЕЧАНИЕ. По этой причине переменная имеет тип «ссыл- ка», на что указывает символ звездочки перед именем переменной в строке определения.
392 ARDUINO: от азов программирования до создания... В строке 33 переменной nota как раз и присваивается зна- чение ссылки. Ссылка извлекается из таблицы tabm[ ]. В строке 34 находится метка. ЧТО ЕСТЬ ЧТО. Метка - это символьное имя, идентификатор, отмечающий место в программе, куда программа может осуществлять переход по команде goto. Метка состоит из имени метки, которое заканчивается дво- еточием. Имя метки также должно соответствовать стандарт- ным правилам компьютерных имен. В строке 35 происходит считывание и проверка состояния текущей кнопки. Номер этой кнопки был передан в функцию playMelody() при ее вызове через параметр numberMelody. СОВЕТ. В процессе воспроизведения мелодии нужно по- стоянно контролировать, нажата ли еще эта кнопка, для того, что бы немедленно прекратить воспроизведение мелодии при ее отпускании. Оператор if в строке 35 проверяет значение, определяющее состояния кнопки, и, если, это значение равно HIGH (кнопка отпущена), выполняется команда return. В данном случае команда return приводит к немедленному завершению функ- ции playMelody(), а, значит, к прекращению процесса воспро- изведения мелодии. Если в результате проверки выяснится, что кнопка еще нажата, то программа начинает процесс воспроизведения мело- дии. И начинается этот процесс проверкой конца мелодии.
Глава 37. Музыкальная шкатулка 393 ПРИМЕЧАНИЕ. Дело в том, что при воспроизведении мелодии программа будет постоянно возвращаться к метке StartMelody, считывая ноту за нотой. И в определенный момент мелодия закончится (оче- редной код ноты окажется равным 255). Прежде, чем начинать расшифровывать код ноты, нужно проверить, не конец ли это мелодии. Поэтому в строке 36 происходит проверка на конец мело- дии. Если код ноты равен OxFF (а это шестнадцатеричный ана- лог десятичного числа 255), то это означает, что мелодия закон- чилась. Если это так, выполняется оператор return в строке 36, и процедура playMelody() завершается. Если мелодия не окончена, то программа приступает к выделению из кода ноты: ♦ кода высоты тона (строка 37); ♦ кода длительности (строка 38). Схематически процесс разделения показан на рис. 37.4. Код тона получается путем наложения на код ноты маски OxlF (см. выражение в строке 37). Число OxlF имеет нули в трех старших разрядах и единицы во всех остальных (00011111). Оператор «&» означает логическую операцию побитового «И». Рис. 37.4. Процесс преобразования кодов ноты
394 ARDUINO: от азов программирования до создания... ЧТО ЕСТЬ ЧТО. Операция «И» называется логическим умноже- нием. \____________________________________________ Если логически перемножить два бита, то результат умно- жения будет равен единице только в том случае, когда оба перемножаемых бита равны единице. Если хотя бы один из перемножаемых битов равен нулю, то и результат равен нулю. Если код ноты побитно перемножить с кодом маски, то в результате такого умножения те биты, которые в коде маски равны нулю, обнулятся и в байте результата. Те биты, которые в маске равны единице, в байте результата останутся такими же, как в исходном коде ноты (см. рис. 37.4). Примерно так же вычисляется код задержки (строка 38). Только предварительно биты кода ноты сдвигаются вправо на 5 шагов, как показано на рис. 37.4. Сдвиг производится при помощи уже знакомого нам оператора «»». После сдвига на код накладывается маска 0x07. Шестнадцатеричное число 0x07 содержит нули в пяти стар- ших двоичных разрядах и единицы в трех младших (00000111). Операция логического умножения «&» сдвинутого кода ноты и кода маски сбрасывает старшие биты, и, таким образом, результатом этих преобразований является код длительности ноты (см. рис. 37.4). Теперь нужно воспроизвести звук с полученными выше параметрами. Но сначала нужно определить — это звук или пауза. Для этого в строке 39 проверяется значение перемен- ной fnota. Если оно не равно нулю, то программа формирует звуковой сигнал с высотой тона fnota и длительностью dnota (строка 40 программы).
Глава 37. Музыкальная шкатулка 395 ПРИМЕЧАНИЕ Конкретное значение частоты сигнала берется из таблицы tabFreq[], куда подставляется код высоты тона. Конкретное значение длительно- сти звука берется из таблицы tabz[], куда под- ставляется код задержки. Далее нужно приостановить работу программы на время, пока звучит звуковой сигнал. Вы, наверное, помните, что команда tone() работает автономно, параллельно с выполне- нием основной программы. ВНИМАНИЕ. Если не предусмотреть задержку, то программа запустит формирование следующего звука тогда, когда еще не закончил звучать предыдущий звук. Поэтому в строке 41 программы предусмотрена команда задержки. Эта команда формирует задержку на 10 миллисе- кунд большую, чем заданная в функции tone() длительность звукового сигнала. Запас по длительности введен для того, чтобы между отдельными звуками всегда была небольшая микропауза и звуки не сливались в процессе воспроизведения мелодии. Если код высоты тона (fnota) оказался равен нулю, то про- грамма в строках 43,44 выполняет формирование музыкаль- ной паузы с кодом длительности dnota. Для этого в строке 43 выполняется команда принудительного выключения звука поТопе(), а в строке 44 формируется пауза. Команда поТопе() применяется в этом месте программы на всякий случай, для надежности. Вообще-то все звуки к этому моменту и так должны прекратиться.
396 ARDUINO: от азов программирования до создания... В строке 45 производится инкремент значения перемен- ной nota. В результате ссылка, хранящаяся в этой переменной, теперь будет указывать на следующую ноту мелодии. Затем, при помощи оператора goto, расположенного в строке 46, управление передается по метке StartMelody. Это означает, что выполнение программы продолжится со строки 35. То есть с первой из команд, расположенных после метки StartMelody. Таким образом, образуется цикл чтения и воспроизведения кодов нот мелодии, который прекратится: ♦ либо в строке 36, если мелодия закончится (встретится код ноты OxFF); ♦ либо в строке 35, если обнаружится, что кнопка с номером ButtonPin отпущена. Приведенный выше способ кодировки нот достаточно тру- доемок. Если вы пожелаете закодировать свою собственную мелодию, то вам может показаться это очень сложной задачей. На виртуальном диске, прилагаемом к книге (адрес диска вы найдете в конце книги) имеется видеоролик, в котором пока- заны простые приемы с использованием программы Exel, зна- чительно облегчающие процесс кодирования мелодий.
ГЛАВА 58 ЭЛЕКТРОННЫЙ ЗАМОК С НЕОБЫЧНОЙ ЛОГИКОЙ РАБОТЫ Постановка задачи Наша книга подходит к концу, поэтому новый пример должен быть достаточно сложным с точки зрения алгоритма. Вашему вниманию предлагается электронный кодовый дверной замок с необычной логикой работы. Данный при- мер не только поможет разобраться в некоторых новых при- емах программирования для Arduino, но может также найти практическое применение в вашем хозяйстве. Этот кодовый замок был разработан как пример еще для самого первого издания книги [4]. В замке применен необычный способ набора кодовой ком- бинации. На первый взгляд замок устроен так же, как обычно выглядят подобные устройства. Замок имеет клавиатуру, состо- ящую из десяти кнопок, предназначенных для ввода цифр от О до 9. Также имеется переключатель режимов: «Запись кода — Работа». К выходу электронной части замка подключен элек- тронный ключ, управляющий механизмом открывания замка (реле или соленоид).
398 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. Необычность замка кроется в алгоритме набора кодовой комбинации. Кодовая комбинация может состоять не только из нажатий той или иной кнопки, но и из сочетаний двух или нескольких одновременно нажатых кнопок. При вводе кода программа просто запоминает любые изме- нения состояния клавиатуры. Затем, в режиме «Работа», вы должны повторить все манипуляции, которые вы выполняли при вводе кодовой последовательности в режиме «Запись кода». Для того чтобы было понятнее, приведем пример кодовой комбинации. Допустим, сначала вы нажимаете кнопку «1». Это первое изменение состояния клавиатуры (было ничего не нажато, стало — нажата одна кнопка). Это состояние запоми- нается в памяти. Далее, к примеру, не отпуская кнопки «1» вы можете, нажать кнопку «3». Это следующее изменение состояния клавиатуры (нажаты одновременно кнопки «1» и «3»). Оно так же запо- минается в памяти. Далее, вы можете, например, отпустить кнопку «1». Или наоборот, не отпуская кнопки «1» и «3» нажать, к примеру, еще и кнопку «8». И все эти изменения последова- тельно запоминаются в памяти. ПРИМЕЧАНИЕ. Не важно, быстро или медленно вы набираете коды. Запоминается лишь последовательность изменения состояний. Окончанием процесса набора кодовой комбинации является ситуация, когда все кнопки окажутся отпущенными, и в течение одной секунды не будет нажата ни одна кнопка. Выше описанным способом набирается кодовая комбина- ция как в режиме «Запись кода», так и в режиме «Работа». Но
Глава 38. Электронный замок с необычной логикой работы 399 в режиме «Записи кода» все эти манипуляции с клавиатурой запоминаются в памяти модуля Arduino, а в режиме «Работа» правильно повторенная кодовая комбинация открывает замок. Такой необычный алгоритм ввода кодовой комбинации существенно усложняет задачу подбора кода для злоумышлен- ников. ПРИМЕЧАНИЕ. ----------------------------------------- /7ри желании, вы всегда можете использовать электронный замок и привычным способом. Просто при наборе кодовой последовательности не нажимайте несколько кнопок одновременно. Теперь разберемся, куда же мы будем записывать набран- ную в режиме записи кодовую последовательность. До сих пор мы использовали два вида памяти. Во-первых, оперативное запоминающее устройство (ОЗУ). В нем хранятся значения всех переменных программы. Во-вторых — программная память (здесь хранится наша исполняемая программа, а также постоянные константы). ОЗУ отличается высоким быстродействием, но информация в ОЗУ хранится лишь до тех пор, пока на модуль подано напряжение питания. При отключении питания все содержимое ОЗУ теряется. ЧТО ЕСТЬ ЧТО. Программная память (Flesh) - это электриче- ски стираемое ПЗУ (постоянное запоминающее устройство), Программа и константы записыва- ются в эту память в процессе заливки програм- мы и не изменяются в процессе ее работы. Для долговременного хранения данных, вводимых пользо- вателем, в современных микроконтроллерах имеется специ- альный вид памяти, которая называется EEPROM.
400 ARDUINO: от азов программирования до создания... ЧТО ЕСТЬ ЧТО. EEPROM (Electrically Erasable Programmable Read- Only Memory) - электрически стираемое пере- программируемое постоянное запоминающее устройство. В модуле Arduino (а, точнее, в микроконтроллере ATmega323) такая память также имеется. Для того чтобы ваша программа могла работать с этим видом памяти необходимо использовать специальную библиотеку. Эта библиотека, в отличие от использованных нами до сих пор библиотек, входит в стандартный пакет среды разработки IDE. Библиотека так и называется «EEPROM». Как добавить библиотеку к программе мы рассматривали в главе 9 данной книги. После подключения библиотеки в распоряжении про- граммиста появляются следующие дополнительные функции: ♦ ЕЕРИОМдугке(НомерЯчейки, Значение); — запись байта данных в ячейку EEPROM памяти. Возвращаемого значе- ния нет; ♦ ЕЕРРОМ.геаб(НомерЯчейки); — чтение байта данных из ячейки памяти EEPROM. Возвращает значение считанного байта. ПРИМЕЧАНИЕ. Как видите, запись в энергонезависимую память EEPROM производится побайтно. Поэтому для записи значений переменных тех типов, кото- рые занимают в памяти более одного байта (см. Приложение 2), вы должны самостоятельно вы- числить значение каждого байта и записать каж- дое такое значение в отдельную ячейку EEPROM. Чаще всего приходится иметь дело с переменными, кото- рые занимают в памяти два байта. Для этого случая в языке
Глава 38. Электронный замок с необычной логикой работы 401 Arduino существуют специальные функции, позволяющие раз- бивать значение на байты, а затем объединять их обратно, в одно значение. Так, функция highByte() получает из значения переменной значение ее старшего байта. Функция lowByte() получает зна- чение младшего байта. А функция word() объединяет старший и младший байты в одно значение. Как это делается, мы уви- дим ниже при разборе уже готовой программы. А пока поста- вим задачу. ЗАДАЧА. Создать схему и программу на основе модуля Arduino, реализующую вышеописанную идею элек- тронного замка. Устройство должно иметь де- сять кнопок для ввода кода обозначенных цифра- ми от «0» до «9», переключатель режима «Запись кода - Работа», а также электронный ключ для управления исполнительным механизмом замка. Схема | Схема электронного замка приведена на рис. 38.1. Внешний вид электронного замка, выполненного с использованием уни- версальной монтажной платы, приведен на рис. 38.2. Как видно из схемы, цифровые кнопки замка подключены к цифровым контактам 0...9 модуля. Переключатель режима представляет собой тумблер на два фиксированных положе- ния, имеющий одну группу из двух контактов: ♦ в режиме «Запись кода» контакты тумблера должны быть замкнуты; ♦ в режиме «Работа» контакты тумблера должны быть разом- кнуты.
402 ARDUINO: от азов программирования до создания... Рис. 38.1. Схема электронного замка Рис. 38.2. Внешний вид электронного замка
Глава 38. Электронный замок с необычной логикой работы 403 Ключевой каскад для управления исполнительным меха- низмом замка подключается к контакту 13. К этому же кон- такту на плате Arduino уже подключен светодиод, специально предназначенный для нужд программиста. Как только на контакт 12 поступит напряжение, открываю- щее замок, светодиод загорится. И мы будем видеть, что замок открыт. ПРИМЕЧАНИЕ. В процессе испытания схемы и программы элек- тронный ключ и исполнительный механизм мож- но не подключать. Для проверки и отладки про- граммы достаточно светодиода. \_____________________________________________ Алгоритм Как в режиме «Записи кода», так и в режиме «Работа» функ- ционирование программы начинается с процедуры ввода кодовой комбинации с клавиатуры. Процедура в цикле мно- гократно считывает состояние клавиатуры и ждет изменения этого состояния. ЧТО ЕСТЬ ЧТО. Состояние клавиатуры - это число, состоящее из 10 двоичных битов информации. Каждый бит этого числа отображает состояние соответству- ющей кнопки клавиатуры. Младший бит (бит номер 0) отра- жает состояние кнопки «0». Следующий бит (бит номер 1) ото- бражает состояние кнопки «1» и так далее.
404 ARDUINO: от азов программирования до создания... Если какая либо кнопка нажата, то соответствующий ей бит равен нулю, если отпущена — единице. Код состояния клави- атуры записывается в переменную, имеющую тип int, то есть занимающую в памяти два байта. Итак, процедура ввода кода с клавиатуры многократно счи- тывает код состояния клавиатуры и ждет, когда при очередном считывании этот код изменится. Каждое новое значение кода записывается в буфер, который расположен в ОЗУ. В результате в буфере постепенно накапливается последовательность кодов, играющая роль ключа для открывания замка. ПРИМЕЧАНИЕ. В процессе ввода кодовой последовательности программа постоянно контролирует время меж- ду двумя последовательными нажатиями кнопок. Если это время превысит контрольное время (в 1 секунду), программа считает, что ввод кодо- вой последовательности завершен и выходит из цикла сканирования кнопок. После того как ввод кодовой последовательности в буфер завершен, дальнейшие действия зависят от режима работы. Если переключатель режимов находится в положении «Запись кода», программа переходит к процедуре записи кодовой последовательности из буфера (в ОЗУ) в долговременную память (EEPROM). При этом каждый код из буфера разделяется на старший и младший байты. И все эти байты записываются по очереди в ячейки EEPROM. Затем туда же записывается и длина кодовой после- довательности.
Глава 38. Электронный замок с необычной логикой работы 405 ПРИМЕЧАНИЕ. Это необходимо, потому что длина последова- тельности - величина не фиксированная. В на- шем кодовом замке мы можем использовать ко- довую последовательность произвольной длины. Она ограничивается лишь объемом буфера. Если же переключатель режима находится в положении «Работа», то после завершения процедуры ввода кодовой последовательности с клавиатуры программа переходит к про- цедуре чтения и сравнения кодов. Коды, записанные ранее, считываются по очереди из ячеек EEPROM и сравниваются со значениями кодов, только что введенных с клавиатуры, и нахо- дящихся в буфере в ОЗУ. Если все коды обеих последовательностей (в EEPROM и в буфере ОЗУ) окажутся одинаковыми, программа дает команду на открывание замка. Программа | Программа электронного замка приведена в листинге 38.1. При создании программы была подтверждена высокая степень совместимости языка Ардуина с другими СИ-подобными язы- ками программирования. Программа, которую мы видим в листинге 38.1, создана путем копирования программы электронного замка, приве- денной в книге [4], написанной на языке СИ среды програм- мирования Code Vision.
406 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. Для адаптации программы с языка СИ Code Vision для работы в среде Arduino пришлось сделать со- всем немного изменений. Но мы не будем в дан- ной книге заниматься сравнением двух программ. Кто хочет, может сравнить их самостоятельно. Мы просто разберем подробно работу програм- мы, приведенной на листинге 38.1. Как уже говорилось выше, программа начинается с присо- единения библиотеки EEPROM.h (строка 1). Далее, в строках 2...8 производится определение различных констант, используемых в дальнейшем в этой программе. И тут используется другой, пока еще нам не знакомый оператор при- своения. Это универсальный оператор присвоения ^define. При помощи этого оператора можно присвоить имя любому значению, выражению или строковой константе. Оператор ^define не требует указания типа значения, так как он опреде- ляет не значение, а только строковый литерал. ПРИМЕЧАНИЕ. Такой способ определение констант использо- вался в исходном варианте программы, взятом из книги [4]. Оттуда он перешел в программу на Arduino. Рассмотрим подробнее назначение определяемых кон- стант. В строке 2 программы определяется константа klfree. Константе присваивается литерал 0x3FF. Это число в шестнад- цатеричном формате, соответствующее коду состояния клави- атуры в случае, если ни одна кнопка не нажата. Это значение понадобится нам в процедуре «ожидания нажатия хотя бы одной из клавиш» и в процедуре «ожидания отпускания всех клавиш».
Глава 38. Электронный замок с необычной логикой работы 407 В строке 3 определяется длительность контрольного про- межутка времени kontrTime. Его мы будем использовать в про- цедуре проверки факта, окончился ли набор кодовой последо- вательности. В строке 4 определяется константа антидребезга. В строке 5 определен размер буфера, куда будет помещена набираемая кодовая последовательность. Эта же величина будет использоваться для определения количества ячеек в EEPROM, в которые мы будем помещать кодовую последова- тельность для длительного хранения. В строке 6 определяется константа klen, которая будет содержать адрес ячейки в EEPROM, в которой мы будем хра- нить длину нашей кодовой последовательности. Для этой цели мы выберем ячейку, расположенную сразу после блока ячеек, зарезервированных для хранения всех байтов самой кодовой последовательности. ПРИМЕЧАНИЕ. Адрес не указывается напрямую, а вычисляется при помощи простого математического выраже- ния. Чтобы узнать, сколько байтов займет кодо- вая последовательность, берется размер буфера в ОЗУ (константа bsize) и умножается на два. Это делается потому, что для каждого элемен- та буфера в памяти EEPROM нужно оставить две ячейки памяти. Адрес ячейки, находящейся сразу после блока ячеек кодо- вой последовательности, будет на единицу больше, чем размер блока (то есть bsize*2+l). Определение адреса ячейки методом вычисления удобно тем, что при изменении размера буфера автоматически изменяется и адрес ячейки для записи длины последовательности. Это гарантирует от ошибок при модифи- кации параметров.
408 ARDUINO: от азов программирования до создания... Листинг 38.1. Программа электронного замка /* Кодовый замок */ 1 ♦include <EEPROM.h> 2 ♦define klfree ОхЗЕЕ // код «Все кнопки отпущены» 3 ♦define kontrTime 1000 // контрольн. промежуток времени 4 ♦define kandr 30 // Константа антидребезга 5 ♦define bsize 30 // Размер буфера для хранения кода 6 ♦define klen bsize*2+l // Ячейка EEPROM для длинны // кодовой последовательности 7 ♦define modePin 11 // Пин переключателя режима 8 ♦define relayPin 13 // Номер контакта привода замка 9 unsigned char ii; // Указатель массива 10 unsigned char i; // Вспомогательный указатель 11 unsigned int codS; // Старый код 12 unsigned int bufr[bsize]; // Буфер в ОЗУ для хранения кода 13 void setup () { // Определение режимов контактов: 14 pinMode(relayPin, OUTPUT); // выход на исп. механизм 15 pinMode(modePin, INPUT_PULLUP); // перекл. режимов // Цикл настройки режимов контактов кнопок: 16 for (int ButtonPin=0; ButtonPin<=9; ButtonPin++) { 17 pinMode(ButtonPin, INPUT_PULLUP); } 18 void loop() { // Определение локальный переменных: 19 unsigned long itime; // хранения текущего времени 20 unsigned int CodC; // код состояния клавиатуры
Глава 38. Электронный замок с необычной логикой работы 409 21 22 23 24 25 26 27 28 29 30 ml: while (incod() != klfree); // ожидание отпускания кнопок while (incod() == klfree); // ожидание нажатия кнопок ii=0; m2: delay(50); // задержка 50 мс codS=incod(); // ввод кода и запись, как старого bufr[ii++]=codS; // запись очередного кода в буфер if (ii>=bsize) goto m4; // проверка конца буфера itime = millis(); // запись текущего времени m3: if (incod() != codS) goto m2; // изменилось ли состояние if (millis()-itime< kontrTime) goto m3; // пров.контр.времени 31 ш4: // Проверка перекл. режимов if (digitalRead (modePin) ==HIGH) goto coitip; // Запись кода в EEPROM 32 EEPROM.write(klen,ii); // Запись длины кода // Запись всех байтов кода 33 34 35 for (i=0; i<ii; i++) { EEPROM.write(i*2,highByte(bufr[i])); EEPROM.write(i*2+l,lowByte(bufr[i])); i 36 goto zamok; // Проверка кода 37 comp: // Проверка длины кода: if (EEPROM.read(klen)!=ii) goto ml; 38 39 for (i=0; i<ii; i++) { CodC = EEPROM.read(i*2)*256 + EEPROM.read(i*2+l); 40 if (CodC!=bufr[i]) goto ml;// Проверка самого кода } // , Открывание замка 41 42 43 zamok: digitalWrite(relayPin,HIGH); // Открываем замок delay(lOOO); // Задержка на 1 сек digitalWrite(relayPin,LOW); // Закрываем замок }
410 ARDUINO: от азов программирования до создания... 44 45 46 47 48 49 50 51 52 53 54 // Функция опроса клавиатуры и антидребезга unsigned int incod (void) { unsigned int cod0=0; // Локальные переменные unsigned int codl; byte k; II----------------------------- Цикл антидребезга for (k=0; k<kandr; k++) { codl=PINB&0x3; // Формируем первый байт кода codl=(codl«8)+PIND; // Формируем полный // код состояния клавиатуры if (codO!=codl) // Сравниваем со старым кодом {' к=0; // Если не равны, сбрасываем счетчик codOcodl; //И присваиваем новое значение // старому коду } } return codl; } В строках 7 и 8 определяются номера контактов для под- ключения переключателя режимов (modePiri) и ключа управле- ния исполнительным механизмом (relayPiri). В строках 9 и 10 определяются две переменные (И и i), которые будут нам служить указателями при работе с буфером и ячейками в EEPROM. В строке 11 определяется переменная для временного хра- нения кода состояния клавиатуры (codS). И, наконец, в строке 12 определяется буфер для хранения кодовой последовательности. Буфер представляет собой мас- сив с именем bufr и размером bsize. В строке 13 начинается описание функции setup(). В теле функции производится настройка режимов всех используемых контактов модуля Arduino. В строке 14 контакт relayPin (управление исполнительным механизмом) переводится в режим вывода информации.
Глава 38. Электронный замок с необычной логикой работы 411 В строке 15 определяется режим работы контакта пере- ключателя режимов (modePin). В строках 16, 17 находится цикл, который определяет режимы работы всех десяти контактов, предназначенных для подключения цифровых кнопок. Основной цикл программы 1оор() начинается в строке 18. В теле функции 1оор() выполняются практически все основные действия программы. Отдельно выполняется лишь задача счи- тывания кода состояния кнопок. Для считывания кода состояния используется функция incod(). Функция считывает информацию с кнопок и возвра- щает код состояния, в котором, как уже говорилось, каждый из десяти младших битов отвечает за состояние своей конкрет- ной кнопки. Функция incod() так же выполняет чистовой этап борьбы с дребезгом контактов. Основная функция 1оор() начинается с определения двух локальных переменных. Переменная itime (см. строку 19) вве- дена для того, чтобы можно было запоминать текущее значе- ние системных часов. Это значение затем используется для определения временных интервалов. Переменная CodC (см. строку 20) используется как вспомо- гательная в операции сравнения кодов. В программе широко используются метки. При помощи меток решена вся логика работы основной задачи. Надеюсь, что вы еще не забыли: метка используется для того, чтобы переходить на строку, следующую непосредственно за меткой из других мест программы. Так, строка 21 помечена меткой «ml:». Кроме метки, в строке 21 находится цикл ожидания отпускания всех кнопок. Если в момент запуска программы одна или несколько кнопок окажутся нажатыми, то это может означать, что набор кодов начался преждевременно и часть нажатий уже пропущено. ПРИМЕЧАНИЕ. Чтобы предотвратить некорректный набор, работа программы приостанавливается до тех пор, пока все кнопки не будут отпущены.
412 ARDUINO: от азов программирования до создания... Цикл ожидания отпускания кнопок многократно обраща- ется к функции incod(), которая возвращает код состояния кно- пок. Полученный код сравнивается с константой klfree, значе- ние которой равно коду полностью отпущенных кнопок. Цикл длится до тех пор, пока эти два кода отличаются друг от друга. Когда коды окажутся одинаковыми, цикл закончится. Далее, в строке 22 находится другой цикл — цикл ожида- ния нажатия хотя бы одной из кнопок. Он очень похож на цикл из строки 21. Отличается только условием. Цикл длится до тех пор, пока код состояния кнопок равен значению klfree. После обнаружения факта нажатия хотя бы одной кнопки программа входит в цикл записи кодовой последовательности в буфер. Для начала обнуляется указатель буфера (строка 23). В строке 24 выполняется небольшая задержка на 50 милли- секунд. Это первый уровень антидребезга. В строке 24 еще раз считывается код состояния кнопок (уже чистый от дребезга). Считанный код записывается в переменную codS. Эта перемен- ная предназначена для хранения старого значения кода. ПРИМЕЧАНИЕ. Далее мы будем многократно перечитывать код, и сравнивать с этим старым значением. Считанное значение кода состояния записывается также и в первую ячейку буфера (строка 26). Одновременно значение указателя буфера увеличивается на единицу (благодаря опера- тору ++). Двойной плюс, как вы можете видеть, стоить после имени переменной. Это значит, что сначала происходит запись значения codS в элемент номер и, и только затем происходит инкрементация И. Новое значение кода состояния будет запи- сываться уже в следующую ячейку буфера. В строке 27 производится проверка конца буфера. Если пользователь попытается ввести слишком длинную кодовую последовательность, при достижении конца буфера ввод кода
Глава 38. Электронный замок с необычной логикой работы 413 прекращается. Оператор if в строке 27 сравнивает значение указателя П с заданным размером буфера. И если конец достиг- нут, передает управление по метке т4, в конец операции ввода кодовой последовательности. Если указатель П не достиг конца буфера, то программа переходит к строке 28. В этой строке считывается и запомина- ется в переменную itime текущее системное время. Далее, в строке 29 считывается новое значение кода состо- яния кнопок и сравнивается со старым. Смысл этой операции — ожидание изменения кода состояния. Пока код состояния при каждом считывании будет неизменным, условие оператора if в строке 29 будет иметь значение «Ложь» и программа каждый раз будет переходить к строке 30. В этой строке происходит проверка контрольного времени. Для этого считывается новое значение системного времени, из него вычитается время, сохраненное в строке 28, и полученная разность сравнивается с величиной контрольного промежутка времени. Если контрольное время не достигнуто, то управление передается к метке m3, и снова выполняется строка 29. В ней снова считывается код состояния кнопок и сравнивается со старым значением. И снова, если значение не изменилось, в строке 30 производится проверка на истечение контрольного промежутка времени. Из этого цикла два выхода: ♦ во-первых, если истечет контрольный промежуток време- ни, программа перестанет переходить к m3, и перейдет к строке ЗГ(то есть закончит процедуру ввода кодовой по- следовательности) ; ♦ во-вторых, если в строке 29 программа обнаружит факт из- менения кода состояния. Тогда произойдет переход по метке m2. Там новый код запишется как старый (в переменную codS), затем он запи- шется в очередную ячейку буфера, далее произойдет проверка буфера на исчерпание его объема (строка 27) и, наконец, в строке 28 будет считано и записано в переменную новое теку- щее значение системного времени.
414 ARDUINO: от азов программирования до создания... Далее программа войдет в новый цикл ожидания измене- ния состояния кнопок с проверкой исчерпания контрольного периода времени. Как бы ни завершился процесс ввода кодовой последова- тельности, в любом случае управление переходит к строке 31. В этой строке находится команда, которая проверяет состоя- ние переключателя режимов. Если контакты переключателя не замкнуты (значение, считанное с контакта modePin равно HIGH), это означает, что включен режим «Работа». Управление передается по метке сотр, к процедуре срав- нения кодовых последовательностей. Эта процедура занимает строки 37...40. Если контакты переключателя режимов зам- кнуты, то управление переходит к строке 32, где начинается процедура записи кодовой последовательности в EEPROM. Выполнив одну из этих процедур (записи или сравнения кодо- вых последовательностей) программа переходит к небольшой процедуре, завершающей выполнение основного цикла, которая начинается в строке 41. Эта маленькая процедура, отмеченная меткой zamok:, вызывает срабатывание механизма замка, и удер- жание его в открытом состоянии в течение 1 секунды. Рассмотрим все три описанные выше процедуры по порядку. Процедура записи в EEPROM начинается в строке 32. В этой строке в ячейку klen долговременной памяти EEPROM записывается значение длины ключевой кодовой последо- вательности. После завершения процедуры ввода кода длина последовательности содержится в переменной П. ПРИМЕЧАНИЕ. Это происходит потому, что указатель буфера (И) в процессе ввода кодов всегда указывает на ячейку буфера, куда должен записываться очеред- ной код. Учитывая, что нумерация ячеек начинается с нуля, значе- ние этой ячейки всегда равно текущей длине кодовой последо- вательности.
Глава 38. Электронный замок с необычной логикой работы 415 В строке 33 начинается цикл записи кодов из буфера в ячейки EEPROM. В качестве указателя цикла используется переменная i. При помощи этого указателя мы будем считывать коды из буфера, начиная с элемента 0 и заканчивая последним элементом введенной кодовой последовательности. Каждый считанный код мы разобьем на два байта (стар- ший и младший) и запишем каждый из них в долговремен- ную память в две последовательные ячейки. А начнем запись с ячейки номер 0. Эта операция выполняется в два этапа. В строке 34 в ячейку памяти с адресом i*2 записывается старший байт очередного элемента буфера. Для извлечения старшего байта из очередного элемента буфера используется стандартная функция языка Arduino highByte(). В строке 34 в ячейку долговременной памяти с адресом i*2+l записывается младший байт значения текущего элемента буфера. Для получения младшего байта используется функция lowByte(). Таким образом, нулевой элемент массива (i=0) будет разделен на два байта. Старший байт будет записан в ячейку с номером 0*2=0. Младший в ячейку с номером 0*2+1=1. Следующий элемент буфера (i=l) будет разделен и записан так: старший байт в ячейку с номером 1 *2=2, младший байт в ячейку с номером 1 *2+1=3. И так далее, для всех кодов последовательности. После записи всей кодовой последовательности программа переходит к процедуре открывания замка по метке «zamok:». Замок на 1 секунду открывается и закрывается. Это служит индикатором того, что ввод кодовой последовательности успешно завершен. ПРИМЕЧАНИЕ. Такой способ индикации выбран для того, чтобы ни вводить в схему лишних светодиодов. Процедура проверки кодов начинается в строке 37. В этой строке из ячейки klen долговременной памяти (EEPROM)
416 ARDUINO: от азов программирования до создания... считывается значение длины кодовой последовательности, записанной туда ранее в режиме «Запись кода». Оно сравни- вается с только что полученным значением длины уже новой кодовой последовательности, хранящейся в буфере. Если два этих значения не равны, то это значит, что код в буфере набран неправильно (не та длина). Управление пере- дается по метке ml в самое начало программы. Открывание замка не происходит. В случае если первая проверка прошла успешно (длина кода совпадает), программа переходит к сравнению самих кодовых последовательностей. Цикл сравнения формируется в строке 38. В качестве указателя цикла так же используется переменная i. В строке 39 считываются оба байта очередного кода после- довательности. Значение старшего байта умножается на 256 и к нему прибавляется значение младшего байта. В результате мы получаем искомый код из очередной позиции кодовой после- довательности. Этот код записывается в переменную CodC. ПРИМЕЧАНИЕ. Нужно отметить, что язык Arduino предлага- ет специальную функцию объединения стар- шего и младшего байтов wordfCmapuiudBadm, МладшийБайт). Если использовать эту функцию, то строка 39 программы может выглядеть следующим образом: CodC = word(EEPROM.read(i*2), EEPROM.read(i*2+l)); В строке 40 значение CodC сравнивается со значением текущего элемента буфера. Они должны совпадать. Если зна- чения не совпадают, управление тут же передается по метке ml и открывание замка не происходит. И только в том случае, когда цикл полностью переберет и сравнит все коды последовательности, все они окажутся попарно равными, цикл завершится нормальным образом и управление плавно перейдет к строке 41, то есть к процедуре открывания замка.
Глава 38. Электронный замок с необычной логикой работы 417 Процедура открывания замка выполняется как в режиме «Запись кода», так и в режиме «Работа». Только при «Записи кода» процедура выполняется всегда по завершении набора кодовой последовательности. И просто индицирует то, что набранная кодовая последовательность благополучно записана в память. В режиме «Работа» открывание замка происходит только в случае полного совпадения введенной кодовой комбинации с комбинацией, записанной ранее в EEPROM. Процедура откры- вания замка очень проста. В строке 41 на выход исполнительного механизма (relayPin) подается сигнал высокого логического уровня. При этом заго- рается светодиод на плате Arduino, помеченный литерой «Ь». Одновременно срабатывает электронный ключ (если, конечно, вы его подключили). Через ключ подается питание на исполни- тельный механизм и открывается замок. В строке 42 формируется задержка длительностью в 1 секунду. За это время вы должны успеть открыть (или хотя бы приоткрыть) дверь так, чтобы замок уже не мог защелкнуться. В строке 43 на выход relayPin подается низкий логический уровень. Исполнительный механизм отпускает щеколду замка. СОВЕТ. Если одной секунды вам не достаточно, чтобы успеть открыть дверь, вы можете увеличить значение задержки в строке 42. Функция опроса клавиатуры и антидребезга выполняет две задачи: ♦ считывает состояние всех кнопок клавиатуры и формирует код состояния; ♦ реализует второй уровень антидребезговой защиты. Для формирования кода состояния программа исполь- зует прямое чтение из регистров. Из главы 23 нашей книги, а также из схемы распиновки модуля Arduino (см. рис. 23.3), мы
418 ARDUINO: от азов программирования до создания... знаем, что цифровые контакты с 0 по 7 подключены к разрядам PD0...PD7 порта PD основного микроконтроллера ATmega323. Именно к этим контактам в нашей схеме подключены кнопки с «О» по «7». Еще две кнопки подключены к контактам 8 и 9 модуля. Эти два контакта подключены уже к другому порту микроконтроллера. Контакт 8 подключен к разряду РВО, а кон- такт 9 к разряду РВ1 порта РВ. ПРИМЕЧАНИЕ. Для того чтобы получить состояние сразу всех кнопок с 0 по 7, можно просто прочитать содер- жимое порта PD. Прочитав восьмиразрядное чис- ло из этого порта, мы получим код, у которого каждый бит будет отражать состояние своей кнопки. Еще два бита, соответствующих остав- шимся двум кнопкам («8» и «9»), можно получить, прочитав содержимое порта РВ. Два младших бита полученного числа будут соответство- вать оставшимся двум кнопкам. При этом нам придется обну- лить шесть старших битов прочитанного числа для того, чтобы случайные сигналы не влияли на результат. Для этого можно наложить на число соответствующую маску. Затем два кода (считанный из порта PD и считанный из порта РВ) объединяются в одно двухбайтовое число и записы- ваются в переменную типа int. Такой способ работы с входной информацией называется «работа на уровне портов». ПРИМЕЧАНИЕ. Этот способ не характерен для программ, напи- санных в программной среде Arduino, но поддер- живается в ней. Работа на уровне портов часто используется в других системах программирова- ния для микроконтроллеров. Например, в среде Code Vision, в программе, описанной в книге [4].
Глава 38. Электронный замок с необычной логикой работы 419 В нашу программу такой метод перекочевал из книги [4], программу из которой мы взяли за основу. Таким образом, мы хотели показать, что язык Arduino достаточно гибок и поддер- живает самые разные приемы программирования, что гаран- тирует высокую переносимость программ. Функция incod() занимает в программе строки 44...54. Начинается функция с определения локальных переменных. Переменные codO и codl (см. строки 45 и 46) предназначены для временного хранения старого и нового значения кода состояния кнопок. Переменная к (строка 47) — это счетчик цикла антидребезга. В строке 48 как раз и объявляется цикл антидребезга. Внутри цикла происходит многократное чтение и формирова- ние кода состояния. В нем реализуется алгоритм антидребезга, который состоит в том, что определенное число раз считанный код состояния должен быть неизменным. Число таких считыва- ний определено константой антидребезга kandr. Если при очередном считывании код изменился, то новое значение кода запоминается, а программа заново начинает отсчет последовательности, в которой коды должны быть оди- наковыми. Функция завершается и возвращает значение кода состояния кнопок только в том случае, когда этот код не изме- нялся при считывании его kandr число раз подряд. Собственно считывание и формирование кода происходит в строках 49 и 50. Сначала считывается значение из порта РВ (строка 49). На считанное значение накладывается маска 0x3 (00000011), которая обнуляет все старшие разряды, оставляя без изменения только два младших. Полученное число запи- сывается в переменную codl. Затем в строке 50 программа считывает значение из порта PD, и складывает его со значением codl сдвинутым на 8 разря- дов влево. Результат всех этих действий снова записывается в codl. После всех этих преобразований два разряда, считанные из порта РВ, окажутся в разрядах 8 и 9 полученного кода. А раз- ряды с 0 по 7 займет код, считанный из порта PD. Это и будет искомый код состояния кнопок, и храниться он будет в пере- менной codl.
420 ARDUINO: от азов программирования до создания... Далее, в строке 51 производится сравнение только что считанного кода состояния из codl и старого значения кода, который должен храниться в переменной codO. При первом считывании переменная codO содержит нулевое значение, записанное туда при создании этой переменной в строке 45 программы. Это равносильно тому, что код состояния изме- нился. Поэтому счетчик цикла сразу же будет обнулен, и цикл начнется сначала. Это произойдет следующим образом: в строке 51 срав- ниваются значения переменных codO и codl. Если они не равны, программа выполняет команды в строках 52 и 53. В строке 52 счетчику цикла антидребезга к присваивается нуле- вое значение. Таким образом, цикл начнется сначала. В строке 53 в переменную codO записывается значение переменной codl. Теперь новое значение кода будет использо- ваться в качестве старого. Цикл в строке 48 будет повторяться kandr раз в том случае, если все эти разы codl будет равен codO. Как только новый код окажется не равным старому, счетчик к опять обнулится и цикл начнется сначала. Если код ни разу не изменялся, цикл завершается, и про- грамма переходит к строке 54. В этой строке находится опера- тор return (возврат). Параметром оператора является возвра- щаемое значение. Оператор return завершает работу функции incod(), и возвращает значение codl. ПРИМЕЧАНИЕ. При желании функцию incodf) можно написать, не используя прямой доступ к регистрам. В листин- ге 38.2 приведен вариант той же функции, в ко- тором для считывания состояния кнопок исполь- зуется стандартный оператор языка Arduino digitalReadf ). \_______________________________________________________ Новая редакция функции incod() отличается от старого только в той части, где происходит считывание и формирова-
Глава 38. Электронный замок с необычной логикой работы 421 ние кода состояния клавиатуры. Вся операция формирования кода занимает строки 6,7 и 8 (см. листинг 38.2). Код состояния формируется в переменной codl. Перед нача- лом операции формирования кода эта переменная обнуляется (см. строку 6 программы). Затем, в строке 7, начинается цикл опроса кнопок. В качестве указателя цикла используется пере- менная ButtonPin. Переменная в цикле изменяется от 0 до 9 и поочередно указывает на контакты, к которым подключены кнопки. В строке 8 значение, записанное в переменной codl, сдвигается на один бит влево. При этом к полученному в результате сдвига значению прибавляется бит состояния текущей кнопки, счи- танный с входа, на который указывает переменная ButtonPin. В результате за десять шагов цикла все десять битов состоя- ния кнопок выстроятся в единое число — код состояния кно- пок. В остальном новая редакция функции incod() ничем не отличается от старой. ВНИМАНИЕ. В листинге 38.2 используется своя локальная ну- мерация строк, не связанная с нумерацией в ли- стинге 38.1. Прежде, чем закончить данную главу, несколько слов о таком важном вопросе, как отладка программ. ПРИМЕЧАНИЕ. К сожалению, среда разработки Arduino не имеет практически никаких средств для отладки про- грамм. Поэтому программистам приходится вы- кручиваться. \J
422 ARDUINO: от азов программирования до создания... Листинг 38.2. Альтернативный вариант функции опроса, клавиатуры и антидребезга // Функция опроса клавиатуры и антидребезга 1 unsigned int incod (void) ( 2 unsigned int cod0=0; // локальные переменные 3 unsigned int codl; 4 byte k; 5 6 7 8 9 10 11 12 // Цикл антидребезга for (k=0; k<kandr; k++) { codl=0; for (int ButtonPin=0; ButtonPin<=9; ButtonPin+t) ( codl= (codl«l) + digitalRead (ButtonPin) ; } if (cod0!=codl) { // сравниваем co старым кодом k=0; // если не равны, сбрасываем счетчик cod0=codl; // новое значение старому коду } return codl; Простые программы можно отлаживать, применяя следую- щие приемы: ♦ написание программы отдельными модулями с опробова- нием каждого модуля по отдельности; ♦ применение метода пробных изменений программы, про- веряющих разные гипотезы возникновения ошибок; ♦ внимательный просмотр текста программы с целью по- нять причину ошибки чисто логически. В число таких приемов также можно включить временное внедрение в программу специальных отладочных программ- ных блоков, выводящих любым доступным способом промежу- точные результаты работы программы.
Глава 38. Электронный замок с необычной логикой работы 423 ПРИМЕР. В процессе отладки программы электронного зам- ка был применен следующий прием. В программу в отладочных целях был временно введен блок опе- раторов, который каждый раз после набора кодо- вой последовательности выводил в компьютер че- рез последовательный канал содержимое буфера, а также кодовую комбинацию, считанную из EEPROM. Эту информацию можно увидеть на компьютере при помощи монитора порта, как мы это делали в главе 35. В про- цессе отладки блок команд перемещался в разные места отла- живаемой программы. Это позволяло наблюдать формирова- ние кодовых последовательностей на разных этапах работы программы. Для того чтобы кнопки «О» и «1» не мешали при передаче данных по последовательному порту, они были временно отклю- чены на период отладки. После завершения процесса отладки все отладочные изменения из программы были удалены. В набор электронных версий программных примеров, нахо- дящийся на виртуальном диске, включена версия программы электронного замка, в которую уже включены отладочные блоки. Скачав пакет электронных версий программных при- меров, вы можете, при желании, самостоятельно запустить и попробовать поработать с этим вариантом программы. То есть освоить работу в режиме отладки. Ж» ВНИМАНИЕ. Версии программ, снабженные отладочными мо- дулями, помечены словом debug.
ГЛАВА 39 КОДОВЫЙ ЗАМОК С МУЗЫКАЛЬНЫМ звонком Постановка задачи В качестве последнего примера покажем, как можно объ- единить две самые сложные схемы и программы, описанные в этой книге в одну. А именно, описанный в предыдущей главе кодовый замок, мы объединим с программой музыкальной шкатулки, превратив «Музыкальную шкатулку» в музыкаль- ный дверной звонок. Не смотря на то, что указанные две про- граммы являются самыми сложными из всех, приведенных в книге программ, их совсем не трудно объединить в одну. ЗАДАЧА. Доработать схему и программу кодового замка, внедрив в него алгоритм воспроизведения мело- дий, который должен служить в качестве му- зыкального дверного звонка. Для этого в схему необходимо добавить кнопку звонка и звукоиз- лучающее устройство. При этом кодовый замок должен работать так же, как он работал при
Глава 39. Кодовый замок с музыкальным звонком 425 отсутствии функции звонка. Однако при нажа- тии кнопки звонка устройство должно воспро- изводить при помощи звукового излучателя одну из десяти заложенных в память мелодий. При каждом нажатии кнопки звонка должна звучать новая мелодия. Схема Схема доработанного электронного замка приведена на рис. 39.1. В схему, в соответствии с поставленной задачей, добавлены: ♦ кнопка звонка, которая подключена к цифровому контакту 10; ♦ звукоизлучатель (динамик), который подключен так же, как это было сделано в схеме музыкальной шкатулки, к контакту 12. Внешний вид собранного устройства показан на рис. 39.2. Рис. 39.1. Схема электронного замка со звонком
426 ARDUINO: от азов программирования до создания... Рис. 39.2. Внешний вид электронного замка со звонком J Алгоритм Алгоритм работы электронного замка и алгоритм воспро- изведения музыки в новой программе будут взяты из про- грамм, описанных в главе 37 и главе 38. Они будут использо- ваться без изменений. Нам нужно только объединить два алго- ритма и заставить их работать совместно. Как мы знаем из главы 38, пока не нажата не одна из цифровых кнопок, программа электронного замка постоянно находится в режиме опроса состояния клавиатуры и ожидает нажатия.
Глава 39. Кодовый замок с музыкальным звонком 427 ПРИМЕЧАНИЕ. Именно в этот цикл опроса нужно включить еще одну проверку: проверку состояния кнопки звонка. В результате цикл по очереди будет проверять то факт нажатия любой из цифровых кнопок замка, то факт нажатия кнопки звонка. При обнаружении нажатия дальнейшие действия про- граммы зависят от того, что именно было нажато. Если нажата одна из кнопок замка, то выполняется алго- ритм ввода кодовой последовательности и далее весь алгоритм замка. Если окажется нажатой кнопка звонка, то выполняется алгоритм воспроизведения мелодии. ПРИМЕЧАНИЕ. От музыкальной шкатулки этот алгоритм от- личается тем, что мелодии воспроизводятся по очереди. Номер воспроизводимой мелодии за- писывается в специально выделенную ячейку в EEPROM. При очередном нажатии кнопки звонка, воспроизводится следующая по порядку мелодия. Программа Объединенная программа электронного замка и музы- кального звонка приведена в листинге 39.1. За основу взята программа электронного замка. Программа воспроизведения мелодии оформлена в виде отдельной функции playMelody(), которая находится в конце листинга 39.1 и занимает строки 78...96.
428 ARDUINO: от азов программирования до создания... В начале программы в блоке определений всех перемен- ных, констант и массивов присутствуют определения как для одной, так и для второй задачи. ПРИМЕЧАНИЕ. Так как большинство строк в блоке определений повторяют аналогичные строки в программах- источниках: программы из листинга 38.1 (элек- тронного замка), и программы из листинга 37.1 (музыкальной шкатулки), мы рассмотрим только те строки описания, которые требуют особых пояснений. И первое отличие мы видим в строке 7 листинга 39.1. Здесь вводится новая константа numuz. Этой константой опре- деляется адрес ячейки в EEPROM для хранения номера теку- щей мелодии. Хранение номера текущей мелодии в энергоне- зависимой памяти позволит программе даже после выключе- ния питания хранить этот номер. При очередном нажатии кнопки звонка номер мелодии увеличивается на единицу, и звонок каждый раз воспроизво- дит новую мелодию. Мелодии нумеруются числами от 0 до 9. Когда, при очередном нажатии кнопки звонка номер мело- дии окажется больше девяти, программа сбрасывает его в ноль. В результате, после девятой мелодии воспроизводится мело- дия номер ноль. Номер ячейка numuz выбирается на единицу большим, чем номер для хранения длины кодовой последова- тельности (вычисляется по формуле klen+1), так как все преды- дущие ячейки в EEPROM уже заняты. В строке 8 определяется еще одна новая константа ringPin. Это номер контакта для подключения кнопки звонка. Еще одна новая константа SoundPin определяется в строке 10. Она пред- ставляет собой номер контакта для подключения динамика. В строках 16...28 мы видим знакомые нам таблицу высоты тона, таблицу длительностей нот и таблицы мелодий.
Глава 39. Кодовый замок с музыкальным звонком 429 Листинг 39.1. Программа электронного замка 1 /* Кодовый замок плюс музыкальный звонок */ ♦include <EEPROM.h> 2 3 4 5 ♦define klfree ОхЗЕЕ // код «Все кнопки отпущены» ♦define kzad 3000 // код задержки при сканировании ♦define kandr 30 // константа антидребезга ♦define bsize 30 // размер буфера // Два адреса ячеек в EEPROM: 6 7 ♦define klen bsize*2+l // длинна кодовой последовательности ♦define numuz klen+1 // номер текущей мелодии // Номера контактов: 8 9 10 . 11 ♦define ringPin 10 // конт. кнопки звонка ♦define modePin И // конт. переключателя режима ♦define SoundPin 12 // конт. звукоизлучателя ♦define relayPin 13 // конт. исполнит, механизма замка 12 13 14 // Определение переменных: unsigned char ii; // Указатель массива unsigned char i; // Вспомогательный указатель unsigned int codS; // Старый код 15 unsigned int bufr[bsize]; // Буфер в ОЗУ для хранения кода 16 // Таблица длительностей нот const unsigned int tabz[] = {20,40,80,160,320,640,1280,2560}; 17 // Таблица - частоты нот const unsigned int tabFreq[]={0,587,622,659,698,740,784, 831,880,932,988,1047,1109,1175,1245,1319,1397,1480, 1568,1661,1760,1865,1976,2093,2217,2349,2489,2637, 2794,2960,3136,3322,3520};
430 ARDUINO: от азов программирования до создания... // Таблицы мелодий //В траве сидел кузнечик 18 byte mell[] = {109,104,109,104,109,108,108,96,108,104, 108,104,108,109,109,96,109,104,109,104,109,108,108,96, 108,104,108,104,108,141,96,109,111,79,79,111,111,112,80, 80,112,112,112, 111, 109, 108,109,109, 96Д09, 111, 79, 79, 111, 111,112,80,80,112,112,112,111,109,108,141,128,96,255}; // Песенка крокодила Гены 19 byte mel2[] = {109,110,141,102,104,105,102,109,110,141, 104,105,107,104,109,110,141,104,105,139,109,110,173,96, 114,115,146,109,110,112,109,114,115,146,107,109,110,114, 112,110,146,109,105,136,107,105,134,128,128,102,105,137, 136,128,104,107,139,137,128,105,109,141,139,128,110,109, 176,112,108,109,112,144,142,128,107,110,142,141,128,105, 109,139,128,173,134,128,128,109,112,144,142,128,107,110, 142,141,128,105,109,139,128,173,146,128,255}; //В лесу родилась елочка 20 byte mel3[] = {132,141,141,139,141,137,132,132,132,141, 141,142,139,176,128,144,146,146,154,154,153,151,149,144, 153,153,151,153,181,128,96,255}; // Happy births day to you 21 byte mel4[] = {107,107,141,139,144,143,128,107,107,141, 139,146,144,128,107,107,151,148,146,112,111,149,117, 117,148,144,146,144,128,255}; // С чего начинается родина 22 byte mel5[] = {99,175,109,107,106,102,99,144,111,175,96, 99,107,107,107,107,102,104,170,96,99,109,109,109,109, 107,106,143,109,141,99,109,109,109,109,104,106,171,96, 99,111,109,107,106,102,99,144,111,143,104,114,114,114, 114,109/111,176, 96,104,116,112,109,107,106,64,73,143, 107,131,99,144,80,80,112,111,64,75,173,128,255};
Глава 39, Кодовый замок с музыкальным звонком 431 23 24 25 26 27 //Из кинофильма «Веселые ребята» byte mel6[] = {105,109,112,149,116,64,80,148,114,64,78, 146,112,96,105,105,109,144,111,64,80,145,112,64,81,178, 96,117,117,117,149,116,64,82,146,112,64,79,146,144,96, 105,105,107,141,108,109,112,110,102,104,137,128,96,105, 105,105,137,102,64,73,142,105,107,109,64,75,137,96,105, 105,105,137,102,105,142,112,64,82,180,96,116,116,116, 148,114,112,142,109,64,78,146,144,96,105,105,107,141, 108,109,112,110,102,104,169,96,96,255}; // Улыбка byte mel7[] = {136,133,170,168,131,134,133,131,193,160, 133,136,138,138,138,140,143,141,140,138,173,200,138,140, 173,128,140,138,133,136,134,202,160,140,138,141,136,140, 138,138,136,131,133,163,161,160,129,132,136,136,136,136, 168,141,129,132,131,131,131,163,131,132,136,134,136,137, 136,134,136,137,173,171,160,141,136,139,137,137,137,169, 141,134,137,136,136,136,168,141,132,131,132,134,137,136, 134,132,134,169,168,160,141,136,139,137,137,137,169,141, 134,137,136,136,136,168,141,132,131,132,134,137,136,134, 132,134,168,193,160,255}; // Гимн России byte mel8[] = {136,173,136,96,106,172,133,96,101,170, 136,96,102,168,129,96,97,163,131,96,101,166,134,96,104, 170,140,141,175,136,177,143,96,109,175,140,136,173,140, 96,106,172,133,96,101,170,136,96,102,168,129,96,97,173, 140,138,168,224,255}; // Спят усталые игрушки byte mel9[] = {168,128,133,168,128,133,168,168,166,165, 163,165,200,143,145,143,145,212,168,128,131,168,128,131, 168,166,165,163,161,165,200,145,148,145,148,214,168,168, 170,168,177,177,170,168,161,161,166,168,170,170,168,166, 165,165,166,165,232,198,195,193,160,224,255}; // Гамма byte mell0[] = {129,130,131,132,133,134,135,136,137, 138,139,140,141,142,143,144,145,146,147,148,149,150,
432 ARDUINO: от азов программирования до создания... 151,152,153,154,155,156,157,158,159,128,159,158, 157,156,155,154,153,152,150,149,148,147,146,145,144, 143,142,141,140,139,138,137,136,135,134,133,132,131, 130,129,128,255}; // Таблица начал всех мелодий 28 byte *tabm[] = {mell, mel2, mel3, mel4, mel5, mel6, mel7, mel8, mel9, mellO}; // ================= 29 void setup () { // Инициализация контактов: 30 31 32 33 pinMode(relayPin, OUTPUT); // конт. механизма замка pinMode(SoundPin, OUTPUT); // конт. звукоизлучателя pinMode(modePin, INPUT_PULLUP); // перекл. режимов pinMode(ringPin, INPUT_PULLUP); // кнопка звонка // Инициализация пинов цифровых кнопок: 34 35 for (int ButtonPin=0; ButtonPin<=9; ButtonPin++) { pinMode(ButtonPin, INPUT_PULLUP); } // ================= 36 37 38 void loop() { unsigned long itime; unsigned int CodC; 39 ml: while (incod() != klfree); // ожидание отпускания кнопок // Ожидание нажатия кнопок: 40 41 42 while (incod() == klfree) { if (digitalRead(ringPin)==LOW) { byte imel = EEPROM.read(numuz); // зап.номер мелодии 43 44 45 if (imel>9) imel=0; playMelody (imel++); EEPROM.write(numuz,imel);
Глава 39. Кодовый замок с музыкальным звонком 433 46 47 48 49 50 } ii=0; m2: delay(50); // задержка 50 мс codS=incod(); // ввод кода и запись, как старого bufr[ii++]=codS; // запись очередного кода в буфер if (ii>=bsize) goto m4; // проверка конца буфера // сканируем состояние кнопок в течении 1 секунды: 51 52 itime = millis(); m3: if (incod() != codS) goto m2; // изменилось ли состояние? // Проверка контрольн. промежутка времени: 53 if (millis()-itime<1000) goto m3; // Проверка переключателя режимов: 54 m4: if (digitalRead(modePin)==HIGH) goto comp; // Запись кода в EEPROM 55 EEPROM.write(klen,ii); // запись длины кода // Запись всех байтов кода 56 57 58 for (i=0; icii; i++) { EEPROM.write(i*2,highByte(bufr[i])); EEPROM. write (i*2+l, lowByte (bufr [i.])); 59 J goto zamok; // Проверка кода // Проверка длины кода 60 61 62 comp: if (EEPROM.read(klen)!=ii) goto ml; for (i=0; icii; i++) { CodC = EEPROM.read(i*2)*256 .+ EEPROM.read(i*2+l); 63 if (CodC!=bufr[i]) goto ml; // проверка кода } // Открывание замка 64 65 66 zamok: digitalWrite(relayPin,HIGH); // открываем замок delay(lOOO); // задержка на 1 сек digitalWrite(relayPin,LOW); // закрываем замок }
434 ARDUINO: от азов программирования до создания... // Функция опроса клавиатуры и антидребезга 67 68 69 70 unsigned int incod (void) { unsigned int cod0=0; // локальные переменные unsigned int codl; byte k; // Цикл антидребезга 71 72 for (k=0; k<kandr; k++) { codl=PINB&0x3; // формируем первый байт кода // Формируем полный код состояния клавиатуры: 73 codl= (codl«8) +PIND; // Сравниваем со старым кодом 74 75 76 if (cod0!=codl) ( k=0; // если не равны, сбрасываем счетчик cod0=codl; // новое значение старому коду } 77 } return codl; } // ================== == // Функция воспроизведения мелодии 78 79 80 81 82 void playMelody (int numberMelody) { byte count; // определяем переменную (счетчик) byte fnota; // код тона ноты byte dnota; // код длительности ноты byte *nota; // ссылка на текущую ноту 83 84 85 nota = tabm[numberMelody]; StartMelody: if (digitalRead(ringPin)==HIGH) return; // Если кнопка // звонка не нажата, закончить 86 87 88 89 90 91 if (*nota==0xFF) return; // проверка на конец мелодии fnota = (*nota)&0xlF; // определяем код тона dnota = ((*nota)»5)&0х07; // определяем код длительности if (fnota!=0) { tone (SoundPin, tabFreq[fnota],tabz[dnota]); delay (tabz[dnota]+10); }
Глава 39. Кодовый замок с музыкальным звонком 435 92 else { 93 noTone(SoundPin); // если пауза выкл. звук 94 delay (tabz[dnota]); 1 95 J nota++; 96 goto StartMelody; } В функцию setup(), которая занимает строки 29...35, вклю- чены команды, определяющие режимы всех используемых в программе контактов модуля Arduino. Строки 36...66 занимает основной цикл программы (т. е. функция 1оор()). Она практически полностью повторяет основ- ной цикл программы кодового замка (см. листинг 39.1). Отличие только в том, что в цикл ожидания нажатия кно- пок (который начинается в строке 40) включены пять новых команд (строки 41...45), которых не было в оригинальной про- грамме замка. В строке 41 находится команда чтения и контроля состоя- ния кнопки звонка. Если кнопка не нажата (считанное значение равно HIGH), то команды в фигурных скобках оператора if не выполняются, и цикл ожидания нажатия кнопок продолжается. Если нажать одну из цифровых кнопок, то условие в кру- глых скобках оператора while в строке 40 перестанет выпол- няться, цикл прервется, а управление перейдет к строке 46, то есть к реализации алгоритма кодового замка. Если же вместо цифровых кнопок нажать кнопку звонка, то в строке 41 считанное с входа ringPin состояние кнопки звонка окажется равным LOW. То есть условие оператора if (в строке 41) окажется выполнено. Поэтому управление перейдет к операторам тела функции if (строки 42....4S). Сначала в строке 42 из ячейки EEPROM с адресом numuz считывается номер текущей мелодии и записывается в пере- менную imel. Этот номер по условиям задачи должен прини- мать значения от 0 до 9, так как в таблицах мелодий у нас зало-
436 ARDUINO: от азов программирования до создания... жено десять мелодий, пронумерованных именно таким обра- зом (начиная с нуля). Однако при первом запуске программы либо в процессе предыдущей работы переменная может иметь и другие значе- ния. Нам нужно проверить, попадает ли значение в заданный диапазон и исправить его, если не попадает. Переменная imel имеет тип byte, а значение этого типа никогда не бывает отрицательным. Поэтому достаточно одной проверки: в строке 43 проверяется, не больше ли imel девяти. Если imel больше девяти, то ему присваивается нулевое значение. В строке 44 вызывается функция воспроизведения мело- дии playMelody(). В качестве параметра в функцию передается только что полученный номер мелодии imel. Одновременно производится инкрементация номера мелодии при помощи оператора «++». В строке 45 новый, увеличенный на единицу, номер мело- дии записывается в ячейку numuz долговременной памяти EEPROM. При следующем нажатии кнопки звонка будет вос- производиться уже новая мелодия. Никаких других отличий от оригинальной версии в той части программы, которая реализует функцию электронного замка, нет. Функция воспроизведения мелодии playMelody() начина- ется в строке 78. Она представляет собой копию основного цикла программы музыкальной шкатулки (см. листинг 37.1), из которой исключены команды, которые опрашивают кнопки. Номер мелодии функция получает через свой единственный входной параметр numberMelody. Полученная выше объединенная программа рассчитана на то, что пользователь будет в каждый момент времени либо набирать кодовую последовательность, либо звонить в звонок. Если попытаться два этих действия выполнить одновременно, то одно действие будет мешать другому. Нажатие кнопки звонка помешает набору кода. Мелодия звонка будет звучать до тех пор, пока нажата кнопка звонка, и нажатие цифровых кнопок при этом будет просто игнорироваться.
ЧАСТЬ VI РАСШИРЯЕМ ФУНКЦИОНАЛЬНОСТЬ ПЛАТ ARDUINO Теперь познакомимся с дополнитель- ными возможностями проекта Arduino. Отличительной особенностью про- екта является то, что он строится по принципу модульного конструктора. Разработано большое количество внеш- них плат расширения, которые можно подключить к основному модулю и полу- чить новые свойства и возможности такой комбинации. Платы расширения позволяют превратить стандартный модуль Arduino в устройство управле- ния, автоматики, электроники, умеющие работать практически в любой области, где применяются микроконтроллеры.
ГЛАВА 40 ПЛАТЫ ARDUINO: ОСОБЕННОСТИ И ВОЗМОЖНОСТИ Плата Arduino Due Плата Arduino Due — плата микроконтроллера на базе процессора Atmel SAM3X8E ARM Cortex-МЗ. Это первая плата Arduino на основе 32-битного микроконтроллера с ARM ядром. Плата содержит: 54 цифровых вход/выхода (из них 12 можно задействовать под выходы ШИМ); 12 аналоговых входов; 4 последовательных порта UART; генератор тактовой частоты 84 МГц; связь по USB с поддержкой OTG; 2 ЦАП; 2 TWI; разъем SPI; разъем JTAG; кнопка сброса; кнопка стирания.
Глава 40. Платы arduino: особенности и возможности 439 ВНИМАНИЕ. В отличие от других плат Arduino, Arduino Due ра- ботает от 5,5 В. Т. е. максимальное напряжение, ко- торое выдерживают вход/выходы, составляет 5,5 В. Подав более высокое напряжение, например, 5 В на выводы Arduino Due, можно повредить плату. Плата Arduino II Leonardo II Плата Arduino Leonardo — контроллер на базе ATmega32u4. Плата содержит: 20 цифровых вход/выходов, из них могут использоваться: 7 — как выходы ШИМ; 12 — как аналоговые входы. Частота кварцевого генератора 16 МГц. Плата имеет: разъем микро-USB, силовой разъем, разъем ICSP и кнопку перезагрузки. ПРИМЕЧАНИЕ. В отличие от всех предыдущих плат,АТтеда52и4 имеет встроенную поддержку для USB соеди- нения. Такая поддержка позволяет задать, как Leonardo будет виден при подключении к компью- теру (это может быть клавиатура, мышь, вир- туальный СОМ порт).
440 ARDUINO: от азов программирования до создания... Плата Arduino YUN Плата Arduino YUN — контроллер на базе ATmega32u4 и AR9331 от фирмы Atheros. Это первый представитель новей- шей серии плат Ардуино со встроенным WiFi. Сочетает в себе широчайшие возможности Linux и простоту использования Ардуино. Процессор от Atheros поддерживает ОС Linino (версия операционной системы Linux). Плата содержит: встроенные модули Ethernet и WiFi; USB-порт; слот для карты микро-SD; 20 цифровых вход/выходов (7 из которых могут использоваться как выходы ШИМ и 12 как аналоговые входы); разъем микро USB; разъем ICSP; 3 кнопки сброса. ПРИМЕЧАНИЕ. Из-за ограниченного объема памяти взаимо- действие Ардуино с различными веб-сервисами является сложной задачей. Ведь многие Web- технологии основаны на объемных текстовых форматах (подобных XML), для анализа которых требуется достаточно много памяти. Поэтому для Arduino YUN была создана специальная библи- отеку Bridge, использование которой позволяет переложить обработку HTTP-транзакций и всех сетевых подключений на сторону Linux.
Глава 40. Платы arduino: особенности и возможности 441 Плата Arduino Micro Плата Arduino Micro — плата микроконтроллера на базе ATmega32u4, была разработана совместно с фирмой Adafruit. Плата содержит: 20 цифровых вход/выходов, их которых: 7 могут использоваться в качестве выходов ШИМ; 12 могут использоваться как аналоговые входы. Частота кварцевого генератора 16 МГц. Плата имеет: гнездо микро-USB; разъем ICSP; кнопку перезагрузки. Малый размер контроллера позволяет легко поместить его на макет- ной плате. ПРИМЕЧАНИЕ. Запитать плату можно от внешнего источни- ка питания 7-12 В (батарейка, аккумулятор или блок питания), используя контакты на плате RAW и GND. Также, можно запитать микропро- цессор напрямую, используя контакты VCC и GND. При этом используйте только ток, прошедший через стабилизатор напряжения 5 В, чтобы не вывести плату из строя.
442 ARDUINO: от азов программирования до создания... Плата Arduino UNO Плата Arduino UNO — самая популярная версия базо- вой платформы Arduino USB. Она во многом похожа на Duemilanove, но имеет новый чип ATMega8U2 для последова- тельного подключения по USB и новую, более удобную марки- ровку вход/выходов. Плата Uno имеет стандартный порт USB. Плата содержит: 14 цифровых входных/выходных выводов (6 из которых могут использоваться в качестве ШИМ выходов), 6 аналоговых входов, кварцевый резонатор 16 МГц, подключе- ние USB, разъем питания, разъем ICSP и кнопку перезагрузки. ПРИМЕЧАНИЕ. Напряжение внешнего источника питания мо- жет быть в диапазоне 6-20 В. Но рекомендует- ся не допускать снижение напряжения ниже 7 В из-за нестабильной работы устройства. Также нежелательно повышать напряжение питания более 12 В, т. к. может перегреется и выйти из строя стабилизатор. Рекомендуемый диапазон напряжения питания 7-12 В.
Глава 40. Платы arduino: особенности и возможности 443 Плата II Arduino Ethernet II Плата Arduino Ethernet — это плата микроконтроллера на базе ATmega328. Плата содержит: 14 цифровых входов/выхо- дов; 6 аналоговых входов. Частота кварцевого генератора 16 МГц. Имеет возможность подключить: RJ45 разъем; разъем питания; соединитель ICSP и кнопку «Reset». На плату может быть добав- лен дополнительный модуль питания через Ethernet (РоЕ). ПРИМЕЧАНИЕ. Выводы 10, И, 12 и 15 зарезервированы для со- пряжения с модулем Ethernet и не могут исполь- зоваться никак иначе. Таким образом, число до- ступных выводов уменьшается до 9, 4 из кото- рых могут использоваться как выходы ШИМ.
444 ARDUINO: от азов программирования до создания... I Плата Arduino Duemilanove Плата Arduino Duemilanove («2009») построена на одном из микроконтроллеров: ATmegal68 или ATmega328. Плата содержит: 14 цифровых входов/выходов, 6 из которых могут использоваться как выходы ШИМ; 6 аналоговых входов; квар- цевый генератор 16 МГц; разъем USB; силовой разъем; разъем ICSP; кнопку перезагрузки. Является предпоследней версией базовой платформы Arduino USB. ПРИМЕЧАНИЕ. Duemilanove (в переводе с итальянского - 2009) была названа в честь года своего выпуска - 2009 год.
Глава 40. Платы arduino: особенности и возможности 445 Плата Arduino Diecimila Плата Arduino Diecimila построена на микроконтроллере ATmegal68. Плата содержит: 14 цифровых входов/выходов, 6 из которых могут использоваться как выходы ШИМ; 6 анало- говых входов; кварцевый генератор частотой 16 МГц. На плате имеются: разъем USB; силовой разъем; разъем ICSP; кнопка перезагрузки. Arduino Diecimila питается через подключение USB или от внешнего источника питания. Выбор источника питания осу- ществляется перемычкой PWR_SEL: для питания через USB необходимо замкнуть ближайшие два вывода к разъему USB, для внешнего источника питания — два ближайших вывода к силовому разъему. Внешнее питание (не USB) может пода- ваться через преобразователь напряжения AC/DC (блок пита- ния) или от аккумуляторной батареи. ПРИМЕЧАНИЕ. Diecimila (в переводе с итальянского - 10000) была названа в честь выпуска 10000-ой платы Arduino.
446 ARDUINO: от азов программирования до создания... I Плата Arduino Nano Плата Arduino Nano компактная платформа с семейства Arduino, которая с одной стороны по функциональности сопо- ставима с платой Uno, а другой стороны, вся эта функцио- нальность вместилось в компактных размерах, сопоставимых с платой Pro mini. Как и любая другая плата, Nano является открытой платформой и поэтому имеет большое количество разнообразных аналогов. Плата построена на микроконтрол- лере ATmega328 (Arduino Nano 3.0) или ATmegal68 (Arduino Nano 2.x), имеет небольшие размеры и может использоваться в лабораторных работах. Плата Nano разработана и произво- дится компанией Gravitech. ПРИМЕЧАНИЕ. Arduino Nano имеет схожую с Arduino Duemilanove функциональность, однако отличается сборкой. Отличие заключается в отсутствии силового разъема и работе через кабель Mini-В USB.
Глава 40. Платы arduino: особенности и возможности 447 Плата II Arduino Mega II Плата Arduino Mega построена на микроконтроллере ATmegal280. Плата содержит: 54 цифровых входов/выходов, 14 из которых могут использоваться как выходы ШИМ; 16 ана- логовых входов; 4 последовательных порта UART. Частота кварцевого генератора 16 МГц. Плата имеет: разъем USB; сило- вой разъем; разъем ICSP; кнопку перезагрузки. Совместима со всеми устройствами расширения, разработанными для моду- лей Duemilanove или Diecimila. Может быть запитана от USB либо от внешнего источника питания. Тип источника выбирается автоматически. В каче- стве внешнего источника питания (не USB) может исполь- зоваться сетевой AC/DC-адаптер или аккумулятор/батарея. Напряжение внешнего источника питания может быть в пре- делах от 6 до 20 В. ВНИМАНИЕ. Уменьшение напряжения питания ниже 7 В приво- дит к уменьшению напряжения на выводе 5 В, что может стать причиной нестабильной работы устройства.
448 ARDUINO: от азов программирования до создания... I Плата Arduino Mega 2560 Плата Arduino Mega 2560 построена на микроконтроллере ATmega2560. Плата содержит: 54 цифровых входа/выхода (14 из которых могут использоваться как выходы ШИМ); 16 анало- говых входов; 4 последовательных порта UART, USB коннектор, разъем питания, разъем ICSP и кнопку перезагрузки. Частота кварцевого генератора 16 МГц. Это пулярное решение для материнской платы 3D прин- тера, которое позволяет подключать драйвера шаговых дви- гателей, датчики температуры экструдера и нагревательной платформы и дисплей. Для работы с 3D принтером необходима также плата RAMPS, которая используется для управления компонентами 3D принтера. Arduino Mega 2560 совместима со всеми платами Duemilanove или Uno. ПРИМЕЧАНИЕ. Плата Arduino Меда 2560 совместима со все- ми платами расширения, разработанными для платформ Uno или Duemilanove.
Глава 40. Платы arduino: особенности и возможности 449 Плата II Arduino ADKII Плата Arduino ADK во многом повторяет Arduino Mega 2560 и построена на микросхеме ATmega2560. USB Host интер- фейс реализован на микросхеме МАХ3421е. Так же, как и Mega 2560, плата имеет: 54 цифровых входов/выходов, 14 из которых могут использоваться как выходы ШИМ; 16 аналоговых входов; 4 последовательных порта UART. Частота кварцевого генера- тора 16 МГц. Плата имеет: USB коннектор; разъем питания; разъем ICSP; кнопка перезагрузки. Последовательное подклю- чение через USB реализовано на микросхеме Atmega8U2, также как в платах UNO и Mega. ПРИМЕЧАНИЕ. Особенность заключается в наличие USB Host ин- терфейса, который позволяет подключать кон- троллер к различным устройствам с интерфей- сом USB, включая телефоны и другие устройства на базе Android.
450 ARDUINO: от азов программирования до создания... Плата Arduino LilyPad Плата Arduino LilyPad разработана с целью использова- ния как часть одежды. Она может быть зашита в ткань со встро- енными источниками питания, датчиками и приводами с про- водкой. Плата построена на микроконтроллере ATmegal68V (маломощная версия с ATmegal68) или ATmega328V. Arduino LilyPad была создана компаниями Leah Buechley и SparkFun Electronics. Плата Arduino LilyPad запитывается через USB или от внешнего источника питания. Напряжение внешнего источника питания должно быть в пределах от 2,7 до 5,5 В. В качестве внешнего источника может использовать обычный сетевой AC/DC адаптер или аккумулятор. ВНИМАНИЕ. Не забывайте, что напряжение питания LilyPad Arduino не должно превышать 5.5В и не должно быть отрицательным. При несоблюдении этого условия устройство может выйти из строя.
Глава 40. Платы arduino: особенности и возможности 451 Плата II Arduino Fio II Плата Arduino Fio, построенная на микроконтроллере ATmega328P, работает при напряжении 3,3 В, с тактовой часто- той 8 МГц. Плата содержит: 14 цифровых входов и выходов, 6 из которых могут использоваться как выходы ШИМ; 8 ана- логовых входов; резонатор; кнопку перезагрузки; отверстия для монтажа выводов. Плата Fio также содержит схему зарядки через разъем USB и позволяет подключить литий-полимер- ную батарею. На лицевой поверхности платформы установлен разъем ХВее. Arduino Fio может применяться в беспроводных сетях. Загрузка скетчей может производиться через кабель FTDI или плату-конвертер Sparkfun. ПРИМЕЧАНИЕ. Дополнительно имеется возможность загру- жать скетчи по беспроводной связи при исполь- зовании адаптера USB-to-XBee, например, ХВее Explorer USB.
452 ARDUINO: от азов программирования до создания... Плата Arduino Mini Плата Arduino Mini построена на микроконтроллере ATmegal68 и предназначена для использования в тех случаях, когда требуются минимальные размеры. Частота кварцевого генератора 16 МГц. Платформа содержит: 14 цифровых вхо- дов и выходов, 6 из которых могут использоваться как выходы ШИМ; 8 аналоговых входов. Программируется при помощи адаптера Mini USB или любого преобразователя USB или RS232 bTTL. ВНИМАНИЕ. Недопустимы как превышение питающего на- пряжения, так и переполюсовка выводов питания.
Глава 40. Платы arduino: особенности и возможности 453 Плата II Arduino Pro II Плата Arduino Pro предназначена для непостоянной уста- новки в объекты или экспонаты. Расположение выводов совме- стимо с платами расширения Arduino. Построена на одном из микроконтроллеров: ATmegal68 или ATmega328. Плата Pro производится в обоих исполнениях 3,3 В / 8 МГц и 5 В /16 МГц. Плата содержит: 14 цифровых входов и выходов, 6 из которых могут использоваться как выходы ШИМ; 6 аналоговых входов; силовой разъем батареи; силовой выключатель; кнопку пере- загрузки; отверстия для монтажа силового разъема; блок ICSP; блоки выводов. ПРИМЕЧАНИЕ. Шестипиновый блок может подключаться к ка- белю FTDI или плате-конвертеру Sparkfun для обеспечения питания и связи через USB.
454 ARDUINO: от азов программирования до создания... Il Плата Arduino II Pro Mini Плата Arduino Pro Mini построена на микроконтроллере ATmegal68. Плата содержит: 14 цифровых входов и выходов, 6 из которых могут использоваться как выходы ШИМ; 6 анало- говых входов; резонатор: кнопку перезагрузки; отверстия для монтажа выводов. Блок из шести выводов может подключаться к кабелю FTDI или плате-конвертеру Sparkfun для обеспечения питания и связи через USB. Существует две версии платформы Pro Mini. Одна версия работает при напряжении 3,3 В и частоте 8 МГц, другая — при напряжения 5 В и частоте 16 МГц. ПРИМЕЧАНИЕ. Плата предназначена для непостоянной уста- новки в объекты или экспонаты. Расположение выводов совместимо с платформой Arduino Mini.
Глава 40. Платы arduino: особенности и возможности 455 Плата USB Serial II Light адаптер II USB Serial Light адаптер преобразует USB-канал в после- довательный RS-232 канал TTL уровня, который можно под- ключить непосредственно к Arduino Mini, Arduino Ethernet или другим платам Arduino, не имеющим своего USB адап- тера. Обеспечивает указанным платам связь с компьютером и загрузку скетчи. Логика конвертора реализована на базе чипа Atmega8U2, запрограммированном как конвертер из USB в последовательный сигнал, такой же, как на Arduino Uno. Для Windows требуется файл .inf с драйверами. Плата имеет встроенный разъем мини-USB. Вы также можете использовать 5 выводов: RX (для приема данных с ком- пьютера), ТХ (для передачи данных), 5V, Ground (общий про- вод) и Reset (Сброс). ПРИМЕЧАНИЕ. Имеются светодиодные индикаторы питания и активности на линиях RX и ТХ.
ГЛАВА 41 ARDUINO SHIELDS ИЛИ ПЛАТЫ РАСШИРЕНИЯ Плата расширения Arduino WiFi Плата расширения Arduino WiFi позволяет контролле- рам Arduino осуществлять сетевое соединение, используя бес- проводную сеть формата 802.11. Плата построена на базе чипа HDG104 Wireless LAN 802.1 lb/g System in-Package. Микроконтроллер Atmega 32UC3 обеспечивает поддержку сетевого стэка (IP) как для TCP, так и для UDP протокола. Плата WiFi, как и большинство плат расширения, соединяется с пла- той контроллера Arduino посредством контактных колодок, расположенных по краям платы.
Глава 41. Arduino shields или платы расширения 457 Размеры соответствуют контактам на контроллерах Arduino UNO и Arduino Mega2560. На плате WiFi имеется слот для micro-SD карт, которые могут быть использованы для хранения и передачи файлов по сети. ПРИМЕЧАНИЕ. Для подключения кАрдуино предусмотрен специ- альный разъем, представляющий собой металли- ческие выводы («папа») с одной стороны плоты и гнезда («мама») - с другой стороны. Такая кон- струкция позволяет подключить кАрдуино сразу несколько плат расширения, разместив их одну над другой. Плата расширения II Xbee Shield II Плата расширения Xbee Shield при помощи модуля Maxstream Xbee Zigbee обеспечивает беспроводную связь нескольким устройствам Arduino в радиусе до 35 метров (в помещении) и до 90 метров (вне помещения). С помощью этой платы вы можете легко подключить все модули из серии Вее к Arduino совместимым платформам и построить беспро- водную сеть. Работа с ХВее организована как пересылка сообщений через последовательное (serial) соединение. Для програм- мирования используется стандартная библиотека «Software Serial». Плата устанавливается поверх самого Ардуино и резервирует для коммуникации 0-й и 1-й контакты. Все остальные контакты соединены напрямую или не закрыва- ются вовсе, то есть могут быть использованы для любых целей обычным способом.
458 ARDUINO: от азов программирования до создания... ПРИМЕЧАНИЕ. Скорость обмена данными: до 250 кбит/с. Устройство работает но частоте 2,4 ГГц. Возможны как простые соединения «точка-точ- ка», так и сети со сложной топологией. I Плата расширения Arduino Motor Плата расширения Arduino Motor (управление моторами) изготовлена на основе микросхемы L298. Данная микросхема является двойным полномостовым драйвером. Он разра- ботан специально для управления индуктивными нагрузками, такими как реле, соленоиды, двигатели постоянного тока и шаго- вые двигатели. Она позволяет управлять двумя двигателями постоянного тока с помощью вашей платы Arduino, независимо регулируя скорость и направление каждого из них. Кроме всего прочего, плата позволяет измерять ток, потребляемый каждым двигателем. Плата совместима с модулями TinkerKit. Если вашему двигателю требуется напряжение более 9 В, рекомендуется разделить шины питания платы расширения и платы Arduino, на которой плата расширения установлена. Это
Глава 41. Arduino shields или платы расширения 459 возможно, если удалить перемычку «Vin СоппесЬна обратной стороне платы. ПРИМЕЧАНИЕ. Чтобы избежать повреждения платы Arduino, на которой установлена плата расширения, реко- мендуется использовать внешний источник пи- тания напряжением от 7 до 12 В. Абсолютный предел напряжения Vin на зажимных контактах составляет 18 В. Плата расширения Ethernet Shield Плата расширения Ethernet Shield обеспечивает подклю- чение к локальной сети посредством сетевого кабеля (витая пара), а через локальную сеть обеспечивается связь с Интернет. Обладает стандартным соединением RJ-45 с интегрированным линейным трансформатором и включенным питанием через Ethernet (РоЕ). Большинство последних версий платы предо- ставляет распиновку 1.0 версии 3 платы Arduino UNO.
460 ARDUINO: от азов программирования до создания... Плата расширения также включает в себя контроллер сброса, служащий для правильного сброса ethernet модуля W5100 при включении питания. Предыдущие версии платы расширения были не совместимы с Arduino Mega и нуждаются в ручном сбросе после подачи питания. Встроенный слот карты памяти micro-SD может быть использован для хранения файлов, предназначенных для пере- дачи по сети. Он совместим со всеми платами Arduino/Genuino. Встроенный micro-SD картридер доступен через SD Library. При работе с этой библиотекой SS находится на выводе 4. ПРИМЕЧАНИЕ. Оригинальная версия платы расширения содер- жит полноразмерный слот SD картридера; но он не поддерживается.
ЧАСТЬ VII ПОЛЕЗНАЯ ИНФОРМАЦИЯ ПО СОВРЕМЕННЫМ МИКРОКОНТРОЛЛЕРАМ Справочная часть книги содержит полезную информацию. Сюда сведена как система команд микроконтролле- ров AVR, так и основные команды языка используемого при составлении программ для модуля ARDUINO. Интересен список типов значений величин, используемых в программах на ARDUINO. Размещение справочной информации в едином блоке облегчает поиск нужных данных при самостоятельной разработке собствен- ных программ. Завершает книгу список полезных ссылок в Интернете и список литературы.
ПРИЛОЖЕНИЕ 1 ОСНОВНЫЕ ОПЕРАТОРЫ ЯЗЫКА ARDUINO Главные функции Оператор Синтаксис Описание setup() void setup() { Строки программы; } Функция используется для инициализации переменных, определения режимов работы линий ввода/вывода и т. п. Функция запускается однократно, либо после нажатия кнопки «Сброс», либо сразу после подачи питания, а также сразу после загрузки в модуль новой версии программы 1оор() void loop() { Строки программы; } Функция 1оор() многократно выполняется в цикле. В теле этого цикла и выполняются все основные операции программы. Функции setup() и 1оор() должны присутствовать в каждом скетче, даже если эти функции не используются Управляющие операторы Оператор Синтаксис Описание if if (Условие) { Оператор; ♦ } Оператор if позволяет выполнять ряд операторов в зависимости от Условия. Условие - это математическое выражение, возвращающее значение Ложь (False) или Истина (True). Для этого используется один из операторов сравнения (<, >, ==, !=). if... else if (Условие) Оператор; else Оператор; Оператор else дополняет оператор if и позволяет выполнить альтернативный набор операторов в случае не выполнения Условия в соответствующем ему операторе if.
Приложение 1. Основные операторы языка Arduino 463 Оператор Синтаксис Описание switch... case switch (Переменная) { case Значение!: Оператор; case Значение2: Оператор; case ЗначениеЗ: Оператор; default: Оператор); } Программный переключатель. Оператор позволяет задавать действия, которые будут выполняться при разных условиях. Если значение переменной в скобках у слова swich равно значению у одного из слов case,то оператор(ы) напротив этого слова выполняется(ются). В противном случае соответствующий оператор игнорируется. Команда break, поставленная в любом месте переключателя, досрочно прекращает перебор case и приводит к выходу из swich. Оператор(ы) после управляющего слова default выполняется(ются), если не выбрана ни одна из опций case for for (i=0; i <= Значение; i++){ Оператор; Оператор; } Оператор цикла. В i - переменная цикла. Оператор имеет три параметра. В первом параметре должно быть указано выражение, которое присваивает переменной цикла начальное значение. Второй параметр - это логическое выражение, при выполнении которого цикл продолжается. В третьем параметре размещается выражение, которое выполняет итерацию цикла. В приведенном примере после каждой итерации переменная i увеличивается на единицу while while (Условие) { Оператор; Оператор; } Оператор while (Пока) используется, как цикл, который будет выполняться, пока Условие в круглых скобках - истина. Операторы в теле цикла должны обязательно в какой-то момент так изменять условие, чтобы оно приняло значение Ложь. Иначе программа войдет в бесконечный цикл и зависнет do ...while do { Оператор; Оператор; } while (Условие); Оператор цикла do ...while работает так же, как и цикл while,только проверка условия происходит не в начале, а в конце цикла. Такой цикл всегда выполняется хотя бы один раз break continue Оператор Break используется для принудительного выхода из циклов switch, do, for и while. Оператор continue пропускает оставшиеся операторы в текущей итерации цикла и передает управление в его начало
464 ARDUINO: от азов программирования до создания... Il Операторы II цифрового ввода/вывода Оператор Синтаксис Описание pinMode() pinMode(pin, mode) Установка режима работы цифрового входа/ выхода. pin - номер контакта. Параметр может принимать значения 1,2,3,4,5,6,7,8,9,10,11,12,13 (а также 14,15,16,17,18,19); mode — режим работы. Параметр mode может принимать значения: OUTPUT — режим вывода информации (устанавливается по умолчанию); INPUT — режим ввода информации; INPUTPULLAP — режим ввода с включением внутреннего подтягивающего резистора digitalRead() digitalRead(pin) Функция чтения из цифрового входа, pin - номер контакта (принимаетте же значение, что и в двух предыдущих операторах). Функция возвращает значение сигнала на выбранном входе. Возвращаемые значения HIGH или LOW (или, что тоже самое, 1 или 0) digitalWrite() digitalWritefpin, value) Оператор вывода информации на цифровой контакт Arduino. Параметр pin - номер контакта, pin может принимать те же значения, что и в предыдущем операторе; value - выводимое значение. Value может принимать значение HIGH или LOW (или, что тоже самое, 1 или 0) I Операторы аналогового ввода/вывода Оператор Синтаксис Описание analogRead() analogRead(An) Функция аналогового чтения с аналогового входа Ап. Параметр может принимать значения: АО, Al, А2, АЗ, А4, А5, А6 analogWrite() analogWrite(pin, value) Процедура аналогового вывода, pin - номер контакта. value - выводимое значение. Вывод производится на цифровые выходы модуля в формате широтно-импульсной модуляции (PWM). Номер контакта (pin) может принимать значение (для Arduino UNO) - 3,5,6,9,10,11. Значение параметра value может принимать значения от Одо 255
Приложение 1. Основные операторы языка Arduino 465 Операторы времени Оператор Синтаксис Описание mittlsO Функция возвращает количество миллисекунд, прошедшее с запуска программы micros() Функция возвращает количество микросекунд, прошедшее с запуска программы delay(tz) Функция программной задержки. Параметр tz определяет время задержки в миллисекундах delayMicroseconds(tz) Функция программной задержки. Параметр tz определяет время задержки в микросекундах Расширенный II ввод/вывод II Оператор Синтаксис Описание tone() tone(pin,fq) tone(pin,fq, tz) Процедура генерации звукового сигнала на цифровом выходе. pin - вывод, на котором будет генерироваться сигнал. fq - частота сигнала в герцах (unsigned int). tz - длительность сигнала в миллисекундах (unsigned long). Если не указан, звук генерируется, пока не поступит команда поТопе() поТопе() noTone(pin) Прекращение генерации звука на указанном контакте shiftOut() shiftOut(dataPin, clockPin, bitOrder, value) Функция последовательного вывода байта данных. Программно реализует SPI канал, используя любые два цифровых контакта. dataPin - контакт, через который побитно выводятся передаваемые данные. clockPin - контакт, который используется для вывода сигнала синхронизации. clockPin - порядок передачи битов. Принимает значения: MSBFIRST (старший бит вперед), LSBFIRST (младший бит вперед). value - передаваемый байт данных. Возвращаемого значения нет shiftln() shiftln(dataPin, clockPin, bitOrder) Функция последовательного ввода байта данных. Работает в паре с функцией shiftOut(). Параметры dataPin, clockPin и bitOrder аналогичны соответствующим параметрам shiftOut. Функция возвращает считанный байт
466 ARDUINO: от азов программирования до создания... Оператор Синтаксис Описание pul$eln() pulseln(pin, value) pulseln(pin, value, timeout) Функция измерения длительности входного импульса. pin - контакт, на котором происходит измерение, value - полярность измеряемого импульса: Если value = HIGH - измеряется длительность положительного импульса. Если value = LOW, измеряется длительность отрицательного импульса. timeout - время ожидания начала импульса (по умолчанию 1 с). Функция возвращает длительность импульса. Функция работает с импульсами длительностью от 10 микросекунд до 3 минут Работа с последовательным портом Оператор Синтаксис Описание SeriaLbegin() SeriaLbegln(rate) Инициализация последовательного порта, rate - скорость передачи информации. Может принимать значения: 300,1200,2400, 4800,9600,14400,19200,38400,57600 или 115200 Serial.print() SeriaLprint(data) Передача строки данных в последовательный порт (печать текста в последовательный порт) Serial.println() Serial, print In (data) Передача строки данных в последовательный порт, завершаемый символом перевода строки SeriaLavallable() Serial.available() Функция проверки количества считанных по последовательному порту байт в буфере. Байты помещаются в буфер автоматически по поступлению Serial.read() Serial.read() Считывание очередного байта из буфера последовательного порта. Если данные отсутствуют, функция возвращает-1 (минус один) Serial.write() SeriaLwrite(val) SeriaLwrite(str) Serial.write(buf, len) Запись данных в последовательный порт, val - число от 0 до 255 (байт), str - текстовая строка в виде набора байтов, buf - массив данных в виде набора байтов, len - длина массива данных Serial.flush() SerlaLflush() Ожидание окончания процесса пер едачи данных
ПРИЛОЖЕНИЕ 2 ТИПЫ ДАННЫХ В ARDUINO IDE Тип Кол-во байт Диапазон значений Примечание boolean 1 байт 0 или 1 . Логическое значение TRUE или FALSE (правда/ ложь) byte 1 байт O...255 число в диапазоне от 0...255 char 1 байт -128 ...127 Хранит код символа в кодировке ASCII unsigned char 1 байт O...255 Хранит код символа в кодировке ASCII int 2 байта -32768 ...32767 Целое число со знаком unsigned int 2 байта Одо 65535 Целое число без знака word 2 байта Одо 65535 То же самое, что unsigned int long 4 байта -2147 483 648... 2 147 483 647 unsigned long 4 байта 0...4 294 967 295 float 4 байта -3.4028235Е38... 3.4028235Е38 Числа с плавающей точкой. Точность 6...7 знаков double 4 байта То же самое, что float Примечания: unsigned char — то же что и byte. Для лучшей читаемости удобнее использовать byte. unsigned int — то же самое, что и word. Для лучшей читае- мости используйте word.
468 ARDUINO: от азов программирования до создания... int — один из самых распространенных типов данных, который очень часто используется для объявления перемен- ных в скетчах для Arduino. unsigned long — чаще всего этот тип данных используется для хранения результатов функции millis(), которая возвра- щает количество миллисекунд, прошедших с момента начала работы программы. float — числа с плавающей запятой не характерны для Arduino. Компилятор обрабатывает программы, использующие этот тип данных, работают очень долго. Рекомендуется, по воз- можности, избегать применения этого типа данных.
ПРИЛОЖЕНИЕ 3 СВОДНАЯ ТАБЛИЦА КОМАНД АССЕМБЛЕРА МИКРОКОНТРОЛЛЕРОВ AVR Группа команд II логических операций II Мнемоника Описание Операция Циклы Флаги AND Rd, Rr «Логическое И» двух РОН Rd 4 - Rd • Rr 1 Z.N.V ANDI Rd, К «Логическое И» РОН и константы Rd< E- Rd • К 1 Z, N,V EOR Rd, Rr «Исключающее ИЛИ» двух РОН Rd 4 - Rd Ф Rr 1 Z, N,V OR Rd, Rr «Логическое ИЛИ» двух РОН Rd 4 — Rd v Rr 1 Z,N,V ORI Rd, К «Логическое ИЛИ» РОН и константы Rd< -RdvK 1 Z.N.V COM Rd Перевод в обратный код Rd * - OFFH - Rd 1 Z,C, N,V NEG Rd Перевод в дополнительный код Rd 4- OOH - Rd 1 Z, C, N.V, H CLR Rd Сброс всех разрядов РОН Rd 4- - Rd Ф Rd 1 Z,N,V SER Rd Установка всех разрядов РОН Rd 4-OFFH 1’ — TSTRd Проверка РОН на отрицательное (нулевое) значение Rd 4 - Rd • Rd 1 Z, N.V
470 ARDUINO: от азов программирования до создания... I Группа команд арифметических операций Мнемоника Описание Операция Циклы Флаги ADD Rd, Rr Сложение двух POH Rd< <- Rd + Rr 1 Z,C, N,V,H ADC Rd, Rr Сложение двух РОН с переносом Rd <— Rd + Rr + C 1 Z,C, N,V,H ADIW Rd, К Сложение регистровой пары с константой Rdh:RdL <- Rdh:Rdl + К 2 Z.C, N,V,S SUB Rd, Rr Вычитание двух РОН Rd < h Rd - Rr 1 Z.C, N,V,H SUBI Rd, К Вычитание константы из РОН Rd <-Rd - К 1 Z, C, N,V,H SBC Rd, Rr Вычитание двух РОН с заемом Rd <- Rd-Rr-C 1 Z.C, N,V,H SBCI Rd, К Вычитание константы из РОН с заемом Rd <- Rd-K-C 1 Z.C, N,V,H SBIW Rd, К Вычитание константы из регистровой пары Rdh:Rdl <- Rdh:Rdl-K 2 Z,C, N,V,S DEC Rd Декремент РОН Rd <-Rd -1 1 Z, N,V INC Rd Инкремент РОН Rd <- Rd +1 1 Z.N.V I Группа команд операций с разрядами Мнемоника Описание Операция Циклы Флаги CBR Rd, К Сброс разряда(ов) РОН Rd «- Rd • (OFFH - К) 1 Z,N,V SBR Rd, К Установка разряда(ов) РОН Rd <- Rd v К 1 Z,N,V CBI A, b Сброс разряда РВВ A.b<-0 2 — SBIA.b Установка разряда РВВ A.b<-1 2 — BCLRs Сброс флага SREG.S «- 0 1 SREG.s BSETs Установка флага SREG.S «-1 1 SREG.s BLD Rd, b Загрузка разряда РОН из флага T(SREG) Rd.b«-T 1 — BSTRr.b Запись разряда РОН в флаг T(SREG) T Rd.b 1 T CLC Сброс флага переноса C<-0 1 c SEC Установка флага переноса C<-1 1 c
Приложение 3. Сводная таблица команд Ассемблера микроконтроллеров AVR471 Мнемоника Описание Операция Циклы Флаги CLN Сброс флага отрицательного числа N<-0 1 N SEN Установка флага отрицательного числа N <-1 1 N CLZ Сброс флага нуля Z<-0 .1 Z SEZ Установка флага нуля Z<-1 1 Z CLI Общий запрет прерываний l<-0 1 1 SEI Общее разрешение прерываний I<-1 1 1 CLS Сброс флага знака S<-0 1 s SES Установка флага знака S<-1 1 s CLV Сброс флага переполнения дополнительного кода V<-0 1 V SEV Установка флага переполнения дополнительного кода V«-l 1 V CLT Сброс пользовательского флага Т T<-0 1 T SET Установка пользовательского флага Т T<-1 1 T CLH Сброс флага половинного переноса H«-0 1 H SEH Установка флага половинного переноса H 1 1 H Группа команд II сравнения II Мнемоника Описание Операция Циклы Флаги CP Rd, Rr Сравнение двух РОН ? (Rd - Rr) 1 Z,N,V,C,H CPC Rd, Rr Сравнение РОН с учетом переноса ?(Rd-Rr-C) 1 Z,N,V,C,H CPI Rd, К Сравнение РОН с константой ? (Rd - К) 1 Z,N,V,C,H
472 ARDUINO^ot азов программирования до создания... II Группа команд II операций сдвига Мнемоника Описание Операция Циклы Флаги ASR Rd Арифметический сдвиг вправо Rd7 Rd6 Rd5 Rd4 -> Rd3 Rd2 Rdl -> RdO 1 Z,C,N,V LSLRd Логический сдвиг влево C 4- Rd7 4- Rd6 4- Rd5 <- Rd4 4- Rd3 4- Rd2 4- Rdl 4- RdO 4-0 1 Z,C,N,V LSR Rd Логический сдвиг вправо 0-> Rd7-> Rd6-> Rd5-> Rd4 -> Rd3 -> Rd2 -> Rdl RdO->C 1 Z,C,N,V ROLRd Сдвиг влево через перенос C <- Rd7 <- Rd6 <- Rd5 <- Rd44-Rd3 4-Rd2 4-Rdl <- Rd0 4-C 1 Z.C.N.V ROR Rd Сдвиг вправо через перенос C-> Rd7-> Rd6-> Rd5-» Rd4 Rd3 -» Rd2 -+ Rdl RdO->C 1 Z.C.N.V SWAP Rd Обмен местами тетрад Rd(3-0) 4-> Rd(7-4) 1 — О Группа команд II пересылки данных Мнемоника Описание Операция Циклы Флаги MOV Rd, Rr Пересылка между РОН Rd 4-Rr 1 — MOVW Rd, Rr Пересылка между парами регистров Rd +l:Rd 4- Rr+l:Rr 1 — LDI Rd, К Загрузка константы в РОН Rd 4-К 1 — LD Rd,X Косвенное чтение Rd 4- [X] 2 — LD Rd,X+ Косвенное чтение с постикрементом Rd 4-[X], X 4-X+l 2 — LD Rd,-X Косвенное чтение с преддекрементом X 4- X-l, Rd 4- [X] 2 — LD Rd,Y Косвенное чтение Rd 4- [Y] 2 - LDRd,Y+ Косвенное чтение с постикрементом Rd 4- [Y],Y4- Y+l 2 — LD Rd,-Y Косвенное чтение с преддекрементом Y 4- Y-l, Rd 4- [Y] 2 —
Приложение 3. Сводная таблица команд Ассемблера микроконтроллеров AVR473 Мнемоника Описание Операция Циклы Флаги LD Rd, Y+q Косвенное относительное чтение Rd <- [Y+q] 2 — LD Rd,Z Косвенное чтение Rd <-[Z] 2 - LD Rd,Z+ Косвенное чтение с постикрементом Rd <- [Z],Z<— Z+l 2 — LD Rd,-Z Косвенное чтение с преддекрементом Z 4- Z-l, Rd 4- [Z] 2 — LD Rd,Z+q Косвенное относительное чтение Rd <- [Z+q] 2 — LDS Rd, k Непосредственное чтение из ОЗУ Rd 4- [k] 2 — STX, Rr Косвенная запись [X]<-Rr 2 - STX+, Rr Косвенная запись с постикрементом [X] <- Rr, X <- X+l 2 — ST-X, Rr Косвенная запись с преддекрементом X 4- X-l, [X] 4- Rr 2 — STY, Rr Косвенная запись [Y] 4-Rr 2 - STY+, Rr Косвенная запись с постикрементом [Y] 4-Rr, Y 4-Y+l 2 — ST-Y,Rr Косвенная запись с преддекрементом Y 4- Y-l, [Y] 4- Rr 2 — STY+q, Rr Косвенная относительная запись [Y+q] 4- Rr 2 — STZ, Rr Косвенная запись [Z] 4- Rr 2 - STZ+, Rr Косвенная запись с постикрементом [Z]4-Rr,Z4-Z+l 2 — ST-Z, Rr Косвенная запись с преддекрементом Z4-Z-l,[Z]4-Rr 2 — STZ+q, Rr Косвенная относительная запись [Z+q] <— Rr 2 — STS k, Rr Непосредственная запись в ОЗУ [k] <— Rr 2 — LPM Загрузка данных из памяти программ R0<-{Z] 3 — LPM Rd,Z Загрузка данных из памяти программ Rd 4- {Z} 3 — LPM Rd,Z+ Загрузка данных из памяти программ и постдекремент Z Rd 4— {Z}, Z 4— Z+l 3 — SPM Запись в программную память {Z} <- R1:RO — —
474 ARDUINO: от азов программирования до создания... Мнемоника Описание Операция Циклы Флаги IN Rd, Р Пересылка из РВВ в РОН Rd Р 1 — OUT Р, Rr Пересылка из РОН в РВВ P<-Rr 1 — PUSH Rr Сохранение байта в стеке STACK <- Rr 2 — POP Rd Извлечение байта из стека Rd 4- STACK 2 — I Группа команд управления системой Мнемоника Описание Операция Циклы Флаги NOP Нет операции - ' 1 — SLEEP Переход в «спящий» режим — 3 — WDR Сброс сторожевого таймера — 1 — BREAK Приостановка программы Используется только при отладке — — I Группа команд передачи управления (безусловная передача управления) Мнемоника Описание Операция Циклы Флаги RJMP Относительный безусловный переход PC 4- PC + к +1 2 — IJMP Косвенный безусловный переход PC4-Z 2 — RCALL Относительный вызов подпрограммы PC 4- PC + к +1 3 — ICALL Косвенный вызов подпрограммы PC<-Z 3 — RET Возврат из подпрограммы PC 4- STACK 4 — RETI Возврат из подпрограммы обработки прерываний PC 4- STACK 4 1
Приложение 3. Сводная таблица команд Ассемблера микроконтроллеров AVR475 Группа команд передачи управления II (пропуск команды по условию) II Мнемоника Описание Условие Циклы Флаги Все команды этой группы пропускают следующую за ней команду (PC <- PC + 1) при разных условиях: CPSE Rd, Rr Сравнение и пропуск следующей команды при равенстве Если Rd = Rr 1/2/3 — SBRCRr.b Пропуск следующей команды если разряд РОН сброшен Если Rr,b = 0 1/2/3 — SBRS Rr, b Пропуск следующей команды если разряд РОН установлен Если Rr.b = 1 1/2/3 — SBICA, b Пропуск следующей команды если разряд РВВ сброшен Если A.b = 0 1/2/3 — SBISA, b Пропуск следующей команды если разряд РВВ установлен Если A.b = 1 1/2/3 — Группа команд передачи управления (передача управления по условию) Мнемоника Описание Условие Циклы Флаги Все команды этой группы выполняют переход (PC <- PC + k + 1) при разных условиях: BRBC s, к Переход, если флаг s регистра SREG сброшен Если SREG.S = 0 1/2 — BRBS s, к Переход, если флаг s регистра SREG установлен Если SREG.S = 1 1/2 — BRCS к Переход по переносу Если С = 1 1/2 — BRCCk Переход, если нет переноса Если С = 0 1/2 — BREQk Переход по условию «равно» Если Z= 1 1/2 — BRNE к Переход по условию «неравно» Если Z = 0 1/2 — BRSHk Переход по условию «больше или равно» Если С = 0 1/2 — BRLOk Переход по условию «меньше» Если С = 1 1/2 —
476 ARDUINO: от азов программирования до создания... Мнемоника Описание Условие Циклы Флаги BRMI к Переход по условию «отрицательное значение» Если N = 1 1/2 — BRPLk Переход по условию «положительное значение» Если N = 0 1/2 — BRGE к Переход по условию «больше или равно» (со знаком) Если (N и V) = 0 1/2 — BRLTk Переход по условию «меньше» (со знаком) Если (N или V) = 1 1/2 — BRHSk Переход по половинному переносу Если Н = 1 1/2 — BRHCk Переход, если нет половинного переноса Если Н = 0 1/2 — BRTSk Переход, если флаг Т установлен Если Т = 1 1/2 — BRTCk Переход, если флагТ сброшен Если Т = 0 1/2 — BRVSk Переход по переполнению дополнительного кода Если V = 1 1/2 — BRVCk Переход, если нет переполнения дополнительного кода 1 Если V = 0 1/2 — BRIDk Переход, если прерывания запрещены Если 1 = 0 1/2 — BRIE к Переход, если прерывания разрешены Если 1 = 1 1/2 —
подводя итоги, ИЛИ О ВИРТУАЛЬНОМ ДИСКЕ-. Подводя итоги, автор смеет надеяться, что данная книга дала вам достаточно полное представление о возможно- стях такого замечательного устройства, как модуль Arduino. Надеюсь, что вы освоили основные приемы схемотехники и принципы составления программ. Автор и редакция издательства «Наука и Техника» поста- рались осветить как можно полнее все возможности модуля. Разобравшись и попробовав самостоятельно собрать и испы- тать каждую из схем, предложенных в книге, вы, как мы наде- емся, уже стали достаточным специалистом в этой отдельной, но очень перспективной области микроэлектроники. И теперь уже самостоятельно сможете осуществлять свои собственные разработки и реализовать свои идеи. Большим подспорьем вам будет виртуальный диск, спе- циально разработанный для данной книги, а также для книги [1]. Виртуальный диск находится в свободном доступе в Интернете: ♦ на сайте автора книги по адресу book.mirmk.ru/wdiskl ♦ на сайте Издательства www.nit.com.ru. На виртуальном диске вы найдете: ♦ тексты всех программных примеров из книги в электрон- ном виде; ♦ инсталляционный пакет среды разработки IDE; ♦ архивы всех используемых в книге программных библиотек; ♦ видеоролики с авторскими обзорами различных вопросов, помогающими полнее освоить материал из книги; * набор вспомогательной справочной информации. Автор данной книги будет благодарен за любые отзывы и замечания. Отзывы присылайте по E-mail: belov@mirmk.ru или на сайт http://book.mirmk.ru.
Список литературы 1. Белов А.В. Программирование ARDUINO. Создаем прак- тические устройства. — СПб: Наука и Техника, 2018. 2. Белов А.В. Микроконтроллеры AVR от азов программиро- вания до создания практических устройств, изд. 2-е, перераб. и доп. — СПб: Наука и Техника, 2017. 3. Белов А.В. Программирование микроконтроллеров для начинающих и не только. — СПб: Наука и Техника, 2016. 4. Белов А.В. Конструирование устройств на микроконтрол- лерах. — СПб: Наука и Техника, 2005. Список ссылок на ресурсы сети Интернет, используемые в книге 1. http://book.mirmk.ru Сайт поддержки всех книг автора «Мир книг по микро- электронике». Здесь вы найдете дополнительные материалы к книге, тексты всех программных примеров в электронном виде, описание других книг на ту же тему. 2. http://book.mirmk.ru/wdiskl Виртуальный диск для книги. 3. https://www.arduino.cc/ Сайт разработчика проекта Arduino (англоязычный). На этом сайте вы можете подробно прочитать обо всех вариантах модуля Arduino, а также скачать пакет для установки интегри- рованной среды разработчика (IDE) и любую его Бетта версию. 4. http://mypractic.ru/urok-8-cifrovaya-filtraciya-signalov-v- programmax-dtya-arduino.html Описание алгоритма работы и текста программ библиотеки Button. 5. http://mypractic.ru/urok-10-preryvanie-po-tajmeru-v- arduino-biblioteka-mstimer2-parallelnye-processy.html Пр ерывание по таймеру в Arduino. Библиотека MsTimer2. Параллельные процессы.
Предлагаем широкий ассортимент технической литературы ведущих издательств (более 2000 наименований): • Компьютерная литература • Радиоэлектроника • Телекоммуникации и связь • Транспорт, строительство • Научно-популярная медицина, педагогика, психология Чем привлекателен наш магазин: • низкие цены; • ежедневное пополнение ассортимента; • поиск книг под заказ; • обслуживание за наличный и безналичный расчет; • гибкая система скидок; • комплектование библиотек; • обеспечение школ учебниками по информатике; * возможна доставка.
Издательство «Наука и Техника» КНИГИ ПО КОМПЬЮТЕРНЫМ ТЕХНОЛОГИЯМ, МЕДИЦИНЕ,РАДО ЭЛЕКТРОНИКЕ F Scan & DJVu Уважав 1тели! Книги издательства > заказать в наше^мГтернет-магазине ника» вы можете: www.mt.com.ru (более 100 пунктов выдачи на территории РФ) «Новый книжный» Сеть магазинов ТД «БИБЛИО-ГЛОБУС» Московский Дом Книги, «ДК на Новом Арбате» Московский Дом Книги, «Дом технической книги» Московский Дом Книги, «Дом медицинской книги» Дом книги «Молодая гвардия» > приобрести в Москве: тел. (495) 937-85-81, (499) 177-22-11 ул. Мясницкая, д. 6/3, стр. 1, ст. М «Лубянка» тел. (495) 781 -19-00,624-46-80 ул.Новый Арбат, 8, ст. М «Арбатская», тел. (495) 789-35-91 Ленинский пр., д.40, ст. М «Ленинский пр.», тел. (499) 137-60-19 Комсомольский пр., д. 25, ст. М «Фрунзенская», тел. (499) 245-39-27 ул. Б. Полянка, д. 28, стр. 1, ст. М «Полянка» тел. (499) 238-50-01 > приобрести в Санкт-Петербурге: Санкт-Петербургский Дом Книги Невский пр. 28, тел. (812) 448-23-57 Буквоед. Сеть магазинов тел. (812) 601-0-601 > приобрести в регионах России: г. Воронеж, «Амиталь» Сеть магазинов г. Екатеринбург, «Дом книги» Сеть магазинов г. Нижний Новгород, «Дом книги» Сеть магазинов г. Владивосток, «Дом книги» Сеть магазинов г. Иркутск, «Продалить» Сеть магазинов г. Омск, «Техническая книга» ул. Пушкина, д.101 тел. (473) 224-24-90 тел. (343) 289-40-45 тел. (831) 246-22-92 тел. (423) 263-10-54 тел. (395) 298-88-82 тел. (381) 230-13-64 Мы рады сотрудничеству с Вами!