XXI век идет по нашей жизни семимильными шагами, внося в современный быт все новые и новые полезные технические решения. Однако, по мнению научной фантастики 50-х годов ХХ-ro века, современное настоящее должно выглядеть по другому: кругом роботы, сплошная автоматика, люди по дому ничем не занимаются - они предоставлены сами себе. А на самом деле что? Как пекли блинчики самостоятельно, так и печем. Шторы раскрываем до сих пор вручную. Может быть, хватит?

О чем речь?

На основе чего можно простому пользователю, знающему хотя бы школьный курс физики, построить систему автоматики? Конечно же на микроконтроллере, посредством языка высокого уровня. Нет, я не издеваюсь, микроконтроллеры - это действительно очень просто! Объясню, что это такое.

Микроконтроллер (МК) - это микросхема, содержащая в себе процессор ОЗУ, ПЗУ и устройства ввода-вывода. По сути, компьютер в виде одной микросхемы. Помимо основных узлов такой микро-ЭВМ может содержать цифро-аналоговые преобразователи (ЦАП), аналогово-цифровые преобразователи (АЦП), различные таймеры, многочисленные интерфейсы, например Ethernet или USB, и многие другие блоки. Все что требуется для работы самой микросхемы, это повесить кварцевый резонатор на определенные выводы и подать питание. К рабочим выводам такой микро-ЭВМ подключаются различные исполнительные устройства или устройства ввода информации. У МК есть память программ и память данных. В памяти программ (flash-пэмять) хранится исполняемый программный код, который предстоит записать туда специальным программатором. Память данных (EEPR0M - энергонезависимая память) позволяет сохранять данные на время выключения микроконтроллер, что позволяет запоминать установки.

Программы для МК пишутся обычно на языке Си или Ассемблер. Иногда можно встретить и интерпретаторы Бейсика.

На Ассемблере можно написать для МК абсолютно все. Это язык программирования низкого уровня, представляющий, по сути, исполняемый набор команд процессора, только в более удобочитаемом виде, чем в машинном коде. Нам он не совсем подходит, точнее, совсем не подходит: учить сотни команд, да и еще их применять не то, что нам нужно, нам бы что-нибудь попроще. Тогда рассмотрим Си - язык богов. Этот процедурный язык программирования высокого уровня получил признание много лет назад, постепенно обрастая новыми возможностями. У него есть замечательная особенность: работать с железом на низком уровне, что позволяет использовать большинство функций. Он легок в изучении, и у него множество братьев - Си-подобных языков. Об одном из них мы сегодня и поговорим.

Чем?

Настал главный вопрос: чем творить будем? Ведь держа в руке одну микросхему, много не сделаешь, хотелось бы что-то готовенькое... Есть такое решение. Предлагаю вашему вниманию специальный аппаратно-программный комплекс, предназначенный для простого и активного использования микроконтроллеров в домашнем хозяйстве. Будем учиться их готовить с помощью свободно распространяемого аппаратно-программного обеспечения под названием Arduino.

Arduino - это вычислительная платформа, представляющая собой плату с микроконтроллером и порты ввода-вывода, позволяющие подключить различные устройства к нему. На плате располагаются микроконтроллер Atmega8, Atmegal 68 или Atmega328 в зависимости от новизны платформы, обвязки для программирования, коммуникационные порты (в RS-232 или USB), система питания микроконтроллера, кварцевый резонатор, кнопка сброса (Reset) и, конечно же, разъемы ввода-вывода.

У данной серии микроконтроллеров 20 цифровых вводов/выводов, 6 из которых поддерживают широтно-импульсную модуляцию (ШИМ), а 6-10-битные аналогово-цифровые преобразователи. МК поддерживает два внешних прерывания, одно прерывание по таймеру, интерфейсы UART и SPI. Подключение производится через 0,1-дюймовые разъемы типа «мама», что позволяет подключить как просто провод, так и ответную часть разъема. Плату Arduino можно заказать готовую или собрать самому - схемы и чертежи печатных плат имеются в открытом доступе. Стоимость таких плат в среднем 700 - 800 рублей, что недорого. При самостоятельной сборке себестоимость составит около 300 - 400 рублей. Для Arduino выпускаются также специальные платы расширения - shields, которые могут быть установлены на разъемы базовой платы. Оригинальные платы можно купить у официальных дистрибьюторов. В нашей стране это Linux-center: http://www. linuxcenter.ru/shop/embedded/arduino/.

