Параллельный ввод-вывод - возможно, использовать вызов функции машинного кода
Я новичок в arduino, но много программировал. У меня есть проект, в котором я хотел бы вывести 4 бита на соседние контакты и прочитать 4 бита с других (4) соседних контактов. (Представьте себе приложение для матричных клавиатур). Чтобы сделать это на C-C++, потребуется много инструкций (и времени), но машинный код
ВЫХОД: ИЛИ (маска) -> выходной порт ; это очищает целевые биты, оставляя другие биты такими, какими они были И (newdata) -> порт вывода ; это устанавливает новые данные в целевые биты>
ВВОД: порт -> регистрация И (регистрация) (маска) -> регистрация>
Есть ли способ реализовать это, например, в виде вызова из IDE. Я сталкивался со многими системами, в которых многоязычные компоненты могут быть скомпилированы в один исполняемый файл.
Если это обычно не делается, то почему бы и нет? Это что-то, чего мне следует избегать по какой-то причине?
Спасибо Дейв
@Dave, 👍0
Обсуждение1 ответ
Лучший ответ:
Вы можете управлять портами ввода-вывода непосредственно из C++, не прибегая к ассемблерному коду.
Микроконтроллер AVR в вашем Arduino (ATmega328P) имеет три порта (PORTB, PORTC и PORTD) с восемью выводами каждый (Px0, Px1, ... Px7). Вы управляете портами с помощью трех 8-разрядных регистров. Каждый бит в регистре представляет один физический вывод (LSB-это вывод 0, MSB-вывод 7):
- DDRx: регистр направления данных. Бит, установленный на "1", соответствует режиму вывода, "0" - входу.
- PORTx: регистр данных. В режиме вывода "1" устанавливает ВЫСОКИЙ уровень порта, "0" - НИЗКИЙ. В режиме ввода определяет, включены ли подтягивания ("1") или нет ("0").
- PINx: регистр ввода и переключения. Прочитайте его, чтобы получить статус всех восьми контактов порта одновременно. Запись в него переключает (НИЗКИЙ -> ВЫСОКИЙ или ВЫСОКИЙ ->> НИЗКИЙ) выбранные контакты (например, >>
PINC = 0b00100001;
переключает контакты PC0 и PC5).
С Arduino у вас нет доступа ко всем выводам всех портов. Чтобы получить сопоставление между именами выводов и портами Arduino, посмотрите любую хорошую ссылку на вывод Arduino (например, на странице Arduino Uno на вкладке "Документация"). Например, вы можете видеть, что все контакты порта D доступны в качестве цифровых контактов Arduino от D0 до D7, например, в Uno. Аналоговые контакты от PORTC.
Макросы предоставляются (с помощью набора инструментов AVR) для имен портов и номеров контактов, чтобы упростить задачу.
Например, PORTB
-это псевдоним для регистра PORTB, который вы можете присвоить ему, как если бы это была обычная переменная C++. PB5
-это индекс вывода 5 в порту B. Поэтому настройка вывода 5 порта B на вывод без влияния на остальные может быть записана следующим образом:
DDRB |= (1 << PB5);
Если вы хотите установить 4 нижних вывода порта D для вывода, а 4 других для ввода, вы можете:
DDRD = 0b00001111; // or 0x0f
Вот пример минимального скетча мигания:
void setup() {
// Set PB5 (D13 - builtin led) LOW
PORTB &= ~(1 << PB5);
// Set PB5 mode to OUTPUT
DDRB |= (1 << PB5);
}
void loop() {
delay(1000);
// переключение PB5
PINB |= (1 << PB5);
}
Сгенерированная сборка является оптимальной, отдельные инструкции для установки или очистки немного в памяти ввода-вывода: (Для получения информации см. Раздел Выходные данные скомпилированной сборки (Визуальный микро))
// настройка
PORTB &= ~(1 << PB5);
1f4: 2d 98 cbi 0x05, 5 ; 5
DDRB |= (1 << PB5);
1f6: 25 9a sbi 0x04, 5 ; 4
// цикл
PINB |= (1 << PB5);
246: 1d 9a sbi 0x03, 5 ; 3
Другой пример, который мигает светодиодом, подключенным к A3, только когда A2 находится на высоком уровне:
void setup() {
// Установите НИЗКИЕ значения PC2 и PC3 (A2 и A3)
PORTC &= ~((1 << PC2) | (1 << PC3));
// Установите режим PC2 на вход, режим PC3 на выход
DDRC = (DDRC & ~(1 << PC2)) | (1 << PC3);
}
void loop() {
delay(1000);
// переключать PC3 только в том случае, если значение PC2 велико
if (PINC & (1 << PC2)) {
PINC = (1 << PC3);
}
}
Опять же, сгенерированная сборка довольно лаконична:
if (PINC & (1 << PC2)) {
PINC = (1 << PC3);
202: 18 e0 ldi r17, 0x08 ; 8
252: 32 99 sbic 0x06, 2 ; 6
254: 16 b9 out 0x06, r17 ; 6
(Инструкция SBIC забавна: пропустите следующую инструкцию, если немного в памяти ввода-вывода чисто.)
Вы даже можете сохранить использование этого регистра r17
с помощью PINC |= ...
в этом случае:
// переключать PC3 только в том случае, если PC2 высокий
if (PINC & (1 << PC2)) {
PINC |= (1 << PC3);
250: 32 99 sbic 0x06, 2 ; 6
252: 33 9a sbi 0x06, 3 ; 6
Конечно, вы также можете прибегнуть к встроенной сборке, но это само по себе искусство, а синтаксис немного своеобразен. Но для простых вещей это просто:
asm("sbi 0x03, 5;"); // переключить PB5
Некоторые ссылки:
- Данные ATmega328P, связанные здесь: Страница микрочипа ATmega328P. См. раздел 14 "Порты ввода-вывода" и 36 "Краткое описание регистрации" для адресов портов ввода-вывода.
- Руководство по набору инструкций AVR (PDF), если вы хотите погрузиться в это.
- Кулинарная книга встроенного ассемблера AVR-GCC для получения подробной информации об использовании встроенного ассемблера GCC для AVR
- Как повторить кусок кода
- Разные и самые быстрые способы вычисления синусов и косинусов в Arduino
- Как передать несколько переменных в функцию?
- Нужна помощь в программировании ардуино на ассемблере
- Как вернуть значение массива символов в функции Arduino IDE?
- Arduino Мигает двумя светодиодами без задержки (количество повторений)
- Как увеличить срок службы EEPROM?
- Светодиод с кнопочным управлением Arduino со сборкой AVR
Смотрит на регистры портов и контактов (при условии, что AVR). Ими можно управлять непосредственно с C или C++, сборка не требуется., @Mat
Если у вас есть AVR Arduino (например, Uno, Nano, ...) [это](https://www.arduino.cc/en/Reference/PortManipulation) обязательно прочтите этот раздел в документации., @chrisl
Что вы подразумеваете под "_a звонком из IDE_"? Возможно, вы захотите пройти несколько уроков, чтобы изучить основы и технические термины. Я уверен, что есть примеры матричных клавиатур., @the busybee
Спасибо Мэту и Крису. Отличная информация. Юрай, я использую "клон" UNO, но хочу, чтобы эта штука работала эффективно, сводя программу к минимуму. Назойливый, Извини. Я знаю, что IDE-неправильный термин, но хотел, чтобы вопрос был как можно более элементарным., @Dave
Если речь идет о механических кнопках с ручным запуском, лучше позаботьтесь о том, чтобы быть достаточно медленным, чтобы избавиться от отскакивающих эффектов. Пока вы ждете несколько мс, пока кнопка не установится, не имеет значения, как вы читаете состояния кнопки., @DataFiddler