# Входы и выходы микроконтроллера ## Управление внешним устройством на примере реле Сейчас мы укажем какие изменения необходимо привнести в ход [лабораторной работы 1.2](https://myitacademy.ru/edu/mod/book/view.php?id=520), чтобы выполнить её на имеющимся в нашем распоряжении оборудовании (Unwired Devices). Для этого задания нам понадобятся: - радиомодуль UNWR с платой-адаптером UMDK-RF ![ud-min2](/assets/images/iot-academy/ud-min2.png) - модуль с двумя электромагнитными реле UMDK-2RDC ![umdk-2rdc](/assets/images/iot-academy/umdk-2rdc.png) <div class='danger'> Обратите внимание, что модули Unwired Devices имеют ключ, показывающий какой стороной нужно подключать модули один к другому. Ключ у всех модулей **всегда** должен быть с одной стороны! </div> Модуль UMDK-2RDC оснащен двумя электромагнитными реле Omron G6D-1A, способными коммутировать нагрузку постоянного или переменного тока (до 250 В переменного тока и ток до 5 А). Модуль UMDK-2RDC может несколько отличаться от приведенного на рисунке выше, так как допускает установку переключателя, позволяющего для каждого из реле выбирать один из трёх GPIO. При отсутствии такого переключателя модуль конфигурируется перемычками на использования `GPIO16` и `GPIO17`. В нашей лаборатории модули с переключателями. ![umdk-2rdc-var](/assets/images/iot-academy/umdk-2rdc-var.png) Возможно сами переключатели еще заклеены защитной пленкой - удалите её, если это никто не сделал до вас. <div class='danger'> Обратите внимание, что для каждого реле **только один** переключатель должен быть установлен в положение `on`, все остальные должны быть в противоположном положении, то есть `off`. </div> ![onoff](/assets/images/iot-academy/onoff.png) Соответствие используемых портов микроконтроллера STM32L151 и обозначение портов ввода-вывода на платах Unwired Devices для каждого из реле приведено в таблице. | Реле | GPIO (UMDK-RF) | Порт STM32L151 | |:--------:|:-----------------:|:---------------:| | K1 | `GPIO5` | `PA_5` | | K1 | `GPIO7` | `PB_9` | | K1 | `GPIO17` | `PA_15` | | K2 | `GPIO4` | `PA_4` | | K2 | `GPIO6` | `PB_8` | | K2 | `GPIO16` | `PB_3` | ### Задача * Измените программу, которую вы написали в прошлый раз (мигалка светодиодом), так, чтобы одновременно со светодиодом включалось и выключалось реле. Подсказка. Вам нужно задействовать ещё один цифровой выход. * Доработайте программу управления реле так, чтобы первое реле включалось (и отключалось) с каждым третьим включением светодиода на плате, а второе - с каждым пятым. ## Считываем нажатие кнопки Для этого задания вам понадобится: - радиомодуль UNWR с платой-адаптером UMDK-RF ![ud-min3](/assets/images/iot-academy/ud-min3.png) В отличии от платы [STM32Nucleo](https://www.st.com/en/evaluation-tools/stm32-nucleo-boards.html) мы будем считывать состояние встроенной кнопки `SAFE`, которая подключена к порту `PB_1` микроконтроллера. Соответственно, код программы в нашем случае будет таким: ```cpp #include "mbed.h" DigitalIn mybutton(PB_1); DigitalOut myled(PB_0); int main() { Serial pc(PA_9, PA_10); mybutton.mode(PullUp); while(1) { pc.printf("Button state is: %d\n\r", mybutton.read()); if (mybutton == 0) { // Button is pressed myled = !myled; // Toggle the LED state wait_ms(200); // 200 ms } } } ``` ### Задача Можно пробовать решить задачу посложнее. Установите модуль кнопок (соблюдая позицию ключа): ![umdk-4btn](/assets/images/iot-academy/umdk-4btn.png) Теперь вы можете получать информацию с четырех дополнительных кнопок через соответствующие порты | Кнопка | GPIO (UMDK-RF) | Порт STM32L151 | |:--------:|:-----------------:|:---------------:| | S1 | `GPIO7` | `PB_9` | | S2 | `GPIO6` | `PB_8` | | S3 | `GPIO5` | `PA_5` | | S4 | `GPIO4` | `PA_4` | > ![Важно][danger] Одновременное подключение модуля кнопок UMDK-4BTN и модуля реле UMDK-2RDC, сконфигурированного на использование портов `GPIO4` - `GPIO7`, **выведет микроконтроллер из строя!**. Напишите программу, проверяющую нажатие каждой из четырех кнопок модуля UMDK-4BTN. P.S. Это фактически [задание 1.2.5 основного курса](https://myitacademy.ru/edu/mod/book/view.php?id=520&chapterid=505), и на наш взгляд его целесообразнее проделать именно сейчас. ## Выдача ШИМ-сигнала с платы Эта часть работы для нашего оборудования претерпит лишь незначительные изменения. Нам понадобится радиомодуль UNWR с платой-адаптером UMDK-RF ![ud-min3](/assets/images/iot-academy/ud-min3.png) И самый простой пример работы с ШИМ будет отличаться только портом, к которому подключен светодиод: ```cpp #include "mbed.h" PwmOut PWM1(PB_0); int main() { PWM1.period(0.010); // set PWM period to 10 ms PWM1=0.5; // set duty cycle to 50% } ``` А вот для управления яркостью светодиода с клавиатуры компьютера рекомендуем посмотреть другой пример, и сказать чем же он отличается: ```cpp // host terminal LED dimmer control #include "mbed.h" int main() { Serial pc(PA_9, PA_10); // tx, rx PwmOut led(PB_0); float brightness = 0.5; const float brightness_step = 0.05f; const int freq[] = {1, 5, 10, 25, 30, 35, 40, 50, 75, 100, 250, 500, 1000}; // Hz int f_length = sizeof(freq) / sizeof(freq[0]); int f_ind = 3; pc.printf("MultiTech xDot board\n\n\r"); pc.printf("Control of LED dimmer by host terminal\n\r"); pc.printf("press '+' or '-' for change duty time\n\r"); pc.printf("press '<' or '>' for change frequency\n\r"); pc.printf("Frequency = %d, Duty = %1.2f\n\r", freq[f_ind], brightness); while(1) { led.period_us( 1000000L / freq[f_ind] ); led = brightness; char c = pc.getc(); wait(0.001); switch (c) { case '+': brightness += brightness_step; break; case '-': brightness -= brightness_step; break; case '<': f_ind--; break; case '>': f_ind++; break; } if (brightness > 1.0f) brightness = 1.0f; if (brightness < 0.0f) brightness = 0.0f; if(f_ind >= f_length) f_ind = 0; if(f_ind < 0) f_ind = f_length - 1; switch (c) { case '+': case '-': pc.printf("Duty = %1.2f\n\r", brightness); break; case '<': case '>': pc.printf("Frequency = %d\n\r", freq[f_ind]); break; case 'i': case 'I': pc.printf("Frequency = %d, Duty = %1.2f\n\r", freq[f_ind], brightness); break; } } } ``` ### Задача - Выполнить всё то, что написано в [основной ветке курса](https://myitacademy.ru/edu/mod/book/view.php?id=520&chapterid=503) - Поэкспериментируйте с различными вариантами частоты ШИМ. Оцените насколько регулирование яркости свечения светодиода в каждом из случаев комфортно для человеческого глаза (незаметно мерцание). ## Считывание аналогового сигнала ~~на примере датчика влажности почвы~~ С аналоговыми датчиками почвы прямо беда! Да и вообще с аналоговыми датчиками у нас в лаборатории не густо. Но это не повод отчаиваться и оставлять [материал](https://myitacademy.ru/edu/mod/book/view.php?id=520&chapterid=504) без внимания. Особенностью аналоговых датчиков является то, что на их выходах генерируется непрерывный (*аналоговый*) сигнал, значение уровня которого является функцией времени. Этим аналоговый датчик и отличается от цифрового, где на выходе присутствует некоторая последовательность бит данных, кодирующих результаты измерения, и в самом минимальном варианте имеющих всего два значения `0` или `1`. Пожалуй, самым простым аналоговым датчиком является переменный резистор: ![wh148-1](/assets/images/iot-academy/wh148-1.png) Напомним, что он фактически представляет собой делитель напряжения ![Rvar](/assets/images/iot-academy/Rvar.png) и при подключении крайних выводов к источнику 3.3&nbsp;В, напряжение на среднем выводе (движок переменного резистора) относительно общего сигнала Uвых&nbsp;=&nbsp;3.3&nbsp;*&nbsp;R2/(R1&nbsp;+&nbsp;R2), где R1 и R2 - это, соответственно, сопротивления между средним и верхним, и средним и нижним выводами. Общее сопротивление при этом не меняется, в каком бы положении ни находился движок этого резистора, R1&nbsp;+&nbsp;R2&nbsp;=&nbsp;Rном&nbsp;=&nbsp;const. Нам подойдет практически любой переменный резистор, с номиналом от 1&nbsp;кОм и выше. Для обработки аналоговых величин в микроконтроллерах используется специальный модуль - АЦП (Аналогово-Цифровой Преобразователь). На платах Unwired Devices аналоговые значения можно подавать на следующие выводы (перечеркнутые значения не поддерживаются платой [MultiTech xDot](https://os.mbed.com/platforms/MTS-xDot-L151CC/), а потому для компиляции программы через [on-line компилятор](https://os.mbed.com/ide/) их не нужно использовать): | GPIO (UMDK-RF) | Порт STM32L151 | |:-----------------:|:---------------:| | `GPIO4` | `PA_4` | | `GPIO5` | `PA_5` | | ~~`GPIO24`~~ | ~~`PA_1`~~ | | `GPIO25` | `PA_2` | | `GPIO26` | `PA_3` | | ~~`GPIO27`~~ | ~~`PA_6`~~ | | ~~`GPIO28`~~ | ~~`PA_7`~~ | Для подключения переменного резистора можно воспользоваться беспаечной макетной платой и тремя проводками. ![unwr_r](/assets/images/iot-academy/unwr_r.png) ![sltwV](/assets/images/iot-academy/sltwV.png) > ![Важно][danger] Только вспомните как соединены контактные площадки на макетной плате! Средние точки - поперек, а точки между красными и синими линиями - вдоль! > **Неправильное подключение может привести к короткому замыканию и выходу платы из строя!** Можно вообще не использовать макетную плату, благо к такому переменному резистору провода можно подключить непосредственно. Только клеммник нужно повернуть на 90 градусов: ![r_wire](/assets/images/iot-academy/r_wire.png) Если подключим левую ножку переменного резистора к плате UMDK-RF к контакту, обозначенному `GND`, правую - к контакту `3V3`, а среднюю - к контакту `4`, то кодом для работы с АЦП будет следующим: ```cpp #include "mbed.h" AnalogIn my_adc(PA_4); // GPIO4 DigitalOut led(PB_0); Serial pc(PA_9, PA_10); // tx, rx int main() { pc.printf("\nSTM32 ADC example\n\r"); while(1) { pc.printf("ADC read = %f\n\r", (my_adc.read()*100)); led = !led; wait_ms(1000); } } ``` Если вы справились со всеми задачами достаточно быстро, то мы можем вам предложить самостоятельно подключить аналоговый датчик освещенности ![pht_module](/assets/images/iot-academy/pht_module.jpg) У нас в лаборатории таких есть две штуки. Схема подключения - все те же три провода, к тем же контактам платы UMDK-RF | Модуль | UMDK-RF | |--------|---------| | VCC | 3V3 | | AO | 4 | | DO | - | | GND | GND | [**^ К оглавлению**](iot/samsung/archive/2020) <link rel="stylesheet" href="assets/css/danger.css" />