shiftIn и 74HC165 (решено)

Тема в разделе "Arduino & Shields", создана пользователем DrProg, 26 май 2015.

  1. DrProg

    DrProg Вечный нерд

    Убил неожиданно много времени пытаясь подключить входной сдвиговый регистр к UNO. В принципе все довольно легко и понятно, но вот встроенная функция shiftIn возвращает состояние 7 ножек из 8, что слева направо читай что сплава налево. С ножками D0-D6 все замечательно, а на D7 никак не реагирует возвращаемым байтом. Может я что не так делал? Подскажите кто в курсе.

    В итоге плюнул и сделал функцию считывания сам:
    Код (Text):
    byte readByte() {
      byte byteR = 0;
      for (int i = 7; i >= 0; i--) {
        if (digitalRead(DATA_PIN)) bitSet(byteR, i);
        digitalWrite(CLOCK_PIN, HIGH);
        digitalWrite(CLOCK_PIN, LOW);
      }
      return byteR;
    }
    Работает превосходно по всеми восьмю ногам. Вдруг кому пригодится. Непосредственно перед считыванием байта состояния ножек, выполнять защелкивание байта в буфере регистра:
    Код (Text):
    void latchData() {
      digitalWrite(LATCH_PIN, LOW);
      digitalWrite(LATCH_PIN, HIGH);
    }
    Впрочем, это нужно делать и перед shiftIn.
     
    Последнее редактирование: 26 май 2015
  2. iglooshtosser

    iglooshtosser Гик

    А это учтено?

    If you're interfacing with a device that's clocked by rising edges, you'll need to make sure that the clock pin is low before the first call to shiftIn(), e.g. with a call to digitalWrite(clockPin, LOW)

    Может причина в этом? Текст из описания shiftin на arduino.cc
     
  3. DrProg

    DrProg Вечный нерд

    Я это видел, не помогает. D7 не отвечала при любых настройках.
     
  4. iglooshtosser

    iglooshtosser Гик

    Странно. Вот исходник:

    Код (Text):
    uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) {
      uint8_t value = 0;
      uint8_t i;

      for (i = 0; i < 8; ++i) {
        digitalWrite(clockPin, HIGH);
        if (bitOrder == LSBFIRST)
          value |= digitalRead(dataPin) << i;
        else
          value |= digitalRead(dataPin) << (7 - i);
        digitalWrite(clockPin, LOW);
      }
      return value;
    }
    Вроде бы делает тоже самое... да и так же.
     
  5. iglooshtosser

    iglooshtosser Гик

    Ха. А разница в том, что DrProg сначала читает потом тикает, а исходная фунцция сначала тикает, а потом читает. Так она один бит, похоже, и теряет :)

    Мои поздравления :)
     
    DrProg нравится это.
  6. DrProg

    DrProg Вечный нерд

    Насколько я понимаю, защелка в LATCH последовательно выставляется в LOW и HIGH, после чего данные фиксируются в буфере и могут быть считаны shiftIn-ом. Что вы имеете ввиду под тиканием? Выставление CLOCK в LOW? Делал и до и после защелкивания. Какие еще варианты?

    Да и еще вот смотрю на код shiftIn-а, по сути то же самое что у меня, только с другой стороны и биты иначе добавляются. Не понятно в чем разница. Но у меня как то проще и нагляднее получилось, не обязательно тики отдельно тикать. )
     
    Последнее редактирование: 26 май 2015
  7. iglooshtosser

    iglooshtosser Гик

    CLOCK в HIGH. собственно по этому событию происходит сдвиг данных в регистре. Смотрите что получается: Если изначально, в момент вызова функции, CLOCK низкий то:
    1. Ваша фунция читает бит, потом выдает HIGH на CLOCK, то есть сдвигает данные, "подает на выход" следующий бит.
    2. Исходная функция выдает HIGH на CLOCK, то есть сдвигает данные, "подает на выход" следующий бит, ПОТОМ читает его. Фактически один бит так никогда и не читается.

    Проверяется просто: нужно перед вызовом shiftin и перед защелкиванием данных выставить CLOCK в HIGH. Если я прав, то прочитаются все 8 бит.
     
  8. DrProg

    DrProg Вечный нерд

    Спасибо, я попробую.
     
  9. Megakoteyka

    Megakoteyka Оракул Модератор

    Разница в том, что shiftIn умеет заталкивать разряды в байт с заданного конца.
     
  10. DrProg

    DrProg Вечный нерд

    Да, так и случилось. Почему тогда пишут что перед считыванием нужно подавать LOW?
    Вот код с обеими вариантами, оба теперь рабочие:
    Код (Text):
    void loop() {


    // стандартный способ 3 строки:
      digitalWrite(CLOCK_PIN, HIGH);
      latch();
      byt = shiftIn(DATA_PIN, CLOCK_PIN, MSBFIRST);

      // собственный способ в 1 строку:
      //byt = readByte();

      digitalWrite(LATCH_PIN_L, LOW);
      shiftOut(DATA_PIN_L, CLOCK_PIN_L, LSBFIRST, byt);
      digitalWrite(LATCH_PIN_L, HIGH);

      //  Serial.println(byt);
      delay (100);
    }

    byte readByte() {
      byte byteR = 0;
      latch();
      for (int i = 7; i >= 0; i--) {
        if (digitalRead(DATA_PIN)) bitSet(byteR, i);
        digitalWrite(CLOCK_PIN, HIGH);
        digitalWrite(CLOCK_PIN, LOW);
      }
      return byteR;
    }

    void latch () {
      digitalWrite(LATCH_PIN, LOW);
      digitalWrite(LATCH_PIN, HIGH);
    }
     
    Данные снимаются через регистр 165 и передаются на 595. В итоге получается вот такое. То есть через 6 пинов можно получать большое количество цифровых входов и выходов, соединяя регистры каскадами. Что и требовалось.

    Думаю не проблема допилить функцию или сделать две одна слева, другая справа. Но вот надо ли? Впрочем, мне моя кажется удобнее и короче.
     
    Последнее редактирование: 27 май 2015
  11. Megakoteyka

    Megakoteyka Оракул Модератор

    Кому-то нужно в одну сторону, кому-то в другую. Функция универсальна.
     
  12. iglooshtosser

    iglooshtosser Гик

    Это мне было очевидно ещё вчера, по итогам изучения кода :oops:

    Думаю что налицо ошибка. Причем ошибка в самой функции, а не в описании.
     
  13. iglooshtosser

    iglooshtosser Гик

    Но, как оказалось в ней баг фича. :) Да и вообще она обладает фатальным недостатком ;)
     
  14. DrProg

    DrProg Вечный нерд

    Юзайте мою, она без недостатков и без подготовок работает. )
    А направление считывания поменять руками работы на 10 секунд.
     
  15. Megakoteyka

    Megakoteyka Оракул Модератор

    Ваша функция использует в качестве номеров пинов константы, объявленные где-то снаружи. А если нужно читать с разных регистров, то как быть? Про порядок сборки байта я уже говорил выше.
    Библиотечная функция универсальна, она принимает и номера пинов, и желаемое направление сборки байта. Вы можете отправить автору библиотеки свои замечания и он ее исправит. И правильно работающая функция появится в новой версии.
     
  16. DrProg

    DrProg Вечный нерд

    Код (Text):
    byte readByteL(int clockPin, int dataPin, int latchPin) {
      byte byteR = 0;
      latch(latchPin);
      for (int i = 7; i >= 0; i--) {
        if (digitalRead(dataPin)) bitSet(byteR, i);
        digitalWrite(clockPin, HIGH);
        digitalWrite(clockPin, LOW);
      }
      return byteR;
    }

    byte readByteM(int clockPin, int dataPin, int latchPin) {
      byte byteR = 0;
      latch(latchPin);
      for (int i = 0; i <= 7; i++) {
        if (digitalRead(dataPin)) bitSet(byteR, i);
        digitalWrite(clockPin, HIGH);
        digitalWrite(clockPin, LOW);
      }
      return byteR;
    }

    void latch (int latchPin) {
    digitalWrite(latchPin, LOW);
    digitalWrite(latchPin, HIGH);
    }
     
  17. Megakoteyka

    Megakoteyka Оракул Модератор

    Какой смысл в двух функциях, если их можно заменить одной?
     
  18. DrProg

    DrProg Вечный нерд

    Можно и одной, согласен, правда будет более громоздкой.
     
  19. Megakoteyka

    Megakoteyka Оракул Модератор

    Одна более универсальная функция будет менее громоздкой, чем две отдельные функции. И программисту проще помнить одно имя функции вместо двух.
    Если код очень критичен ко времени выполнения, то есть смысл делать отдельную функцию и оптимизировать ее по самое не могу, но это явно не тот случай.
     
  20. DrProg

    DrProg Вечный нерд

    Я не стремлюсь заменить библиотечную функцию своей. С встроенной были недопонимания, написал свою, потом разобрались что к чему. Но для тренировки задача полезная.