Как увеличить пропускную способность последовательного порта
У меня есть массив чисел, которые будут вычтены из показаний АЦП
синусоидальной волны частотой 50 Гц. Используя Serial.begin(57600);
, я могу только
выводить 25 выборок за цикл синусоидальной волны или около 1250 выборок за цикл.
второй. мои вопросы:
- как быстро изменяется приращение числа массива с y++ в моем int sinus[]? потому что, когда я вижу последовательный монитор со скоростью передачи данных 52700 бод, он может отображать только около 25 чисел за цикл (50 Гц)
- как увеличить скорость приращения y++ в моем массиве?
int sinus[] = {
70, 72, 83, 92, 108, 132, 157, 182, 207, 230, 243, 255, 255,
255, 250, 238, 217, 193, 169, 143, 118, 98, 88, 77, 72, 80
};
int dataSensor;
int hasil[26];
int datasensor2;
int dataBaru;
int x;
int y;
int intPin = 2;
int output;
int output2;
int toggle;
int toggle2;
int z;
void setup() {
TCCR1A = 0b00000010;
TCCR1B = 0b00011100;
TCCR0A = 0; //отключаем миллис, задержку и mciros
TCCR0B = 0;
ICR1 = 3200;
Serial.begin(57600);
pinMode(A1, INPUT);
pinMode(A0, INPUT);
pinMode(A2, INPUT);
pinMode(intPin, INPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
attachInterrupt(0, genJeah, RISING);
}
void genJeah() { // рост интрупси
y = 5;
}
void loop() {
dataSensor = analogRead(A0);
toggle = digitalRead(A1);
toggle2 = digitalRead(A2);
dataBaru = map(dataSensor, 0, 1023, 0, 255);
for (x = 0; x < 25; x++) {
hasil[x] = sinus[x];
}
// для (x=0; x<100; x++){
output = sinus[y] - dataBaru;
Serial.println(output);
y++;
if (y > hasil[26]) {
y = 0;
}
}
@john caren, 👍1
Обсуждение2 ответа
Если вам нужна пропускная способность, прекратите отправку чисел в формате ASCII и просто отправляйте числа.
Другими словами, используйте Serial.write()
вместо Serial.print()
: вы можете отправлять ~25 тыс. целых чисел в секунду со скоростью передачи данных 52 тыс. бод.
Поскольку вы фактически переназначаете выходной сигнал АЦП в один байт, это означает, что вы можете легко достичь пропускной способности 48 К/с с помощью этого простого изменения.
Если вам также нужна низкая задержка, учтите, что USB-соединение на самом деле основано на пакетах, а не на потоке, что означает, что вы будете получать данные порциями, независимо от того, как часто вы пишете. Вы можете немного ускорить очистку канала за счет пропускной способности.
будет ли он работать с последовательным плоттером?, @Juraj
Вы имеете в виду графическое представление, включенное в Sloeber?, @Roberto Lo Giacco
В Arduino IDE тоже есть последовательный плоттер., @Juraj
Извините, не знал об этом. Для Sloeber я написал библиотеку (PlotPlus), которая, вероятно, сможет достичь пропускной способности 10 К/с, учитывая использование двух дополнительных байтов протокола. Я не уверен, что он совместим с Arduino IDE, сам никогда не пробовал., @Roberto Lo Giacco
разве Serial Plotter не читает числа как текст?, @Juraj
Как я уже сказал, я не могу говорить за реализацию Arduino IDE, но Sloeber использует двоичный протокол., @Roberto Lo Giacco
как быстро увеличивается приращение номера массива с y++ в моем int синус[]?
Увеличение int
происходит достаточно быстро. Даже на медленном Uno y++
будет
выполнение займет менее одной микросекунды, так что вы можете сделать это миллион
раз в секунду, если хотите...
когда я вижу на последовательном мониторе скорость передачи данных 52700, он может показывать только около 25 чисел за цикл (50 Гц)
Ваш loop()
делает больше, чем y++
, нет, неудивительно, что это занимает
больше времени!
Там есть две медленные функции:
analogRead()
занимает около 110 мксSerial.println()
изначально работает быстро, но как только выходной буфер полный, он работает на скорости последовательного порта.
Ограничивающим фактором здесь является Serial.println()
. Вы печатаете
В среднем 4,6 байт на образец (2,6 печатных символов,
плюс CR и LF). Каждый байт соответствует 10 битам в проводе (один запуск
бит, 8 бит данных и один стоповый бит). Это 46 бит на выборку.
со скоростью 57 600 бит в секунду. Отношение этих чисел дает
Вы испытали 1250 проб в секунду.
как увеличить скорость приращения y++ в моем массиве?
Очень сложно ответить на этот вопрос, потому что вы не объяснили, что
вы на самом деле пытаетесь достичь. Если я по наивности отнесусь к вопросу
номинал, самый простой вариант — просто повторить y++
несколько раз
за итерацию цикла:
y++;
y++;
y++;
y++;
Очевидно, это можно оптимизировать
y += 4;
и компилятор, возможно, даже сможет определить эту оптимизацию с помощью сам по себе.
Но, возможно, вас не так уж заботит ускорение y++
, и
вместо этого вы хотите обрабатывать больше выборок данных в секунду? Если это
случае, то вы можете ускорить цикл, ускорив последовательный порт:
Serial.begin(115200);
печатая только каждый второй образец (или один образец каждые N):
static bool print_this_sample;
if (print_this_sample) {
Serial.println(output);
}
print_this_sample = !print_this_sample;
распечатывая один образец время от времени:
static uint32_t last_print_time;
if (millis() - last_print_time >= PRINT_PERIOD) {
last_print_time += PRINT_PERIOD;
Serial.println(output);
}
распечатав образцы в двоичном формате (сначала убедитесь, что они умещаются в байт):
Serial.write((byte) output);
Теперь Я подозреваю, что вы действительно хотите, чтобы ваша обработка
синхронизирован с сетью 50 Гц. Если это так, вы будете
придется полностью переосмыслить свою программу и задуматься о таймингах:
в какое конкретное время вы хотите взять каждую пробу? Ардуино
функции синхронизации (millis()
и micros()
) должны помочь.
Как видите, половина ответа состоит из моих предположений о том, что вы можете хочу достичь. Это признак того, что вопрос написан очень плохо. Обычно ваша задача — объяснить это подробно. Пожалуйста, перепишите задать вопросы и предоставить всю необходимую информацию, которая поможет нам понять ваш проект и трудности, с которыми вы столкнулись.
Можно добавить, что преобразование чисел займет несколько сотен микросекунд, поскольку оно включает в себя целочисленное деление., @Mikael Patel
спасибо, опять же, это очень отличное объяснение, @john caren
- Последовательный порт не работает со скоростью выше 19200
- Отсутствует время при использовании таймера
- Использование millis() и micros() внутри процедуры прерывания
- Как сделать очень долгую функцию delay(), несколько часов
- Разница между «time_t» и «DateTime»
- Получение BPM из данного кода
- Возможно ли иметь массив массивов int?
- Как считать время в секундах?
что означает «номер хода»?, @jsotola
поможет ли повышение последовательной скорости до 230400? - 57600 выводит 5760 символов в секунду, поэтому даже если вы выводите один символ как можно быстрее, вы не будете создавать 5760 «точек данных» в секунду (причина, по которой вы получаете только около 2500 символов в секунду, заключается в том, что вы выводите в среднем 2,3 цифры). за «выход», @Jaromanda X
Другая возможность повышения скорости — отправка байтовых данных вместо данных ASCII. Было бы это приемлемо?, @chrisl
Я отредактировал заголовок и тело вашего вопроса, чтобы сделать его более понятным. Я считаю, что мой переписывание точно отражает то, что вы намеревались написать, но не стесняйтесь редактировать заново, если я что-то неправильно истолковал. Обратите внимание: для вашего вопроса тот факт, что вы вычитаете значения из массива, совершенно не имеет значения. В идеале вам следует удалить эту часть (и соответствующий код) из вопроса, чтобы сосредоточить его на одной проблеме. Если вопрос не касается ошибки компиляции, вам также следует перед публикацией кода убедиться, что он хотя бы компилируется., @Edgar Bonet
Ваш код не компилируется, поэтому он не может работать с той или иной скоростью. Например, где объявлено
y
? АintPin
? А «переключить»? Нельзя ожидать, что мы поможем ускорить код, который даже не компилируется., @Nick GammonArduino @ 16 МГц с AVR MCU может выполнять максимум 8,9 тыс. выборок АЦП в секунду (10 бит, 112 мкс). Это предполагает тот же канал (вывод). Смена аналогового контакта занимает дополнительное время. Верхний предел эскиза составляет ок. 1 тыс. выборок/с только для АЦП (10 бит). Преобразование целого числа в строку для печати занимает дополнительное время, но ADC может работать параллельно. Также вместо этого можно инициировать АЦП для 8-битного преобразования., @Mikael Patel
Не используйте AnalogRead, поскольку AnalogRead блокируется во время преобразования. Лучше прочитать значение результата АЦП, а затем сразу начать новое преобразование (асинхронно), а остальной код выполнить в цикле., @Gerben
как читать adc без использования AnalogRead? @Гербен, @john caren
я снова отредактировал свой вопрос @jsotola, @john caren
я снова отредактировал свой вопрос @EdgarBonet, @john caren
я снова отредактировал свой вопрос @NickGammon, @john caren
как читать adc без использования Analogread?
- это уже другой вопрос, не так ли? Однако посмотрите это: http://www.gammon.com.au/adc., @Nick GammonСм. ссылку Ника Гэммонса; раздел «Читать без блокировки»., @Gerben