Замените 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);
}

Это самый лаконичный способ. Есть ли способ упростить это?

, 👍0

Обсуждение

Вы же знаете, что ваш код не имеет смысла, не так ли? Подобный вывод данных с одного вывода никогда не принесет ничего полезного. Вам нужен тактовый сигнал (синхронный последовательный порт) или чтобы оба конца соединения согласовали достаточно точную синхронизацию (асинхронный последовательный порт). Или вы просто для краткости опустили эту часть кода?, @Majenko

Для краткости я многое опустил. очевидно..., @Noel

Тогда это нормально. Я тебя отпущу., @Majenko


2 ответа


Лучший ответ:

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


1

Если вам нравятся мобильность, читаемость и производительность, есть несколько библиотек (например, 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