Итак. Вот примерный алгоритм, которому я следовал:
- Идем на arduino.ru и высматриваем в колонке типов все, связанное с символами.
- Решаем, какую форму представления будем использовать (Я остановился на классе String, т.к. имел неприятный опыт с
месивоммассивом). Судорожно пытаемся написать свою функцию с преферансом и профурсетками- Ищем подробное описание класса.
- Ищем нужные операторы.
- Пишем!
А алгоритм работы основного тела программы прост:
- Циклично проверяем, есть ли в буфере com порта доступный для чтения байт, если есть, читаем.
- Если принятый байт — символ переноса строки ('\n'), то вызываем самописную функцию парсинга, если же нет, то добавляем принятый байт в созданную переменную типа String.
- Парсим, наконец, строку.На самом деле, т.к. практическое использование парсинга строк у меня не горит, то данная функция носит всего лишь демонстративный характер, сравнивая полученную строку с уже записанной в памяти константной строкой. Итак, используя оператор equals сравниваем принятую строку с записанной, и, если оператор возвращает true, выходим из функции обработчика, если же нет, сравниваем со следующей. Если строки эквивалентны, то опять же, выходим из функции-обработчика, возвращая результат. Ну а уж если и это условие не сработает, то все равно выйдем из функции и скажем, что что строка не верна.
- В зависимости от принятого результата с помощью switch case выбираем нужный.
- Обнуляем принятую строку, чтобы потом начать собирать ее заново.
#define led 13
String input_string = "";
const String Led_off = "switch led off";
const String Led_on = "switch led on";
bool led_running;
void setup() {
Serial.begin(9600);
}
void loop() {
while (Serial.available() > 0) {
char c = Serial.read();
if (c == '\n') {
Serial.print("Input_string is: ");
Serial.println(input_string);
switch ( parse(input_string, Led_off, Led_on) ) {
case 10:
led_running=false;
Serial.println("Switching off is done");
break;
case 11:
led_running=true;
Serial.println("Switching on is done");
break;
case 0:
Serial.println("invalid String");
break;
}
input_string = "";
digitalWrite(led, led_running);
} else {
input_string += c;
}
}
}
byte parse(String input_string, const String Led_off, const String Led_on) {
if (input_string.equals(Led_off) == true) {
return 10;
}
else if (input_string.equals(Led_on) == true) {
return 11;
}
else return 0;
}
Так, я не понял, что за дела? Почему не загорается светодиод? Ах да, как же это я запамятовал, в void setup нужно добавить:
pinMode(led, OUTPUT);
P.S.: Немаловажно установить монитор com порта в Arduino IDE в режим «Новая строка», т.к. в любом другом посылаемая строка не будет сопровождаться символом ее окончания '\n'.
P.P.S.: В холиваре по поводу того, что ардуино нинужна — участвовать не собираюсь, изучая основы программирования и алгоритмизации я ничего дурного не сделал.
P.P.P.S.: Если статья будет принята адекватно, напишу следующую о том, что у меня вышло с улучшением функционала функции парсинга. Ну, с богом!.
Комментарии (25)
ZloAlien
16.11.2015 11:38+1Не могу не упомянуть протокол «Firmata». (http://robocraft.ru/blog/arduino/283.html)
ToSHiC
16.11.2015 11:51+1Очень рекомендую изучить тему текстовых парсеров на основе конечных автоматов. Например, можно попробовать написать простейший парсер (для начала консольный, а не для ардуины) на связке bison + flex.
Alexeyslav
16.11.2015 12:00+2Холивары холиварами… но последствия адрдуины уже имеются.
Что если вашей программе на вход скормить очень длинную строку? Памяти в контроллере мало, и она совмещена со стеком… быстро переполняется и разрушает стек с соответствующими последствиями.
Надо добавлять контроль максимальной длины строки, для защиты от непреднамеренных ошибок хотябы. Если набрали в строку 32{подставить своё значение не больше свободного объёма RAM} символа а перевода строки всё ещё нет — дальнейшие символы надо игнорировать во избежание разрушения стека — что-то пошло не так.proudmore
16.11.2015 12:14Спасибо за взгляд со стороны и вскрытую уязвимость. Там, где я думал применять эту конструкцию, он бы себя не проявил. Ну, а на счет последствий… Вот вы беретесь утверждать, что мир МК юзерфрендли для абсолютных нубов? Я, лично, сомневаюсь. Я бы и не подумал даже сюда лезть. Однако сейчас я уже могу писать быдлокод — прогресс налицо. И, да, отказываться от Arduino IDE я таки собираюсь.
Alexeyslav
16.11.2015 14:05Не обязательно отказываться от Arduino IDE, надо просто изучить как она работает. В дальнейшем она может сэкономить массу времени на создании пилотных версий проектов, каких-то единичных вещей которые должны отработать минуту-десять-час и больше не понадобятся.
Достаточно уметь работать без неё, изучить работу голого контроллера чтобы понять как на железо ложится программа написанная в среде ардуино и т.д.
Я так думаю едва ли стоит переходить на чистый С для МК если вы не собираетесь становится профессиональным программистом. Всё то же самое можно делать и в Arduino IDE, просто не использовать универсальные громоздкие обёртки.proudmore
16.11.2015 14:12+2Мне 19 лет, и то, чем я сейчас занимаюсь, мне нравится. Я пойду учится делать это профессионально. Хочу остаться в этой сфере.
k12th
16.11.2015 12:14+1Тут дело не в ардуине — это стандартный недосмотр, который может допустить кто угодно (привет, HeartBleed).
ToSHiC
16.11.2015 12:48На самом деле конкретно тут и не нужно строку в ОЗУ хранить, достаточно 2-3 байт для хранения состояния парсера, ну и сотня-другая байт флешки для хранения кода парсера.
k12th
16.11.2015 12:52+1Я к тому, что наезд на ардуино тут необоснованный:) Конечно, можно оптимальнее и безопаснее сделать.
r00tGER
16.11.2015 14:32Насколько помню, ардуиновский обработчик последовательного порта, просто перестанет писать в буфер, размер которого можно менять, кстати.
В стеке ничего не потрется.
А вот обработка «не ожидаемых» пакетов полностью на разработчике.
r00tGER
16.11.2015 14:15Я так понимаю, вы сделали свой протокол. Но, зачем в текстовом виде?
Почему не работать двоичными данными. Тогда не будет жутких обработок строк.
Например нужно записать значение в аналогАут:
0х01 0х01 0хАА — всего три байта — команда, порт и значение.
А теперь представьте, насколько быстрее сравнение (свитч туда-же) работают с байтам.
Предлагаю, разобраться и написать статью, как сделать это без стрингов (соответственно, и без парсеров).
Столько интересного, а подсчет контрольной суммы, а переменная длина пакета, а переспросы, а ответные статусы…
Навалом же готового.proudmore
16.11.2015 14:18Я хочу попробовать связать контроллер с вебом посредством отправки и принятия GET запросов. Следовательно, работа со строками необходима :)
Но в Вашем направлении тоже стоит предпринять какие-то шаги, буду иметь ввиду.r00tGER
16.11.2015 14:26Ну, урл в любом случае стринговый :)
Хотя-бы простой парсер ресурса и параметров, конечно нужен.proudmore
16.11.2015 14:30Можно и по ip заходить же ) Если учитывать, что дальше локальной сети моей квартиры это не уйдет, то вполне себе норм :)
proudmore
16.11.2015 14:37Да и не стал бы я писать сюда с самодельным протоколом работы с двоичными данными :) Как вы правильно сказали, и так навалом всего.
apple01
18.11.2015 22:26Посмотрите мою статью в которой я управляю ардуиной методом GET запросов с последующим парсингом комманд
http://habrahabr.ru/post/259579/
Actor
17.11.2015 05:03Можно вобще слать 1 байт, условно разбив байт на значения, к примеру:
| 00 | 0 | 0 | 0010 | | | | | | | | Номер порта, с которым что то делаем | | Бит действия, GET / SET | Режим порта HIGH / LOW Еще что либо
geovas333
16.11.2015 19:17Что-то вспомнилось, как я будучи студентом 3-го курса пытался впихнуть в attiny2313 (с 2кб памяти) программу способную определять скорость вращения двигателя и выводить результат на ЖК экран. Я тогда так увлекся оптимизацией кода по выводы данных на экран, что совсем позабыл про цель работу. В конечном итоге скорость определялась мягко говоря не очень… Кто бы что ни говорил, но Arduino (а точнее atmega328p и более старшие модели), помогает решать многие проблемы одним простым sprintf-ом, например, оставляя время на более важные проблемы.
AlanDrakes
17.11.2015 07:14Может, попробуете посмотреть в сторону готовой библиотеки MicroRL?
Помнится, я писал аналогичные «затычки» как для парсинга строк, так и для вывода на экран (странное то, что сначала — на ЖК экран, а уже затем — в консоль), но решил наконец перейти на готовое. Или на сублиматы — подготовленное к использованию.
vladikas
Буду следить за публикациями.