Свои действия я буду вести на самодельной платформе, служащей мне верой и правдой почти год (на фото 1 - слева). Именно с этой платформой я и начал освоение микроконтроллеров, которое успешно веду и по сей день. Мой контроллер называется MRC-28, является полностью совместимым с Arduino, и был найден на сайте http://robozone.su/ (зачем изобретать велосипед?). Впоследствии таких контроллеров я сделал около десятка и оснастил ими лабораторию в университете.


На плате имеются сам микроконтроллер, порты ввода/ вывода, преобразователь уровней для последовательного порта и сам разъем последовательного порта. Также имеются разъемы для подключения блока питания. Питание МКсоставляет 5 В. На вход MRC-28 должно подаваться не меньше 7 В. 5 В присутствуют на разъемах в некоторых точках, что очень удобно при подключении внешних устройств.

Теперь поговорим о среде программирования. Называется она так же - Arduino и представляет собой кросс-платформенную, основанную на Java, интегрированную среду программирования. Скачать ее можно с официального сайта http://arduino.cc под необходимую ОС - Windows,Linuix, MacOS. Окно программы состоит из нескольких частей: панель меню, панель кнопок быстрого доступа, область ввода кода и область вывода служебной информации. Рассмотрим вкратце каждую часть по отдельности.

В панели меню основное внимание следует обратить на пункт Tools/Board - в нем надо выбрать нашу плату. Какую именно выбирать - зависит от вашей платы. Если у вас оригинальная плата, то по названию, если совместимая - то чаще всего по типу контроллера. Также стоит выбрать последовательный порт, на котором висит наш контроллер. Используя USB, найдите информацию о том, какой это последовательный порт. Пункт File/Preferences позволяет установить папку для скетчей - так называемых проектов. В File также можно выбрать уже имеющиеся скетчи и открыть примеры. Примерами пренебрегать не стоит на всех этапах обучения, на их основе удобно составлять скелет будущей программы, сводя к минимуму его ручной ввод. Кнопки под меню позволяют запустить и остановить компиляцию программы, создать/открыть/сохранить скетч, записать программу в микроконтроллер, а также вызвать терминал последовательного порта. В области ввода кода мы, собственно, пишем программу. Окно оборудовано вертикальной и горизонтальной полосами прокрутки. Область вывода служебной информации служит для вывода ошибок при компиляции, предупреждений, ошибок программирования контроллера и т.д. Освоение программы занимает не более 10 минут.

Как?

Научимся использовать основные функции Arduino. Лучшим способом для этого является полное изучение раздела справки - Reference (Extended).

Программа для МК состоит из двух основных функций:

void setup () и void 1оор()
Функция void setup() выполняется всего один раз -при запуске контроллера. В ней мы можем определить, какие порты будут входами, какие выходами, какие уровни будут на выходных портах и т.д. В общем, любая подготовительная работа, которая должна выполниться лишь единожды, пишется здесь. Функция void loop() исходя из названия, выполняется бесконечное число раз, если не указано обратное. Это основной цикл программы. В самом начале документа обычно указываются название программы, автор и как его найти. Оформляется шапка в виде комментария/**/ /*Это многострочный текстовый комментарий*/

Далее указываются директивы препоцессора:

#include
//объявили библиотеку управления ЖК-дисплеем После всего этого можем объявить глобальные переменные:

unsigned int FlagBgConduct[12][4]; // объявили какую-то положительную целочис-лительную матрицу.

Сделали? Теперь уже рисуем каркас нашей будущей программы:


Программа также может включать абсолютно любые подфункции, в которые удобно вынести часто выполняемые действия: отправка чего-либо в порт, работа с данными и т.п. Это необязательные компоненты программы и зависят они только от ее архитектуры.

Теперь разберем основные функции работы с портами. Существует две основные группы таких функций: функции работы с цифровыми портами ввода/вывода и функции работы с аналоговыми портами ввода/вывода.

1. Функции работы с цифровыми портами ввода/ вывода.

Для начала порт надо определить как входной или выходной. Делается это функцией:

pinMode(pin, тос!е)//где pin - номер нужного нам входа на плате, mode=INPUT| OUTPUT в зависимости от наших потребностей. Теперь в выходной порт можно что-то записать:

digitalWrite(pin, уа1ие)//где pin - номер нашего порта, value=HIGH|LOW, устанавливает, соответственно, высокий или низкий уровень на выходе. Из входного порта можно принять данные:

