«Бегущая строка» — динамическая индикация на примере светодиодной матрицы RL-M2388 и Arduino Mega

    Данная статья не претендует на толкование как единственно возможного метода отображения и прокрутки информации на светодиодной матрице. Я с удовольствием выслушаю ваши замечания и предложения по улучшению метода/функций. Данная статья – изложение личного опыта и описание результата, которого я добился.

    Немного теории

    В данной светодиодной матрице находится 64 красных светодиода. Если выводить контакты каждого светодиода отдельно, то понадобится 64 контакта на корпусе матрицы и микроконтроллер с 65 цифровыми портами ввода/вывода. Это нецелесообразно и невыгодно. Поэтому на заводе-изготовителе светодиоды объединяют в матрицы различных размеров (в нашем случае 8х8), то есть в 8 групп по строкам и столбцам следующим образом:
    image

    В таком случае нам понадобится лишь 16 цифровых вводов/выводов. Например, чтобы зажечь светодиод в левом верхнем углу, нам нужно на pin13 (см. картинку) подать лог 1, а на pin9 лог 0. Такой способ отображения называется статическая индикация.

    «Хорошо, а если нам, например, нужно зажечь несколько светодиодов в разных позициях матрицы, а все остальные оставить выключенными?» — спросите Вы. При статической индикации это не представляется возможным. Для этого нужно использовать динамическую индикацию.

    Динамическая индикация

    Быстро мелькающий объект кажется человеческому глазу постоянно светящимся. Это свойство человеческого глаза – инертность. Как вы догадались, именно на этом свойстве и основан метод вывода информации в светодиодной матрице. Например, чтобы вывести на «экран» некий символ, нужно последовательно, проходя все «пиксели» матрицы с высокой скоростью, включать светодиод в нужном месте.

    Условия, которые необходимо соблюдать при программировании матриц динамической индикации:
    1. Длительность отображения каждого столбца/строки («пикселя» в моем случае) постоянна, одинакова для всех столбцов/строк («пикселей» в моем случае).
    2. Частота смены столбцов/строк («пикселей» в моем случае) не меняется.

    Принцип действия прошивки микроконтроллера

    Признаюсь, когда у меня появилась отладочная плата на МК Atmega1280 и светодиодная матрица, я и понятия не имел что такое динамическая индикация и для чего она нужна. До понимания необходимости ее использования я дошел методом проб и методом «тыка».

    Принцип действия прошивки:

    1. Вывод символа на экран

    Давайте представим, что наша светодиодная матрица – это двухмерный массив размерностью I на J, совпадающей с размерностью нашей матрицы. В нашем случае это 8 на 8 пикселей. Итак, есть двухмерный массив типа boolean. К примеру:

    boolean A[8][8] =
    {0,0,1,1,1,1,0,0,
     0,1,0,0,0,0,1,0,  
     0,1,0,0,0,0,1,0,  
     0,1,0,0,0,0,1,0,  
     0,1,1,1,1,1,1,0,  
     0,1,0,0,0,0,1,0,  
     0,1,0,0,0,0,1,0,  
     0,1,0,0,0,0,1,0}  


    В цикле мы проверяем, если элемент массива A[i][j]=1, тогда включаем светодиод на матрице, находящийся в позиции (I;J), делаем паузу на отображения светодиода и выключаем светодиод в позиции (I;J). В результате работы программы по такому алгоритму на экране матрицы выведется символ «А» (в двумерном массиве именно этот символ отображен). Назовем этот алгоритм «Вывод на экран». Итак, с выводом информации на экран с помощью динамической индикации разобрались.

    2. Прокрутка информации на экране

    Конечно, классно выводить на экран неподвижную информацию, но было бы интереснее «оживить» ее – заставить передвигаться. Рассмотрим алгоритм перемещения информации:

    В бесконечном цикле выполняем:
    1. Вызываем алгоритм «Вывод на экран».
    2. Берем 1й столбец матрицы А и записываем его в буфер (двухмерный массив BUFFER[8][1]).
    3. Записываем содержимое матрицы с позиции A[i][j+1] в позицию A[i][j]. То есть мы по сути «сдвинули» матрицу влево на один столбец.
    4. Записываем в последний столбец матрицы А (в свободный, так как мы сдвинули матрицу влево на один столбец) содержание буфера BUFFER. Назовем этот алгоритм «Прокрутка информации».

    Вот и весь алгоритм прокрутки информации на экране. Теперь, зная алгоритмы вывода и прокрутки информации с помощью динамической индикации, мы можем приступить к практике.

    Подключение матрицы к отладочной плате

    Каждый из 16ти выводов матрицы пронумерован. В соответствии этим номерам были подпаяны и выведены 8 контактов, отвечающих за строки, и 8 контактов, отвечающих за столбцы. У меня, например, матрица подключена так:

    Выводы, отвечающие за строки 23,25,27,29,31,33,35,37 – это номера выводов ножек микроконтроллера;
    Выводы, отвечающие за столбцы 39,41,43,45,47,49,51,53 — это номера выводов ножек микроконтроллера.

    Программирование

    Программирование и прошивка микроконтроллера производится в среде разработки Arduino IDE.

    Что необходимо знать для понимания кода программы, написанного ниже:

    Функция pinMode()
    Устанавливает режим работы заданного вход/выхода(pin) как входа или как выхода.
    pinMode(pin, mode), где pin: номер вход/выхода(pin), который Вы хотите установить; mode: режим одно из двух значение — INPUT или OUTPUT, устанавливает на вход или выход соответственно.

    Функция digitalWrite()
    Подает HIGH или LOW значение на цифровой вход/выход (pin).
    digitalWrite(pin, value), где pin: номер вход/выхода(pin); value: значение HIGH или LOW

    Функция delayMicroseconds()
    Останавливает выполнение программы на заданное в параметре количество микросекунд (1 000 000 микросекунд в 1 секунде).
    delayMicroseconds(us), где us: количество микросекунд, на которое приостанавливается выполнение программы. (unsigned int)

    Структура любой программы (скетча, так как в среде разработки ардуино программы называются именно так) имеет следующий вид:

    void setup()
    {
    …
    }
    
    void loop()
    {
      …
    }


    В функции setup() производятся настройки портов ввода/вывода МК, настройка подключенных устройств к МК, периферии МК, а так же выполняется все то, что нужно выполнить ОДИН раз.
    В функции loop() пишется тело программы, которое будет выполняться циклически, пока микроконтроллер включен.

    Выполним настройку выводов микроконтроллера. Состояний портов ввода/вывода существует два вида: настроен на вход либо на выход. В нашем случае нужно настроить на выход.

    
    const int row[8]={23,25,27,29,31,33,35,37}; // Помните 8 выводов, отвечающих за строки и
    const int col[8]={39,41,43,45,47,49,51,53}; // столбцы? А вот и они. 
    
    void setup()
    {
         for (int i=0; i<8; i++)
    {
         pinMode(row[i],OUTPUT); // В цикле все выводы переводим в режим «на вывод»
         pinMode(col[i],OUTPUT); // Выключаем все светодиоды
    }
         for (int i=0; i<8; i++)
             {
                 digitalWrite(row[i],HIGH);
             }
    }


    Давайте теперь реализуем алгоритмы, которые я описал выше. Итак, мы имеем двухмерный массив:

    
    boolean A[8][8] = 
    {0,0,1,1,1,1,0,0,
    0,1,0,0,0,0,1,0,  
    0,1,0,0,0,0,1,0,  
    0,1,0,0,0,0,1,0,  
    0,1,1,1,1,1,1,0,  
    0,1,0,0,0,0,1,0,  
    0,1,0,0,0,0,1,0,  
    0,1,0,0,0,0,1,0} 


    Напишем функцию, которая реализует алгоритм «Вывод на экран».

    int v=3; //Скорость прокручивания информации. То есть по сути это количество итераций цикла отрисовки информации в матрице
    int dms=400; //Скорость обновления «пикселей». То есть время, когда светодиод находится во включенном состоянии. Чем оно больше, тем более заметнее глазу будет мерцание изображения
    void paint(boolean screen[8][8], int v) //В качестве параметров передаем матрицу и параметр v  
    {  
    int i, j;
    for (int c=0; c <v; c ++) // Тот самый цикл задержки отрисовки информации 
      {
        for (i=0; i<8; i++)
          for (j=0; j<8; j++)
            {
              if (screen[i][j]= =1) // Если элемент массива = 1
                {
                  digitalWrite(row[i], LOW); 
                  digitalWrite(col[j], HIGH); 
                  delayMicroseconds(dms); 
     	      digitalWrite(row[i], HIGH); 
                  digitalWrite(col[j], LOW); //  То включить светодиод                 в проверяемой позиции, задержать включенным, выключить светодиод.
                }
                else 
                   {
                      digitalWrite(row[i], HIGH); 
                      digitalWrite(col[j], LOW); 
                      delayMicroseconds(dms);
                      digitalWrite(row[i], HIGH); 
                      digitalWrite(col[j], LOW);
                  } // Иначе выключить светодиод в проверяемой позиции, задержать включенным, обновить экран. (даже если светодиод и был выключенным в этой позиции, то все равно его нужно «выключить» для того, чтобы проверка в цикле и действия проходили с одинаковой задержкой. Если в позиции 1 – то выполняются действия, если в позиции 0 – все равно должно что-то выполнится либо выполнится задержка, сопоставимая с задержкой выполнения включения светодиода)
            } 
        }
    }


    Напишем функцию, которая реализует алгоритм «Прокрутка информации».

    void scroll(boolean screen[8][8]) // В качестве параметра передаем наш двухмерный массив   
    {
    boolean buf[8][1]; 
      for (int i=0; i<8; i++)
      {
        buf[i][0]=screen[i][0]; // Считали 1ю колонку в буфер
      }
      for (int i=0; i<8; i++)
        for (int j=0; j<8; j++)
          {
            screen[i][j]=screen[i][j+1]; // Сдвинули матрицу на один столбец влево
          }
      for (int i=0; i<8; i++)
      {
        screen[i][8-1]=buf[i][0]; // Записали содержимое буфера (первую колонку) в конец матрицы
      }
    }


    Теперь приведу полный код программы:

    
    const int row[8]={23,25,27,29,31,33,35,37};
    const int col[8]={39,41,43,45,47,49,51,53};
    int v=3; 
    int dms=400; 
    
    boolean A[8][8] = 
    {0,0,1,1,1,1,0,0,
    0,1,0,0,0,0,1,0,  
    0,1,0,0,0,0,1,0,  
    0,1,0,0,0,0,1,0,  
    0,1,1,1,1,1,1,0,  
    0,1,0,0,0,0,1,0,  
    0,1,0,0,0,0,1,0,  
    0,1,0,0,0,0,1,0};  
    
    void setup()
    {
      for (int i=0; i<8; i++)
        {
          pinMode(row[i],OUTPUT);
          pinMode(col[i],OUTPUT);
        }
      for (int i=0; i<8; i++)
        {
          digitalWrite(row[i],HIGH); 
        }
    }
    
    void loop()
    {
    	paint(A, v);
    	scroll(A);
    }
    
    void paint(boolean screen[8][8], int v) 
    {  
    int i, j;
    for (int c=0; c <v; c ++) 
      {
        for (i=0; i<8; i++)
          for (j=0; j<8; j++)
            {
              if (screen[i][j]==1)            
               {
                  digitalWrite(row[i], LOW); 
                  digitalWrite(col[j], HIGH); 
                  delayMicroseconds(dms); 
     	      digitalWrite(row[i], HIGH); 
                  digitalWrite(col[j], LOW); 
               }
                else 
                 {
                     digitalWrite(row[i], HIGH); 
                     digitalWrite(col[j], LOW); 
                     delayMicroseconds(dms); 
                     digitalWrite(row[i], HIGH); 
                     digitalWrite(col[j], LOW);
                } 
            } 
        }
    }
    
    void scroll(boolean screen[8][8]) 
    {
    boolean buf[8][1]; 
      for (int i=0; i<8; i++)
      {
        buf[i][0]=screen[i][0]; 
      }
      for (int i=0; i<8; i++)
        for (int j=0; j<8; j++)
          {
            screen[i][j]=screen[i][j+1]; 
          }
      for (int i=0; i<8; i++)
      {
        screen[i][8-1]=buf[i][0]; 
      }
    }


    Вот и все. Заливайте эту программу в свой микроконтроллер и наблюдайте, как буква «А» будет «бежать» влево. Добавлю, что массивом размерностью 8 на 8 элементов ограничиваться не стоит. Например, я использовал массив размером 8 на 86. Написал в нем целую фразу, как видно на этом видео.

    Удачи!
    Поделиться публикацией
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 80
    • НЛО прилетело и опубликовало эту надпись здесь
      • 0
        почему 65? 8*8=64.

        второй вопрос уже к производителям. наверное все же выгоднее и логичнее производить матрицы без контроллера. обеспечивает встраиваемость и гибкость применения. я так думаю.
        • +8
          Потому что 64 катода, скажем, и один общий контакт для анодов. Или наоборот.
          • 0
            Вы правы. исправляю.
            • –1
              64 цифровых выходов + земля, 65-тый выход не нужен
          • 0
            + земля
        • 0
          Вы напрямую матрицу к микроконтроллеру подключаете или там более сложная схема?
          • 0
            я в радиоэлектронике не силен, мягко говоря. нет, выводы, отвечающие за строки подключаются (в моем случае) через резисторы. чтобы не вышли из строя ножки контроллера в лучшем случае и чтобы он не сгорел в худшем.
          • –2
            [irony]Красота оформления кода, и его структурированность просто поражают.[/irony]
            • +1
              знаете, код форматирован нормально. а как этот код отображается после публикации — другое дело. не пойму почему так.
              • +1
                буду благодарен, если вместо иронии подскажете как исправить)
                • 0
                  может это поможет

                  Подсвечивает код программы (поддерживается bash, cpp, cs, xml, html, java, javascript, lisp, lua, php, perl, python, ruby, sql, scala, tex)
                  • 0
                    чёрт, скушало теги source lang=«язык» и закрывающий тег /source
                • +1
                  Если чуть выше окна с комментарием нажать на ссылку «html-теги», то появится не плохая подсказка.
              • 0
                Вы наверное своим примером можете улучшить учебные примеры по arduino.
                • +1
                  Напрямую аноды матрицы к выводам контроллера обычно не подключают. На то есть минимум две причины:

                  1) Нагрузочная способность выводов. Даже если выходного тока хватит на питание всех диодов столбца одновременно, внутреннее сопротивление выходного буфера заявит о себе, и столбец, в котором включены два светодиода, будет светиться ярче, чем столбец с четырьмя.
                  Ситуацию усугубляет то, что в устройствах с динамической индикацией светодиоды работают в импульсном режиме, и на них подают ток больше номинального (часто в несколько раз).

                  2) Хорошо, если столбцов всего 8, а если их, скажем, 128 (как на большом табло «бегущая строка»)? Для коммутации столбцов удобно использовать счетчики, дешифраторы или сдвиговые регистры. В последнем случае достаточно использовать всего 2 вывода контроллера (сброс и сдвиг) независимо от количества столбцов.
                  • +3
                    Дичайше неэкономное использование ножек. Поставьте сдвиговые регистры, на любое количество светодиодов уйдёт всего 4 ножки или меньше.
                    • 0
                      Сдвиговые регистры не всегда подходят для таких вещей — например при инициализации регистров их выходы пляшут как хотят (такой Новый Год пускай идет доли секунды, но бывает очень портит весь проект).
                      • 0
                        Ничто не мешает буферезировать их.
                        • +1
                          Если это так критично — подключите линии строк через дополнительный буфер с tri-state выходами. Алгоритм работы следующий:
                          1) Подали питание;
                          2) Проинициализировали регистры;
                          3) Переключили буфер из Z-состояния в рабочее.
                          • 0
                            Для этого придумали ещё одну ножку — сброс
                            • 0
                              Ардуина даже не успевает даже загрузиться пока пляшут регистры. Единственный придуманный колхоз — повесит питание регистров через «реле», и дальше включать его при готовности управлять (2 секунды после подачи питания).
                              • +3
                                А, понял о чём вы. Тогда можно подтягивающий резистор на reset повесить.
                                • 0
                                  хмм, где вы были раньше…

                                  в итоге после пляски 3х регистров — поставил Arduino Mega на эти задачи. Сердито получилось))
                                • 0
                                  Извините, немного не в теме, но что в Ардуино зашито такого, что грузится целых 2 секунды?
                                  • 0
                                    ничего сверх естественного, но Ардуинка подключена по USB к компьютеру, который ресетит его при загрузке.

                                    Посторюсь, даже доли секунды достаточно чтобы испортить картину — у меня на выходе регистров через ключи стояло 24 двигателя. Эта карусель сбивала датчики положения валов.
                                    • 0
                                      Понятно. В таком случае разрешение работы периферии по отдельному сигналу готовности должно спасти от дискотеки.
                                    • +2
                                      Бутлоадер, который ждёт 2 секунды?
                                • 0
                                  Транзистор поставьте, который зажигает светодиоды, делов-то. Пока он закрыт, никакие пляски в регистрах ничего не испортят.
                                  • +1
                                    Регистры разные есть. Есть и с защелкой. Пока строб не дашь ничего не шелохнется. 595й вроде бы такой, но могу ошибаться с номером.
                                    • +2
                                      Да, у 74HC595 защёлка есть, и стоит он копейки. Хорошая штука, я через него не то что светодиодную матрицу, а LCD на HD44780 и сервы подключал.
                                  • +1
                                    я в общих чертах имею представление, что такое сдвиговые регистры, но с ними не работал. к тому же, в данном случае задача была не «как экономить порты ввода\вывода», а разобраться с принципом динамической индикации. ну и как вдобавок написать «бегущий» текст.
                                    • 0
                                      думаю, поняв алгоритм людям несложно будет это все реализовать со сдвиговыми регистрами. хотя, те кто работает со сдвиговыми регистрами, думаю, давно знают как программировать дин. индикацию :)
                                      • 0
                                        Какой-то парадокс курицы и яйца получился, не находите? В статье подробности не описаны, потому что «тем, кто подробности знает, эта статья не нужна».
                                        Принципы динамической индикации изложены отлично, не спорю, но хотя бы пару предложений о том, «как это делают в настоящих проектах» стоит добавить.
                                        • +1
                                          согласен. только я не делал «настоящих проектов» с матрицами и сдвиговыми регистрами. поэтому, эта статья — не более чем моя личная маленькая победа) о как загнул.
                                          • 0
                                            Если это победа лично ваша, и опыта или полезной информации другим она не принесет то зачем делать статью?

                                            ИМХО если вы включите все 8 светодиодов в одном столбце то нагрузка превысит допустимые значения по Даташиту, да это не критично но при продолжительной перегрузке МК будет греться и через «N-ое время» выйдет из стоя.
                                            • 0
                                              не выйдет из строя. к ножкам МК выводы строк подключены через резисторы.
                                              • 0
                                                А ты ток посчитал? какой в общем будет? явно более 80 мА
                                                • 0
                                                  я скажу так. ( в который раз:) в электронике я не силен. считал не я и паял тоже. вот. но я УВЕРЕН, что все там в порядке на 100%.
                                                  • 0
                                                    В этом случае яркость одного диода будет в 8 раз выше чем зажженых 8ми диодов. Цветастая получится картинка :)
                                                    • 0
                                                      так ведь в моей реализации в один момент времени включен только один светодиод всегда. 8 одновременно не включатся никак в моем коде)
                                                      • 0
                                                        А! У вас поточечная. Ну тогда да, согласен. Но это тускло. Хотя у данной матрицы весьма неплохой запас по яркости. Видать диоды светятся чуть ли не от святого духа (Помню были у меня зверские светодиоды которые начинали светиться если их просто в руки за разные ножки взять)
                                                        • 0
                                                          яркость программно можно «регулировать». задерживать больше времени светодиод в состоянии «включен». но можно дорегулироваться, что будет ярко, но картинка заметно мигает. или наоборот, мигание совсем нет, все плавно, но очень тускло.
                                                • +1
                                                  Перечитал внимательно код. У вас же развертка идет и по строкам, и по столбцам! То есть в данный момент времени горит не больше одного светодиода. Да, проблему нагрузочной способности это решает, но в целом такое решение хорошим не назовешь.
                                                  — частота обновления картинки в восемь раз ниже, чем могла бы быть;
                                                  — вместо побайтного вывода используется побитовый — слишком громоздкий и неэффективный код получается;
                                                  — нужны искуственные задержки для выключенных пикселей.
                                                  • 0
                                                    Ocelot, спасибо, я ошибся — думал что реализация как раз по байтовая, да в таком случае с нагрузкой все в порядке.
                                                    • 0
                                                      По поводу обновления картинки: на видео легко увидеть, что обновляется не весь массив, а его часть (будто выключили v-sync). Чем это обусловлено и как это исправить?
                                                      • +1
                                                        Увеличить скорость прорисовки, сделать как раз байтовую динамическую индикацию, когда обновляется 1 строка/столбец за шаг но в таком варианте обязательно использование внешних ключей (транзисторов)
                                                      • 0
                                                        я ведь написал, что это не эталон, как программировать дин. индикацию.

                                                        а как проверить одновременно строку, например? я пробегаю по массиву двумерному и где в массиве TRUE, то есть 1, в том месте включаю светодиод.

                                                        мне интересно посмотреть и услышать комментарии как другие реализовуют.
                                                        • 0
                                                          Пусть матрица 8x8 и управляется 16 выводами (8 столбцов — PORTB, 8 строк — PORTC) через ключи, чтобы решить проблему мощности, но без всяких сдвиг. регистров.
                                                          Состояние экрана хранить в виде массива из восьми байт, причем каждый байт соответствует столбцу.
                                                          Вывод:
                                                          
                                                          unsigned char screen_buffer [8];
                                                          // ...
                                                          for (char i=0; i<8; i++)
                                                          {
                                                             PORTB = (1 << i); // включили столбец i
                                                             PORTC = screen_buffer [i]; // зажгли нужные пиксели столбца
                                                             delay ();
                                                          }
                                                          
                                                          • 0
                                                            если можно привести код, например, зажечь какой-нибудь символ. для болей ясности.
                                                            • 0
                                                              Вместо //… вставить следующее:
                                                              
                                                              screen_buffer [0] = 0x1F; // 00011111
                                                              screen_buffer [0] = 0x3F; // 00111111
                                                              screen_buffer [0] = 0x6C; // 01101100
                                                              screen_buffer [0] = 0xCC; // 11001100
                                                              screen_buffer [0] = 0xCC; // 11001100
                                                              screen_buffer [0] = 0x6C; // 01101100
                                                              screen_buffer [0] = 0x3F; // 00111111
                                                              screen_buffer [0] = 0x1F; // 00011111
                                                              

                                                              Это для буквы A. Возможно значения придется инвертировать (смотря какие применяются ключи) или изменить порядок (смотря как скоммутированы выводы).
                                                              По-хорошему нужно один раз объявить набор констант с матрицами для всех символов, а потом просто копировать в screen_buffer / менять указатель. Бегущая строка организуется путем сдвига элементов в массиве screen_buffer:
                                                              
                                                              void shift (unsigned char &screen_buffer)
                                                              {
                                                                 for (char i=0; i<7; i++)
                                                                 {
                                                                     screen_buffer [i] = screen_buffer [i+1];
                                                                 }
                                                                 screen_buffer [7] = 0x00;
                                                              }
                                                              
                                                              • 0
                                                                в первом куске кода, конечно, индексы не все 0, а от 0 до 7.
                                                                • 0
                                                                  жесть. это круто. мои мозги мыслили только в направлении точечной прорисовке картинки. оказывается можно целиком построчно\поколонно рисовать. спасибо.
                                                                  • 0
                                                                    Только вам под это дело придется схему переделывать. Т.к. один вывод не протащит через себя сразу 8 точек. либо они будут в восемь раз тусклей одного.
                                                                    • 0
                                                                      Ну я же написал:
                                                                      >через ключи, чтобы решить проблему мощности
                                                                      • 0
                                                                        я понял. просто взял на заметку, что есть такой способ.
                                                                  • 0
                                                                    я тоже так думал сделать. для каждой буквы объявить массив 8х8 типа boolean правда.

                                                                    а бегущая строка и у меня организуется путем сдвига массива влево на одну колонку.

                                                                    а вобще, мой подход корректен? или я изобрел велосипед с квадратными колесами?
                                                                    • 0
                                                                      Вполне корректен, не считая некоторой громоздкости кода, но для учебных целей это даже хорошо.
                                                                      Сейчас еще такая идея в голову пришла: если выводим бегущую строку, и отображаемая область значительно меньше полной картинки, то эффективнее не сдвигать весь буфер экрана, а менять координаты «окна» вывода. Примерно так:
                                                                      
                                                                      unsigned char screen_buffer [256];
                                                                      unsigned int position, endpos, column;
                                                                      
                                                                      // здесь забиваем в screen_buffer всю строку
                                                                      
                                                                      for (position = 0; position < 256; position++) // сдвиг окна
                                                                      {
                                                                         endpos = position + 8; // определяем правую границу окна
                                                                      // вывод столбцов,
                                                                      // попавших в окно
                                                                         for (column=position; column<endpos; column++) 
                                                                         {
                                                                            delay (1);
                                                                            if (column > 255) continue; // проверка границ
                                                                            PORTB = (1 << column); // включили столбец 
                                                                            PORTC = screen_buffer [column]; // зажгли нужные пиксели столбца
                                                                         }
                                                                        delay (1000);
                                                                      }
                                                                      

                                                                      На будущее: вместо циклов с задержками правильнее использовать таймеры и прерывания.
                                                                      • 0
                                                                        Еще поправочка. Вместо:
                                                                        for (column=position; column<endpos; column++)
                                                                        ...
                                                                        PORTB = (1 << column);

                                                                        нужно написать:
                                                                        for (char i=0, column=position; column<endpos; i++, column++)
                                                                        ...
                                                                        PORTB = (1 << i);

                                                                        Всё, спать пора!
                                                                        • 0
                                                                          логично
                                                  • +1
                                                    Проблема динамической индикации только в одном — большая загрузка проца (когда число точек идет на сотни) и низкая яркость их. А срегистрами получается все очень дубово, можно воообще даже статично сделать, но это много регистров уйдет :)
                                                    • 0
                                                      если придется мне программировать матрицу на сдвиговых регистрах — обязательно напишу о получившемся) хотя до меня все уже давно написано и сделано и разжевано.
                                                      • 0
                                                        При дин. яркости можно ставить большие токи(максимально допустимые) или даже вылазить то тут уже надо смотреть при каком токе идет перегрев а при каком деградация.

                                                        на счет мк, чаще всего под большие матрицы ставят отдельные мк к которыми управляют с Основного мк, получается что то на подобии самодельного графического дисплея

                                                        регистры используют не на квадратных матрицах а на бегущих строках чаще всего…
                                                        • +1
                                                          Ну тут регистр незачем ставить, всего 16 выводов. Но если матрица большая… то регистры то что доктор прописал. Даже в динамике, правда вешать их надо будет на SPI и гонять данные на 100Мбит, а может и выше.
                                                          • 0
                                                            AVR такую скорость не потянет только ARM или что то работающие на таких скоростях
                                                            • 0
                                                              Ой не мегабит, 100-400 килобит. :))) SPI там аппаратная, так что это ее даже не напряжет. А скорости аврки вполне хватает, чтобы обслуживать LED CUBE 16x16x16
                                                  • +1
                                                    Здесь так много говорят о сдвиговых регистрах, что стало ужасно интересно как это все реализовать вместе с Arduino. Стал искать по статьям на хабре и… ничего не нашел. Тут столько людей об этом знают и никто ничего про это не написал? Или никто не реализовал ничего?

                                                    Большое спасибо автору — все доступно, просто и понятно. На подходе Arduino, скоро буду экспериментировать и начну с вашей статьи =)
                                                    • +2
                                                      Интернет хабром не ограничивается, тем более есть «электронный хабр» — easyelectronics.ru, и там статей про сдвиговый регистр достаточно.
                                                      • +1
                                                        Ну это понятно, не первый день в сети. Все равно жаль, что приходится куда-то ходить и что-то искать вместо того, что бы прочесть это все на родном хабре =)
                                                        • +1
                                                          Если все-все-все пихать на хабр, то он быстро превратится в нетематическую помойку.
                                                      • +8
                                                        Тот кто пользуется сдвиговыми регистрами, чаще всего использует просто AVR или PIC без Arduino
                                                        • 0
                                                          robocraft.ru/blog/arduino/519.html лови про регистры. очень просто описано
                                                          • 0
                                                            О, спасибо большое!
                                                            • +1
                                                              Вообще это основы, поэтому когда вы вдруг начнете читать хоть какой угодно мануал для новичков, вы всеравно на них наткнетесь.
                                                          • 0
                                                            буду рад, если поможет статья.
                                                            • +2
                                                              А что там писать? Три строчки? Я вам и тут напишу: два входа, 8 выходов. Выставляете бит на входе, дрыгаете вверх-вниз ножку сдвига, при этом бит, который был на входе появляется на 0-м выходе, что было на 0-м появляется на 1-м, и так далее (данные на выходе сдвигаются). Подключив каскадом следующий регистр входом на 7-й выход предыдущего — получим регистр с 16-ю выходами, и так каскадировать можно до бесконечности.

                                                              Есть еще вход сброса, есть регистры с защелками — на выходе данные не ползут, а буферизируются, появляются только по вашей команде. Но это частности.
                                                            • 0
                                                              Мой первый проект с микроконтроллером — это как раз бегущая строка. Делал на регистрах, что интересно, вообще мало понимал до того, как со всем этим хозяйством делать, но ничего — разобрался. Сделал успешно работающую строчку 7х5, потом решил сделать ее длиннее и перенести на печатную плату, но что-то там в регистрах загуляло не то, и в итоге в буфер писалось не то, что нужно. Так теперь изделие валяется не доделанное.
                                                              • 0
                                                                а можно код того, что на видео?
                                                                • 0
                                                                  или опишите, пожалуйста, что менять надо под больший массив

                                                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.