29 декабря 2016
Кравченко Виктор

Arduino: Подключение нескольких кнопок к одному аналоговому входу

Радиотехника и электроника Цифровые устройства Arduino
01

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

02
03

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

04

Схема №1 — резистивно-последовательная

Принципиально схема может исполняться в 2 вариантах и выглядит следующим образом:

По данной схеме реализована обратная связь о состоянии системы в проекте Codius.AutoFeeder 1.0.

Видео о проекте:

05
Несмотря на кажущуюся схожесть схемы работают немного по разному
Несмотря на кажущуюся схожесть схемы работают немного по разному
06

Различия схем заключаются в том, что при нажатии кнопки S4 на левой схеме, аналоговый вход считает максимальное напряжение — 5 В, а кнопка S1 даст минимальное напряжение, сниженное всеми резисторами в цепи. В правой схеме, наоборот, максимальное напряжение даст кнопка S1.

07

Приведенные схемы — пример последовательного соединения резисторов. Как известно, для последовательного соединения резисторов:

08
09
Rобщ=R1+R2+...+Rn
10

При нажатии любой кнопки в схеме мы получаем классический резистивный делитель напряжения:

11
12

В котором значения напряжений и сопротивлений находятся в зависимости, выражающейся следующей формулой:

13
Uвых=Uвх×R2R1+R2
14

Из формулы видно, что зависимость выходного напряжения Uвых от сопротивлений R1 и R2 нелинейная, а экпоненциальная. График это подтверждает. Единственный нюанс заключается в том, что на оси абсцисс номиналы резистора R1, представлены в номиналах стягивающего резистора R2 x=R2:

15
Например, если $R_2=10 КОм$, то при $R_1=3 \times R_2=30 КОм, U_{вых}=1,25 В$
Например, если R2=10КОм, то при R1=3×R2=30КОм,Uвых=1,25В
16

Исходя из графика можно наглядно представить каким образом рассчитать номиналы резисторов в зависимости от количества кнопок. И здесь, как обычно, возможны 2 варианта — либо подбирать номиналы так, чтобы разбить интервал на равные промежутки напряжений, либо использовать в схеме резисторы только одного номинала:

17
Пример использования 4 резисторов для 5 кнопок. brСлева резисторы подобраны под равномерную дискретность напряжений, справа — резисторы одного номинала.
Пример использования 4 резисторов для 5 кнопок.
Слева резисторы подобраны под равномерную дискретность напряжений, справа — резисторы одного номинала.
18

В первом случае (левый график), номиналы резисторов подобраны таким образом, чтобы обеспечить равные интервалы при определении значений напряжения АЦП. Такой подход очень удобен для количества кнопок 2n, (при n2), т. е. 4, 8, 16,… Удобство заключается в том, что результат работы АЦП при помощи битового сдвига можно округлить, при этом максимально нивелировать погрешности АЦП и номиналов резисторов. Пример:

