Каскад из шести сдвиговых регистров

Тема в разделе "Arduino & Shields", создана пользователем Viktor161, 16 мар 2014.

  1. Viktor161

    Viktor161 Нуб

    Добрый день форумчане!
    В инете полно информации по подключению сдвиговых регистров 74HC595, но на всех примерах не более 2х штук, в силу своей малоопытности обращаюсь за помощью. Задача заставить бегать светодиод по линейке из 48шт(6 регистров). Нашел скетч для двух регистров, пробовал его доработать но требуемого результата не добился, остальные дублируют первые два регистра. Как я понимаю проблема в неправильной организации отправки байт в каскад..
    Прикладываю код с которым работал:
    Код (Text):
    #include <SPI.h>

    enum { REG = 8 };


    /* Теперь шлём по 16 бит. Важный момент: так как по умолчанию
    * данные передаются, начиная со старшего бита, сначала нужно
    * послать старший байт, затем - младший - тогда всё 16 бит
    * передадутся в правильном порядке.
    */
    void writeShiftRegister16(int ss_pin, uint16_t value)
    {
      digitalWrite(ss_pin, LOW);
      /* Фокус вот в чём: сначала шлём старший байт */
      SPI.transfer(highByte(value));
      /* А потом младший */
      SPI.transfer(lowByte(value));
      digitalWrite(ss_pin, HIGH);
    }


    void setup()
    {
      SPI.begin();

      pinMode(REG, OUTPUT);
      writeShiftRegister16(REG, 0);
    }


    /* Слегка изменим функцию для работы с 16-битными значениями */
    void rotateLeft(uint16_t &bits)
    {
      uint16_t high_bit = bits & (1 << 15) ? 1 : 0;
      bits = (bits << 1) | high_bit;
    }


    void loop()
    {
      static uint16_t nomad = 1;

      writeShiftRegister16(REG, nomad);
      rotateLeft(nomad);

      delay(1000 / 8);
    }
     
  2. Viktor161

    Viktor161 Нуб

    Не ужели никто не знает ответ на этот вопрос????:(:(
     
  3. Megakoteyka

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

    А в 6 регистров разве не нужно 6 байт записать?
    Иначе откуда возьмутся 48 сигналов на ногах регистров?
     
  4. Viktor161

    Viktor161 Нуб

    Нужно, как это правильно сделать?
     
  5. Megakoteyka

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

    Как-нибудь так:
    Код (Text):
    void writeShiftRegister16(int ss_pin, uint8_t *values, int count)
    {
      digitalWrite(ss_pin, LOW);
      for(int i = 0; i < length; i++)
        SPI.transfer(values[i]);
      digitalWrite(ss_pin, HIGH);
    }
    В эту функцию нужно передать массив из 6 байт.
     
  6. Viktor161

    Viktor161 Нуб

    Ругается:
    sketch_mar17a.ino: In function 'void setup()':
    sketch_mar17a:11: error: too few arguments to function 'void writeShiftRegister48(int, uint8_t*, int)'
    sketch_mar17a:25: error: at this point in file
     
  7. Viktor161

    Viktor161 Нуб

    Вот код походу я там накосячил..
    Код (Text):
    #include <SPI.h>

    enum { REG = 8 };


    void writeShiftRegister48(int ss_pin, uint8_t *values, int count)
    {
      digitalWrite(ss_pin, LOW);
      for(int i = 0; i < 3; i++)
        SPI.transfer(values[i]);
      digitalWrite(ss_pin, HIGH);
    }


    void setup()
    {
      SPI.begin();

      pinMode(REG, OUTPUT);
      writeShiftRegister48(REG, 0);
    }



    void rotateLeft(uint8_t &bits)
    {
      uint8_t high_bit = bits & (1 << 7) ? 1 : 0;
      bits = (bits << 1) | high_bit;
    }


    void loop()
    {
      static uint8_t nomad = 1;

      writeShiftRegister48(REG, nomad);
      rotateLeft(nomad);

      delay(1000 / 8);
    }
     
    Последнее редактирование: 17 мар 2014
  8. Megakoteyka

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

    Ошибка заключается в том, что функция принимает 3 аргумента, а Вы ей передаете только 2.
    Кроме того, нужно завести массив из 6 байт и передавать его (и его размер), а Вы передаете почему-то только один байт. И еще - в функцию передается количество байт, а Вы написали цикл на 3 итерации вместо того, чтобы использовать переданное количество.
     
  9. Viktor161

    Viktor161 Нуб

    С одним каскадом разобрался и опять завис, каскадов у меня будет 2шт и работать они будут одновременно, а сейчас получается по очереди. Я уже догадался что нужно избавляться от delay. Из прочитанного в интернете не могу сообразить как мне написать прогу бегущий огонек с использованием millis? Вот текст программы с delay. Подсажите пож кто чем может...
    Код (Text):

    int latchPin1 = 53;
    int latchPin2 = 49;
    int clockPin = 52;
    int dataPin = 51;


    void setup() {

      pinMode(latchPin1, OUTPUT);
      pinMode(latchPin2, OUTPUT);
      pinMode(dataPin, OUTPUT);
      pinMode(clockPin, OUTPUT);

    }
    void loop()
    {
              int index;
              int delayTime = 70;      
              for(index = 0; index <= 39; index++)
              {
                registerWrite1(index, HIGH);
                delay(delayTime);        
              }      
              for(index = 39; index <= 0; index--)
              {
                registerWrite2(index, HIGH);
                delay(delayTime);        
              }    
    }
     

    void registerWrite1(int whichPin, int whichState) {
      byte bitsToSend[5] = {0, 0, 0, 0, 0};
      digitalWrite(latchPin1, LOW);
      bitWrite(bitsToSend[whichPin/8], whichPin%8, whichState);
      for(int i = 0; i < 5; i++) shiftOut(dataPin, clockPin, LSBFIRST, bitsToSend[i]);
      digitalWrite(latchPin1, HIGH);
    }
    void registerWrite2(int whichPin, int whichState) {
      byte bitsToSend[5] = {0, 0, 0, 0, 0};
      digitalWrite(latchPin2, LOW);
      bitWrite(bitsToSend[whichPin/8], whichPin%8, whichState);
      for(int i = 0; i < 5; i++) shiftOut(dataPin, clockPin, LSBFIRST, bitsToSend[i]);
      digitalWrite(latchPin2, HIGH);
    }
     
     
  10. Megakoteyka

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

    Попробуйте вот такую логику:

    Код (Text):
    #define INTERVAL 70
    long _nextTime;// время очередной операции
    int counter = 0;// счетчик операций

    // тип операции - плюс или минус
    enum EOperation
    {
      PLUS,
      MINUS
    };

    EOperation _operation = PLUS;

    void setup()
    {
      _nextTime = millis() + INTERVAL;
    }

    void loop()
    {
      long time = millis();
      if(time >= _nextTime)
      {
        _nextTime = time + INTERVAL;
        Work();
      }
    }

    // функция будет вызываться каждые INTERVAL миллисекунд
    void Work()
    {
      // машина состояний
      switch(_operation)
      {
        case PLUS:
          // registerWrite1(...)
          counter++;
          if(counter == 40)
            _operation = MINUS;
          break;
         
        case MINUS:
          // registerWrite2(...)
          counter--;
          if(counter == 0)
            _operation = PLUS;
          break;
      }
    }
     
    Добавляя различные состояния в enum и соответствующие им ветки в switch, можно получить любое поведение программы.
     
  11. Viktor161

    Viktor161 Нуб

    Спасибо, не могли бы вы подсказать, какие аргументы нужно вставить в скобках registerWrite1(...)? И состояния enum и switch вручную добавлять?
     
  12. Viktor161

    Viktor161 Нуб

    Со скобками разобрался, работает только функция PLUS. MINUS не хочет?
     
  13. Megakoteyka

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

    Должно работать, там вроде ошибиться негде было. Покажите свой код или попробуйте вставить отладочный вывод в Serial в ветках switch. Тогда в мониторе увидите, чем занимается программа. Выводите, например, значение счетчика и название ветки.
     
  14. Megakoteyka

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

    Конечно, а какие еще могут быть варианты? :)
     
  15. Viktor161

    Viktor161 Нуб

    Я лучше код покажу!!:)
    Код (Text):
    #define INTERVAL 70
    long _nextTime;// время очередной операции
    int counter = 0;// счетчик операций
    int latchPin1 = 53;
    int latchPin2 = 49;
    int clockPin = 52;
    int dataPin = 51;

    // тип операции - плюс или минус
    enum EOperation
    {
      MINUS,
      PLUS
     
    };

    EOperation _operation = PLUS;

    void setup()
    {
      pinMode(latchPin1, OUTPUT);
      pinMode(latchPin2, OUTPUT);
      pinMode(dataPin, OUTPUT);
      pinMode(clockPin, OUTPUT);
      _nextTime = millis() + INTERVAL;
    }

    void loop()
    {
      long time = millis();
      if(time >= _nextTime)
      {
        _nextTime = time + INTERVAL;
        Work();
      }
    }

    // функция будет вызываться каждые INTERVAL миллисекунд
    void Work()
    {
      // машина состояний
      switch(_operation)
      {
        case PLUS:
          registerWrite1(counter, HIGH);
          counter++;
          if(counter == 40)
            _operation = MINUS;
          break;
       
        case MINUS:
          registerWrite2(counter, HIGH);
          counter--;
          if(counter == 0)
            _operation = PLUS;
          break;
      }
    }
    void registerWrite1(int whichPin, int whichState) {
      byte bitsToSend[5] = {0, 0, 0, 0, 0};
      digitalWrite(latchPin1, LOW);
      bitWrite(bitsToSend[whichPin/8], whichPin%8, whichState);
      for(int i = 0; i < 5; i++) shiftOut(dataPin, clockPin, LSBFIRST, bitsToSend[i]);
      digitalWrite(latchPin1, HIGH);
    }
    void registerWrite2(int whichPin, int whichState) {
      byte bitsToSend[5] = {0, 0, 0, 0, 0};
      digitalWrite(latchPin2, LOW);
      bitWrite(bitsToSend[whichPin/8], whichPin%8, whichState);
      for(int i = 0; i < 5; i++) shiftOut(dataPin, clockPin, LSBFIRST, bitsToSend[i]);
      digitalWrite(latchPin2, HIGH);
    }
    Ну например что бы я мог задать количество повторов, и он автоматом их гонял)
     
  16. Megakoteyka

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

    С ходу не вижу ошибок, должно работать. Давайте попробуем все же вставить отладочный вывод, вот так:
    Код (Text):
    // функция будет вызываться каждые INTERVAL миллисекунд
    void Work()
    {
      // машина состояний
      switch(_operation)
      {
        case PLUS:
          registerWrite1(counter, HIGH);
          counter++;
          Serial.print("P, counter = ");
          Serial.println(counter);
          if(counter == 40)
          {
            _operation = MINUS;
            Serial.println("changed to MINUS);
          }
          break;

        case MINUS:
          registerWrite2(counter, HIGH);
          counter--;
          Serial.print("M, counter = ");
          Serial.println(counter);
          if(counter == 0)
          {
            _operation = PLUS;
            Serial.println("changed to PLUS);
          }
          break;
      }
    }
    Что теперь выводится в монитор порта?
     
  17. Viktor161

    Viktor161 Нуб

    Спасибо!!
    В мониторе вот:
    Код (Text):
    P, counter = 1
    P, counter = 2
    P, counter = 3
    P, counter = 4
    P, counter = 5
    P, counter = 6
    P, counter = 7
    P, counter = 8
    P, counter = 9
    P, counter = 10
    P, counter = 11
    P, counter = 12
    P, counter = 13
    P, counter = 14
    P, counter = 15
    P, counter = 16
    P, counter = 17
    P, counter = 18
    P, counter = 19
    P, counter = 20
    P, counter = 21
    P, counter = 22
    P, counter = 23
    P, counter = 24
    P, counter = 25
    P, counter = 26
    P, counter = 27
    P, counter = 28
    P, counter = 29
    P, counter = 30
    P, counter = 31
    P, counter = 32
    P, counter = 33
    P, counter = 34
    P, counter = 35
    P, counter = 36
    P, counter = 37
    P, counter = 38
    P, counter = 39
    P, counter = 40
    changed to MINUS
    M, counter = 39
    M, counter = 38
    M, counter = 37
    M, counter = 36
    M, counter = 35
    M, counter = 34
    M, counter = 33
    M, counter = 32
    M, counter = 31
    M, counter = 30
    M, counter = 29
    M, counter = 28
    M, counter = 27
    M, counter = 26
    M, counter = 25
    M, counter = 24
    M, counter = 23
    M, counter = 22
    M, counter = 21
    M, counter = 20
    M, counter = 19
    M, counter = 18
    M, counter = 17
    M, counter = 16
    M, counter = 15
    M, counter = 14
    M, counter = 13
    M, counter = 12
    M, counter = 11
    M, counter = 10
    M, counter = 9
    M, counter = 8
    M, counter = 7
    M, counter = 6
    M, counter = 5
    M, counter = 4
    M, counter = 3
    M, counter = 2
    M, counter = 1
    M, counter = 0
    changed to PLUS
     
    Все правильно, но задача стоит другая. Мы строим светомузыкальный фонтан. Таких каскадов будет 4шт (один на контур) для управления клапанами и светом, работать они будут одновременно, но с разными программами, например: 1й по часовой стрелке, 2й против, третий молчит, 4й все открыты. Так же будет модуль управления частотными преобразователями по ШИМ.
    Как это реализовать с одного контроллера я так и не могу понять, реально ли это вообще?? Появилась мысля) если на модуле с регистрами я установлю ардуино мини (работает он по spi?? на сайте пишут "SPI: 10 (SS), 11 (MOSI), 12 (MISO), 13 (SCK). Посредством данных выводов осуществляется связь SPI, которая, хотя и поддерживается аппаратной частью, не включена в язык Arduino.")
    в которой у меня будут четыре стандартные программы : вправо, влево, закрыто, открыто. Эти программы будут привязаны к пинам входов, а на главном контроллере буду писать периодичность потенциалов на выходы. В результате чего смогу изменять картину работы фонтана. Как вы думаете?? Может есть какой нить вариант по проще??
     
  18. denziko

    denziko Нерд

    фонтаны это красиво :) мы вот тут одному алигарху на фазенду "мутим" светомузыкальный фонтанчик из
    связки arduino pro mini + tlc5940nt + msgeq7, чего и вам советую :)
    проще говоря на тлц намного легче и плавней будет открывать-закрывать краник чем на битовом 74HC595 :)
    хотя для 74HC595 есть отличная библиотека ShiftPWM
     
    Unixon нравится это.
  19. Unixon

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

    ШИМ на регистрах сдвига это что-то идеологически неправильное... как чесать левой пяткой правое ухо. Вот выделенный ШИМ контроллер или LED-драйвер с ШИМом - это намного интереснее.
     
  20. denziko

    denziko Нерд

    вот пример как на одном контроллере идет обработка звука, света и помпами.
    вместо помп у меня пока всего два куллера крутят от нч типа :)
    сделал медленно кулера чтоб была видна зависимость от звука.