Как последовательно сдвигать двоичный файл в регистр сдвига (последовательный ввод, параллельный вывод)

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

Вот схема моей первоначальной идеи:

С одного конца разъема (выход на схеме) я хочу выполнить сдвиг в двоичном коде, который находится в степени 2. Например, сдвиг в 0001, проверка непрерывности путем считывания 75HC165 (параллельный ввод, последовательный вывод), затем очистка регистра и затем сдвиг в 0010, а затем 0100 и так далее. Для правильно закрепленного жгута проводов двоичное вычитание записи и чтения будет равно нулю.

Вот мой цикл, который пытается выполнить описанное выше:

void loop() {
  for (int i = 1; i < 4; i++) {
    reset_SIPO_register();
    shift_SIPO(pow(2,i));
    delay(2000);
    shift_SIPO(0x00));
    check_continuity(); // еще не реализовано
  }
}

void reset_SIPO_register() {
  digitalWrite(reset_pin, LOW);
  digitalWrite(reset_pin, HIGH);
}

void shift_SIPO(int sequence) {
  digitalWrite(latch_pin, LOW);
  shiftOut(data_pin, clock_pin, MSBFIRST, sequence);
  digitalWrite(latch_pin, HIGH);
}

Я тестирую эту концепцию на макете со светодиодами, и все вышеперечисленное работает. Однако светодиод загорается по одному, и они не гаснут, не следуя двоичному коду.

Есть ли что-то, чего я здесь не понимаю? Спасибо!

, 👍-1

Обсуждение

да, вам не хватает полной принципиальной схемы и полного кода из вашего сообщения, @jsotola


1 ответ


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

2

Не используйте pow(). Это функция, которая работает с числами с плавающей запятой. Это примерно эквивалентно (для y> 0)

double pow(double x, double y)
{
    return exp(y * log(x));
}

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

В качестве примера, если вы вычислите pow(2, i) для i = 3, вы получите 7.9999980926513671875. Это на 4 ULPs меньше точного значения. Передача этого числа в shift_SIPO() неявно преобразует его в int, и это преобразование всегда округляется до нуля. Таким образом, вы получаете 7, т.е. 0в0111.

То, что вам нужно, - это целочисленная, точная реализация pow(2, i). Оказывается, это довольно просто: возьмите целое число 1 в двоичном формате, затем сдвиньте его i раз влево. То есть

shift_SIPO(1 << i);
,

Спасибо! это сработало!, @Brendon Cheung