DMX-512 Визуализация уровней каналов

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

  1. azsochi

    azsochi Нуб

    Собираю устройство, которое подключается к DMX-512 контроллеру, получает от него данные и отображает уровни каналов на дисплее. Использован двухстрочный символьный дисплей, подключенный через SPI-драйвер.

    В первой строке отображаются уровни каналов в виде столбиков, во второй - первый отображаемый на дисплее канал и общее количество каналов, на которые контроллер выдает данные.

    Есть возможность листать диапазон отображаемых каналов вдумя кнопками.

    Все собрал, прошил, и даже работает, но есть один косяк. В момент запуска микроконтроллера в первом отображаемом кадре вся информация верна, при отображении последующих кадров, arduino кудато-съедает несколько каналов.

    Т.е. если контроллер выдает 60 каналов, то в момент включения или перезагрузки arduino, отображается общее количество каналов 60 и первый канал на дисплее является действительно первым. Но сразу после смены кадров, отображается количество кадров 57, а первым отображается, в реальности пятый.

    Пробовал еще загонять сигнал на 30 каналов - тоже самое, только сначала все правильно, а потом показывает общее количество каналов 29, а на месте первого показывает вообще непонятно что.

    Все остальное работает без проблем - прокрутка листает.

    У же целый день смотрю в код и не пойму в чем косяк. Может кто-нибудь свежим взглядом увидит...

    Вот код:

    Код (C++):
    #include <Conceptinetics.h>
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>

    #define DMX_SLAVE_CHANNELS   100 //ЕСЛИ БУДУТ ПРОБЛЕМЫ ТО УМЕНЬШИТЬ

    LiquidCrystal_I2C lcd(0x27,16,2);

    DMX_Slave dmx_slave ( DMX_SLAVE_CHANNELS );

    unsigned long       lastFrameReceivedTime;
    unsigned long       lastFrameTranceivedTime;

    byte qa[8] =
    {
      B00000,
      B00000,
      B00000,
      B00000,
      B00000,
      B00000,
      B00000,
      B11111
    };
    byte ws[8] =
    {
      B00000,
      B00000,
      B00000,
      B00000,
      B00000,
      B00000,
      B11111,
      B11111
    };
    byte ed[8] =
    {
      B00000,
      B00000,
      B00000,
      B00000,
      B00000,
      B11111,
      B11111,
      B11111
    };
    byte rf[8] =
    {
      B00000,
      B00000,
      B00000,
      B00000,
      B11111,
      B11111,
      B11111,
      B11111
    };
    byte tg[8] =
    {
      B00000,
      B00000,
      B00000,
      B11111,
      B11111,
      B11111,
      B11111,
      B11111
    };
    byte yh[8] =
    {
      B00000,
      B00000,
      B11111,
      B11111,
      B11111,
      B11111,
      B11111,
      B11111
    };
    byte uj[8] =
    {
      B00000,
      B11111,
      B11111,
      B11111,
      B11111,
      B11111,
      B11111,
      B11111
    };
    byte ik[8] =
    {
      B11111,
      B11111,
      B11111,
      B11111,
      B11111,
      B11111,
      B11111,
      B11111
    };

    int lvAr[DMX_SLAVE_CHANNELS]; // Входящие значения DMX-512 каналов
    int outAr [16]; // Значения каналов, выводимые на дисплей
    int chRx; // количество принятых каналов /////////////////////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    #define KEY_BUTTON_1_PIN A2  //пин к которому подключена панель управления
    int KeyButton1Value=0;  //значение с панели управления
    long KeyButton1TimePress=0;  //последнее время когда на панели не было нажатых кнопок
    long KeyButton1Latency=100000;  //задержка перед считыванием состояния панели управления после нажатия
    int KeyButton1WasChecked=0;  //метка означающая что нажатие кнопки на панели было обработано
    long KeyButton1RepeatLatency=1500000;  //время после которого удерживание кнопки начинает засчитываться как многократные быстрые нажатия
    long KeyButton1RepeatTimePress=0;  //вспомогательная переменная для обработки повторных нажатий
    long KeyButton1TimeFromPress=0;  //переменная для хранения времени между временем когда не было зажатых кнопок и временем проверки
    long KeyBoardTime1=0;                //
    long KeyBoardTime2=0;                // Переменные для обработки времени для обработки событий клавиатуры
    long KeyBoardTimeInterval=25000;     //

    int start = 0;  // +1 номер канала, который выводится на экран первым

    void setup() {          
      dmx_slave.enable ();
      dmx_slave.setStartAddress (1);
      dmx_slave.onReceiveComplete ( OnFrameReceiveComplete );
      Wire.begin();
      lcd.init();
      lcd.backlight();
      lcd.home();

      lcd.createChar(0,qa);
      lcd.createChar(1,ws);
      lcd.createChar(2,ed);
      lcd.createChar(3,rf);
      lcd.createChar(4,tg);
      lcd.createChar(5,yh);
      lcd.createChar(6,uj);
      lcd.createChar(7,ik);

      lcd.clear();
      pinMode (KEY_BUTTON_1_PIN, INPUT);
      pinMode (10, OUTPUT);
      pinMode (11, OUTPUT);
      pinMode (12, OUTPUT);
      pinMode (13, OUTPUT);
    }

    void loop()
    {
      //проверка таймера для обработки нажатий клавиатуры
      KeyBoardTime2=micros();
      if ((KeyBoardTime2-KeyBoardTime1)>KeyBoardTimeInterval)
        {
          KeyBoardTime1=KeyBoardTime2;
          KeyBoardCalculate();
        }
      if (lastFrameReceivedTime > lastFrameTranceivedTime){
        printLevel (outAr);  // Вывод значений на дисплей
        lastFrameTranceivedTime = millis();
      }
    }

    void OnFrameReceiveComplete (unsigned short channelsReceived)
    {
      chRx = int(channelsReceived);
      for (int i=0; i<chRx; i++){
        lvAr = dmx_slave.getChannelValue (i+1);
      }
      for (int i=0; i<16; i++){
          outAr=lvAr[i+start];
      }
      lastFrameReceivedTime = millis();
    }

    void printLevel(int lv[16])
    {
      byte dispLv[16];
      for (int i=0; i<16; i++){
        switch (lv/32) {    //// добавить регулировку чувствительности
          case 0:
            dispLv=0;
            break;
          case 1:
            dispLv=1;
            break;
          case 2:
            dispLv=2;
            break;
          case 3:
            dispLv=3;
            break;
          case 4:
            dispLv=4;
            break;
          case 5:
            dispLv=5;
            break;
          case 6:
            dispLv=6;
            break;
          case 7:
            dispLv=7;
            break;
        }
      }
      lcd.setCursor(0, 0);
      for (int i=0; i<16; i++){
        lcd.write(dispLv);
      }
      lcd.setCursor(0, 1);       //
      lcd.print("^");            // Вывод общего количества
      lcd.print("     Total:");  // принятых каналов
      lcd.print(chRx);           //
      lcd.setCursor(1, 1);       // и номер первого канала на дисплее
      lcd.print(start+1);        //
    }

    void UpPress()
    {
      if((start) < (chRx-15)) start++;
    }
    void DownPress()
    {
      if(start > 0) start--;
    }

    void ButtonPress()
    {
      if ((KeyButton1Value>150) and (KeyButton1Value<300))
        {
          UpPress();
        }
      if ((KeyButton1Value>350) and (KeyButton1Value<650))
        {
           DownPress();
        }
    }

    void KeyBoardCalculate()
    {
      //Часть отработки нажатия клавиши
      KeyButton1Value=analogRead(KEY_BUTTON_1_PIN);
      //если сигнал с кнопки нулевой то обнуляем метку обработки нажатия
      if ((KeyButton1Value<=50) or (KeyButton1Value>=1000))
        {
          //Сохраняем время последнего сигнала без нажатой кнопки
          KeyButton1TimePress=micros();
          KeyButton1WasChecked=0;
          KeyButton1RepeatTimePress=0;
        }
         
      KeyButton1TimeFromPress=micros()-KeyButton1TimePress;
      //исключаем шумы
      if ((KeyButton1Value>50) and (KeyButton1Value<1000))
        {
          //отработка первого нажатия
          if ( ((KeyButton1TimeFromPress)>KeyButton1Latency) and (KeyButton1WasChecked==0))
            {
               KeyButton1Value=analogRead(KEY_BUTTON_1_PIN);
               ButtonPress();
               KeyButton1WasChecked=1;
               KeyButton1RepeatTimePress=0;
            }
       
          //отработка повторных нажатий
          if ( ((KeyButton1TimeFromPress)>(KeyButton1RepeatLatency+KeyButton1RepeatTimePress)) and (KeyButton1WasChecked==1))
            {
               KeyButton1Value=analogRead(KEY_BUTTON_1_PIN);
               ButtonPress();
               KeyButton1RepeatTimePress=KeyButton1RepeatTimePress+100000;
            }
        }
    }
    Да, кстати, если выдавать сигнал на 16 каналов, то отображается все коректно.
     
    Последнее редактирование: 19 сен 2015
  2. olegoriy

    olegoriy Гик

    Какой контроллер DMX используете?
    Меня смущает фраза " и общее количество каналов, на которые контроллер выдает данные.".
    Могу ошибаться но протокол DMX 512 подразумевает выдачу сигнала сразу на все 512 каналов от 0 до 255.
    Ведь если вы подключаете пульт с задранными каналами предположим от 1 до 100, а остальные в ноль , то приборы стоящие на адресе от 101 до 512 послушненько молчат не из-за того что к ним не чего не приходит , а из-за того что к ним приходят нули по адресам.
     
  3. olegoriy

    olegoriy Гик

    Интересен другой момент!!!
    Если Arduino дружит с этим протоколом , то возможно ли создания на ее основе контроллера который будет выдавать DMX 512 совместимый через usb c популярными программами типа
    Daslight Virtual Controller 3 ( 2) ( 1) или
    Sunlite Suite 2 (1)

     
  4. olegoriy

    olegoriy Гик

  5. DrProg

    DrProg Вечный нерд

    Что сразу бросилось в глаза, вот это вот можно написать одной строкой:
    Код (C++):
    switch (lv/32) { //// добавить регулировку чувствительности
    case 0:
    dispLv=0;
    break;
    case 1:
    dispLv=1;
    break;
    case 2:
    dispLv=2;
    break;
    case 3:
    dispLv=3;
    break;
    case 4:
    dispLv=4;
    break;
    case 5:
    dispLv=5;
    break;
    case 6:
    dispLv=6;
    break;
    case 7:
    dispLv=7;
    break;
    }
    А именно:
    Код (C++):
    dispLv = lv/32;
    Код с китайского сайта?
     
    ИгорьК нравится это.
  6. azsochi

    azsochi Нуб

    Стандарт DMX512 не обязывает выдавать данные на все 512 каналов. Важна стартовая последовательность бит (импульс break, Mark-After-Break и стартовый код), а за ней могут быть данные хоть всего на 1 канал... И так по кругу...
     
  7. azsochi

    azsochi Нуб

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