LXF163: Arduino: зажигаем светодиоды
Olkol (обсуждение | вклад) (→Один из нескольких) |
Olkol (обсуждение | вклад) (→Один из нескольких) |
||
(не показана 1 промежуточная версия 1 участника) | |||
Строка 203: | Строка 203: | ||
if (data & (1<<y)) { | if (data & (1<<y)) { | ||
− | dolight(y); | + | dolight(y);}}} |
− | + | ||
− | } | + | |
− | + | ||
− | } | + | |
− | + | ||
− | } | + | |
Здесь два цикла. Один цикл (с переменной y) определяется количеством светодиодов, которые у нас есть. В каждой итерации значение бита (сдвинутое, чтобы оказаться в нужном месте) сравнивается с байтом, который мы назвали data – подробнее о нем чуть позже. Если значения совпадают, соответствующий светодиод включается. | Здесь два цикла. Один цикл (с переменной y) определяется количеством светодиодов, которые у нас есть. В каждой итерации значение бита (сдвинутое, чтобы оказаться в нужном месте) сравнивается с байтом, который мы назвали data – подробнее о нем чуть позже. Если значения совпадают, соответствующий светодиод включается. | ||
Строка 267: | Строка 261: | ||
if (data & (1<<y)) { | if (data & (1<<y)) { | ||
− | dolight(y); | + | dolight(y);}}}} |
− | + | ||
− | } | + | |
− | + | ||
− | } | + | |
− | + | ||
− | } | + | |
− | + | ||
− | } | + | |
Этот простой цикл перебирает 12 значений битовых масок из массива sequence. В конце каждой итерации также мигнет светодиод на плате – так мы сможем обнаружить неправильные соединения проводников или странное поведение схемы. Код в этом виде работает, но кое-что можно изменить. Во-первых, на время, в течение которого горят светодиоды в одной итерации, слабо влияет их количество, но об этом времени стоит позаботиться, чтобы избежать более серьезной проблемы. | Этот простой цикл перебирает 12 значений битовых масок из массива sequence. В конце каждой итерации также мигнет светодиод на плате – так мы сможем обнаружить неправильные соединения проводников или странное поведение схемы. Код в этом виде работает, но кое-что можно изменить. Во-первых, на время, в течение которого горят светодиоды в одной итерации, слабо влияет их количество, но об этом времени стоит позаботиться, чтобы избежать более серьезной проблемы. | ||
Строка 281: | Строка 267: | ||
В общем случае такие действия лучше всего оформлять в виде процедуры прерывания, в зависимости от того, что вам нужно. Затем она может получить набор значений sequence из массива или постоянно проходить по «шаблону», заданному в глобальной переменной – ее затем можно будет изменить в основном коде. Мы говорили о таймерах и прерываниях во многих из предыдущих статей, и вы должны суметь сделать что-нибудь на скорую руку! | В общем случае такие действия лучше всего оформлять в виде процедуры прерывания, в зависимости от того, что вам нужно. Затем она может получить набор значений sequence из массива или постоянно проходить по «шаблону», заданному в глобальной переменной – ее затем можно будет изменить в основном коде. Мы говорили о таймерах и прерываниях во многих из предыдущих статей, и вы должны суметь сделать что-нибудь на скорую руку! | ||
− | Недостатки чарлиплексирования | + | ===Недостатки чарлиплексирования=== |
Хотя чарлиплексирование позволяет изящно и эффективно использовать выходы, ряд проблем ограничивают его достоинства. Самая большая из них – не слишком хорошее масштабирование. По мере увеличения количества светодиодов они не только горят все более тускло (светятся в течение меньшего интервала времени), но и код для управления ими занимает все больше и больше доступного процессорного времени. Другой недостаток проявляет себя, если один из светодиодов выходит из строя. Неисправности светодиодов не всегда означают только то, что они не горят – сюда включается и нежелательное влияние на схему, например, непредусмотренная емкость, утечки тока и прочие неприятные вещи. В этих случаях из-за одного неработающего светодиода весь дисплей может начать вести себя странно. | Хотя чарлиплексирование позволяет изящно и эффективно использовать выходы, ряд проблем ограничивают его достоинства. Самая большая из них – не слишком хорошее масштабирование. По мере увеличения количества светодиодов они не только горят все более тускло (светятся в течение меньшего интервала времени), но и код для управления ими занимает все больше и больше доступного процессорного времени. Другой недостаток проявляет себя, если один из светодиодов выходит из строя. Неисправности светодиодов не всегда означают только то, что они не горят – сюда включается и нежелательное влияние на схему, например, непредусмотренная емкость, утечки тока и прочие неприятные вещи. В этих случаях из-за одного неработающего светодиода весь дисплей может начать вести себя странно. | ||
Но не сбрасывайте его со счетов – для малого количества светодиодов оно очень удобно и позволяет сэкономить на добавочных компонентах, энергопотреблении и пространстве. Оно годится не только для зажигания светодиодов. С подходящими компонентами можно сберечь несколько контактов для управления двигателями (которым не нужно несколько высоких уровней сразу) или для входов – эти неудобные матричные клавиатуры эффективнее сканировать с несколькими диодами и подходящей схемой Чарли или целого массива других входов. | | Но не сбрасывайте его со счетов – для малого количества светодиодов оно очень удобно и позволяет сэкономить на добавочных компонентах, энергопотреблении и пространстве. Оно годится не только для зажигания светодиодов. С подходящими компонентами можно сберечь несколько контактов для управления двигателями (которым не нужно несколько высоких уровней сразу) или для входов – эти неудобные матричные клавиатуры эффективнее сканировать с несколькими диодами и подходящей схемой Чарли или целого массива других входов. | |
Текущая версия на 02:33, 21 октября 2018
|
|
|
Электроника. Аппаратные проекты с открытым кодом, расширяющие ваш кругозор.
Содержание |
[править] Arduino: Да будет свет
Ник Вейч изо всех сил старается не ослепнуть от блеска, с которым он зажег столько светодиодов всего на нескольких выходах.
В туманном прошлом, когда у всех нас на ковре было чуть меньше ожогов от припоя, мы призадумались об использовании 8-сегментных дисплеев – и читатели предложили нам мультиплексировать выходы. Это хорошее предложение с рядом преимуществ, но оно имеет и недостатки.
Главный недостаток здесь в том, что на управление дисплеем нужно время. Если заставить Arduino постоянно менять значения сегментов, у него не останется времени ни на что другое. Поэтому если управление дисплеями – не главная задача вашей схемы на Arduino, мультиплексирование выходов эффективно только в небольшом, более управляемом масштабе. Существует несколько способов мультиплексирования (то есть, использования одного входа/выхода для выполнения нескольких задач), и один из самых простых – мультиплексирование методом Чарли.
[править] Чарлиплексирование
Одно из ограничений при подключении светодиодов к Arduino – контакты. Если подключать по светодиоду на каждый вывод, выводы закончатся довольно скоро. В предыдущих статьях мы рассмотрели способы увеличения количества адресуемых выводов, обычно с помощью дополнительных микросхем, например, сдвиговых регистров, но есть и другой метод, дополнительных микросхем не требующий – чарлиплексирование.
Назван метод именем Чарли Аллена [Charlie Allen], инженера из компании Maxim, который столкнулся с той же проблемой, пытаясь управлять дисплеями со множеством светодиодов. Основная идея этого метода проста: контакты Arduino можно считать выходами, но они также и входы. Представьте себе следующую простую схему:
» Схема 1 Два контакта, два выхода. С их переводом в «единицу» светодиоды загораются. Все просто. Но теперь подумайте о том, что выходы могут быть в «единице» или в «нуле», а светодиоды– будучи диодами – как-никак работают однонаправленно.
Возможна и такая схема:
» Схема 2 Важнейшее отличие в том, что теперь состояния «единица» и «ноль» применяются для управления выводами. Когда один в «единице», а другой в «нуле», светодиод загорается. Поменяйте их местами, и загорится другой светодиод.
Мило, правда? Но особо прыткие в подсчетах заметили, что светодиодов не стало больше. В «обычной» схеме мы зажгли два светодиода. В новой схеме их все еще два. Да, но этот шаг необходим, чтобы перейти к следующему – иначе он взорвет ваш мозг. При увеличении числа контактов до трех, схема станет такой:
» Схема 3 Это большой шаг вперед. С тремя выходами и замысловатой схемой мы можем управлять шестью светодиодами.
Здесь важно отметить: чтобы это заработало, нам придется воспользоваться тем, что контакты Arduino могут находиться в трех состояниях. Вам знакомы «единица» и «ноль», но, конечно, есть и еще одно – состояние большого сопротивления (или состояние входа), в котором контакт по сути никак не влияет на схему. Переведя один из контактов в это состояние (и таким образом отключив его) и переводя другие два в «единицу» или «ноль», мы можем обращаться к каждому из шести светодиодов.
[править] Выполняем вычисления
Если поразмыслить, то у нас есть два варианта в наборе из трех пар светодиодов (три варианта), но они могут работать в любом направлении, что дает нам 2 × 3, или 6. Углубившись в математику, можно вывести формулу для N контактов – это N2-N или N(N-1) светодиодов. В большинстве случаев сложность заключается в том, чтобы нарисовать схему и запомнить, как располагать светодиоды. Задачу определенно облегчает их расположение в парах в противоположном направлении. Да, и не забудьте добавить к каждому контакту последовательно резистор, для ограничения тока. Так как в схеме их всегда два, выберите значение сопротивления, которым обычно пользуетесь, и разделите его на два. Теперь переходим к управлению светодиодами.
Конечно, манипуляции с тремя портами для управления набором светодиодов несколько обременительны, но возможны. Настоящие трудности начнутся, когда вы поймете, что для этого недостаточно просто записать в них значения, так как мы работаем с логикой с тремя состояниями (1,0,X). Осложнение еще в том, что для изменения этих значений нужно использовать различные вызовы из Arduino (даже если пойти коротким путем и записывать значения напрямую в адреса портов, вы обнаружите, что все равно нужно изменять другой регистр). Как сделать это для нашей схемы с тремя контактами? Допустим, это контакты 10, 11 и 12 Arduino. Прежде всего инициализируем их в функции setup():
void setup() {
pinMode(10, OUTPUT);
pinMode(12, OUTPUT);
pinMode(11, OUTPUT);
delay(6000);
}
В процессе работы мы будем изменять режимы одного из этих контактов, но нет ничего страшного в том, чтобы задать все режимы с самого начала, чтобы мы видели, какие контакты используются. Зачем здесь задержка? Это просто привычка, появившаяся у меня после того, как я часами пытался оживить неработающие платы Arduino. Задержка дает последовательному интерфейсу время заметить, что его пытаются перепрограммировать. От души рекомендую делать так же. Теперь перейдем собственно к зажиганию светодиодов:
void loop() {
// light each in sequence
digitalWrite(11, HIGH);
digitalWrite(12, LOW);
pinMode (10, INPUT);
delay(100);
pinMode (10, OUTPUT);
digitalWrite(11, LOW);
digitalWrite(12, HIGH);
pinMode (10, INPUT);
delay(100);
pinMode (10, OUTPUT);
digitalWrite(11, HIGH);
digitalWrite(10, LOW);
pinMode (12, INPUT);
delay(100);
pinMode (12, OUTPUT);
…
Здесь можно остановиться (конечно, остались еще три сочетания контактов, но ход мысли нам теперь ясен, к тому же вы всегда можете заглянуть в код на DVD, если не напишете его сами). Для каждого светодиода нам нужно установить один вывод в «единицу», другой в «ноль», а третий – в состояние входа. По сути это состояние отключает его – это лишь состояние высокого сопротивления, но для остальной схемы контакт выглядит выключенным, если не пытаться прочесть с него данные. Задержка позволяет нам увидеть, как светодиод загорается, потом мы переводим вывод в состояние «отключено», так что не запутаемся. Если подумать, то пример можно улучшить, последовательно обрабатывая два светодиода, для зажигания которых нужно отключить определенный контакт; это сэкономит несколько вызовов. Но это не главное.
Бывают, конечно, ситуации, в которых нужно пройти по всем имеющимся светодиодам для создания стробоскопического эффекта, как на автомобиле из сериала «Рыцарь дорог», но чаще нужно только включать и выключать определенные светодиоды.
Эта длинная запись в коде – не лучший вариант, и для управления светодиодами нам нужен способ покруче. Простой вариант – массивы. Если задать несколько массивов со значениями контакта, их можно использовать как аргументы функции, включающей и выключающей светодиоды.
uint8_t cathode[6] = {12,11,10,11,12,10};
uint8_t anode[6] = {11,12,11,10,10,12};
uint8_t off[6] = {10,10,12,12,11,11};
Тип uint8_t – то же, что и байт, но это более явное определение. Как видите, мы создали три массива – для катода, анода и «выключенного» контакта. Они содержат числовые значения контактов для каждого светодиода последовательно. Например, если нужно включить светодиод № 3, то контакт 11 нужно перевести в «ноль», контакт 10 – в «единицу», а контакт 12 – в состояние входа.
Вы можете кое-что улучшить в этом коде, но все это вопрос компромисса. Например, можно оставить только массивы для катода и анода, так как третий контакт в любом случае выключен. Верно, но тогда в коде придется брать два существующих значения и определять, значение какого контакта не задано. Либо можно «выключить» все контакты, а затем включить те, которые используются. Оба варианта возможны, но нежелательны.
На данном этапе это несущественно, но в целом мы хотим, чтобы код, включающий и выключающий входы, работал максимально быстро. Дополнительные действия и вычисления приведут лишь к трате циклов таймера и к нежелательным переключениям, которые могут обусловить и мерцание.
Так или иначе, вот наш главный цикл, который выполняет ту же задачу, что и прежде – включает светодиоды последовательно:
void loop() {
for (int i=0;i<6;i++){
pinMode(off[i],INPUT);
pinMode(cathode[i],OUTPUT);
digitalWrite(cathode[i],LOW);
pinMode(anode[i],OUTPUT);
digitalWrite(anode[i],HIGH);
delay(250);
}
}
Этот код ничего не предполагает – он просто задает состояния выключенного контакта, затем проверяет, что состояния двух остальных контактов заданы верно, и записывает в них значения. Хотя для последовательного включения светодиодов мы обернули это в цикл, можно оформить это и в виде функции:
void loop() {
for (int i=0;i<6;i++){
lightlamp(i);
delay(250);
}
}
void lightlamp(int i){
pinMode(off[i],INPUT);
pinMode(cathode[i],OUTPUT);
digitalWrite(cathode[i],LOW);
pinMode(anode[i],OUTPUT);
digitalWrite(anode[i],HIGH);
}
что несомненно упросит использование этого кода в более сложных случаях.
[править] Один из нескольких
Думаю, вы согласитесь: это здорово. Теперь без дополнительных схем можно управлять, например, 12 светодиодами всего с четырех контактов. Однако на данный момент у нашего плана есть маленький недостаток. Для простых случаев он и правда удобен. Если нужно зажечь светодиод – вы его зажигаете. Но когда нужно зажечь несколько светодиодов одновременно, исходный метод – по одному контакту на каждый светодиод – лучше. В основе нашей текущей системы – «адресация» светодиодов с помощью контактов благодаря мультиплексированию данных. Теперь нам нужно полностью мультиплексировать выход. Физически адресовать несколько светодиодов сразу невозможно, но можно переключаться между ними так быстро, что будет казаться, что они горят одновременно.
Интересно, что такое мультиплексирование светодиодов стало популярным не только из-за ограничений адресации, но и из-за экономии энергии. Если один светодиод потребляет в среднем около 20 мА, то шесть будут потреблять 120 мА. Если взять эквивалент схеме с чарлиплексированием с шестью контактами, мы получим 6 × 5 × 20 мА = 600 мА, а это больше, чем обеспечивается стандартным USB-подключением. Вряд ли несколько светодиодов могут причинить столько неприятностей (разумеется, к ним можно подключить внешний источник питания), но если учесть, что мультиплексирование может снизить энергопотребление на 97 %, это хорошая идея, особенно для схем с питанием от батарейки.
Внесем несколько простых изменений в функцию включения светодиодов и будем подавать на каждый из них небольшой импульс вместо того, чтобы просто включать его:
void dolight(int light_number){
pinMode(off[light_number],INPUT);
pinMode(cathode[light_number],OUTPUT);
digitalWrite(cathode[light_number],LOW);
pinMode(anode[light_number],OUTPUT);
digitalWrite(anode[light_number],HIGH);
delay(2);
pinMode(cathode[light_number],INPUT);
pinMode(anode[light_number],INPUT);
}
Этот код очень похож на предыдущий, но на сей раз перед выходом он отключает свет после короткой задержки. Возможно, вам придется установить значение задержки опытным путем в зависимости от числа светодиодов в вашей схеме.
Теперь мы можем включать светодиод на короткий период времени, и пора подумать о том, как зажигать несколько светодиодов одновременно. Очевидное решение – цикл. Если у нас есть набор значений, например, битовая маска, для светодиодов, которые нужно зажечь, мы можем пройтись по ним в цикле, включая их.
На самом деле, делать это будет нужно неоднократно. Если нужно включить два светодиода на секунду, лучше включить каждый на 1/500 секунды 250 раз, чем один раз на полсекунды. Имея период одного включения светодиода, можно пройтись по циклу заданное количество раз, и в итоге мы получим заданную общую продолжительность включения. Это звучит несколько сложнее, чем есть на самом деле:
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
byte data = sequence[index];
for (int cycle=0; cycle<50; ++cycle){
for (int y=0; y<5; ++y) {
if (data & (1<<y)) {
dolight(y);}}}
Здесь два цикла. Один цикл (с переменной y) определяется количеством светодиодов, которые у нас есть. В каждой итерации значение бита (сдвинутое, чтобы оказаться в нужном месте) сравнивается с байтом, который мы назвали data – подробнее о нем чуть позже. Если значения совпадают, соответствующий светодиод включается.
Внешний цикл под управлением переменной cycle просто выполняется заданное количество раз. Это означает, что в каждой итерации все необходимые светодиоды загораются и гаснут нужное количество раз, создавая впечатление, что они горят.
Единственная загадка – переменная byte. Как видно из первой строки кода, мы получаем ее из другого массива. Это просто массив битовых масок, отражающий последовательность включения светодиодов. Мы записали ее в двоичной нотации, так ее гораздо проще понять:
uint8_t sequence[12] ={
B00000001,
B00000011,
B00000111,
B00001111,
B00011111,
B00111111,
B00100000,
…
}
Итак, нам нужно только передать эти битовые маски функции, которая будет отображать их в течение определенного периода времени.
void loop() {
for (int i=0;i<12;i++){
dosequence(i);
delay(500);
digitalWrite(13,HIGH);
delay(1);
digitalWrite(13,LOW);
}
}
void dosequence(int index){
byte data = sequence[index];
for (uint8_t cycle=0; cycle<50; ++cycle){
for (uint8_t y=0; y<5; ++y) {
if (data & (1<<y)) {
dolight(y);}}}}
Этот простой цикл перебирает 12 значений битовых масок из массива sequence. В конце каждой итерации также мигнет светодиод на плате – так мы сможем обнаружить неправильные соединения проводников или странное поведение схемы. Код в этом виде работает, но кое-что можно изменить. Во-первых, на время, в течение которого горят светодиоды в одной итерации, слабо влияет их количество, но об этом времени стоит позаботиться, чтобы избежать более серьезной проблемы.
В общем случае такие действия лучше всего оформлять в виде процедуры прерывания, в зависимости от того, что вам нужно. Затем она может получить набор значений sequence из массива или постоянно проходить по «шаблону», заданному в глобальной переменной – ее затем можно будет изменить в основном коде. Мы говорили о таймерах и прерываниях во многих из предыдущих статей, и вы должны суметь сделать что-нибудь на скорую руку!
[править] Недостатки чарлиплексирования
Хотя чарлиплексирование позволяет изящно и эффективно использовать выходы, ряд проблем ограничивают его достоинства. Самая большая из них – не слишком хорошее масштабирование. По мере увеличения количества светодиодов они не только горят все более тускло (светятся в течение меньшего интервала времени), но и код для управления ими занимает все больше и больше доступного процессорного времени. Другой недостаток проявляет себя, если один из светодиодов выходит из строя. Неисправности светодиодов не всегда означают только то, что они не горят – сюда включается и нежелательное влияние на схему, например, непредусмотренная емкость, утечки тока и прочие неприятные вещи. В этих случаях из-за одного неработающего светодиода весь дисплей может начать вести себя странно.
Но не сбрасывайте его со счетов – для малого количества светодиодов оно очень удобно и позволяет сэкономить на добавочных компонентах, энергопотреблении и пространстве. Оно годится не только для зажигания светодиодов. С подходящими компонентами можно сберечь несколько контактов для управления двигателями (которым не нужно несколько высоких уровней сразу) или для входов – эти неудобные матричные клавиатуры эффективнее сканировать с несколькими диодами и подходящей схемой Чарли или целого массива других входов. |