int digitalRead(pin)//pin - номер нашего входа. Получить из порта можно либо 1 (HIGH) либо О (LOW).

С портами вывода, оснащенными ШИМ поступаем чуть иначе:

analogWrite(pin, value)//pin - номер порта (у платформ с указанными ранее МК это 3, 5,6,9, 10, и 11). value - коэффициент заполнения 8 бит - от 0 до 256. Частота ШИМ-сигнапа, по документации, около 490 Гц. Однажды вызвав эту функцию, ШИМ будет продолжать работать до следующей команды по поводу этого порта - этой же командой или командами digitalRead()/ digitalWrite().
Теперь порты аналогового ввода. Это входы 10 бит АЦП, т.е. мы можем получить величину от 0 до 1024. Прочитать значение одного из 6 портов можно командой:

int analogRead(pin)//rfle pin - номер аналогового порта, от 0 до 6, отличающегося по нумерации от цифровых портов. Хотя на платах цифровые порты пронумерованы лишь от 0 до 13, всегда можно использовать нумерацию при объявлении типа цифрового порта от 0 до 19, в таком случае определенный аналоговый порт становится цифровым, а номер такого цифрового порта равен 13 плюс номер соответствующего аналогового порта. Если вам из-за каких-то проблем с разводкой необходимо запитать микросхемку, датчик или иное устройство от порта ввода вывода МК, смело можете это делать - максимальный ток нагрузки на порт МК составляет 20 мА.

Теперь изучим функции времени. Функций две: это время в милли/микросекундах с момента начала работы МК и время в милли/микросекундах задержки времени.

Время, прошедшее с начала работы МК, вызывается функциями:

unsigned long millis() //в миллисекундах. Этот таймер переполнится примерно через 50 дней.

unsigned long micros()//B микросекундах. Этот таймер переполнится примерно через 70 минут.

Задержка между выполнением каких-либо команд довольно часто необходима. Ее реализуем с помощью:

delay(ms) //задержка в миллисекундах;

delayMicroseconds(us)//зaдepжкa в микросекундах Отступая от темы, сразу скажу, что в функции, выполняемой во время прерывания, задержки времени не работают. Их приходится писать самому.

Следующий класс функций, который нам пригодится, это класс работы с последовательным портом. Класс включает в себя следующие функции: Serial.Ьед!п(скорость в бодах) - устанавливает скорость работы последовательного порта. Она может быть следующей: 300, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, или 115200. Никогда не стоит торопиться, могут не успевать как компьютер, так и микроконтроллер.

Serial.available() - возвращает число байт, доступных для чтения или 0 если их нет. Максимальное число байт в буфере - 128.

Serial.read() принимает данные из порта.

Serial.print() отправляет данные в порт.

Serial.println() также отправляет данные в порт, но вдобавок переводит строку.
Serial.write() отправляет данные в порт в байтовом виде.

Рассмотрим имеющийся в Reference пример:

Что?

Пожалуй, хватит уже рассказывать, приступим к делу! Что мы вообще хотели бы сделать? Сделаем систему управления светом в доме? Только сразу предупреждаю - проводами опутать придется всю квартиру.

Нам понадобится:

Сама платформа в любом ее исполнении и БП для ее питания, желательно с аккумулятором для бесперебойности. Также потребуется БП для питания исполнительных реле, о которых поговорим чуть позже. Исполнительные реле нужны современные, которые можно выпаять из телевизоров или купить на радиорынке. Стоит одна такая релюшка 15-25 рублей. Переключающий контакт необходим минимум один. Куча силовых проводов - желательно купить моток провода 0,75 мм - он у нас будет силовым (в мотке, как минимум, 10 м). Еще больше понадобится сигнального провода. Можно купить пару разноцветных мотков оченьтонкого одинарного провода, и/ или моток двойного тонкого провода. Этот провод будет тянуться от исполнительного реле в нашей плате. Из радиодеталей помимо реле потребуются еще транзистор типа КТ315, резистор на 1 к и мелкий конденсатор на 0,1 мкФ(фото2).

Прикинем, сколько у нас исполнительных устройств, которые надо включить/выключить. По их количеству паяем наши релюшки по схеме 1. Паять можно как на макетной/печатной плате, так и навесом. Левые контакты будут подключаться к нашей плате. Нижний - к общему проводу, верхний - к выходному порту. Силовые контакты реле на схеме указаны в выключенном положении. Чтобы управлять лампой, ставим данное реле параллельно выключателю SA1 нормально-разомкнутыми контактами SA2. Тогда наша умная система не будет мешать основной электрике (схема 2).

