Совместное использование пина

Бывает такая ситуация что свободных пинов на контролере не осталось или их просто мало как в случае с ATtiny 85, а нужно прицепить еще пару кнопок или даже больше чем пару. И что в этом случае делать? В этом случае может помочь аналоговый вход с 10-битным аналого-цифровым преобразователем (АЦП). Напряжение, проданное на этот вход будет преобразовано в значение от 0 до 1023, где 0 соответствует 0 В, а 1023 — опорному напряжению, заданному с помощью analogReference(). Как правило оно равно напряжению питания — 5В. Напряжение питания и разрядность могут изменяться в зависимости от платы и настроек, но суть совместного использования пина остается той же: мы можем заставить разные кнопки подавать различное напряжение на аналоговый вход и по прочитанному значению определять какая из кнопок была нажата. Или даже комбинацию кнопок. Но давайте все по порядку.

Простой делитель напряжения.

Самый простой способ, простой способ как получить разные напряжения для разных кнопок это использование делителя напряжения как это показано на схеме ниже.

Кнопки на простом делителе напряжения.

Используя последовательно соединенные сопротивления одинакового номинала можно получить напряжения с равномерным шагом. На данном примере это 5, 4, 3, 2, 1, 0 вольт. Равный шаг по напряжению дает равных шаг по значению АЦП и чтобы получить номер нажатой кнопки, достаточно значение функции analogReference() поделить на шаг.

int button = analogReference() / 204;

И, к примеру, нажав на третью кнопку получим на выходе 3В, что советует значению АЦП 613 и поделив на шаг получаем 3.

Из-за помех и погрешностей в реальном значении сопротивлении резисторов и работе АЦП, значения могут отличаться, но не настолько чтобы спутать номера кнопок.

Многие читатели уже отметили, что если ни одна кнопка не нажата, то аналоговый вход находится как бы подвешенном состоянии. В этом состоянии с него можно вычитать все что угодно, навеянное различными помехами. Чтобы это устранить необходим резистор подтяжки.

Простая схема с делителем с резистором подтяжки.

На следующей схеме добавлен резистор подтяжки, который подтягивает аналоговый вход платы к 0 если ни одой кнопки не нажато. Но при нажатой кнопке он вносит изменения в равномерное распределение напряжения по кнопкам. А именно, если раньше напряжение было равно U_{bt} = U {n * R\over N*R} = U {n \over N}, Где N — Общее количество резисторов, а n — количество резисторов под кнопкой. То после добавления резистора подтяжки, он встает параллельно сопротивлению нижнего плеча делителя. Это уменьшает сопротивление всего плеча и подтягивает напряжение к нулю. При высоких значения резистора подтяжки, его влияние для 5ти кнопок все еще невелико и можно использовать код с делением значения АЦП на шаг.

Обратите внимание, что если нажат самый верхний выключатель, то он соединяет АЦП напрямую с источником питания, и нажатие любого другого выключателя не изменяет показание на АЦП. Но если исключить самый верхний включатель, то схема снова превращается в делитель напряжения даже при двух нажатых выключателях.

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

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

Последовательная схема

Модифицируем предыдущую схему убрав нижний резистор, через который шла утечка тока при отжатых кнопках.

Теперь, если ни одной копки не нажато — цепь разомкнута и ток по ней не протекает. А аналоговый вход платы стянут к земле, что дает стабильный ноль на выходе АЦП.

Если же кнопка нажата, то схема снова превращается в классический делитель, в котором верхнее плечо составляют резисторы до кнопки, а нижнее — резистор подтяжки. Напряжение на АЦП высчитывается по формуле: U_{bt} = U {R \over {R + (R_1 + .. + R_n)}}.

По этой формуле видно что переменная величина, кнопка, находится в знаменателе, это значит, что зависимость нелинейная и при равных номиналах кнопочных резисторов, напряжение на АЦП выглядит как-то так:

График напряжений на АЦП в зависимости от кнопки

Заметно, что чем больше кнопок — тем мельче шаг по напряжению. Как видно из формулы: U'_{n} = U {R * R_{b} \over {(R + R_{b} * n)^2}}, чем дальше, тем шаг очень быстро становится мелким и для того чтобы нажатие кнопки оставалось четким их надо размещать на «верхней» части графика.

Давайте подберем сопротивления используя общую формулу: R{n} = R * ( {U \over U_b} - 1) = R * ({ {U - U_b} \over U_b})

