Прошу совета. (Бегущая строка.)

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

  1. olegoriy

    olegoriy Гик

    Доброй ночи!
    Хотелось бы посоветоваться.
    Купил вот такие матрицы : http://ru.aliexpress.com/item/LED-D...517.html?adminSeq=201767208&shopNumber=713545
    И очень разочаровался.
    Пять таких матриц через сдвиговые регистры не могу запустить уже третий день(проклял их уже)
    Дело даже не в коде а в подключении.
    Суть не в этом.
    ГЛАВНЫЙ ВОПРОС:
    Если я куплю 1500 светодиодов и соберу панель 10х150 , хватит ли возможностей ардуины нано или уно?
    Горизонтальные 10 строк хочу пустить катодами, а вертикальные 150 анодами.
     
  2. Unixon

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

    В чем именно проблема?
     
  3. olegoriy

    olegoriy Гик

    Да то ножки не в ту сторону посчитаю , спаяю все, потом матерюсь.
    Потом понял что на макетке припаял матрицы не так как хотел.
    Еще стал подавать 3.3 вольта , чтобы проверить и спалил 3 светодиода.
    После все было отпаяно и переделано с резисторами.
    И теперь еще где-то на второй строчке подкорачивает( не было времени разбираться , рабочий день закончился.)
    Главной сути вопроса не меняет : Хватит ли ардуины на 10 Х 150 с выводом букв или предположим анимации???
     
  4. Unixon

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

    Ох... По мне так это от недостатка проектирования все. Сначала нужно собрать все данные по компонентам, рассчитать режим работы, нарисовать принципиальную схему, по ней монтажную, еще раз все перепроверить, потом по монтажной схеме собрать устройство. Если есть какие-то сомнения, собирать по частям, отлаживая каждый блок по отдельности.
     
  5. Unixon

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

    Давайте посчитаем.

    1) Сколько нужно памяти, чтобы хранить 1 кадр для такой матрицы? 8 байт на матрицу, 1200Кб на кадр. ОК, пойдет.

    2) Сколько нужно времени, чтобы вывести кадр? Зависит от включения матриц. Чем больше матриц могут работать независимо, тем меньше проблем с динамикой, но тем больше регистров нужно записать.

    Как минимум, нужно заполнить 10 регистров для анодов + 15 для катодов, итого 25 байт на строку, 2Кб на кадр. При использовании аппаратного SPI на полной частоте процессора в 16МГц получаем не более 1К строк в секунду, при FPS=25 это будет 40 циклов на кадр, т.е. можно себе позволить скважность ~2.5%. Реально программа будет еще тормозить в разных местах и скорость будет меньше, но в качестве первого приближения все вроде бы выглядит возможным.

    Возьмем другой вариант. Пусть анодный регистр будет общий для всех матриц, а катодный регистр будет у каждой матрицы свой. Тогда каждая строка будет размером 151 байт, но кадр будет всего 1208 байт. При прочих равных получаем 66 циклов на кадр, дальше либо играем со скважностью, либо с FPS. Во втором варианте максимальный FPS при равной скважности получается в ~1.65 раз больше.

    А вот анимация будет очень короткой, через PROGMEM можно втащить только 64Кб, т.е. не более 2 секунд анимации при посредственном FPS, через PROGMEM_FAR можно попытаться утянуть все 256К на меге, но это очень неудобно и даст всего секунд 4-5 анимации. Если сжатие какое применить, может и немного больше.
     
    Последнее редактирование: 1 окт 2015
    olegoriy нравится это.
  6. Unixon

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

    Аноды в любой из схем нужно питать через транзисторы - либо NPN биполярники, либо P-канальные полевики. Резисторы только на катодах. Для повышения импульсного тока при динамической индикации катодные резисторы можно попробовать шунтировать небольшими емкостями, чтобы время зарядки шунта было порядка времени свечения строки.
     
    Последнее редактирование: 1 окт 2015
  7. olegoriy

    olegoriy Гик

    Большое спасибо за более чем исчерпывающий ответ.
     
  8. olegoriy

    olegoriy Гик

    Разобрался со своими матрицами. Оказываеться та на которой спалил светодиоды коротила всю конструкцию в момент подачи на эти светодиоды.

    Но теперь проблемма в другом.
    Дальше чем, пробежаться бегущим огоньком по всем светодиодам, мыслей не каких нет.
    Точнее мыслей куча, что выводить на "экран" я то найду, но как это осуществить программно даже боюсь представить.
    Не могу придумать как выводить хотя бы стационарные цифры, не говоря уже о бегущих буквах.:(
     
  9. Unixon

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

    Все уже придумано до нас. Ваша сложная задача разбивается на две попроще:
    1) рисование чего-либо в экранном буфере (framebuffer) в памяти МК;
    2) вывод экранного буфера на светодиодную матрицу;
     
  10. olegoriy

    olegoriy Гик

    Спасибо сейчас погуглю.
    А пока на данный момент пришел к такому коду:
    Выводим цифры " 1 2 3 4 "
    Код (C++):
     #define latch_Pin  5           // Регистр катодов
    #define CLOCK_PIN  6
    #define data_Pin  7
    #define latch_Pin1  2          // Регистр анодов
    #define CLOCK_PIN1  3
    #define data_Pin1  4
    byte segment[9] = {                                          
       0b00000000, 0b10000000, 0b01000000, 0b00100000, 0b00010000,
       0b00001000, 0b00000100, 0b00000010, 0b00000001
    };
      byte segments1[9] = {                                                    // Цифра 1
       0b11111111, 0b11000001, 0b11110111, 0b11110111, 0b11110111, 0b11010111,
       0b11100111, 0b11110111, 0b11111111
    };
      byte segments2[9] = {                                                    // Цифра 2
       0b11111111, 0b11000011, 0b11011111, 0b11101111, 0b11110111, 0b11011011,
       0b11011011, 0b11100111, 0b11111111
    };
    byte segments3[9] = {                                                     // Цифра 3
       0b11111111, 0b11100111, 0b11011011, 0b11111011, 0b11100111, 0b11111011,
       0b11011011, 0b11100111, 0b11111111
    };
    byte segments4[9] = {                                                     // Цифра 4
       0b11111111, 0b11111011, 0b11111011, 0b11111011, 0b11000011, 0b11011011,
       0b11011011, 0b11011011, 0b11111111
    };

    int v = 1;
    void setup() {
       pinMode(latch_Pin, OUTPUT);
       pinMode(CLOCK_PIN, OUTPUT);
       pinMode(data_Pin, OUTPUT);
     
       pinMode(latch_Pin1, OUTPUT);
       pinMode(CLOCK_PIN1, OUTPUT);
       pinMode(data_Pin1, OUTPUT);
       

    }

    void loop() {
         for (int i=1; i <= 8; i++){
         digitalWrite(latch_Pin1, LOW);                            
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[i]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         digitalWrite(latch_Pin1, HIGH);
       
         digitalWrite(latch_Pin, LOW);                            
         shiftOut(data_Pin, CLOCK_PIN, MSBFIRST, segments4[i]);    
         digitalWrite(latch_Pin, HIGH);
         delay(v);
       
         digitalWrite(latch_Pin1, LOW);                            
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         digitalWrite(latch_Pin1, HIGH);
       
         digitalWrite(latch_Pin, LOW);                            
         shiftOut(data_Pin, CLOCK_PIN, MSBFIRST, segments4[0]);    
         digitalWrite(latch_Pin, HIGH);
       
       
       
         digitalWrite(latch_Pin1, LOW);                            
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[i]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         digitalWrite(latch_Pin1, HIGH);
         digitalWrite(latch_Pin, LOW);                            
         shiftOut(data_Pin, CLOCK_PIN, MSBFIRST, segments3[i]);    
         digitalWrite(latch_Pin, HIGH);
         delay(v);
       
         digitalWrite(latch_Pin1, LOW);                            
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         digitalWrite(latch_Pin1, HIGH);
       
         digitalWrite(latch_Pin, LOW);                            
         shiftOut(data_Pin, CLOCK_PIN, MSBFIRST, segments4[0]);    
         digitalWrite(latch_Pin, HIGH);
       
         digitalWrite(latch_Pin1, LOW);                            
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[i]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         digitalWrite(latch_Pin1, HIGH);
         digitalWrite(latch_Pin, LOW);                            
         shiftOut(data_Pin, CLOCK_PIN, MSBFIRST, segments2[i]);    
         digitalWrite(latch_Pin, HIGH);
         delay(v);
       
         digitalWrite(latch_Pin1, LOW);                            
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         digitalWrite(latch_Pin1, HIGH);
       
         digitalWrite(latch_Pin, LOW);                            
         shiftOut(data_Pin, CLOCK_PIN, MSBFIRST, segments4[0]);    
         digitalWrite(latch_Pin, HIGH);
       
         digitalWrite(latch_Pin1, LOW);                            
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[i]);
         digitalWrite(latch_Pin1, HIGH);
         digitalWrite(latch_Pin, LOW);                            
         shiftOut(data_Pin, CLOCK_PIN, MSBFIRST, segments1[i]);    
         digitalWrite(latch_Pin, HIGH);
         delay(v);
       
         digitalWrite(latch_Pin1, LOW);                            
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         digitalWrite(latch_Pin1, HIGH);
       
         digitalWrite(latch_Pin, LOW);                            
         shiftOut(data_Pin, CLOCK_PIN, MSBFIRST, segments4[0]);    
         digitalWrite(latch_Pin, HIGH);
       
         }
    Вроде цифры видно, но моргает нереально))
    Это пока все что смог придумать сам.
     
  11. DrProg

    DrProg Вечный нерд

    Моргает потому, что digitalWrite ну очень медленная функция, когда ее много. Советую заменить на аналоги из FastIO или на прямое обращение к портам, заработает в десятки раз быстрее. Плата какая? Да, и выводить на регистры можно каскадом, сэкономите пины и программка будет выглядеть менее громоздко.


    И еще, писать программу столбиком должны только китайцы, они это любят больше риса. А для остальных придуманы циклы.
     
    ИгорьК и olegoriy нравится это.
  12. olegoriy

    olegoriy Гик

    Плата ардуно нано.
    5 Регистров анодов ыключены каскадом.
    1 Регистр катодов отдельно.( думал так будет проще)
    Про"Советую заменить на аналоги из FastIO или на прямое обращение к портам"
    ткните плиз носом где почитать)
     
  13. DrProg

    DrProg Вечный нерд

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

    Прямое обращение к портам более универсально и проще в освоении. Функции выглядят примерно так:

    Код (C++):
    inline  void PBdigWH(byte NB) {                 // установка 1 в бит NB порта B
      PORTB |= 1 << NB;
    }

    inline  void PBdigWL(byte NB) {                 // установка 0 в бит NB порта B
      PORTB &= ~(1 << NB);
    }
     
    Тут важно один раз вычислить какие пины на вашей плате соответствуют какому порту и какому биту, например на Меге D13 пин это 7 бит порта B. Если используется, например, порт A, легко заменить в приведенных выше функциях PORTB на PORTA. И вместо ShiftOut написать свою функцию на основе этих:

    Код (C++):
    void writeByteP(byte byteW) {                          // аналог shiftOut, работает быстрее во много раз
      for (int i = 0; i <= 7; i++)
      {
        if (bitRead(byteW, i)) {
          PBdigWH(DATA_PIN);
        } else {
          PBdigWL(DATA_PIN);
        }
        PBdigWH(CLOCK_PIN);
        PBdigWL(CLOCK_PIN);
      }
    }
    Опять же в качестве DATA_PIN и CLOCK_PIN должны быть указаны не пины платы, а биты используемого порта. Найдете сами какой порт и биты соответствуют пинам 5, 6 и 7 у Нано? Очень полезно немного вникнуть, игра стоит свеч.

    У вас, кроме этого, в программе я бы вообще многое заменил. Например, зачем нужно вот это:
    Код (C++):
    byte segment[9] = {                                        
       0b00000000, 0b10000000, 0b01000000, 0b00100000, 0b00010000,
       0b00001000, 0b00000100, 0b00000010, 0b00000001
    Двигать активный бит можно гораздо проще в цикле командой ">>".

    И вот это вот:
    Код (C++):
      byte segments1[9] = {                                                    // Цифра 1
       0b11111111, 0b11000001, 0b11110111, 0b11110111, 0b11110111, 0b11010111,
       0b11100111, 0b11110111, 0b11111111
    };
      byte segments2[9] = {                                                    // Цифра 2
       0b11111111, 0b11000011, 0b11011111, 0b11101111, 0b11110111, 0b11011011,
       0b11011011, 0b11100111, 0b11111111
    };
    ...и так далее. Если используете массивы, то используйте их полностью. В данном случае сделайте двухмерный bytesegments[4][9], это позволит автоматизировать, а не вызывать изображение каждого символа вручную.

    Сама же программа должна состоять из вложенных циклов запихивания массивов в регистры, включая регистр катодов (я его обычно ставлю первым).
     
    ИгорьК и olegoriy нравится это.
  14. olegoriy

    olegoriy Гик

    Еще не прочитал ваше последнее сообщение, просто переполняют имоции.
    Да это нахрен какоето чудо!! Большое спасибо дрожание пропало void loop() сократился до такого:
    Код (C++):
    void loop() {
         for (int i=1; i <= 8; i++){
         PORTD = B00000000;                            
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[i]);
         shiftOut(data_Pin, CLOCK_PIN, MSBFIRST, segments4[i]);    
         PORTD = B00100100;
       
         PORTD = B00000000;                            
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[i]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin, CLOCK_PIN, MSBFIRST, segments3[i]);    
         PORTD = B00100100;
       
         PORTD = B00000000;                            
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[i]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin, CLOCK_PIN, MSBFIRST, segments2[i]);    
         PORTD = B00100100;
       
         PORTD = B00000000;                            
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[i]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin1, CLOCK_PIN1, LSBFIRST, segment[0]);
         shiftOut(data_Pin, CLOCK_PIN, MSBFIRST, segments1[i]);    
         PORTD = B00100100;
         }
     
  15. DrProg

    DrProg Вечный нерд

    Все это можно утрамбовать в несколько строк кода, при этом подняв произволительность во много раз. Но если совершенствовать нет смысла, то ладно. )
     
    ИгорьК нравится это.
  16. olegoriy

    olegoriy Гик

    Совершенствовать смысл и желание есть.
    Массив сделал двумерным по вашему совету.
    И с кодом еще поработаю над сокращением.