Помогите пожалуйста разобраться! С софтого порта данные приходят целые ввожу например 1;455,413,290 и так же вторые данные 0;12 из примера софт сериал приходят целыми Далее в моем коде данные в софт сериал приходят тоже целыми а в порт монитора после парсинга приходит не то что посылал протокол работает только числа не те что посылаю. Код (C++): #include <SoftwareSerial.h> SoftwareSerial softSerial(2, 3); // Создаём объект softSerial указывая выводы RX, TX #define LED_1 6 #define LED_2 13 int VelocityPars[] = {0, 0, 0}; int SpeedPars[] = {0, 0, 0}; int ledstate1; int ledstate2; byte Key; bool flagKey = 0; void setup() { softSerial.begin(38400); softSerial.setTimeout(10); Serial.begin(9600); pinMode(LED_1, OUTPUT); pinMode(LED_2, OUTPUT); } // протокол: // 0 - KEY (1-12) // 1 - SpeedPars (0..700,0..700,0..700) // 2 - VelocityPars (0..700,0..700,0..700) void loop() { if (softSerial.available()) { static byte prevAm = 0; static uint32_t tmr = 0; byte ad = softSerial.available(); if (ad != prevAm) { prevAm = ad; tmr = millis(); } if ((ad && millis() - tmr > 10) || ad > 60) { uint32_t us = micros(); char str[30]; // указатели на строки int amount = softSerial.readBytesUntil(';', str, 30); str[amount] = NULL; softSerial.println(str); int ints[5]; int count = 0; char* offset = str; while (true) { ints[count++] = atoi(offset); offset = strchr(offset, ','); if (offset) offset++; else break; } switch (ints[0]) { // ключ case 0: Key = ints[1]; flagKey = 1; Serial.println("KEY"); Serial.println(Key); break; case 1: SpeedPars[0] = ints[1]; SpeedPars[1] = ints[2]; SpeedPars[2] = ints[3]; Serial.println("Speed"); for (int i = 0; i < 3; i++) { Serial.println(SpeedPars[i]); } break; case 2: VelocityPars[0] = ints[1]; VelocityPars[1] = ints[2]; VelocityPars[2] = ints[3]; Serial.println("Velocity"); for (int i = 0; i < 3; i++) { Serial.println(VelocityPars[i]); } break; } } } byte KEY = Key; if ((KEY == 6) && (flagKey == 1)) { flagKey = 0; ledstate2 = !ledstate2; KEY = 0; Serial.println(KEY); } if ((KEY == 5) && (flagKey == 1)) { flagKey = 0; ledstate1 = !ledstate1; KEY = 0; Serial.println(KEY); } digitalWrite(LED_2, ledstate2); digitalWrite(LED_1, ledstate1); } вот что наблюдаю в порте: оно же: https://disk.yandex.ru/d/NU66mJ8APuWrTQ
Есть второй вариант работает аналогично Код (C++): #include "Parser.h" #include <SoftwareSerial.h> SoftwareSerial softSerial(2, 3); // Создаём объект softSerial указывая выводы RX, TX #define LED_1 6 #define LED_2 13 int VelocityPars[] = {0, 0, 0}; int SpeedPars[] = {0, 0, 0}; int ledstate1; int ledstate2; byte Key; bool flagKey = 0; void setup() { softSerial.begin(38400); softSerial.setTimeout(10); Serial.begin(9600); pinMode(LED_1, OUTPUT); pinMode(LED_2, OUTPUT); } // протокол: // 0 - KEY (1-12) // 1 - SpeedPars (0..7000,0..7000,0..7000) // 2 - VelocityPars (0..7000,0..7000,0..7000) void loop() { if (softSerial.available()) { static byte prevAm = 0; static uint32_t tmr = 0; byte ad = softSerial.available(); if (ad != prevAm) { prevAm = ad; tmr = millis(); } if ((ad && millis() - tmr > 10) || ad > 60) { uint32_t us = micros(); void clear(); char str[30]; // указатели на строки int amount = softSerial.readBytesUntil(';', str, 30); str[amount] = NULL; softSerial.println(str); Parser data(str, ','); int ints[5]; int am = data.parseInts(ints); switch (ints[0]) { // ключ case 0: Key = ints[1]; flagKey = 1; Serial.println("KEY"); Serial.println(Key); break; case 1: SpeedPars[0] = ints[1]; SpeedPars[1] = ints[2]; SpeedPars[2] = ints[3]; Serial.println("Speed"); for (int i = 0; i < 3; i++) { Serial.println(SpeedPars[i]); } break; case 2: VelocityPars[0] = ints[1]; VelocityPars[1] = ints[2]; VelocityPars[2] = ints[3]; Serial.println("Velocity"); for (int i = 0; i < 3; i++) { Serial.println(VelocityPars[i]); } break; } } } byte KEY = Key; if ((KEY == 6) && (flagKey == 1)) { flagKey = 0; ledstate2 = !ledstate2; KEY = 0; Serial.println(KEY); } if ((KEY == 5) && (flagKey == 1)) { flagKey = 0; ledstate1 = !ledstate1; KEY = 0; Serial.println(KEY); } digitalWrite(LED_2, ledstate2); digitalWrite(LED_1, ledstate1); } парсинг Код (C++): #ifndef Parser_h #define Parser_h // простой и быстрый парсер строк в отдельные строки и числа class Parser { public: Parser (char* data, char newDiv = ',') { buf = data; div = newDiv; } ~Parser() { clear(); } void clear() { if (str) free(str); } int amount() { int i = 0, count = 0; while (buf[i++]) if (buf[i] == div) count++; // подсчёт разделителей return ++count; } int split() { int am = amount(); // количество данных clear(); // освобождаем буфер str = (char**)malloc(am * 2); // создаём буфер str[0] = buf; // строка 0 int i = 0, j = 0; // счётчики while (buf[i]) { // пока не NULL if (buf[i] == div) { // если разделитель buf[i] = NULL; // меняем на NULL str[++j] = buf + i + 1; // запоминаем начало строки } i++; } return am; } int16_t getInt(int num) { return atol(str[num]); } float getFloat(int num) { return atof(str[num]); } bool equals(int num, const char* comp) { return !strcmp(str[num], comp); } int parseInts(int* data) { int count = 0; char* offset = buf; while (true) { data[count++] = atoi(offset); offset = strchr(offset, div); if (offset) offset++; else break; } return count; } int parseBytes(byte* data) { int count = 0; char* offset = buf; while (true) { data[count++] = atoi(offset); offset = strchr(offset, div); if (offset) offset++; else break; } return count; } char* buf = NULL; char** str = NULL; char* operator [] (uint16_t idx) { return str[idx]; } char div; private: }; #endif
Цифры в мониторе порта - это произвольные значения со стека (или ригистры), так как печатаются неинициализированные ячейки массива. Код: Код (C++): char str[30]; // указатели на строки int amount = softSerial.readBytesUntil(';', str, 30); str[amount] = NULL; softSerial.println(str); На входе данные: 1;455,413,290 после выполнения этого кода в массиве будет: Код (C++): str[0]='1'; str[1]=\0; Дальше: Код (C++): int ints[5]; int count = 0; char* offset = str; while (true) { ints[count++] = atoi(offset); offset = strchr(offset, ','); if (offset) offset++; else break; } offset настраиваете на начало str[]. в цикле в ints[0] записываете 1. Дальше в str[1] = \0 Вызов: Код (C++): offset = strchr(offset, ','); ничего не найдет, так как в str[1] записан 0, а это признак конца строки. В offset будет записан \0 Поэтому вы вывалитесь из цикла, и перейдете в switch() В нем вы ничего не проверяя печатаете: Код (C++): SpeedPars[0] = ints[1]; SpeedPars[1] = ints[2]; SpeedPars[2] = ints[3]; Serial.println("Speed"); for (int i = 0; i < 3; i++) { Serial.println(SpeedPars[i]); } ints[5] - массив локальный, он не инициализируется. В ints[1] - ints[3] вы ничего не записывали, поэтому печатается мусор со стека (или регистров)
Ничего не понял! Это что же получается я массив пытаюсь записать указатели? А как правильно записать массив ints[ ] ?
Даже если носом тыкнуть не обижусь Пробовал перетащить в переменную Тоже и ничего не вышло Ну это и понятно Код (C++): for (int i = 0; i < count; i++) { ints[i] = str[i]; Serial.println(data[i]); } Не могу понять почему в str[0]='1'; Записывается как положено единица а в str[1] ничего? Буду очень признателен! четвертый день пытаюсь хоть что то получить.
Попытался записать data В порт стали приходить адекватные данные. Код (C++): while (true) { data[count++] = atoi(offset); // пишем число в буфер offset = strchr(offset, ','); // поиск следующей запятой if (offset) offset++; // если это не NULL - продолжаем else break; // иначе покидаем цикл } for (int i = 0; i < count; i++) { ints[i] = data[i]; Serial.println(ints[i]); } Ключ переключает switch Но все что прописано в нем не работает(
Что делает строка: Код (C++): int amount = softSerial.readBytesUntil(';', str, 30); То есть считываются данные до символа ';' и позже, в конце ставится \0. Все. Откуда взяться остальным данным до конца строки? (остальные три параметра).
Ага вот теперь боле менее стало понятно Я думал что она пропускает Символ ';', То есть мне нужно еще раз считать данные?
В вашу обработку millis(), я не вникал, там несколько запутано, править не стал. Значение micros() не используется, хотя получается. С "Key" - тоже не однозначно. Вы пишите, что Key 1-12: Код (C++): // протокол: // 0 - KEY (1-12) И в тоже время обрабатываете Key 0: Код (C++): switch (ints[0]) { // ключ case 0: Key = ints[1]; flagKey = 1; Serial.println("KEY"); Serial.println(Key); break; Как я вижу очень хотите использовать: Код (C++): softSerial.readBytesUntil() Поэтому подправил только чтение параметров, остальное... все ваше: Код (C++): #include <SoftwareSerial.h> SoftwareSerial softSerial(2, 3); // Создаём объект softSerial указывая выводы RX, TX #define LED_1 6 #define LED_2 13 #define MAX_PARAMS 3 int VelocityPars[MAX_PARAMS] = {0, 0, 0}; int SpeedPars[MAX_PARAMS] = {0, 0, 0}; int ledstate1; int ledstate2; byte Key; bool flagKey = 0; void setup() { softSerial.begin(38400); softSerial.setTimeout(10); Serial.begin(9600); pinMode(LED_1, OUTPUT); pinMode(LED_2, OUTPUT); } // протокол: // 0 - KEY (1-12) // 1 - SpeedPars (0..700,0..700,0..700) // 2 - VelocityPars (0..700,0..700,0..700) void loop() { if (softSerial.available()) { static byte prevAm = 0; static uint32_t tmr = 0; byte ad = softSerial.available(); if (ad != prevAm) { prevAm = ad; tmr = millis(); } if ((ad && millis() - tmr > 10) || ad > 60) { uint32_t us = micros(); char str[30]; // массив для строки int ints[MAX_PARAMS]; int count = 0; int amount = softSerial.readBytesUntil(';', str, 30); str[amount] = 0 ; softSerial.println(str); Key = atoi(str); if (amount && Key >= 0 && Key <= 12) { do { amount = softSerial.readBytesUntil(',', str, 30); str[amount] = 0; if (amount) ints[count] = atoi(str); else break; } while (++count < MAX_PARAMS); switch (Key) { // ключ case 0: flagKey = 1; Serial.println("KEY"); Serial.println(Key); break; case 1: Serial.println("Speed"); for (int i = 0; i < count; i++) { SpeedPars[i] = ints[i]; Serial.println(SpeedPars[i]); } break; case 2: Serial.println("Velocity"); for (int i = 0; i < count; i++) { VelocityPars[i] = ints[i]; Serial.println(VelocityPars[i]); } break; } } while (softSerial.available()) //скинем оставшиеся символы из буфера если key не входит в диапазон 0-12 softSerial.read(); } } byte KEY = Key; if ((KEY == 6) && (flagKey == 1)) { flagKey = 0; ledstate2 = !ledstate2; KEY = 0; Serial.println(KEY); } if ((KEY == 5) && (flagKey == 1)) { flagKey = 0; ledstate1 = !ledstate1; KEY = 0; Serial.println(KEY); } digitalWrite(LED_2, ledstate2); digitalWrite(LED_1, ledstate1); }
Спасибо вам огромное! Немного не то но теперь я уже разберусь что и как. Теперь мне понятно что делать! У меня было ints это ключ а Key это был байтовый параметр наподобие массива SpeedPars[] только приходило не три а один параметр.
Доброго времени суток! Простите, что выпимши пишу, но посему ВСЕ хотят символьный обмен? Мне по душе бинарный... я о том, что по аналогии не люблю Modbus ASCII и уважаю Modbus RTU. Текстовый то же хорошо, но для отладки. Ну вы сами представьте, на обеих сторонах надо вести преобразование текст<-->данные... если для ПК это "курить бамбук", то для МК это уже дополнительная работа! ЗЫ; простите, что встреваю, но 1Л кончился и я иду за вторым!