При R = 10k (резистор стяжки) и шаге в 0.5В сопротивления будут 1.1К 1.4К 1.8К 2.4К 3.3К 5К

Напряжения на кнопках с шагом 0.5В

При такой схеме чтобы узнать какая кнопка нажата нам нужно значение аналогового входа поделить на 0.5 вольт. Но ведь аналоговый вход выдает значение не в вольтах, а в отсчетах от 0 до 1023, так как же их поделить на вольты? Ответ прост: 0.5 вольт соответствует {0.5 В \over 5 В} * 1024 = 102.4 отсчетам. Но не очень удобно работать с дробными значениями поэтому давайте подберем шаг равный или близкий степени двойки. В этом случае мы сможем вычислять номер кнопки через битовый сдвиг: {0.625 В \over 5 В} * 1024 = 128 = 2^7. И наши резисторы при Rстяжки = 10k равны 1.4К, 1.9К, 2.6К, 4К, 6.6К, 13.3К.

Теперь чтобы получить номер кнопки нужно выполнить команду:

button_id = analogRead(A1) >> 7;
Сдвиг отбрасывает младшие 7 бит, поэтому если значение АЦП будет чуть ниже ожидаемого, то мы получим номер кнопки на единицу меньше от верного. Чтобы этого избежать применим округление:
button_id = ( analogRead(A1) + 64 ) >> 7; 

Графически это выглядит так:

Голубая линия отображает номер кнопки в зависимости от разбросов в значениях резисторов и напряжений. Сам номер кнопки обозначен на правой оси.

Использования ресет пина (Reset pin) для чтения кнопки.

Даташит для ATTiny85 говорит что ресет наступает если на PB5/ADC0 подается напряжение ниже V_{RST}. В качестве фактического значения указан диапазон 0.2 - 0.9 V_{cc} или 1 — 4.5 вольт. Даже шаг 0.625 В дает напряжение на первой кнопке в 4.375 В, что ниже максимальной границы, но по отзывам все же можно использовать диапазон свыше 2.2 вольт, а это интервал в 2.8 В, в котором можно разместить аж 4 кнопки с шагом 0.625 В. Также в даташите графики Figure 22-27, Figure 22-26, Figure 22-31 дают надежду на использование верхнего диапазона в 2.5 вольта для наших нужд.

Из графиков выше берем Rподтяжки = 55К и порог по напряжению сброса в 2.3В и получается следующая схема для кнопок на пине ресета.

Нижняя кнопка дает напряжение в 2.5 вольта, что очень близко к порогу срабатывания ресета, поэтому лучше обойтись только тремя, а то и двумя кнопками. Иначе можно получать неожиданные ресеты из-за различных наводок. Цепочку из двух или трех нижних резисторов можно заменить одним, равным их сумме.

Чарлиплексинг (Charlieplexing)

Что если остались только цифровые выходы? Например, esp8266 содержит только один ADC пин. Сколько нужно цифровых пинов чтобы обеспечить работу 6 кнопок? 6? — нет достаточно только трех. Секрет кроется в том, что GPIO пины поддерживают так называемое высокоомное состояние или состояние выключен (другие названия: высокоимпедансное состояние,  Z-состояние, high impedance , hi-Z, tri-stated или floating state).

На на схемах выше три цифровых вывода микросхемы попарно соединены парой кнопок, таким образом что через каждую ток может идти только в одном направлении. Для этого последовательно кнопке добавлен диод. Всего подключено 6 кнопок. Выводы сконфигурированы следующим образом А — чтение, В — высокий уровень (H), C — отключен (высокоомное состояние). в этом случае только при нажатой кнопке BA (схема С3) на выводе А появится высокий уровень. Для того чтобы в остальное время выводе был низкий уровень нужно использовать резистор подтяжки.

На следующей схеме показан случай когда нажато сразу две кнопки BC-CA

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

На схеме С4 замкнута только одна копка и ток идет через одно сопротивление. Оно достаточно мало чтобы на выходе А был зарегистрирован высокий уровень. Но в случае нажатия сразу двух кнопок (Схема С5), ток проходит последовательно через два сопротивления и в этом случае напряжения на входе А недостаточно для регистрации ложного нажатия кнопки ВА.

Ссылки

Использованный симулятор цепи: http://www.falstad.com/circuit/circuitjs.html

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *