Привет, Мир!

Теория

Базовые принципы

Говоря упрощенно, все, что умеет делать микроконтроллер:

  • Выполнять программный код
  • Подавать логическое значение (высокий или низкий уровень напряжения) на некоторые свои ноги (пины).
  • Считывать логическое значение с некоторых своих пинов.
  • Считывать (с некоторой точностью) напряжение (некоторого допустимого диапазона) на своем пине через механизм АЦП - Аналого-Цифровой Преобразователь (ADC - Analog-to-Digital Converter)
  • Подавать напряжение на свои пины через механизм ЦАП - Цифро-Аналоговый Преобразователь (DAC - Digital-to-Analog Converter), или притворяться, что подает определенное напряжение через механизм ШИМ - Широтно-Импульсная Модуляция (PWM - Pulse-Width Modulation). Микроконтроллеры в нашем курсе (atmega 328p и esp8266) не имеют DAC на борту, поэтому вывод аналогового значения будет происходит генерацией ШИМ-сигнала.

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

// #include some_headers

main()
{
        DDRA |=1<<PA0;  /* PA0 will now be the output pin */
        while(1)
        {
                PORTA &= ~(1<<PA0);/* PA0 LOW */
                sleep(1000);/* 1000 ms delay */
                PORTA |=(1<<PA0); /* PA0 HIGH */
                sleep(1000);/* 1000 ms delay */
        }
}

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

В нашем курсе мы будем использовать мультиплатформенный фреймворк Arduino. Он имеет достаточно скромный API. Рассмотрим hello-world платформы:

void setup() {
    pinMode(LED_BUILTIN, OUTPUT); // Назначение пина 13 в качестве выходного
}

void loop() {
    digitalWrite(LED_BUILTIN, HIGH); // Установка пина 13 в состояние "1", светодиод загорается
    delay(1000);            // Задержка на 1000 миллисекунд
    digitalWrite(LED_BUILTIN, LOW);  // Установка пина 13 в состояние "0", светодиод гаснет
    delay(1000);
}
  • Функция setup() выполнится однократно при запуске микроконтроллера.
  • Функция loop() - бесконечный цикл
  • pinMode(pinNum,INPUT|INPUT_PULLUP|OUTPUT) - заставляет микроконтроллер сконфигурировать свой пин на ввод или вывод.
  • digitalWrite(pinNum, HIGH|LOW) - пишем логический 0 или 1 в сконфигурированный пин. LED_BUILTIN - это констана, на плате разработчика часто присутствует светодиод подпаянный к некоторому пину, для Arduino nano это 13. HIGH и LOW - это 1 и 0 соответственно. Все, что не
  • delay(1000) - задержка в 1000 миллисекунд или 1 секунду.

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

Пины

На Arduino nano пины, с которыми мы будем работать обозначены как:

  • D2 - D13 - в программе мы обращаемся к ним просто по номеру: digitalWrite(2, HIGH)
  • A0 - A7 - обращаемся к ним по соответсвующим константам: digitalWrite(A2, HIGH)

В свою очередь они делятся на:

  • Те, что поддерживают GPIO - то есть для них можно вызывать digitalWrite и прочие
  • Те, на которые выведен АЦП(ADC) - для них можно вызвать analogRead()
  • Умеющие выдавать ШИМ(PWM) сигнал - - для них можно вызвать analogWrite()
  • Те, на которые выведены хардварные интерфейсы (i2c, SPI)
    Arduino nano pinout|500
    Arduino nano pinout

Светодиоды (LED)

Светодиод, это в первую очередь диод - он пропускает ток только в одном направлении, как бонус еще и светится. Светодиод нелинейный элемент и имеет ряд характеристик, которые различаются в том числе в зависимости от цвета. В рамках курса характеристики нам не интересны, просто договоримся не путать полярность и всегда подключать через токоограничивающий резистор (чтобы ничего не сгорело).

Схема светодиода|=center=|600
Схема светодиода

Подключение светодиода через Т/О резистор|=center=|600
Подключение светодиода через Т/О резистор

Резисторы

Резисторы это проводники с большим сопротивлением. В нашем курсе они будут применяться как токоограничивающие для светодиодов (номиналом 220Om) и резисторы подтяжки для кнопок (номиналом 10kOm). На корпусе у них есть цветные колечки, они там не для красоты - если под рукой нет мультиметра, по ним определяется номинал - не иначе как издевательство над людьми. Повезло, что в наборе они несколько отличаются оттенком (тот что на 10к немного с зелена)

Резисторы из набора|500
Резисторы из набора

Подключаем кнопки

Кнопка это нормально разомкнутый проводник. Пока мы держим на ней палец, она проводит ток. На кнопке в нашем наборе 4 ноги - они просто продублированы.

Для считывания логических значений с пинов, Arduino предоставляет следующий функционал:

pinMode(btnPin, INPUT);
...
int val = digitalRead(btnPin);
... 
digitalWrite(LED_BUILTIN, val);

Попробуйте подсоединить провод к btnPin и потрогать его руками - микроконтроллер будет считывать нестабильное значение - наводоки с пальца или вообще из воздуха.

Понятно, что такое поведение нежелательно. Чтобы его избежать выполняется подтяжка (pullup, pulldown) - добавим резистор номиналом 10kOm между input пином, и противоположным уровнем относительно считываемого (если второй конец кнопки подсоединен к низкому уровню GND то подтягиваем к 5v и наоборот)


Микроконтроллер может выполнить подтяжку за нас, в случае AVR только pullup:

pinMode(btnPin, INPUT_PULLUP);

Тогда подключаем кнопку вторым пином к GND и обходимся без резистора. Учитывайте, что в этом случае ненажатая кнопка выдаст единицу, а нажатая ноль.

Breadboard

Нужен для создания макетов электронных схем. Внутри отверстия соединены следующим образом:

|400

Задачи

1.1 - Светофор

Основываясь на blink-example, собрать схему на трех светодиодах - красном, желтом и зеленом и заставить их работать по принципу автомобильного светофора (только с меньшими задержками):

Схема смены состояний светофора
Схема смены состояний светофора

Не забываем токоограничивающие регистры

1.2 - Переключаем светодиоды

Подключите к микроконтроллеру две кнопки и горстку светодиодов. Выбирайте кнопками какой из светодиодов сейчас горит (переключаемся влево-вправо).