Нужно ускорить процедуру чтения UART
- Войдите на сайт для отправки комментариев
Ср, 24/03/2021 - 22:33
тут ниже тема чужая, не буду в нее влезать...
есть модуль ESP-01 он по WiFi раздает контент, все работает относительно быстро пока его не подключаю к MEGA по UART,
Мега шлет относительно маленькие пакеты 1 раз в секунду, ESP их разбирает и все работает, но уже сильно медленнее...
Да я читал, что String медленный, но не понимаю на сколько он медленный, может кто подскажет что-то конкретное по ускрению этого кусочка?
// эти ID используются в HTML и передаются от контроллера по UART
const char out_id [PARAM_COUNT][21] = {
{"main\0"}, // - контроль того, что данные меняются и основной контроллер работает
{"data\0"}, // - текущая дата
{"time\0"}, // - текущее время
{"sd\0"}, // - модуль SD карты
{"display\0"}, // - модуль дисплея
{"keybord\0"}, // - модуль клавиатуры
{"term\0"}, // - установленнаяя температура в доме
{"t_home_1\0"}, // - датчик 1 в доме
{"t_home_2\0"}, // - датчик 2 в доме
{"t_out_1\0"}, // - датчик 1 на улице
{"t_out_2\0"}, // - датчик 2 на улице
{"t_heat_in\0"}, // - датчик температуры возвращаемого теплоносителя
{"t_heat_out\0"}, // - датчик температуры исходящего теплоносителя
{"m_heat\0"}, // - насос циркуляции для отопления
{"t_heat\0"}, // - датчик температуры котла
{"t_water_in\0"}, // - датчик температуры подпитки в контур горячей воды
{"t_water_out\0"},// - датчик температуры исходящей горячей воды
{"m_water\0"}, // - насос циркуляции для горячей воды
{"v_water\0"}, // - датчик скорости циркуляции горячей воды в контуре
{"pressure\0"}, // - давление воздуха на улице
{"light\0"} // - освещенность на улице
};
char out_value [PARAM_COUNT][11];
char out_status [PARAM_COUNT][6];
void loop() {
LoopReadData();
}
void LoopReadData() {
//
// формат: <id=value;status>
//
char c;
int16_t ii;
String inString = "";
String s_out_id = "";
String s_out_value = "";
String s_out_status = "";
while(Serial.available()) {
c = Serial.read(); // принять байт как символ
if (c == '<') { // начало параметра
clear_buf(&(buf_UART[0]), 0);
} else if (c == '>') { // окончание параметра
ii = find_byte_buf(&(buf_UART[0]), '=');
if (ii != 0) {
inString = buf_UART;
s_out_id = inString.substring(0, ii);
inString = inString.substring(ii+1);
ii = inString.indexOf(';');
if (ii < 0 ) {
s_out_value = inString;
s_out_status = "";
} else {
s_out_value = inString.substring(0, ii);
s_out_status = inString.substring(ii+1);
}
for (uint8_t i = 0; i < PARAM_COUNT; i++) {
if (s_out_id == (String)(out_id[i])) {
s_out_value.getBytes((uint8_t*)(&(out_value[i][0])), s_out_value.length()+1);
s_out_status.getBytes((uint8_t*)(&(out_status[i][0])), s_out_status.length()+1);
}
}
}
clear_buf(&(buf_UART[0]), 0);
} else if ((uint8_t)c < 32) { // эти символы пропускаем
} else { // добавляем в буфер
ii = find_byte_buf(&(buf_UART[0]), 0);
*((uint8_t*)(buf_UART+ii)) = c;
}
}
}
тормозит find_byte_buf
тормозит find_byte_buf
там особо тормозить нечему
uint8_t find_byte_buf(char* buf, uint8_t b){ for (uint8_t i = 0; i < 250; i++) { if (*((uint8_t*)(buf+i))==b) {return i;} } return 0; }там особо тормозить нечему
uint8_t find_byte_buf(char* buf, uint8_t b){ for (uint8_t i = 0; i < 250; i++) { if (*((uint8_t*)(buf+i))==b) {return i;} } return 0; }Фига-се, нечему! линейный поиск на 250 элементов. К тому же он неправильно написан.
А что Вы так хитро разбираете, почему на написать простой автомат разбора? Можете внятно сформулировать задачу? Тогда я попробовал бы подсказать как автомат написать.
допустим поиск можно немного оптимизировать, но не думаю, что это много даст
uint8_t find_byte_buf(char* buf, uint8_t b){ for (uint8_t i = 0; i < 250; i++) { uint8_t a = *((uint8_t*)(buf+i)); if ( a == 0 ) {return 0;} if ( a == b ) {return i;} } return 0; }по факту мне нужно разобрать строку вида
на 3 строки
Можно расписать кто какие задержки вносит, тогда и принимать решение.
Данные по UART передаются за время X и скорость обработки на это время не влияет. Какую ДОПОЛНИТЕЛЬНУЮ задержку вносит разбор строки?
Дополнение. И может не стоит каждый раз искать хвост буфера, а хранить в глобальной переменной указатель на него.
по факту мне нужно разобрать строку вида
на 3 строки
По символу '<' очищаете все три строки и принимаете символы в первую пока не поступит '=' Тогда начинаете прием во вторую до символа ';', по нему начинаете прием в третью строку до >. Только очищать - это не совсем забивать все нулями, лучше просто указатель устанавливать на начало строки. Можно 3 указателя держать, но лучше один и переменную состояния приема. А завершать прием в каждую строку - не забывать добавлять 0 в конец. Ну и контроль длинны, чтоб за буфера не вылетать.
Кстати на String этот Ваш код не сильно то и завязан, выкиньте его и забудьте.
Можно еще и совместить с поиском id в таблице out_id. Тогда по завершению приема id сразу будет известен есть ли в таблице и с каким индексом. Нет предела совершенству...
На esp есть sscanf, std::map, и прочие удобства не на улице. Не надо писать код как инвалид.
На esp есть sscanf, std::map, и прочие удобства не на улице. Не надо писать код как инвалид.
regex?
по факту мне нужно разобрать строку вида
на 3 строки
На какие три строки. Я же Вам написал, что могу попробовать Вам помочь, но для этого мне нужно чёткое описание задачи и несколько примеров типа "входящая строка->результат". А не фраза "на три строки" про текст в котором всего два значения.
Нужна помощь? Не ленитесь объяснить задачу.
Очень неаккуратное регулярное выражение. Такие можно применять на мощных процессорах, где вопрос ресурсов вообще не стоит.
на столько я понял то вживую входящие данные будут выглятеть как то вот так: <45=333;ОК>
жаль нет под рукой железки, интересно замерить...
хотя че гадать, давайте дождемся пока чел выложит пример входящих данных, сравню тогда ваш и свой вариант. самому интересно.
<t_home_1=099;E1>
<t_home_1=-02;OFF>
<t_home_1=015;OK>
Вообще я пойду путем одновременного поиска ID в списке с чтением данных.
добавлю в out_id колонку "количество" и заведу новый байтовый массив для отсева (что-то вроде индексного дерева будет), и параметры value и status буду считывать сразу по назначению, то есть вообще обойдусь без буферизации buf_UART
кстати вопрос:
0.15 сек на получение ответа в браузере на JSON запрос - это нормально? ответ примерно 1200 символов
Вообще я пойду путем одновременного поиска ID в списке с чтением данных.
добавлю в out_id колонку "количество" и заведу новый байтовый массив для отсева (что-то вроде индексного дерева будет), и параметры value и status буду считывать сразу по назначению, то есть вообще обойдусь без буферизации buf_UART
Та не нужен никакой байтовый массив. Вы постоянно усложняете ))) Приняли первый символ id - пробежались по out_id до элемента, у которого он такой же. Запомнили его индекс. Приняли второй символ - сравнили его с вторым символом у запомненного. Совпало - продолжаем прием, после приема третего символа аналогично. Не совпало - бежим по out_id и ищем элемент, у которого первый символ совпадает с аналогичным у ранее найденного элемента, а второй с принятым - запомним теперь его.
Пример. Допустим принимаем посимвольно "t_heat\0"
1. Приняли t, нашли в элемент "time\0", т.к. первый символ совпал.
2. Приняли _, второй символ не совпал, значить движемся по out_id дальше, ищем элемент, у которого первый символ как у "time\0", а второй _. нашли в элемент "t_home_1\0".
3. Приняли h, совпал с третим символо в "t_home_1\0". продолжаем
4. Приняли e, четвертый символ не совпал с таковым в "t_home_1\0", значить движемся по out_id дальше, ищем элемент, у которого первые три символ как у "t_home_1\0", а четвертый e. нашли в элемент "t_heat_in\0".
Если out_id был бы большой по размеру (или есть перспектива что выростит), имело бы смысл его записать сортированным и искать более интелектуально. Но при том размере, что в примере это без толку.
На esp есть sscanf, std::map, и прочие удобства не на улице. Не надо писать код как инвалид.
regex?
Не. rkit просто тупой.
Если out_id был бы большой по размеру (или есть перспектива что выростит), имело бы смысл его записать сортированным и искать более интелектуально. Но при том размере, что в примере это без толку.
можно и сортировано, для этого нужны 2 переменные,
изначально эти переменные устанавливаем в начало и конец массива, получили первый знак, пробежались от первой ко второй переменной по первой букве, где совпало туда сдвигаем переменные.
единствено не удобно будет придется забить 0 до конца элемента и хранить в сортированном виде
Не нужно. Выиграша по времени на небольшом наборе данных не будет. А сложней всеж.
зато не нужно хранить все символы которые уже были проверены и не нужно по ним бегать
Зачем их хранит? Они и в out_id хорошо хранятся. Это первые символы в элементе из out_id , найденном на предыдущем этапе. Пишу же, хранить достаточно " индекс по out_id и номер принимаемого символа". Больше ничего для поиска по мере приема не нужно.
ппц лютая борьба за каждый байт , у вас что проект на тиньке? Написали ведь, что пакеты маленькие. Что нельзя на буфер байт 20 выделить? и строко_сишными процедурами парсить.
А толку выделять ненужное. Выделитель, ты код пишешь или стену мажешь? ТС уже навыделял был, с чем сюда и обратился. Так что иди се, с миром, выделяй из себя в другом месте, можешь даже сразу фреймворками откладывать ;)
переписал без использования String, постарался написать относительно быстрый код, стало лучше но все равно очень странное поведение.
когда ESP подсоединена к USB (через переходник/программатор) и с консоли я туда кидаю строки типа "<t_home_1=099;E1>" и кидаю часто то все равно сайт грузится ровно, скорость получения ответа 120....150 мсек,
как только я подключаю к МЕГЕ то скорость получения JSON в браузере становится очень сильно не стабильная, от 200 до 1500 мсек, плавает и на первый взгляд не зависит от того много или мало туда МЕГА отдает данных
собственно сам код, но я уже не думаю, что дело в нем...
// ----------------------------------------------------------- // описание данных для json и получения от главного контроллера // эти ID используются в HTML и передаются от контроллера по UART // ВНИМАНИЕ !!! данный список должен быть отсортирован по ID // идентификатор не более 20 символов const char out_id [PARAM_COUNT][21] = { {"data\0"}, // - текущая дата {"display\0"}, // - модуль дисплея {"keybord\0"}, // - модуль клавиатуры {"light\0"}, // - освещенность на улице {"m_heat\0"}, // - насос циркуляции для отопления {"m_water\0"}, // - насос циркуляции для горячей воды {"main\0"}, // - контроль того, что данные меняются и основной контроллер работает {"pressure\0"}, // - давление воздуха на улице {"sd\0"}, // - модуль SD карты {"t_heat_in\0"}, // - датчик температуры возвращаемого теплоносителя {"t_heat_out\0"}, // - датчик температуры исходящего теплоносителя {"t_heat\0"}, // - датчик температуры котла {"t_home_1\0"}, // - датчик 1 в доме {"t_home_2\0"}, // - датчик 2 в доме {"t_out_1\0"}, // - датчик 1 на улице {"t_out_2\0"}, // - датчик 2 на улице {"t_water_in\0"}, // - датчик температуры подпитки в контур горячей воды {"t_water_out\0"},// - датчик температуры исходящей горячей воды {"term\0"}, // - установленнаяя температура в доме {"time\0"}, // - текущее время {"v_water\0"} // - датчик скорости циркуляции горячей воды в контуре }; // массивы для хранения данных полученых от контролера и которые передаются в HTML uint8_t out_id_length [PARAM_COUNT]; char out_value [PARAM_COUNT][11]; char out_status [PARAM_COUNT][6]; // глобальные переменные которые используются для получения и разбора данных от контроллера uint8_t out_min_pointer=0; // указатель на перый элемент списка out_id который нам подходит uint8_t out_max_pointer=0; // указатель на последний элемент списка out_id который нам подходит uint8_t out_tec_pointer=0; // указатель на найденный элемент списка out_id, по которомы мы ччитаем value и status char out_value_tec[11]; // буфер для хранения считываемого параметра value char out_status_tec[6]; // буфер для хранения считываемого параметра status uint8_t out_num_char=0; // номер символа в читаемом параметре ID, value,status uint8_t out_step=0; // шаг на котором мы при получении данных. // 0 - ждем начала блока "<" // 1 - читаем ID, и ждем "=" // 2 - читаем value, и ждем ";" // 3 - читаем status, и ждем ">" // 4 - все верно прочитано, можно копировать в память // ----------------------------------------------------------- void setup() { out_value_tec[0] = 0; out_status_tec[0] = 0; // инициализация массивов for (uint8_t i = 0; i < PARAM_COUNT; i++) { for (uint8_t ii = 0; ii < 20; ii++) { if (out_id[i][ii] == 0) { out_id_length[i] = ii; break; } } out_value[i][0] = 0; out_status[i][0] = 0; } } void loop() { LoopReadData(); } void LoopReadData() { // // формат: <id=value;status> // char c; while(Serial.available()) { c = Serial.read(); // принять байт как символ #ifdef ON_DEBUG_ECHO Serial.write(c); #endif if ((uint8_t)c < 32) { // эти символы пропускаем и считаем сначала out_step = 0; #ifdef ON_DEBUG_ECHO // Serial.write('#'); // сообщаем, что пришло не то, чего ждем #endif } else if (out_step == 0) { // 0 - ждем начала блока "<" if (c == '<') { // начало параметра out_step = 1; out_min_pointer=0; out_max_pointer=(uint8_t)(PARAM_COUNT)-1; out_tec_pointer=0; out_num_char=0; out_value_tec[0] = 0; out_status_tec[0] = 0; } else { #ifdef ON_DEBUG_ECHO Serial.write('#'); // сообщаем, что пришло не то, чего ждем #endif } } else if ((out_step == 1) && (out_num_char < 20)) { // ищем идентификатор uint8_t fl = 0; uint8_t fl_end = out_max_pointer; for (uint8_t i = out_min_pointer; i <= out_max_pointer; i++) { if ((out_num_char > 0) && (out_id[i][out_num_char] == 0) && (c == '=')) { // мы нашли нужный id out_tec_pointer = i; out_num_char=0; out_step = 2; break; } else if (out_id_length[i] < out_num_char) { // слишком короткий ключ } else if (out_id[i][out_num_char] == c) { // пока вроде подходит fl_end = i; if (fl == 0) { out_min_pointer = i; fl = 1; } } else if (out_id[i][out_num_char] > c) { // уже стало больше break; } } if (out_step == 1) { if (fl == 0) { // ни один вариант не сработал out_step = 0; #ifdef ON_DEBUG_ECHO Serial.write('#'); // сообщаем, что пришло не то, что ждем #endif } else { out_max_pointer = fl_end; out_num_char++; } } } else if (out_step == 2) { if (out_num_char > 10) { out_num_char = 10; #ifdef ON_DEBUG_ECHO Serial.write('#'); // сообщаем, что пришло не то, что ждем #endif } else { out_value_tec[out_num_char] = c; } if (c == ';') { out_value_tec[out_num_char] = 0; out_step = 3; out_num_char = 0; } else { out_num_char++; } } else if (out_step == 3) { if (out_num_char > 5) { out_num_char = 5; #ifdef ON_DEBUG_ECHO Serial.write('#'); // сообщаем, что пришло не то, что ждем #endif } else { out_status_tec[out_num_char] = c; } if (c == '>') { out_status_tec[out_num_char] = 0; out_step = 4; } else { out_num_char++; } } if (out_step == 4) { memcpy (&(out_value [out_tec_pointer][0]), &(out_value_tec[0]), 11); memcpy (&(out_status [out_tec_pointer][0]), &(out_status_tec[0]), 5); out_step = 0; #ifdef ON_DEBUG_ECHO // сообщаем, что пакет загружен Serial.println(); Serial.print("load:"); Serial.print(out_tec_pointer, DEC); Serial.println(":"); Serial.print(out_id [out_tec_pointer]); Serial.print('-'); Serial.print(out_value [out_tec_pointer]); Serial.print('-'); Serial.println(out_status [out_tec_pointer]); #endif } } }пока вот так https://ibb.co/McxQ5p9
нафига блокирующий код с while ? ведь еще что то в лупе висит, может поэтому тормозит не?
нафига блокирующий код с while ? ведь еще что то в лупе висит, может поэтому тормозит не?
что именно Вы называете "блокирующий код" ? у меня нет ни одной паузы, и код не ждет когда весь пакет придет, именно по этому у меня глобальные а не локальные переменные которые отвечают за разбор данных.
хотя может и стоит поставить выход из цикла по таймеру, например 0.1 сек
я имел ввиду, почему бы не читать по одному символу за каждый проход луп?
был час на работе свободный, предлагаю такой говнокод
#define UART Serial const byte MAX_CHAR_ID = 20; // максимальное количество символов ID const byte MAX_CHAR_VALUE = 10; // максимальное количество символов VALUE const byte MAX_CHAR_STATUS= 5; // максимальное количество символов STATUS #define DEBUG // раскоментировать для отладки const byte MAX_BUFFER = MAX_CHAR_ID+MAX_CHAR_VALUE+MAX_CHAR_STATUS+8; // размер буфера парсилки char currStr[MAX_BUFFER]; // буфер парсилки struct parameter { const char out_id[MAX_CHAR_ID+1]; char out_value [MAX_CHAR_VALUE+1]; char out_status[MAX_CHAR_STATUS+1]; }; parameter Parameter[] = { "data", "", "", // - текущая дата "display", "", "", // - модуль дисплея "keybord", "", "", // - модуль клавиатуры "light", "", "", // - освещенность на улице "m_heat", "", "", // - насос циркуляции для отопления "m_water", "", "", // - насос циркуляции для горячей воды "main", "", "", // - контроль того, что данные меняются и основной контроллер работает "pressure", "", "", // - давление воздуха на улице "sd", "", "", // - модуль SD карты "t_heat_in", "", "", // - датчик температуры возвращаемого теплоносителя "t_heat_out", "", "", // - датчик температуры исходящего теплоносителя "t_heat", "", "", // - датчик температуры котла "t_home_1", "", "", // - датчик 1 в доме "t_home_2", "", "", // - датчик 2 в доме "t_out_1", "", "", // - датчик 1 на улице "t_out_2", "", "", // - датчик 2 на улице "t_water_in", "", "", // - датчик температуры подпитки в контур горячей воды "t_water_out", "", "", // - датчик температуры исходящей горячей воды "term", "", "", // - установленнаяя температура в доме "time", "", "", // - текущее время "v_water", "", "", // - датчик скорости циркуляции горячей воды в контуре }; byte parameter_quantity = sizeof(Parameter)/(MAX_CHAR_ID+MAX_CHAR_STATUS+MAX_CHAR_VALUE+3); // количество параметров //------------------------функция чтения информации из уарт void UART_read() { static bool timer = 0; static uint32_t prevtime = 0; // таймер выхода из сбора строки по таймауту static bool stringStat = 0; // статус строки 0 - ждем начала, 1 - принимаем, if (timer && millis() - prevtime>500) // если данные оборвались { timer = 0 ; currStr[0] = 0; stringStat=0; // заканчиваем набор строки #ifdef DEBUG Serial.println("reset parse by timeout!"); #endif } if (!UART.available()) return;// если на уарте ниче нет, выходим char currSymb[2] = {0}; // символьный кэш currSymb[0] = UART.read(); // читаем очередной символ if (currSymb[0] == '>') // если полностью получили строку - парсим: {if (stringStat){ bool IDfind = 0; // флаг совпадает ли ID с одним из списка // парсим строку: for (int i=0; i<parameter_quantity; i++) { if (strstr(currStr, Parameter[i].out_id)>0) // если нашли знакомый ID { IDfind = 1; char*ravno=0, *tzz=0; ravno = strchr(currStr, '='), tzz = strchr(currStr, ';'); // ищем '=' ';' if (!ravno || !tzz) { #ifdef DEBUG Serial.println ("Not find '=' & ';'"); // не нашли ругнемся #endif } else{ // нашли - действуем strncpy (Parameter[i].out_value, ravno+1, tzz - ravno-1); //парсим value Parameter[i].out_value[tzz - ravno-1] =NULL; //NULL в конце value strcpy (Parameter[i].out_status, tzz+1); //парсим status #ifdef DEBUG Serial.print("id: "); Serial.println (Parameter[i].out_id); Serial.print("value: "); Serial.println (Parameter[i].out_value); Serial.print("status: "); Serial.println (Parameter[i].out_status); #endif break; }//end find '=' ';' is OK } //end find ID is OK } if (!IDfind) #ifdef DEBUG Serial.println ("ID not find"); // поругаемся, если нет такого IDв списке #endif timer = 0 ; currStr[0] = 0; stringStat=0; // в конце парсинга нулим буфер }} else if (currSymb[0] == '<') {currStr[0] = 0; stringStat = 1; timer = 1; prevtime = millis();} // принято начало строки else if (stringStat) {strcat (currStr,currSymb); prevtime = millis();} //набираем строку if (strlen(currStr)>=MAX_BUFFER-3) // если буфер закончился { timer = 0 ; currStr[0] = 0; stringStat=0; // сброс сбора строки #ifdef DEBUG Serial.println ("reset parse by over buffer"); #endif } } //-------------------------------- void setup() { UART.begin(38400); } void loop() { UART_read(); // функция чтения из UART // тут остальной код }я имел ввиду, почему бы не читать по одному символу за каждый проход луп?
По моему while(Serial.available()) скорее полезен, чем вреден.
Мертвое зависание в данном цикле невозможно (если темп обработки быстрее темпа поступления новых).
(Дополнено - для перестраховки можно добавить выход из цикла при завершении разбора.)
А если в буфере скопилось несколько символов, то значит внешний цикл работает слишком медленно, и обработка по одному символу может только ухудшить ситуацию.
А вы попробуйте обработку посимвольно, при нормальной реализации все отлично работает.
если проблему ТС решит код, в котором за проход луп по символу добавляется, то говорить не о чем.
У меня вообще думка, что код тут вообще не при чем....
буду пробовать мерить чего там с UART происходит, просто все отличие схемы когда все стабилно от плавающей - внешнее воздействие.
размеру и частоте передачи я повторил уровень соединения с мегой. и все равно все стабильно...
что-то мне кажется проблема в том, что соединенные напрямую ttl 5в и 3.3в могут что-то выкидывать, сейчас поищу схемки, соберу на коленке и проверю. Я делаю ставку не на мой код а на код который обрабатывает непосредственно сигнал UART и заполняет кольцевой буфер, он сидит на внутреннем прерывании и вполне может давать такую картину
vde69, 16 МГц мк это достаточно мощная сила, уж обработать строку точно может. В loop проверяете serial.available, если символ есть не нулевой - отправляете его в отдельную процедуру, там уже флагами определяете / запоминаете статус / позиции / логику и обрабатываете. Если по логике необходимо производить какие либо действия - отправляете в функцию флаг - пришёл ли реальный символ.
ха... ха... ха...
подключил вот с таким делителем https://i.stack.imgur.com/GOb3K.jpg и все шалтай балтай пропали, все стало ровненько и красиво....
вывод - ттл5 ->>> ттл3.3 даже если работает не значит, что правильно:)
теперь придется на плате резисторы мостырить....
зы
резисторы 4.7к и 2.2к
К сведению - нормальный терминал даёт тайм-код.
Под линуксом я пользуюсь minicom
что-то я рано обрадовался...
короче ситуация
1. на плате с которой сняты все модули кроме ESP-01 - НЕ работает
2. на переходнике/програматоре (от USB) - работает
промерял все контакты, на програматоре 3.34вт, на плате 3.26вт. UART ни там ни там не используется вообще.
Тут меня осенило, надо затестить осцилограф (который в общем купил "поигратся"), промерил напряжения на плате (их 3шт)
+12в идет от основного БП (идет на мегу) - небольшие импульсы, напряжение "играет" в диапазоне 0.1в
+5в идет от +12 через понижайку (должно идти на перефирийку, экран и т.д.) - небольшие импульсы, напряжение "играет" в диапазоне 0.1в, то есть от 5 до 5.1 вт
+3.3в идет от +12 через понижайку (идет на модули которые питаются от +3,3) - вот тут меня ждала неожиданность, очень сильно "играет", в диапазоне от 2.8в до 3.7в, а вольтметр показывает ровне 3.3
понижайки одинаковые, но та которая на 3.3 греется (даже если убрать нагрузку), короче пока основная версия - надо питание "выпрямлять", или понижайку менять или что-то навешивать типа кондеров, фиритов и т.д.
ВТ - ВАТТЫ, ВОЛЬТЫ не ватты.
ESP довольно требовательны по питанию, не так даже по стабильности напряжения, как по току в импульсе. По памяти до 300мА надо. Потому хороший конденсатор заметно помогает. А средний ток не так уж и велик.
Вообще внутренности ESP - дело довольно темное, официальной науке не известное;) Но некоторые особенности архитектуры сами по себе способны генерить нестабильность времени ответа. Дело в том, что код хранится в флеше, а по ходу работы , перед исполнением очередного "куска" кода, как минимум некоторая часть его, иногда, считывается из флеша в ОЗУ. Это не быстрый процесс. Следовательно если вдруг вызывается функция, кода которой которой нет в ОЗУ, то он начинает считываться, затирая ранее существовавший, и возможно скоро потребующийся снова. Так возникает тормозня. Напоминает свопинг на ПК.
В некоторой степени этим можно управлять атрибутом ICACHE_RAM_ATTR. Но насколько он будет не проигнорен - ХЗ. Но от
voidICACHE_RAM_ATTRLoopReadData() {.... Хуже не будет.Еще замечено, ESP любит хороший WiFi. С его антеной - нифига не удивительно. Но помехи, повторный отправки, сбор фрагментов при нарушенном порядке их прихода и пр. прелести плохого канала, наложенные на отот механизм подгрузки в ОЗУ кусков кода существенно могут тормозить работу. Плохой WiFi также возникнет при недостатке тока. Просто мощность излучения понизится и с слабенькой антенны до роутера сигнал задавят помехи. Так что в ESP все завязано жестко.
поставил на выход понижайки кондер на 470мф, стало заметно лучше.
с точки зрения скорости возврата json в браузер стало от 150 до 250 при чем в не зависимости где стоит ESP на плате или на програматоре.
по осцилографу - большой "дребезг" ушел, остались колибания в диапазоне 0.1 вольта (внешне похожи на синусоиду), и периодически провалы с 3.3 до 0 вольт, но очень короткие, на моем осцилографе просто как полосочка вниз почти до нуля. При чем они есть даже при снятых платах, то есть это не просаживание а скорее кратковременный пробой на землю, наверно именно по этому эта понижайка греется...
На второй понижайке таких провалов нет. там вроде все нормально.
В перспективе буду переделывать плату питания (она между основным блоком питания и остальными элементами, сейчас на ней понижайки и клемы, еще будут кондеры), посоветуйте чего туда предусмотреть... Делал ее отдельно, что-бы отнести подальше от основной платы, по трем причинам - 1. тепловыделение, 2 - наводки от ВЧ блоков, 3. удобно разобрать
зы
и кстати после того как поставил кондер, понижайка перестала грется !!! Кто объяснит почему? понижайка nfrfz https://aliexpress.ru/item/32725286642.html?spm=a2g0o.search0302.0.0.39d36b4brnWUoa&algo_pvid=e13921ac-e57b-41ca-80a0-b0991d77b4b6&algo_expid=e13921ac-e57b-41ca-80a0-b0991d77b4b6-6&btsid=0b8b036a16170390028723113e6e8a&ws_ab_test=searchweb0_0,searchweb201602_,searchweb201603_&sku_id=61230666072
<t_home_1=099;E1>
<t_home_1=-02;OFF>
<t_home_1=015;OK>
В общем дошли руки и я все таки затестил разбор строки при помощи регулярных выражений )) мне понравилось. Использовал вот эту библиотеку
Кусок кода который ее использует вот
//////////////////// Serial.print("Start at: "); Serial.println(millis()); MatchState ms; char *str = "GET /?atname=MIXXMANN&atpin=9999&atpin1=8888&atpin2=7777&atpin3=6666&atpin4=555 HTTP/1.1v"; ms.Target (str); unsigned int index = 0; char buf [100]; while (true){ char result = ms.Match ("(%w+)=(%w+)", index); if (result == REGEXP_MATCHED) { //Serial.println ("-----"); //Serial.print ("Matched on: "); //Serial.println (ms.GetMatch (buf)); //Serial.println ("Captures:"); for (int j = 0; j < ms.level; j++) Serial.println (ms.GetCapture (buf, j)); index = ms.MatchStart + ms.MatchLength; } else break; } Serial.print("End at: "); Serial.println(millis()); ////////////////////Ну и собственно результат разбиения на подстроки
Отрабатывает в пределах 1мс. Насколько я понимаю оч даже не плохо. Может кому пригодится
Засек в микросекундах
С выводом в консоль 512мкс
Без вывода в консоль 342мкс.
Мне кажется регулярки тоже имеют право на жизнь. Хотя бы за то что они читабельнее и гибче. и писанины меньше. Хотя, "на вскус и цвет" все фломастеры разные ))
Отрабатывает в пределах 1мс.
На чём? На ESP? На малине?
Если на UNO, то что-то сомневаюсь. И очень сильно. Сдаётся мне, Вы нас обманываете.
Я добавил необходимое к Вашему скетчу и, заодно, заменил millis на micros, чтобы поточнее было. Запустил его. Вот получившийся код
#include <Regexp.h> void setup(void) { Serial.begin(57600); Serial.print("Start at: "); Serial.println(micros()); MatchState ms; char *str = (char *)"GET /?atname=MIXXMANN&atpin=9999&atpin1=8888&atpin2=7777&atpin3=6666&atpin4=555 HTTP/1.1v"; ms.Target (str); unsigned int index = 0; char buf [100]; while (true) { char result = ms.Match ("(%w+)=(%w+)", index); if (result == REGEXP_MATCHED) { for (int j = 0; j < ms.level; j++) Serial.println (ms.GetCapture (buf, j)); index = ms.MatchStart + ms.MatchLength; } else break; } Serial.print("End at: "); Serial.println(micros()); } void loop(void) {}а вот - результат
Как-то больше похоже на 7,2мс, чем на "в пределах одной"? Нет? Я что-то напутал?
Вы, кстати, очень неаккуратно замеряете время (параллельно выполнению работает Serial). Если это исключить, то получается 2,5мс, но всё равно никак не "в пределах одной".
Без вывода в консоль 342мкс.
Блин, на чём Вы это запускаете? У меня получается совсем не так (см. мой пост выше).
Может приведёте полный скетч, чтобы я Ваш мог запустить?
Блин, на чём Вы это запускаете? У меня получается совсем не так (см. мой пост выше).
Может приведёте полный скетч, чтобы я Ваш мог запустить?
Гыг.. та там кусок тестового скетча... пробую с вебсервером поигратся...
#include <Arduino.h> #include "EEPROM.h" #include <WiFi.h> #include <Regexp.h> #define EEPROM_SIZE 512 const char *ssid = "MIXXMANM"; const char *password = "31011983"; int connections = 0; String atname; String atpin; WiFiServer server(80); String responseHTML = "<!DOCTYPE html><html>" "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">" "<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}" "</style></head>" "<body><h1>MIXXMANN SETUP</h1>" "<form action=\"\" method=\"GET\">" "<p>AT name: <input type=\"text\" name=\"atname\" size=\"15\" maxlength=\"13\" value=\"%atname%\"></p>" "<p>AT pin: <input type=\"text\" name=\"atpin\" size=\"15\" maxlength=\"4\" value=\"%atpin%\"></p>" "<input type=\"submit\" value=\"SET\">" "</form>" "</body></html>"; String header; void showConnectionsCount() { Serial.print("connections coun:"); Serial.println(connections); } void WiFiStationConnected(WiFiEvent_t event, WiFiEventInfo_t info){ connections += 1; showConnectionsCount(); } void setup() { WiFi.mode(WIFI_AP); WiFi.softAP(ssid, password); WiFi.onEvent(WiFiStationConnected, SYSTEM_EVENT_AP_STACONNECTED); IPAddress ip_address = WiFi.softAPIP(); server.begin(); Serial.print("AP IP address: "); Serial.println(ip_address); Serial.begin(115200); EEPROM.begin(EEPROM_SIZE); atname=EEPROM.readString(0); atpin=EEPROM.readString(16); if (atname.isEmpty()){atname="MIXXMANN";} if (atpin.isEmpty()){atpin="9999";} if (atname.length()>13) {atname=atname.substring(0,13);} if (atpin.length()>4) {atpin=atpin.substring(0,4);} //////////////////// Serial.println(micros()); MatchState ms; char *str = "GET /?atname=MIXXMANN&atpin=9999&atpin1=8888&atpin2=7777&atpin3=6666&atpin4=555 HTTP/1.1v"; ms.Target (str); unsigned int index = 0; char buf [100]; while (true){ char result = ms.Match ("(%w+)=(%w+)", index); if (result == REGEXP_MATCHED) { //Serial.println ("-----"); //Serial.print ("Matched on: "); //Serial.println (ms.GetMatch (buf)); //Serial.println ("Captures:"); for (int j = 0; j < ms.level; j++) // Serial.println (ms.GetCapture (buf, j)); index = ms.MatchStart + ms.MatchLength; } else break; } Serial.println(micros()); //////////////////// } void loop() { }Запускаю на ESP32 Ai-Thinker
Замерил по вашей рекомендации особо ниче не поменялось
Это на mega2560
Прискорбно однако.
Евгений, чесно не обманываю. ... но вот что прям такая разительная разница между есп и мегой меня немного повегла в шок. Порядок цен ведь тот же...