Arduino serial теряет данные

valera0141
Offline
Зарегистрирован: 25.05.2017

Всем привет. Прошу помощи, чтобы разобраться в проблеме. Хочу сконструировать цветомузыку, которая будет управляться с компьютера. Написал программу для компьютера, которая перехватывает звук с пк, анализирует и отправляет данные по ком порту. Пример отправляемой строки "C10,128,100,255;", где C - команда, 10 - номер светодиода, а дальше значение цвета rgb. На стороне ардуины написал код, который принимает эти данные. В setup указал:

Serial.begin(115200);

В loop сделал так:
 

void loop() 
{
  // Если пришли данные
  if (Serial.available() > 0) 
  {
    // считаем 
    //strcpy(portStr, Serial.readStringUntil(';').c_str());
    char portStr[128]; // буфер для приёма данных с порта`
    Serial.readBytesUntil(';', portStr, 128);
    
    if (strlen(portStr) > 0)
    {
      switch(portStr[0]) // по первому символу определяем команду
      {
        case 'C': // пример команды "C1,25,100,255;"
          changeColor(portStr);
          break;
      }
    }
  }
}

И реализовал саму функцию зажигания светодиода 

void changeColor(char* portStr)
{
  int i = 0,r = 0,g = 0,b = 0;

  int cnt = maxLedsNum/ledsNum; // просчитаем с каким шагом зажигать светодиоды (на случай, если их менее 64)
  
  sscanf(portStr, "C%02d,%03d,%03d,%03d", &i, &r, &g, &b);

  Serial.println((String) "" + (i/cnt) + " " + r + " " + g + " " + b);
  
  ledsP[i/cnt] = CRGB(r,g,b);
  
  if (i == 0)
    digitalWrite(LED_BUILTIN, (r == 0 & g == 0 & b == 0) ? LOW : HIGH);
    
  FastLED.show();
}

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

valera0141
Offline
Зарегистрирован: 25.05.2017
if (i == 0)
    digitalWrite(LED_BUILTIN, (r == 0 & g == 0 & b == 0) ? LOW : HIGH);

 

Этот кусок кода просто дублирует первый светодиод на дебаговый светодиод

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Ты уверен, что строка 14 работает как задумано? "&" это битовая операция,  не логическая. 

valera0141
Offline
Зарегистрирован: 25.05.2017

Там нужно && поставить?

valera0141
Offline
Зарегистрирован: 25.05.2017

Вообще работает как надо этот кусок

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

valera0141 пишет:

Там нужно && поставить?

В данном случае - пофиг.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

ЕвгенийП пишет:

В данном случае - пофиг.

Соглашусь. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

valera0141 пишет:

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

Если правда не успевает, то есть много путей, которые можно использовать (или все сразу)

  1. не передавать значения текстом. Сначала Вы преобразуете числа в текст, передаёте, а на ардуине вызываете sscanf и преобразуете обратно. Зачем?
  2. "FastLED.show();" - очень дорогая операция и если Вы гоните много светодиодов за раз, то нафига выполнять её ради каждого? Почему не выполнить один раз, когда вся пачка принята? Или вообще разделить приём данных и "FastLED.show();"? Например, данные просто принимать и пихать в массив, а "FastLED.show();" вызывать независимо от данных раз, скажем в 20мс, какие изменения накопились, то и вывелось?
  3. наконец, кто мешает экспериментально определить минимальную задержку на PC при которой ещё всё нормально и использовать её?
valera0141
Offline
Зарегистрирован: 25.05.2017

Звучит всё интересно. Попробую

valera0141
Offline
Зарегистрирован: 25.05.2017

ЕвгенийП пишет:

valera0141 пишет:

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

Если правда не успевает, то есть много путей, которые можно использовать (или все сразу)

  1. не передавать значения текстом. Сначала Вы преобразуете числа в текст, передаёте, а на ардуине вызываете sscanf и преобразуете обратно. Зачем?
  2. "FastLED.show();" - очень дорогая операция и если Вы гоните много светодиодов за раз, то нафига выполнять её ради каждого? Почему не выполнить один раз, когда вся пачка принята? Или вообще разделить приём данных и "FastLED.show();"? Например, данные просто принимать и пихать в массив, а "FastLED.show();" вызывать независимо от данных раз, скажем в 20мс, какие изменения накопились, то и вывелось?
  3. наконец, кто мешает экспериментально определить минимальную задержку на PC при которой ещё всё нормально и использовать её?

Даже если отправлять данные только для одного светодиода и закоментить FastLED.show();, ардуино всё равно перестаёт реагировать на команды при постоянной быстрой отправки данных

b707
Онлайн
Зарегистрирован: 26.05.2017

valera0141 пишет:

Даже если отправлять данные только для одного светодиода и закоментить FastLED.show();, ардуино всё равно перестаёт реагировать на команды при постоянной быстрой отправки данных

так оно и понятно, в команде readbytesUntil() есть скрытый таймаут 1 секунда, вот все и зависает.

Если хотите быстрой обработки - не используйте подобные команды, напишите сами чтение байт из порта, пока не встретится ";"

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

valera0141 пишет:
ардуино всё равно перестаёт реагировать

Ну, во-первых, ключевой фразой в моём сообщении было "Если правда не успевает" - в коде я не разбирался, я только сказал как можно ускорить.

А во-вторых, а чего Вы хотели? PC быстрее ардуины в 180 раз (поделите 3ГГц на 16МГц)! Понятное дело, что если гнать без задержек, то там всё переполнится. На этот случай был п. №3 в моей рекомендации.

valera0141
Offline
Зарегистрирован: 25.05.2017

b707 пишет:

valera0141 пишет:

Даже если отправлять данные только для одного светодиода и закоментить FastLED.show();, ардуино всё равно перестаёт реагировать на команды при постоянной быстрой отправки данных

так оно и понятно, в команде readbytesUntil() есть скрытый таймаут 1 секунда, вот все и зависает.

Если хотите быстрой обработки - не используйте подобные команды, напишите сами чтение байт из порта, пока не встретится ";"

 

переписал получение данных с порта. Всё побежало, тормоза исчезли

MaksVV
Offline
Зарегистрирован: 06.08.2015

Логично было бы выложить итоговый код