19
Предположим 4 кнопки генерируют напряжения — 5 В (первая кнопка без резистора), 3.75 В, 2.5 В, 1.25 В, что соответствует значениям АЦП — 1023, 767, 511, 255. Теперь, если к полученным значениям применить операцию битового сдвига, получим значения 4, 3, 2, 1 для кнопок, и 0 для состояния покоя:
1
2
3
4
5
6
7
8
9
10
11
void setup() { Serial.begin(9600); Serial.println( (1023 >> 8) + 1); // 4 Serial.println( (767 >> 8) + 1); // 3 Serial.println( (511 >> 8) + 1); // 2 Serial.println( (255 >> 8) + 1); // 1 } void loop() { }
Сдвигаем на 8 бит потому из 10-битного значения нужно оставить всего 2 бита, в которых закодированы значения от 0 до 3. К ним прибавляется единица, чтобы отделить полученные состояния от состояния спокойствия — 0. В случае использования большего количества кнопок сдвиг нужно уменьшать — для 8 кнопок до 7, для 16 до 6 и т. д.

Но если пороговое значение 1023 никогда не будет превышено, то значения 767, 511 и 255 могут колебаться и в большую и в меньшую сторону. Так вот, чтобы значение 512 не давало результат 3, а значение 256 не давало результат 2, от преобразуемого значения нужно вычесть половину диапазона между значениями — 128.
1
2
3
4
5
6
for (int i = 1023; i >= 0; i--) { int result = i; Serial.print(i); Serial.print(": "); Serial.println( ((result - 128) >> 8) + 1); }
В этом случае погрешность АЦП будет устранена — ошибок уже не будет.
Результат:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1023: 4 ... 896: 4 895: 3 ... 640: 3 639: 2 ... 384: 2 383: 1 ... 128: 1 127: 0 // ... // состояние покоя 0: 0 //
Весь диапазон жестко поделен на сектора значений.
Соответственно для большего количества кнопок диапазон будет уменьшаться.
20

Но использовать этот вариант можно и с количеством кнопок не кратным 2n. В этом случае погрешность АЦП устраняется программно другими методами — внедрением значения ошибки.

21

Недостаток такого способа заключается в ограничении количества кнопок – при увеличении их числа, номиналы резисторов кнопок, отвечающих за низкие напряжения (менее 1 В), растут в геометрической прогрессии.

22

Формула для расчета номиналов резисторов для установки равных промежутков напряжений для количества кнопок k, и привязанных к номиналу стягивающего регистра Rcт (если принять Rcт за единицу, то полученные коэффициенты можно использовать при расчете сопротивлений при другом заданном стягивающем сопротивлении):

23

u=Uвхk — шаг дискретности выходного напряжения

24
Rn=Uвх×Rстu×(kn)Rстn1i=1Ri, при nZ1nk1
25

Поскольку первая кнопка замыкается без резистора, то резистор нулевого сопротивления опускаем, отсюда nk1 — эта кнопка даст результат равный Uвх5В. Рассмотрим расчет номиналов на примере приведенных 5 кнопок и 4 резисторов, стягивающий резистор Rст=10КОм (полученный результат будет в КОм):

26
u=Uвхk=5В5=1В
27
R1=5В×10КОм1В×(51)10КОм0КОм=2,5КОм
28
R2=5В×10КОм1В×(52)10КОм(2,5КОм)=4,167КОм
29
R3=5В×10КОм1В×(53)10КОм(2,5КОм+4,167КОм)=8,333КОм
30
R4=5В×10КОм1В×(54)10КОм(2,5КОм+4,167КОм+8,333КОм)=25КОм
31

Результат: нам понадобятся резисторы следующих номиналов — 2.5 КОм, 4.167 КОм, 8.333 КОм, 25 КОм.

32
Расположение резисторов с указанными номиналами и получаемые напряжения на каждой кнопке, в зависимости от выбранной схемы
Расположение резисторов с указанными номиналами и получаемые напряжения на каждой кнопке, в зависимости от выбранной схемы
33 На заметку:
Данный способ, автор считает наиболее предпочтительным. При чем, имеет смысл рассчитывать схему с количеством кнопок равным 2n, а использовать столько, сколько нужно. Например, если нужно 3 кнопки, то рассчитывать схему на 4 кнопки, а если нужно 5 кнопок, то схему сформировать исходя из 8 кнопок.

Этот способ также на программном уровне упрощает трактовку результатов, исключая дополнительные затраты ресурсов на проверку принадлежности к диапазонам.
34

Для второго случая, все намного проще – установлены резисторы одного номинала. При чем лучше, если этот номинал будет меньше номинала стягивающего резистора x. В этом случае первые кнопки попадут в диапазон, где различия между напряжениями максимальны:

35
На рисунке 10 резисторов, номиналом 0.1$x$ — например, при номинале стягивающего резистора 10 КОм, номинал резисторов кнопок — 1 КОм
На рисунке 10 резисторов, номиналом 0.1x — например, при номинале стягивающего резистора 10 КОм, номинал резисторов кнопок — 1 КОм
36

Диапазон напряжений находится по формуле, при номинале стягивающего резистора Rст и номинале прочих резисторов R:

37
Uвыхn=Uвх×RстR×n+Rст
38

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

39
40

Основной отличительной особенностью резистивно-последовательной схемы является игнорирование нажатия нескольких кнопок — результат всегда будет указывать на нажатие единственной кнопки с меньшим по отношению к другим нажатым кнопкам суммарным сопротивлением:

41
При одновременном нажатии 2 и 3 кнопки, ток потечет по контуру через 3 кнопку
При одновременном нажатии 2 и 3 кнопки, ток потечет по контуру через 3 кнопку
42 На заметку:
Достоинства схемы:
  • предсказуемое поведение,
  • сравнительная легкость расчетов,
  • нажатие нескольких кнопок одновременно приводит к предсказуемому результату,
  • варианты реализации — одинаковый шаг изменения выходного напряжения на выходе или одинаковые номиналы используемых резисторов.

Недостатки:
  • накапливаемая погрешность подбираемых номиналов резисторов,
  • для первого случая (равномерная дискретность значений напряжений) сложность расчетов,
  • ограничение количества кнопок в диапазоне напряжений до 1 В,
  • принципиален порядок расположения резисторов на схеме.
43
Есть ещё один комбинированный способ подключения нескольких кнопок к одному аналоговому входу МК, при котором при использовании одинаковых номиналов напряжений, на выходе получаются напряжения равномерной дискретности.

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

Схема №2 — резистивно-параллельная

Принципиально схема может исполняться в 2 вариантах и выглядит следующим образом:

45
Обе схемы абсолютно идентичны
Обе схемы абсолютно идентичны
46

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

47
48
1Rобщ=1R1+1R2++1Rn
49

И как следствие:

50
Rобщ=11R1+1R2++1Rn
51

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

52 На заметку:
Важно иметь ввиду, что при подключении одной кнопки без сопротивления, для генерации 5 В (это не противоречит общей концепции) и, при её нажатии, вся схема не будет реагировать на нажатия других кнопок. Эта ситуация является исключением в общем правиле однозначной идентификации каждой комбинации из нажатых кнопок.
53

Расчет номиналов сопротивлений схож с расчетом из резистивно-последовательной схемы, за тем лишь исключением, что каждое последующее сопротивление не нужно корректировать на полученные ранее:

54
Rn=Uвх×RстUвыхnRст
55

Например, у нас есть схема из 3 кнопок, которые должны генерировать соответственно 1 В, 2.5 В и 4 В. Номинал стягивающего резистора 10 КОм, входное напряжение 5 В. Расчет номиналов резисторов будет следующим:

56
R1=5В×10КОм1В10КОм=40КОм
57
R2=5В×10КОм2,5В10КОм=10КОм
58
R3=5В×10КОм4В10КОм=2,5КОм
59

Но самое интересное, в этой схеме всплывает тогда, когда одновременно нажимается несколько кнопок — а с тремя кнопками этих комбинаций 4: 1+2, 1+3, 2+3, 1+2+3.

60

Немного математики...

Количество комбинаций нажатий кнопок определяется по формуле числа сочетаний из общего числа n-объектов по k-штук в комбинации:

61
Ckn=n!(nk)!×k!
62

Но поскольку у нас исключены нажатия по одной кнопке (поведение по умолчанию), и возможны нажатия не только 2, но и всех кнопок сразу, то общая формула для нахождения числа сочетаний будет находиться путем сложения числа сочетаний 2 кнопок, числа сочетаний 3 кнопок и т. д. и будет иметь вид:

63
Cnобщ=С2n+C3n++Cnn
64
Cnобщ=nk=2n!(nk)!×k!
65

Например, для 5 кнопок, помимо 5 «официальных» обособленных нажатий по одной кнопке, общее количество комбинаций рассчитывается следующим образом. Количество комбинаций нажатий по две кнопки (1+2, 1+3, 1+4, 1+5, 2+3, ...) будет:

66
C25=5!(52)!×2!=10
67

Количество комбинаций нажатий 3 кнопок (1+2+3, 1+2+4, 1+2+5, 2+3+4, ...):

68
C35=5!(53)!×3!=10
69

Количество комбинаций нажатий 4 кнопок (1+2+3+4, 1+2+3+5, 1+2+4+5, 1+3+4+5, 2+3+4+5):

70
C45=5!(54)!×4!=5
71

И количество одновременных нажатий 5 кнопок — 1. Итого:

72
Cnобщ=10+10+5+1=26
73

26 комбинаций! Помимо 5 стандартных. А для 6 кнопок возможных комбинаций уже 57 (не считая 6 нажатий по одной кнопке)!!! Но все бы ничего если бы не...

74

Назад к кнопкам

Вернемся к нашим 3 кнопкам и рассчитаем напряжение, которое будет получено, путем одновременного нажатия 1 и 3 кнопки (1 В и 4 В). Как известно, для двух параллельных сопротивлений, общее сопротивление находится по формуле:

75
R=R1R2R1+R2
76
R=40КОм×2,5КОм40КОм+2,5КОм=2,35КОм
77
Uвых=Uвх×RстR+Rст=5В×10КОм2,35КОм+10КОм=4,05В
78

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

79

В случае одновременного нажатия всех трех кнопок:

80
R=1140КОм+110КОм+12,5КОм=1,9КОм
Rобщ=11R1+1R2++1Rn
81
Uвых=Uвх×RстR+Rст=5В×10КОм1,9КОм+10КОм=4,2В
82 На заметку:
Достоинства схемы:
  • простота подбора номиналов,
  • не важен порядок установки резисторов — каждый номинал включается в схему с соответствующей кнопкой,
  • возможно наращивание дополнительного функционала за счет интерпретаций комбинаций нажатий.

Недостатки:
  • подходит только для малого количества кнопок (до 5) — при включении в схему более 5 кнопок, поведение схемы при одновременном нажатии двух и более кнопок становится непредсказуемым.
83

Хватит математики, в бой!

Подкрепим теорию примерами на практике, работать будем с 4 кнопками.

84 На заметку:
Для ускорения расчетов номиналов элементов схем данной статьи, автором написан Калькулятор.xlsx (24,9 KB), который можно совершенно бесплатно скачать и производить расчеты.
85

Пример №1. Резистивно-последовательная схема, номиналы резисторов будем подбирать под равные промежутки напряжения. Воспользовавшись калькулятором, получаем следующие номиналы резисторов — 3.334 КОм, 6.666 КОм, 20 КОм — как раз в наличии 3.3 КОм, 6.8 КОм и 20 КОм. Собираем схему:

Принципиальная схема
Принципиальная схема
86
87

Ниже представлен код, который выдает сообщение каждый раз, как состояние нажатия кнопок меняется. Скетч, с учетом программного устранения дребезга:

88 Arduino (C++)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
int pinIn = A0; int keyValue = 0; // Состояние покоя void setup() { pinMode(pinIn, INPUT); Serial.begin(9600); } void loop() { int newKeyValue = GetKeyValue(); // Получаем актуальное состояние кнопок с коррекцией дребезга if (keyValue != newKeyValue) { // Если новое значение не совпадает со старым - реагируем на него keyValue = newKeyValue; // Актуализируем переменную хранения состояния if (keyValue > 0) { // Если значение больше 0, значит кнопка нажата Serial.println("Key pressed: " + String(keyValue)); } else { // Если 0, то состояние покоя Serial.println("all keys are not pressed"); } } } int GetKeyValue() { // Функция устраняющая дребезг static int oldKeyValue; // Переменная для хранения предыдущего значения состояния кнопок static long lastChange; // Переменная для хранения времени последнего изменения состояния int actualKeyValue = analogRead(pinIn); // Получаем актуальное состояние if ((actualKeyValue != oldKeyValue) && (millis() - lastChange > 200)) { // Пришло новое значение, и с последнего изменения прошло достаточно времени oldKeyValue = actualKeyValue; // Запоминаем новое значение lastChange = millis(); // Обнуляем таймер } return oldKeyValue; // Отправляем старое, либо уже модифицированное новое значение }
89

Но если этот код запустить в том виде, в котором он представлен то увидим, как погрешность преобразования АЦП вносит свои коррективы в его работу:

90
91

Для исправления будем использовать битовый сдвиг, описанный в 18 абзаце. Если обратить внимание на погрешность получаемых значений, с учетом не идеально подобранных номиналов резисторов и их погрешности, она не превышает ±16 единиц. А это составляет 16+16=32=25. Значит и сдвигать можно только на 5 бит — результат будет стабильным. Но для упрощения интерпретации будем сдвигать на 8 бит, чтобы результатом получать номер нажатой кнопки 1...4. Откорректируем несколько строк:

92 Arduino (C++)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
int pinIn = A0; int keyValue = 0; // Состояние покоя void setup() { pinMode(pinIn, INPUT); Serial.begin(9600); } void loop() { int newKeyValue = GetKeyValue(); // Получаем актуальное состояние кнопок с коррекцией дребезга if (keyValue != newKeyValue) { // Если новое значение не совпадает со старым - реагируем на него keyValue = newKeyValue; // Актуализируем переменную хранения состояния if (keyValue > 0) { // Если значение больше 0, значит кнопка нажата Serial.println("Key pressed: " + String(keyValue)); } else { // Если 0, то состояние покоя Serial.println("all keys are not pressed"); } } } int GetKeyValue() { // Функция устраняющая дребезг static int oldKeyValue; // Переменная для хранения предыдущего значения состояния кнопок static long lastChange; // Переменная для хранения времени последнего изменения состояния int actualKeyValue = analogRead(pinIn); // Получаем актуальное состояние
//actualKeyValue = ((actualKeyValue - 16) >> 5) + 1; // Для 32 кнопок
//actualKeyValue = ((actualKeyValue - 32) >> 6) + 1; // Для 16 кнопок
//actualKeyValue = ((actualKeyValue - 64) >> 7) + 1; // Для 8 кнопок
actualKeyValue = ((actualKeyValue - 128) >> 8) + 1; // Для 4 кнопок
if ((actualKeyValue != oldKeyValue) && (millis() - lastChange > 200)) { // Пришло новое значение, и с последнего изменения прошло достаточно времени oldKeyValue = actualKeyValue; // Запоминаем новое значение lastChange = millis(); // Обнуляем таймер } return oldKeyValue; // Отправляем старое, либо уже модифицированное новое значение }
93

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

94
В примере из предыдущего скетча раскомментирована 30 строка — для 8 кнопок, а 31 закомментирована
В примере из предыдущего скетча раскомментирована 30 строка — для 8 кнопок, а 31 закомментирована
95

...модифицируем код таким образом, чтобы нажатие генерировалось только после получения 10 подряд идущих одинаковых значений (модифицированная функция GetKeyValue()):

96 Arduino (C++)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int GetKeyValue() { // Функция устраняющая дребезг static int count; static int oldKeyValue; // Переменная для хранения предыдущего значения состояния кнопок static int innerKeyValue; int actualKeyValue = analogRead(pinIn); // Получаем актуальное состояние //actualKeyValue = ((actualKeyValue - 16) >> 5) + 1; // Для 32 кнопок //actualKeyValue = ((actualKeyValue - 32) >> 6) + 1; // Для 16 кнопок //actualKeyValue = ((actualKeyValue - 64) >> 7) + 1; // Для 8 кнопок actualKeyValue = ((actualKeyValue - 128) >> 8) + 1; // Для 4 кнопок if (innerKeyValue != actualKeyValue) { // Пришло значение отличное от предыдущего count = 0; // Все обнуляем и начинаем считать заново innerKeyValue = actualKeyValue; // Запоминаем новое значение } else { count += 1; // Увеличиваем счетчик } if ((count >= 10) && (actualKeyValue != oldKeyValue)) { // Счетчик преодолел барьер, можно иницировать смену состояний oldKeyValue = actualKeyValue; // Присваиваем новое значение } return oldKeyValue; }
97

Пример №2. Резистивно-последовательная схема, номиналы резисторов будут одинаковые — 3.3 КОм. Количество кнопок также 4. Схема остается прежней — меняются только номиналы резисторов.

98
99

Воспользовавшись калькулятором (24,9 KB), получаем следующие напряжения на выходе (с соответствующими значениями АЦП) — 5 В (1023), 3.76 В (769), 3.01 В (615) и 2.51 В (513). Для проверки на модифицированной схеме запускаем скетч:

100 Arduino (C++)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
int pinIn = A0; int keyValue = 0; // Состояние покоя void setup() { pinMode(pinIn, INPUT); Serial.begin(9600); } void loop() { int newKeyValue = GetKeyValue(); // Получаем актуальное состояние кнопок с коррекцией дребезга if (keyValue != newKeyValue) { // Если новое значение не совпадает со старым - реагируем на него keyValue = newKeyValue; // Актуализируем переменную хранения состояния if (keyValue > 0) { // Если значение больше 0, значит кнопка нажата Serial.println("Key pressed: " + String(keyValue)); } else if (keyValue < 0) { // Если -1 - неизвестное состояние, незапрограммированное нажатие Serial.println("unknown pressed"); } else { // Если 0, то состояние покоя Serial.println("all keys are not pressed"); } } } int GetKeyValue() { // Функция устраняющая дребезг static int count; static int oldKeyValue; // Переменная для хранения предыдущего значения состояния кнопок static int innerKeyValue; // Здесь уже не можем использовать значение АЦП, так как оно постоянно меняется в силу погрешности int actualKeyValue = GetButtonNumberByValue(analogRead(pinIn)); // Преобразовываем его в номер кнопки, тем самым убирая погрешность if (innerKeyValue != actualKeyValue) { // Пришло значение отличное от предыдущего count = 0; // Все обнуляем и начинаем считать заново innerKeyValue = actualKeyValue; // Запоминаем новое значение } else { count += 1; // Увеличиваем счетчик } if ((count >= 10) && (actualKeyValue != oldKeyValue)) { oldKeyValue = actualKeyValue; // Запоминаем новое значение } return oldKeyValue; } int GetButtonNumberByValue(int value) { // Новая функция по преобразованию кода нажатой кнопки в её номер int values[5] = {0, 513, 615, 769, 1023}; int error = 15; // Величина отклонения от значений - погрешность for (int i = 0; i <= 4; i++) { // Если значение в заданном диапазоне values[i]+/-error - считаем, что кнопка определена if (value <= values[i] + error && value >= values[i] - error) return i; } return -1; // Значение не принадлежит заданному диапазону }
101

В коде написана дополнительная функция GetButtonNumberByValue(), проверяющая причастность полученного АЦП значения к диапазонам, закрепленным за каждой кнопкой, с учетом заданного значения ошибки error. Результат:

102
103

Пример №3. Резистивно-параллельная схема, количество кнопок также 4. Для упрощения будем использовать номиналы резисторов из примера №1 — 3.3 КОм, 6.8 КОм, 10 КОм и 20 КОм. Стягивающий резистор также 10 КОм. Расчетные напряжения получаемые на выходе (с соответствующими значениями АЦП) будут следующими: 3.76 В (769), 2.98 В (609), 2.5 В (511) и 1.67 В (341).

104

Как раз для примера, опять же при помощи калькулятора (24,9 KB), рассчитаем значение общего сопротивления и выходного напряжения, получаемое при одновременном нажатии 2, 3 и 4 (6.8 КОм, 10 КОм и 20 КОм) кнопок. Получаем общее сопротивление 3.37 КОм, и выходное напряжение — 3.74 В (765), что как видно очень близко к значениям первой кнопки. Посмотрим что будет происходить в реальности.

Принципиальная схема
Принципиальная схема
105

Тестовая схема выглядит следующим образом:

106
107

Скетч оставляем из примера №2, за тем лишь исключением, что модифицируем идентификационные значения. Для большей показательности не будем в коде отрабатывать сценарии одновременного нажатия большого количества кнопок (делается это очень просто, оставим для домашнего задания). Заменим 49 строку предыдущего скетча на:

108 Arduino (C++)
1
int values[5] = {0, 769, 609, 511, 341};// Массив значений АЦП
109

Запустив код, можно убедиться в недостатках этой схемы — одновременное нажатие 3 и 4 кнопки интерпретируется как нажатие 2 кнопки, а одновременное нажатие кнопок 2, 3 и 4 — как нажатие 1 кнопки.

110

Демонстрационное видео:

111
Подписывайтесь на канал , чтобы быть в курсе обновлений!
112 На заметку:
Исходники для скачивания:
Пример №1 Пример №2 Пример №3
Принципиальная схема: sample_circuit_01.png (28,4 KB)
sample_circuit_eagle_01.sch (289 KB)
sample_circuit_02.png (27,8 KB)
sample_circuit_eagle_02.sch (289 KB)
sample_circuit_03.png (28,0 KB)
sample_circuit_eagle_03.sch (290 KB)
Макет: sample_sketch_01.png (72,5 KB)
sample_circuit_fritzing_01.fzz (8,22 KB)
sample_sketch_02.png (72,3 KB)
sample_circuit_fritzing_02.fzz (8,22 KB)
sample_sketch_03.png (72,2 KB)
sample_circuit_fritzing_03.fzz (8,50 KB)
Код: sample_code_01.ino (2,78 KB) sample_code_02.ino (3,54 KB) sample_code_03.ino (3,57 KB)

Все одним файлом — Materials.rar (365 KB)
comments powered by HyperComments