Внимание! Работа с электросетью опасна! Пусть все подключения ведут квалифицированные специалисты!

К каждому такому выключателю должны подходить 3 наших провода, общие для всех выключателей земля, питание +12 В и отдельный для каждого провод - сигнал управления. Разведите питание для всех релюшек, подключите их. Теперь берем все сигнальные провода (я надеюсь, они у вас пронумерованы?) и вместе с землей тянем в сторону МК не более чем на 5 метров с открытыми проводами или 10 метров витой парой. Подключаем сигнальные провода к
Порты 0 и 1 не трогаем - на них у нас висит последовательный порт. Теперь напишем простейшую программу, которая будет принимать данные с компьютера и зажигать соответствующую лампу, висящую на одном из портов 2-9:

Чтобы зашить программу в наш контроллер, необходимо нажать на панели кнопку Upload и подождать. Сразу оговорюсь, пользователям старых версий платформ придется перезагрузить контроллер самостоятельно, нажав кратковременно кнопку Reset на плате сразу после нажатия кнопки Upload. Для проверки программы на отсутствие синтаксических (но никак не логических) ошибок необходимо нажать кнопку со стрелочкой - программа просто скомпилируется. При компиляции в окне информации выдается размер будущей программы - она должна уместиться в нашем контроллере. Для Atmega8 емкость памяти - 8кб, из которых 1кб занят начальным загрузчиком, позволяющим загружать наши программы без использования внешнего программатора. Для Atmega168 - 16 кб, для Atmega328 - 32 кб. Не думайте, что этого очень мало, наша программа занимает всего 2682 байта. Теперь откроем консоль Arduino, выберем соответствующую скорость передачи и дождемся приглашения к вводу. Введем двухзначное число из формата: первая цифра - номер лампы; вторая - ее состояние (1 - горит, 0 - не горит). Отправили и сразу получаем отчет, что такая-то лампа включена/выключена.

Наша программа - это всего лишь пример использования платформы. Каким именно образом вы будете использовать данную программу с данными возможностями - уже другой вопрос. В нее бы стоило добавить некоторую защиту от ввода неправильных данных, подобие меню, позволяющее включить или выключить сразу все лампы, вызвать некоторые специфические функции. Как именно вы будете вызывать эти специфические функции - пусть будет вашим домашним заданием. А вот саму специфическую функцию мы сейчас разберем.

Ведь, как известно, не за горами Новый год. Его приближение ознаменовано праздничным настроением. Давайте из кучи старых лампочек и нашей платы соз-дадим красивую иллюминацию, т.е. напишем программу «Елочная гирлянда».

Допустим, у нас имеется 8 лампочек или гирлянд, как вам больше нравится, и они подключены через наши релюшки к плате (только учтите, что максимальный ток гирлянды не должен превышать номинальный ток, указанный на реле, иначе оно быстро выйдет из строя). Для переключения ламп можно придумать огромное количество различных алгоритмов. За тем, какой должен в данный момент работать, следит переменная flag. Давайте реализуем следующие алгоритмы:

Реверсивные бегущие огни (flag=0).

Случайно-загорающаяся гирлянда (flag=1).

Включение и выключение ламп по нарастающей (flag=2).

Для реализации обоих алгоритмов создадим наш скелетик:

void setup(){}

void loop (){}

Пробежимся по логике работы всех алгоритмов. Суть первого в следующем: зажигаем первую лампу, ждем некоторое время, гасим ее и сразу зажигаем следующую. Дойдя до конца, зажигаем лампы в обратном порядке. Второй алгоритм работает на основе генератора случайных чисел, зажигая случайную лампу в нашем диапазоне, ждет некоторое время и выключает ее. Третий алгоритм зажигает все лампы накатом, постепенно, начиная с первой. Когда все лампы горят, последовательно их выключает.

Листинг программы:

Будем считать, что теперь мы достаточно хорошо изучили основные свойства микроконтроллеров. В следующий раз мы расширим возможности нашего «умного дома», подключим к нему датчики и наладим автоматику системы. Также напишем удобную программу на Qt, через которую с компьютера в графическом режиме будем следить за системой и управлять ей.