Реклама ⓘ
Главная » Arduino
Призовой фонд
на апрель 2024 г.
1. 100 руб.
От пользователей

Похожие статьи:


Реклама ⓘ

Объект String в Arduino и команды через последовательный порт

Сколько ни изучаю Arduino, она не перестаёт удивлять меня своей простотой. К примеру, собирая и тестируя систему "умного дома", я думал, что подача команд с компьютера будет самой сложной частью - это же надо принимать строку из последовательного порта, распознавать её, следить, чтобы не возникало ошибок... Однако оказалось достаточно почитать сайт Arduino.cc да потестить пару примеров, как стало ясно - разработчики постарались, чтобы оградить нас от написания длинного и унылого кода. К слову сказать, с задачей в итоге я справился за вечер, под конец даже подумывая: "а какую бы ещё команду прикрутить?.."

Итак, предположим, вы уже умеете программировать Arduino и можете разобраться в своём или чужом коде. Одним из основных понятий являются переменные и их типы. Ну-ка навскидку? byte, int, long, char, string... Два последних - по сути одно и то же, ибо string - массив переменных типа char (Кто-нибудь сейчас должен возразить, что char представляется в виде байтового числа, но речь не об этом). Итак, всё, что принимается из последовательного порта, следует читать, как char:

char inChar[] = "             ";
byte z = 0;
while (Serial.available()) {
  inChar[z] = Serial.read();
  z++;
}

Это первый пример, который может придти в голову. Создаём пустую строку, затем, если есть, что читать из последовательного порта, посимвольно её заполняем. Функция Serial.available() возвращает количество байт, доступных для чтения, а если там пусто - то 0, очевидно. Этим можно пользоваться, чтобы узнать длину поданной команды, хотя мы и так её узнаем в приведённом примере - это величина переменной z на выходе из цикла. Да, строка из пробелов (ASCII код пробела - не ноль!) - это терпимо, но всё-таки не очень хорошо, по возможности избегайте этого. А догадливый читатель сможет похвалить себя, если сразу догадается, что стоит исправить в вышеприведённом коде. Для тех, кто не догадался - подсказка: char inchar[6] - строка длиной 6 символов. Если строке присваивается значение, компилятор позволяет не указывать явно её длину, поэтому в примере квадратные скобки пустые.

Кстати, не стоит забывать прописать в setup()

Serial.begin(9600);

А во встроенном мониторе порта, в который, собственно, и будут отправляться команды, указать скорость - 9600 бод, иначе увидите крякозябры.

Далее, что делать с полученной строкой? Те, кто предложат сравнивать побайтово строку с известными значениями (а такая мысль наверняка кому-то может придти в голову) после прочтения статьи переместятся вперёд во времени лет на 20. Из прошлого, я имею в виду :)

Поиск по документации Arduino IDE даёт два варианта, что такое string. Это сам string как строка char'ов, и String, являющийся объектом. Что такое объект? Согласно википедии, это "некоторая сущность в виртуальном пространстве, обладающая определённым состоянием и поведением, имеющая заданные значения свойств (атрибутов) и операций над ними (методов)". Другими словами - переменная со встроенными функциями, делающими что-то с этой переменной. Чтобы начать работать с этим объектом, напишем что-нибудь такого вида:

String input = "";

while (Serial.available()) {
  input += Serial.read();
  
}

Здесь к input будут добавляться всё новые символы, пока буфер не иссякнет. Тогда можно будет анализировать полученную строку, например, так:

input.toLowerCase();
if(input.startsWith("pause")) {
   String toWait =  input.substring(5);
   toWait.trim();
   int delaytime = toWait.toInt();
   if(delaytime>0) {
      if(delaytime<10000) {
         delay(delaytime);
      }
   }
}  

Код использует очень удобные функции, встроенные в объект String. Это startsWith(), которая возвращает единицу, если строка начинается с того, что записано в скобках, substring(), возвращающая кусок строки, начинающийся в данном случае с 5-го символа (считается, начиная с нуля), trim(), отбрасывающий всё лишнее по краям строки, ну и toInt(), превращающий то, что осталось, в число типа Int. Это число неплохо ещё и проверить на предмет попадания в рамки ожидаемого. В итоге, если дать команду "PauSe 567 ", то МК подождёт ровно 567 миллисекунд.

Про trim() стоит написать отдельно. Он нужен не только для того, чтобы отбросить пробел в начале получившейся строки, но в первую очередь - чтобы избавиться от символов в её конце. Это служебные символы, добавляющиеся при отправке сообщения - NL (новая строка) и CR (возврат каретки). Они нужны как раз для того, чтобы сигнализировать о конце команды, но могут и помешать. Поэтому, несмотря на то, что в мониторе порта можно выбрать, какие из этих символов посылать или не посылать ничего, лучше перестраховаться. Тем более, что делается это в одну строчку кода.

