Дорогие пидоры, благодаря цифровой электронике в наши дни
электронное управление чем угодно настолько простое, что для его
реализациине нужно ни оканчивать МИРЭА, ни читать
Искусство схемотехники ХоровицаиХилла (сильно переоценённая книжка,
на самом деле), ни уметь паять.
И я постараюсь вам это показать.
Hello World цифровой электроники мигание светодиодом мы пропустим и перейдём сразу к болееменее функциональной, практической задаче: управлению шторой.
Всё просто. Есть штора.
К ней приделам шаговый двигатель, работающий от драйвера ULN2003A. Обмоткам нужна большая мощность, а сигнальные линии цифровых устройств обычно маломощные, так что ULN2003A, пробрасывающий сигналы одинкодному.
ULN2003A на плате драйвера
Схема ULN2003A
У шторы есть переключатель Вверх/Стоп/Вниз.
Переключатель, вид спереди
Переключатель, вид сзади
А также два концевикаоптопары, которые должны не дать шторе
окончательно намотаться
на барабан или наоборот, свалиться вниз гармошкой (а затем
намотаться на барабан изнанкой наружу).
Концевик-оптопара на направляющей
Не распаянные концевики-оптопары
Итак, задача обработать сигналы от переключателя, концевиков и при необходимости покрутить шаговым двигателем в нужную сторону.
В чистом виде оптопары и переключатель выдают не совсем те сигналы, к которым приспособлена цифровая электроника.
Если мы просто подключимся к боковым контактам переключателя, мы не зафиксируем на них никакого напряжения. И даже если мы подключим центральный контакт переключателя к питанию, то на отключённой линии будет неопределённое состояние, возможно предыдущее, оставшееся после переключения, а возможно наведённое какойнибудь помехой. Поэтому нужно сделать так называемую подтяжку. Либо на контакте будет напряжение, приложенное к центральному контакту, либо там будет напряжение приложенное к подтягивающему резистору. Если подтягивающий резистор соединён с землёй, то, соответственно, на отключённом контакте будет ровно ноль вольт.
Подтяжки переключателя
Аналогично, с оптопарами. В оптопарах ИКдиод светит (либо не светит) в фототранзистор. Если мы присоединим фототранзистор эмиттером напрямую к земле, а коллектором к питанию через подтягивающий резистор, то в точке соединения фототранзистора и резистора напряжение будет зависеть от освещённости.
Без света фототранзистор закрыт, и в точке соединения с
резистором будет напряжение, подключённое к резистору.
Освещён фототранзистор начинает очень хорошо пропускать через себя
ток и в точке будет напряжение земли, то есть ноль.
Подтяжки фототранзисторов
Важное замечание!
Нижнее срабатывание концевикаоптопары это изменение с
логического нуля на логическую единицу.
Штора вошла в щель нижней оптопары, закрыла свет, фототранзистор
закрылся, резистор подтянул вывод к питанию.
Нижнее срабатывание концевикаоптопары это наоборот, изменение с
логической единицы на логический ноль.
Штора вышла из щели верхней оптопары, на фототранзистор начал
попадать свет, фототранзистор открылся и сам стянул напряжение
вывода к земле.
С входами разобрались. Теперь выходы. Для управления шаговым двигателем потребуется четыре цифровых линии. Суть управления в том, чтобы по очереди подавать на выводы катушки электродвигателя такие напряжения, чтобы намагниченный ротор последовательно разворачивался по направлению магнитного поля.
Последовательность сигналов управления шаговым двигателем
С электрической частью всё. Управлять нашей шторой мы будем при помощи платформы Arduino на базе микроконтроллера ATmega328P, запрограммированной на языке C.
Первым делом нам нужно определиться с тем, какие именно выводы мы задействуем и настроить их на вход или на выход.
Подключение входов и выходов к Arduino
Выписываем набор констант и в специальной функции setup (которую Arduino в обязательном порядке автоматически один раз запускает сразу после старта) указываем направление На вход/на выход.
const int btn_up = 7;
const int btn_down = 6;
const int opt_up = 5;
const int opt_down = 4;
const int coil_A = 10;
const int coil_B = 11;
const int coil_C = 12;
const int coil_D = 13;
void setup() {
pinMode(btn_up, INPUT);
pinMode(btn_down, INPUT);
pinMode(opt_up, INPUT);
pinMode(opt_down, INPUT);
pinMode(coil_A, OUTPUT);
pinMode(coil_B, OUTPUT);
pinMode(coil_C, OUTPUT);
pinMode(coil_D, OUTPUT);
}
Основная логика работы будет в специальной функции loop (которую
Arduino бесконечно повторяет раз за разом).
Здесь логика прямо как человеческом языке:
- Если переключатель нажат вверх И верхний концевик пока не
сработал,
крутись вверх на один шаг, затем сделай небольшую паузу
- Если переключатель нажат вниз И нижний концевик пока не
сработал,
крутись вниз на один шаг, затем сделай небольшую паузу
void loop() {
if(is_btn_up && is_not_opt_up){
rotate_up();
delay(delay_value);
}
if(is_btn_down && is_not_opt_down){
rotate_down();
delay(delay_value);
}
}
Правда нам теперь нужно определить, что значит переключатель нажат вверх, ну, то есть что такое is_btn_up?
Для этого перед функцией loop пишем:
#define is_btn_up digitalRead(btn_up)
#define is_btn_down digitalRead(btn_down)
#define is_not_opt_up !digitalRead(opt_up)
#define is_not_opt_down digitalRead(opt_down)
По сути, на место is_btn_up ставится функция чтения логического состояния на указанном входе digitalRead. Аргументом (входным параметром) указывается номер входа, для btn_up это 7, а значением функции является логическое состояние.
Остаётся добавить логику работы функций rotate_up и
rotate_down.
Тут следует отметить, что очерёдность подачи напряжения на обмотки
двигателя возможно рассчитывать на лету, но проще заготовить
расположение этих напряжений для всех шагов заранее, создав массив
(перед функцией loop):
const int phase_array[4] = {B00110000,
B00011000,
B00001100,
B00100100};
Для функций вращения нам потребуется также переменная, хранящая
текущий номер шага (всего четыре шага, нумерация от нуля до
трёх),
а также константа, отвечающая за скорость вращения мотора (она
использовалась внутри loop в качестве аргумента функции delay):
int phase_current = 0;
const int delay_value = 3;
Функция вращения наверх будет выглядеть вот так:
void rotate_up() {
phase_current = phase_current + 1;
if(phase_current > 3) phase_current = 0;
PORTB = phase_array[phase_current];
}
К текущему номеру шага прибавляем единицу.
Если номер шага превысил 3, значит приравниваем его к 0.
Затем вывыводим на выходы Arduino заготовленную для данного шага
константу из массива.
Для вращения вниз логика будет обратная:
вычитаем из номера шага единицу,
если номер шага стал меньше 0, приравняем его к 3,
ну и выводим на выходы константу.
void rotate_down() {
phase_current = phase_current - 1;
if(phase_current < 0) phase_current = 3;
PORTB = phase_array[phase_current];
}
Готово!
Компилируем, записываем прошивку в Arduino, всё работает: