Arduino DUE и 1 LED module P10

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

  1. iJohn

    iJohn Нерд

    Доброго времени суток!

    Есть отичная тема Связка Mega2560 с p10 led module. Так вот она решила примерно 80% моих проблем и вопросов.

    У меня только Arduino DUE, и все библиотеки предлагаемые в теме выше да и вообще все что я смог найти в нете не подходят для DUE, так как там архитектура ARM а не AVR, а библиотеки под последнюю как раз и заточены.

    С темы что написал выше взял код, и не могу разобраться в нем до конца, что бы мог сам кодировать свои изображения, собственно вот код, вопросы потом:
    Код (Text):
    // названия пинов такие же, как и на модуле P10
    int nOE  = 13;
    int A    = 12;
    int B    = 11;
    int CKL  = 10;
    int SCLK = 9;
    int R    = 8;

    int vrem=0;  //Начало отсчета времени для переключения слов
    int pa=60; // Интервал переключения

    unsigned char screen [128]; //Видеопамять

    // тут зашифрованно изображение, алгоритм данного изображения я не могу понять
    char sl1 [] = {
    255,128,128,128,255,4,96,4,255,0,192,0,255,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  
    128,128,128,128,0,14,49,0,0,0,128,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                      
    128,128,128,128,0,31,31,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                              
    128,128,128,255,0,49,14,255,0,128,0,255,1,1,1,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0                                      
    };
    char sl2 [] = {
    255,128,128,128,255,68,100,132,255,64,192,64,255,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                                                                                      
    130,128,128,129,0,46,49,0,8,128,128,32,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                                                                                      
    129,128,128,130,0,31,63,0,16,0,0,16,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                                                                                      
    128,128,128,255,128,49,78,255,32,128,128,255,1,1,1,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0                                                                                      
    };

    void setup() {
      pinMode(R, OUTPUT);  
      pinMode(CKL, OUTPUT);  
      pinMode(SCLK, OUTPUT);  
      pinMode(nOE, OUTPUT);  
      pinMode(A, OUTPUT);  
      pinMode(B, OUTPUT);
    }

    void loop() {
      for(byte i=0; i<4 ; i++)
      {
        SelectStr(i); // Выбор псевдостроки
        SendBytes(screen + i*32); // Рисуем псевдостроку /+ i*32
        digitalWrite(nOE, HIGH); // Включаем матрицы
        delayMicroseconds(300); // Пауза 200
        digitalWrite(nOE, LOW); // Отключаем матрицы
      }
      if (vrem == pa) {
      for(int i = 0; i < 128; i++) //Заносим в видеопамять первое слово
        {
          screen[i]  = sl1[i];
        };
      };
     
      if (vrem == pa*2) {
      for(int i = 0; i < 128; i++) //Заносим в видеопамять второе слово
        {
          screen[i]  = sl2[i];
        };
        vrem=0;
      };
    vrem=vrem+1; // Увеличение отсчета времени
    }

    void SelectStr(byte n) // Выбор псевдостроки
    {
      if (n & B00000001) digitalWrite(A, LOW); else digitalWrite(A, HIGH);  
      if (n & B00000010) digitalWrite(B, LOW); else digitalWrite(B, HIGH);  
    }

    // ниже никаких комментариев не было, и тут я ничего не понял
    void SendBytes(unsigned char* b) // Рисуем псевдостроку
    {
      byte i;
      byte k;
      for(k = 0; k<16; k++)
        for(i = 0; i<8; i++)
        {
          digitalWrite(CKL, LOW);
          if((b[k] & (1 <<  (7-i))) ) {
            digitalWrite(R, LOW);
          } else {
            digitalWrite(R, HIGH);
          }
          digitalWrite(CKL, HIGH);  
        }
      digitalWrite(SCLK, HIGH);
      digitalWrite(SCLK, LOW);
      return;
    };
    Вопрос № 1. Можете на пальцах объяснить как примерно понимать что здесь будет отображено, я бы понял если бы там были 1 - горит, 0 не горит. Но эти два массива выводят два кадра по очереди, вот 1 из них. Но как заполнять массив если я хочу придумать свои изображения.
    [​IMG]
    Код (Text):
    char sl1 [] = {
    255,128,128,128,255,4,96,4,255,0,192,0,255,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  
    128,128,128,128,0,14,49,0,0,0,128,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                      
    128,128,128,128,0,31,31,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                              
    128,128,128,255,0,49,14,255,0,128,0,255,1,1,1,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0                                      
    };
    char sl2 [] = {
    255,128,128,128,255,68,100,132,255,64,192,64,255,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                                                                                      
    130,128,128,129,0,46,49,0,8,128,128,32,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                                                                                      
    129,128,128,130,0,31,63,0,16,0,0,16,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                                                                                      
    128,128,128,255,128,49,78,255,32,128,128,255,1,1,1,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0                                                                                      
    };
    Вопрос № 2. В функцию SendBytes передается (screen + i * 32), но screen это же массив символов, что значит(screen + i * 32). Я пытался вывести Serial.begin(String(screen + i * 32)), думал посмотреть что выведет в строку, но вылезает ошибка.

    Код (Text):
    unsigned char screen [128]; //Видеопамять
    ...
    void loop() {
      for(byte i=0; i<4 ; i++)
      {
        SelectStr(i); // Выбор псевдостроки
        SendBytes(screen + i*32); // Рисуем псевдостроку /+ i*32
        digitalWrite(nOE, HIGH); // Включаем матрицы
        delayMicroseconds(300); // Пауза 200
        digitalWrite(nOE, LOW); // Отключаем матрицы
      }
    ...
    Вопрос № 3. Самый главный. Не могу никак понять алгоритм данной функции. И как понять это условие if((b[k] & (1 << (7-i))) ) ?

    Там ## между решеток ## в кде вопрос еще один :)

    Код (Text):
    void SendBytes(unsigned char* b) // Рисуем псевдостроку
    {
      byte i;
      byte k;
      for(k = 0; k<16; k++)
        for(i = 0; i<8; i++)
        {
          digitalWrite(CKL, LOW);
          if((b[k] & (1 <<  (7-i))) ) {
            digitalWrite(R, LOW);
    #### данное условия никогда не истина и не выполняется,
    но если убрать то выйдет бардак, ставил туда Serial.begin() и он ниразу не вылез, а ниже отображается ####
          } else {
            digitalWrite(R, HIGH);
          }
          digitalWrite(CKL, HIGH);  
        }
      digitalWrite(SCLK, HIGH);
      digitalWrite(SCLK, LOW);
      return;
    };
    Массив screen состоит из 128 элементов, который передается в эту функцию, но в цикле проходит всего for(k = 0; k<16; k++) 16 итераций, что я понял не так?

    P.S. Забыл уточнить, этот код был расчитан на 2 таких панели, т.е. screen как я понял хранит информацию для двух панелей, а мне бы с одной разобраться :)

    Собственно как формировать картинку то? Как она преобразуется из моей головы например в массив значений, а потом из этого массива на панель?
     
  2. geher

    geher Гуру

    Сопоставив размеры экрана (16х32), а также разрядность (char-8 бит) и размерность массива (128) с указанием на то, что код рассчитан на два таких экрана, логично предположить, что каждый байт - это 8 бит, 8 светодиодов.
    Связь между конкретными светодиодами и байтами навскидку не просматривается. Надо пробовать выдавать нулевой массив с одним взведенным битом в одном из байтов и смотреть, что загорится. И так перебрать все возможные точки.

    screen+i*32 эквивалентно в данном случае адресу элемента screen [i*32].
    Serial.begin(String(screen + i * 32)) при этом выглядит странно. Может быть, Serial.print?
    Serial.begin вроде как инициализирует последовательный порт с указанием скорости.

    Это означает, что проверяется бит k-го элемента массива b с номером 7-i (нумерация начинается с 0 с младшего бита).
    Если бит 1, то условие истинно (результат больше 0)
    По сути выражение в if обнуляет все биты в байте (символе), являющемся элементом массива, кроме того, что с номером (7-i). И если данный бит не 0, то и результат не ноль.
    Таким образом проверяются все биты в байте, начиная со старшего.

    По факту в функцию передается четыре раза (вызывается функция) указатель на элемент массива с номером i*32. Потом в функции отрабатывается 16 байт начиная с указанного таким образом элемента массива (последовательно "закидываются в пин"). Указатель, переданный в качестве параметра сам по себе рассматривается как массив, начинающийся с указанного байта.
    В результате обрабатываются 16 байт через 16 не обрабатываемых. Четыре итерации проходят таким образом весь массив.
    Это заставляет полагать, что экран поделен на 4 зоны (псевдостроки), каждая из которых кодируется 16-тью байтами, каждый бит из которых "зажигает" один светодиод.
    Т.е. на самом деле управляется одна панель. Данные второй, которые вроде как должны присутствовать в массиве судя по размеру, просто пропускаются.

    Взводить биты в байтах массива. Единственное что придется установить экспериментально - соответствие каждого бита в байте конкретному светодиоду.
    Смысл примерно такой
    255=11111111b - "горят" все светодиоды, соответствующие байту. Такие байты в массиве должны, скорее всего, соответствовать строкам или столбцу с краю экрана, где горят все светодиоды.
    128=10000000b - "горит" первый (или последний, смотря как считать) светодиод.
    64=01000000b - второй.
    32=00100000b - третий.
    И т.д.
     
    iJohn нравится это.
  3. iJohn

    iJohn Нерд

    Во всем прав! Просто я не знаю в каком формате P10 принимает данные, т.к. много разных способов видел, этот вариант более менее рабочий, вот и довожу его до ума. Уже есть успехи, как доделаю до конца, выложу всю инфу. Может кому пригодится гайд :)
     
  4. Zaremchichak

    Zaremchichak Нерд

    модуль принимает данные в обычном формате.. На каждом модуле установлены сдвиговые регистры 74hc595 в количестве 16 штук.. Проще говоря мы должны вдувать на них перед зажиганием каждой строки данные - 0 чтобы зажечь светодиод и 1 чтобы он погас... 255 - эквивалент того, что ни один светодиод не будет включен, 128 = 0b10000000, тобиш будет гореть 7 светодиодов в линии... Далее: из буфера идут вышоды на дешифратор. Дешифратор зажигает через полевики строки. Всего 4 сдвоенных полевика, для управления 16 строчками.. Они запараллелены, иначе говоря зажигатеся одновременно 1,5,9,13 строки. Потом 2,6,10,14.. Смысл поняли в общем) Что нужно сделать: 1.Перевести OE в low. 2. Вдуть на сдвиговые регистры данные 3. при помощи дешифратора зажечь нужную строку (00,01, 10, 11 на выходы АВ) 4. Перевести OE в high. Сдвиговые регистры соединины последовательно, поэтому и изображение в массивах хранится построчно
     
    Последнее редактирование: 27 ноя 2014
    iJohn нравится это.
  5. iJohn

    iJohn Нерд

    Благодарю :) Очень понятно объяснил! Только почему 1 - не горит, 0 горит?? :) Я привык что 1 - true, 0 - false. Т.е. истина горит, ложь - ничего не происходит :) Этот вопрос просто из любопытства.
     
  6. Zaremchichak

    Zaremchichak Нерд

    Здесь усе совсем просто.. Полевики у нас коммутируют +5 вольт. То есть, для зажигания строки целиком на нее подается плюс. Для передачи данных для столбцов используется микросхема 74HC595 - на выходе у нее при подаче 1 так же появляется +5вольт. Соответственно, чтобы светодиод, с одной стороны запитанный полевиком к +5, загорелся, на его второй выход необходимо подать логический 0 со сдвигового регистра
     
  7. Zaremchichak

    Zaremchichak Нерд

    Вот вам немножко кода, правда на AVR GCC. Вывод на экран я делаю по второму таймеру..
    Код (Text):
    ISR (TIMER2_COMP_vect)
    {int i;
    cnt_reg_tick_2++;          
    if (cnt_reg_tick_2==12)
    {  

            line++; //переменная, которая переключает строки

            if (line>3) line=0; //как только прошли четыре строки, возвращаемся на начало

                switch (line)
                {
                case 0x00 :
                    DES_OE_low();//отключаем данные на дешифраторе
                    ST_CP_low(); //отпускаем защелку данных на сдвиговом регистре
                   
                    for (i=0;i<32;i++)  //я работаю с двумя модулями, кормлю по 8 бит (0xFF)  32 сдвиговых регистра      
                    {
                    output_led_state(screenbuf[line][i]); //здесь мы выводим данные на первую строку
                    }

                    ST_CP_high();//выводим данные на регистр
                    DES_A_low();//выставляем значения для включения первой строки
                    DES_B_low();
                    DES_OE_high();//включаем полевики разрешив это  на дешифраторе
                //DES_OE_low();
                break;

                case 0x01 :
                    DES_OE_low();
                    ST_CP_low();
                    for (i=0;i<32;i++)  
                    {
                    output_led_state(screenbuf[line][i]);
                    }  

                    ST_CP_high();  
                    DES_A_high();
                    DES_B_low();
                    DES_OE_high();
                break;

                case 0x02 :
                    DES_OE_low();
                    ST_CP_low();
                    for (i=0;i<32;i++)  
                    {
                    output_led_state(screenbuf[line][i]);
                    }
                    ST_CP_high();  
                    DES_A_low();
                    DES_B_high();
                    DES_OE_high();
               
                break;

                case 0x03 :
                    DES_OE_low();
                        ST_CP_low();
                    for (i=0;i<32;i++)  
                    //for (i=32;i>-1;i--)
                    {
                    output_led_state(screenbuf[line][i]);
                    }
                    ST_CP_high();
                    DES_A_high();
                    DES_B_high();
                    DES_OE_high();
                break;
                }

    cnt_reg_tick_2=0;      
    //
    }
    Инициализация портов
    Код (Text):
    void port_init()
        {
        //ИНИЦИАЛИЗАЦИЯ ПОРТОВ ДЕШИФРАТОРА
            //НАСТРОЙКА ПИНОВ НА ВЫХОД
            DDRD |= 1<<6;//DES_A;
            DDRD |= 1<<7;//DES_B;
            DDRC |= 1<<2;//DES_OE;
            //DDRD |= 1<<5;//PWM; //РЕГУЛИРОВКА ЯРКОСТИ
            //УСТАНОВКА ПОРТОВ В НУЖНОЕ СОСТОЯНИЕ
            DES_A_low();
            DES_B_low();
            DES_OE_high(); //HIGH, АКТИВНЫЙ НОЛЬ
        //    PORTD &= ~_BV(PD5); //HIGH, АКТИВНЫЙ НОЛЬ
        //КОНЕЦ НАСТРОЙКИ ДЕШИФРАТОРА

        //НАСТРОЙКА ПОРТОВ РЕГИСТРОВ СДВИГА
            DDRD |=1<<SH_CP_PIN;
            DDRB |=1<<DS_PIN;
            DDRB |=1<<ST_CP_PIN;
            DS_low();
            ST_CP_low();
            SH_CP_low();

        //Конфигурирование входа радиоканала
        DDRD &= ~(1<<PD2);
        PORTD |=_BV(PD2);

        }
    Вывод на регистры сдвига
    Код (Text):
    void output_led_state(unsigned char __led_state)
    {
      SH_CP_low();
      for (int i=0;i<8;i++)//пробегаем все 8 бит
      {

        if ((__led_state&0x80)==0x00) DS_low(); //проверяем, что выводится - 0 или 1
        else DS_high();
        SH_CP_high(); //дернем ногу, чтобы сказать
        SH_CP_low(); //регистру, что передача бита закончена
        __led_state=__led_state<<1;//сдвигаем данные на 1 бит
      }

    }
    Объявление выводов в хедер файле
    Код (Text):
    #define DES_A    PORTD6 //порты дешифратора
    #define DES_B    PORTD7
    #define DES_OE    PORTC2

    //макроопределения
    #define DES_A_low()  PORTD&=~_BV(DES_A)
    #define DES_A_high() PORTD|=_BV(DES_A)
    #define DES_B_low()  PORTD&=~_BV(DES_B)
    #define DES_B_high() PORTD|=_BV(DES_B)
    #define DES_OE_low()  PORTC&=~_BV(DES_OE)
    #define DES_OE_high() PORTC|=_BV(DES_OE)

    //Порты сдвигового регистра
    #define DS_PORT    PORTB //пин на передачу данных
    #define DS_PIN    5

    #define ST_CP_PORT PORTB //пин защелки
    #define ST_CP_PIN  7
    #define SH_CP_PORT PORTD//пин сдвига на 1 бит
    #define SH_CP_PIN  4

    #define DS_low()  DS_PORT&=~_BV(DS_PIN)
    #define DS_high() DS_PORT|=_BV(DS_PIN)
    #define ST_CP_low()  ST_CP_PORT&=~_BV(ST_CP_PIN)
    #define ST_CP_high() ST_CP_PORT|=_BV(ST_CP_PIN)
    #define SH_CP_low()  SH_CP_PORT&=~_BV(SH_CP_PIN)
    #define SH_CP_high() SH_CP_PORT|=_BV(SH_CP_PIN)
     
  8. tika

    tika Нуб

    Доброго времени суток! Подскажите как можно уменьшить расстояние между точками в цифровом секундомере в панели P10 вот куски. 0:00.00 или точи занимают строго размер цифр?

    #include <SPI.h> //SPI.h must be included as DMD is written by SPI (the IDE complains otherwise)
    #include <DMD.h>
    #include <TimerOne.h>
    //#include "Arial_black_16.h"
    #include "SystemFont5x7.h"
    //#include "Small.h"
    #include <Bounce2.h

    #define DISPLAYS_ACROSS 3
    #define DISPLAYS_DOWN 1
    ________________________________________________________________________

    //initialize TimerOne's interrupt/CPU usage used to scan and refresh the display
    Timer1.initialize( 5000 ); //period in microseconds to call ScanDMD. Anything longer than 5000 (5ms) and you can see flicker.
    Timer1.attachInterrupt( ScanDMD ); //attach the Timer1 interrupt to ScanDMD which goes to dmd.scanDisplayBySPI()
    dmd.clearScreen( true ); //true is normal (all pixels off), false is negative (all pixels on)
    // dmd.selectFont(Arial_Black_16);
    dmd.selectFont(SystemFont5x7);
    ____________________________________________________________________
    void print_time2(unsigned long t_milli)
    {
    int days, hours, mins, secs;
    int fractime;
    unsigned long inttime;

    inttime = t_milli / 1000;
    fractime = t_milli % 100;

    days = inttime / (24*3600);
    inttime = inttime % (24*3600);

    hours = inttime / 3600;
    inttime = inttime % 3600;

    mins = inttime / 60;
    inttime = inttime % 60;

    secs = inttime;
    sprintf(buffer2, "%01d:%02d.%02d", mins, secs, fractime);
    dmd.drawString( 55,8, buffer2, 9, GRAPHICS_NORMAL );
    }
     
  9. tika

    tika Нуб

    Доброго времени суток! Подскажите как модно уменьшить расстояние между точками в цифровом секундомере в панели P10 вот куски. 0:00.00 или точи занимают строго размер цифр? что- бы влезло в 1 панель P10.

    #include <SPI.h> //SPI.h must be included as DMD is written by SPI (the IDE complains otherwise)
    #include <DMD.h>
    #include <TimerOne.h>
    //#include "Arial_black_16.h"
    #include "SystemFont5x7.h"
    //#include "Small.h"
    #include <Bounce2.h

    #define DISPLAYS_ACROSS 3
    #define DISPLAYS_DOWN 1
    ________________________________________________________________________

    //initialize TimerOne's interrupt/CPU usage used to scan and refresh the display
    Timer1.initialize( 5000 ); //period in microseconds to call ScanDMD. Anything longer than 5000 (5ms) and you can see flicker.
    Timer1.attachInterrupt( ScanDMD ); //attach the Timer1 interrupt to ScanDMD which goes to dmd.scanDisplayBySPI()
    dmd.clearScreen( true ); //true is normal (all pixels off), false is negative (all pixels on)
    // dmd.selectFont(Arial_Black_16);
    dmd.selectFont(SystemFont5x7);
    ____________________________________________________________________
    void print_time2(unsigned long t_milli)
    {
    int days, hours, mins, secs;
    int fractime;
    unsigned long inttime;

    inttime = t_milli / 1000;
    fractime = t_milli % 100;

    days = inttime / (24*3600);
    inttime = inttime % (24*3600);

    hours = inttime / 3600;
    inttime = inttime % 3600;

    mins = inttime / 60;
    inttime = inttime % 60;

    secs = inttime;
    sprintf(buffer2, "%01d:%02d.%02d", mins, secs, fractime);
    dmd.drawString( 55,8, buffer2, 9, GRAPHICS_NORMAL );
    }