А вот и список функций (методов) объекта String.

  • charAt() - возвращает символ, стоящий на указанном месте

  • concat() - функция конкатенации, т.е слияния двух строк в одну. Правда string1 = string1 + string2 это то же самое, что и string1.concat(string1, string2), а записывается проще и понятнее.

  • equals() - возвращает единицу, если строка посимвольно равна тому, что написано в скобках. Есть ещё equalsIgnoreCase(), который игнорирует регистр (верхний или нижний)

  • endsWith() - который работает аналогично startsWith()

  • indexOf() - возвращающий место в строке символа(или строки) в скобках. Ищет с конца и возвращает -1, если не найдено.

  • length() - выдающий длину строки

  • setCharAt() - требующий место и символ, который надо поставить на это место, например: string1.setCharAt(3, 'd') поставит d третьим символом в строке взамен того, что там стояло

  • И ещё несколько других, которые вряд ли вам понадобятся, если вы не в силах залезть на arduino.cc и прочитать о них :)

Вот и всё, что хотел рассказать. Надеюсь, эта статья поможет не бояться ООП и научить вашего домашнего робота на Arduino повиноваться сигналам с компа

Теги:

Опубликована: Изменена: 11.02.2016 0 0
Я собрал 0 1
x

Оценить статью

  • Техническая грамотность
  • Актуальность материала
  • Изложение материала
  • Полезность устройства
  • Повторяемость устройства
  • Орфография
0

Средний балл статьи: 1.8 Проголосовало: 1 чел.

Комментарии (10) | Я собрал (0) | Подписаться

0
Fonoton #
Есть такой вопрос по пересылке данных по Serial между двумя ARduino:
На одной Arduino формируются данные в виде структуры из трех значений (int, int, float). Как эту структуру передать по Serial на другую Arduino?
Ответить
0

[Автор]
Q109 #
Лично я никогда не использовал Serial для связи двух МК - могут возникнуть проблемы, особенно если ещё и преобразователь интерфейса (USB) использовать. Для этих целей лучше подходит i2c, благо есть готовая библиотека.
Вариантов, на самом деле, масса: можно передавать значения побайтово (можно вообще заморочиться и 8 пинов использовать для этого), и, зная размер каждого типа данных, вовремя переключаться на приём следующего значения. Можно дополнительный разделительный сигнал придумать, чтобы быть уверенным, что никакие данные не потерялась при передаче. Саму структуру целиком передать вряд ли получится.
Ответить
0
Fonoton #
Смысл связи через Serial- применение приемопередатчиков APC220. Они являются радиоудлинителями Serial.
Я попытался структуру на передающей стороне запихнуть в Serial такой командой:
Serial.write (uint8_t *)&data, sizeof(Packet));
где data - это экземпляр структуры Packet

На принимающей же Arduino пробую сформировать строку с помощью кода, предложенного Вами:
String input[] = "";
while (Serial.available()) {
input += Serial.read();
}
Что я делаю не так?
Ответить
0
Костя #
Очевидно же, что вместо String input[] = ""; надо писать String input = "";
Автор - исправьте!
Ответить
0

[Автор]
Q109 #
Это всё-таки массив, и неплохо бы это указывать, хоть и без указания точного его размера.
Ответить
0

[Автор]
Q109 #
Что не так? Скобочки посчитайте
Ответить
0
luzik24 #
Выдает ошибку incompatible types in assignment of 'int' to 'String [1]' в строке input += Serial.read();
Что тут не так?


void setup() {
Serial.begin(9600);
}

void loop() {
String input[] = "";

while (Serial.available()) {
input += Serial.read();
}

input = input.toLowerCase();
if(input.startsWith('pause')) {
String toWait = input.substring(5);
toWait.trim();
int delaytime = toWait.toInt();
if(delaytime>0) {
if(delaytime<10000) {
delay(delaytime);
}
}
}



}
Ответить
0
Руслан #
Привет. есть такой код
if (val.indexOf("+CMT") > -1 ) { //если пришла смс
if (val.indexOf("Sos") > -1) { //ищем *Sos*
digitalWrite(bizzer, HIGH);
delay(300);
digitalWrite(bizzer, LOW);
val = "";
}
}
код не работает.Подскажите как найти слово с смс.Набросайте код если не трудно
Ответить
0
Серега #
Скажите пожалуйста, нигде не могу найти такую тему. Делаю часы, для проверки их работы нужно вывести данные на экран последовательного порта в таком виде в одну строку ... : ... : ...
Под ... подразумеваются переменные часов.
Ответить
0
mnhunte #
возможно пример не верен либо устарел -

input += Serial.read();
не работает как надо - возвращает данные в ASCII
должно быть - input +=Serial.readString();
Ответить
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется электрическая мощность?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

Raspberry Pi 2
Raspberry Pi 2
FM-модуль RDA5807M USB осциллограф DSO-2090
вверх