Программируем Arduino. Основы работы со скетчами
Шрифт:
Маскирование битов
Нередко при приеме данных от периферийных устройств, независимо от вида связи, данные поступают упакованными в байты, в которых часть битов может нести служебную информацию. Создатели периферийных устройств часто стараются втолкнуть как можно больше информации в минимальное число бит, чтобы добиться максимальной скорости передачи, но это усложняет программирование взаимодействий с такими устройствами.
Операция маскирования битов позволяет игнорировать некоторую часть данных в байте или в большой структуре данных. На рис. 9.1 показано, как выполнить маскирование
Рис. 9.1. Маскирование битов
В описаниях двоичных чисел вы обязательно столкнетесь со словосочетаниями «самый младший» и «самый старший». В двоичных числах, записанных с соблюдением правил, принятых в математике, самым старшим битом является крайний левый бит, а младшим значащим — крайний правый. Крайний правый бит может иметь ценность только 1 или 0. Вам также встретятся термины самый старший бит (Most Significant Bit, MSB) и самый младший бит (Least Significant Bit, LSB). Самый младший бит иногда называют также нулевым битом (бит 0), первый бит (бит 1) — следующий по старшинству и т.д.
В примере, изображенном на рис. 9.1, байт включает несколько значений, но нас интересуют только три младших бита, которые нужно извлечь как число. Для этого можно выполнить поразрядную операцию И (AND) данных с маской, в которой три младших бита имеют значение 1. Поразрядная операция И (AND) для двух байт в свою очередь выполняет операцию И (AND) для каждой пары соответствующих битов и конструирует общий результат. Операция И (AND) для двух битов вернет 1, только если оба бита имеют значение 1.
Далее показана реализация этого примера на Arduino C с использованием оператора &. Обратите внимание на то, что поразрядная операция И (AND) обозначается единственным символом &, а логическая операция И (AND) — двумя: &&.
byte data = 0b01100101;
byte result = (data & 0b00000111);
Переменная result в данном случае получит десятичное значение 5.
Сдвиг битов
Часто необходимые биты в принимаемых данных могут занимать не самые младшие разряды в байте. Например, если из данных, изображенных на рис. 9.1, потребуется извлечь число, определяемое битами с 5-го по 3-й (рис. 9.2), то вам придется сначала применить маску, чтобы оставить интересующие биты, как в предыдущем примере, а затем сдвинуть биты на три позиции вправо.
Сдвиг вправо в языке C выполняется оператором >>, за которым следует число, определяющее количество разрядов, на которое производится сдвиг. В результате часть битов будет сдвинута за границу байта. Далее приводится реализация примера из предыдущего раздела на языке C:
byte data = 0b01101001;
byte result = (data & 0b00111000) >> 3;
Представьте, что вы получили два 8-битных байта и должны собрать из них одно 16-битное значение типа int. Для этого можно сдвинуть биты старшего байта в один конец значения int, а затем прибавить второй байт. Этот процесс иллюстрирует рис. 9.3.
Рис. 9.2. Маскирование и сдвиг битов
Рис. 9.3. Объединение двух байтов в значение типа int
Чтобы реализовать это в Arduino C, нужно сначала записать highByte в переменную результата типа int, сдвинуть влево на восемь позиций, а потом прибавить lowByte:
byte highByte = 0x6A;
byte lowByte = 0x0F;
int result = (highByte << 8) + lowByte;
Аппаратная часть SPI
На рис. 9.4 изображена типичная схема подключения к Arduino двух ведомых устройств.
Рис. 9.4. Плата Arduino и два ведомых устройства SPI
Линии тактового сигнала системы (System Clock, SCLK), выход ведущего/вход ведомого (Master Out Slave In, MOSI) и вход ведущего/выход ведомого (Master In Slave Out, MISO) подключаются к контактам на плате Arduino с теми же именами, которые в модели Uno соответствуют контактам D13, D11 и D12. В табл. 9.2 перечислены наиболее распространенные модели плат и соответствие контактов линиям интерфейса SPI.
Таблица 9.2. Контакты интерфейса SPI на плате Arduino
Модель
SCLK
MOSI
MISO
Uno
13 (ICSP3)
11 (ICSP4)
12 (ICSP1)
Leonardo
ICSP3
ICSP4
ICSP1
Mega2560
52 (ICSP3)
51 (ICSP4)
50 (ICSP1)
Due
ICSP3
ICSP4
ICSP1
Линиями выбора ведомого могут быть любые контакты на плате Arduino. Они используются для выбора определенного ведомого устройства непосредственно перед передачей данных и его отключения по завершении обмена данными.
Ни к одной из линий не требуется подключать подтягивающее сопротивление.
Поскольку в некоторых моделях Arduino, в том числе Leonardo, контакты интерфейса SPI имеются только на колодке ICSP, многие платы расширений часто имеют гнезда SPI для подключения к колодке контактов ICSP. На рис. 9.5 изображена колодка ICSP с подписанными контактами.
Рис. 9.5. Контакты ICSP на плате Arduino Uno
Обратите внимание на то, что на плате Arduino Uno имеется вторая колодка ICSP, рядом с кнопкой сброса. Она предназначена для программирования интерфейса USB.
Протокол SPI
Протокол SPI на первый взгляд кажется сложным и запутанным, потому что данные передаются и принимаются обеими сторонами, ведущим и выбранным ведомым, параллельно. Одновременно с передачей ведущим устройством (Arduino) бита по линии MOSI ведомое устройство посылает другой бит по линии MISO плате Arduino.
Обычно Arduino посылает байт данных и затем восемь нулей, одновременно принимая результат от ведомого устройства. Так как частота передачи устанавливается ведущим устройством, убедитесь в том, что она не слишком высока для ведомого устройства.