Замените digitalWrite выборочной побитовой операцией.
У меня есть следующий код с помощью digitalWrite, который я собираюсь написать только с использованием побитовых операций. Никаких проблем с переносимостью здесь нет. (для atmega328p здесь)
#define DATAOUT 11//MOSI
byte commandbits = B11000000;
for (int i = 7; i >= 3; i--) {
digitalWrite(DATAOUT, commandbits & (1 << i));
}
Я придумал что-то вроде этого, и это работает.
#define DATAOUT 11//MOSI
byte commandbits = B11000000;
for (int i = 7; i >= 3; i--) {
PORTB = (PORTB &(~(1<<3))) | (((commandbits &(1 << i))>>i) << 3);
}
Это самый лаконичный способ. Есть ли способ упростить это?
@Noel, 👍0
Обсуждение2 ответа
Лучший ответ:
Лично я бы немного расширил это:
if (commandbits & (1 << i)) {
PORTB |= (1<<3);
} else {
PORTB &= ~(1<<3);
}
Он гораздо читабельнее, и в нем меньше изменений, с которыми можно возиться. Кроме того, в AVR есть операции установки и очистки битов, которые можно использовать, тем более что теперь он использует литеральные значения. На самом деле вы можете заменить эти значения литералами:
if (commandbits & (1 << i)) {
PORTB |= 0x08;
} else {
PORTB &= 0xF7;
}
Это была моя первая идея. Я об этом не упоминал, но в моем случае чем быстрее, тем лучше. Мне придется провести проверку синхронизации одного лайнера и другого., @Noel
если вы хотите быстрее, вам нужно посмотреть ассемблерный код, который создает компилятор. Я думаю, что оператор if на самом деле будет быстрее, чем ваш код. AVR могут выполнять только один битовый сдвиг, поэтому <<3
будет тремя инструкциями. Обратите внимание, что компиляторы довольно умны. Так что не заменяйте (1<<3)
на 0x08
, думая, что так будет быстрее., @Gerben
Я подтверждаю, что if else работает намного быстрее. Спасибо за ваш вклад, Маженко и Гербен., @Noel
Если вам нравятся мобильность, читаемость и производительность, есть несколько библиотек (например, Arduino-GPIO):< /п>
#include "GPIO.h"
GPIO<BOARD::D11> data;
// Настраивать
data.output();
// Ручное развертывание цикла для повышения скорости. Можно попросить компилятор это сделать
// Функция-член write()
data.write(commandbits & 0x80);
data.write(commandbits & 0x40);
data.write(commandbits & 0x20);
data.write(commandbits & 0x10);
data.write(commandbits & 0x08);
// Или используя оператор присваивания
data = commandbits & 0x80;
data = commandbits & 0x40;
data = commandbits & 0x20;
data = commandbits & 0x10;
data = commandbits & 0x08;
И это так же быстро, как и прямой доступ к порту, написанный вручную.
Интересный. Ваш пример заставил меня задуматься, что мне лучше избавиться от цикла for и заменить (1<<i) их значением., @Noel
- Шестнадцатеричное/Байтовое реверсирование и преобразование
- Как инициализировать цифровой выходной контакт как LOW
- Использование контактов NodeMCU D8 (GPIO15), D4 (GPIO2) и D3 (GPIO0).
- Отправка цифрового сигнала с одного Arduino на другой для запуска события
- LSB/MSB и shiftOut
- Использование массивов, двоичных данных и битового чтения
- Случайная ошибка "Compilation error: Error: 13 INTERNAL: exit status 1". Как устранить или что вызывает эту ошибку
- Как настроить выходы без использования digitalWrite?
Вы же знаете, что ваш код не имеет смысла, не так ли? Подобный вывод данных с одного вывода никогда не принесет ничего полезного. Вам нужен тактовый сигнал (синхронный последовательный порт) или чтобы оба конца соединения согласовали достаточно точную синхронизацию (асинхронный последовательный порт). Или вы просто для краткости опустили эту часть кода?, @Majenko
Для краткости я многое опустил. очевидно..., @Noel
Тогда это нормально. Я тебя отпущу., @Majenko