Освой программирование играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

Serial Monitor. Общаемся с компьютером

Для общения между платой Arduino и компьютером или другим устройством используется последовательный порт, который иногда называют UART or USART. У некоторых моделей Arduino может быть несколько портов. Порт соединяется через цифровой пин 0 (RX) и 1 (TX) при подключении к компьютеру через USB, поэтому не используйте пины 0 и 1 для ввода/вывода.

Вам часто придётся использовать общение между устройствами для обмена информацией. Можно как посылать сигнал с компьютера, например, с клавиатуры, так и принимать сигналы с платы.

В Arduino IDE есть специальный значок с изображением лупы, который запускает Serial Monitor.

Для общения используется класс Serial. В методе setup() мы открываем порт для общения функцией Serial.begin() с указанием скорости в бодах (baud). Доступные скорости можно посмотреть в настройках порта. Значение 9600 является стандартным и его можно не менять.

Чтобы отправить сообщение в порт, используются методы print() (символы идут подряд) или println() (с переводом на новую строку).

Serial Port

Давайте выведем какое-нибудь сообщение. Это можно сделать в методе setup(), так как нам не нужно повторять одну и ту же фразу бесконечно. Метод loop() оставляем пустым.


void setup() {
  Serial.begin(9600);
  Serial.println("Hello Kitty!");
  Serial.print("Мяу!");
}

void loop(){
  
}

Если посылаем строку, то обрамляем её кавычками. Если число, то кавычки не используем. Изменим функцию setup().


void setup() {
  Serial.begin(9600);
  Serial.print("А у кошки "); Serial.print(4); Serial.println(" ноги,");
  Serial.print("А сзади у ней длинный хвост.");
}

void loop() {

}

Можно заменить строки и числа на переменные. Перепишем пример.


String cat = "А у кошки ";
int leg = 4;

void setup() {
  Serial.begin(9600);
  Serial.print(cat); Serial.print(leg); Serial.println(" ноги,");
  Serial.print("А сзади у ней длинный хвост.");
}

void loop() {

}

Немного о числах. При работе с дробными числами, можно указать число знаков после запятой.


void setup() {
  float number = 9.434346502;
  Serial.begin(9600);
  Serial.print(number, 2);
}

void loop() {

}

Работа с массивами и строками

Разберём пример отправки строк в случайном порядке. Любая строка уже является массивом символов. Поэтому вместо типа String, можно использовать массив char[]. Для примера создадим массив из четырёх имён и будем выводить их в случайном порядке через разные промежутки времени, используя функцию random().


char* catNames[] = {
  "Барсик",
  "Васька",
  "Мурзик",
  "Рыжик"
};

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

void loop() {
  int delayPeriod = random(2000, 5000);
  delay(delayPeriod);
  int index = random(4);
  Serial.println(catNames[index]);
}

Serial port

Приём данных

Выводить данные в порт просто. А вот принимать данные с компьютера и других источников сложнее. При отправлении данных, они складываются в буфер, ожидая, когда плата их прочитает. Объём буфера составляет 64 байта. Чтобы постоянно не читать пустой буфер, есть специальная функция проверки буфера Serial.available(). Она возвращает число байт, которые лежат в буфере. Обычно в коде создают условие проверки - если в буфере больше 0 байт, то выполняем какие-то команды.

Для демонстрации создадим странный пример - создадим переменную, присвоим ей данные через Serial.read() и попросим её прислать полученные данные через Serial.print(). Получится круговорот данных или эхо.


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

void loop() {
  if (Serial.available() > 0) {
    int data = Serial.read();
    Serial.println(data);
  }
}

Проверяем на числах. Отправляем число 9, а получаем 57. Если вы получаете две строки с числами 57 и 10, то в нижней части окна выберите настройку No line ending вместо Newline.

Попробуем также отправить букву. Опять вместо t возвращается 116. Ерунда какая-то. Всё просто, функция read() работает с символьными значениями и мы видим код символа из стандартной таблицы символов ASCII.

Чтобы решить проблему, нужно изменить тип данных на char.


char data = Serial.read();

Вроде проблема решена. Мы можем принимать отдельные цифры и буквы. Но буквы только английские, а числа только однозначные.

Если мы планируем работать только с однозначными числами, то можно написать такой код.


int data = Serial.read() - '0';

Решение какое-то половинчатое. А как быть с большими числами или словами?

Если отправить двузначное число 23, то ответ разбивается на части - 2 и 3. Получается, что переменная получит последнее число 3 (промежуточные значения перезаписываются). Чтобы обработать всё число, нужно использовать метод parseInt().


int data = Serial.parseInt();

Теперь вы можете вводить любые числа. Но, наверное, вы заметите теперь небольшую задержку в ответах. Метод внутри себя перемалывает данные. Кстати, вы можете использовать и обычные символы. Если набор символов состоит только из букв, то вернётся 0. Если будут попадаться и цифры, то будут возвращаться цифры. Попробуйте комбинировать различные сочетания цифр и букв, чтобы понять, как будут обрабатываться данные.

Управление светодиодом с клавиатуры

Напишем пример управления встроенным светодиодом с клавиатуры. Если нажата клавиша 1, то светодиод должен загореться, при нажатии клавиши 0 выключим светодиод.


int ledPin = 13;
byte incomingByte;

void setup() {
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  if (Serial.available() > 0) {
    incomingByte = Serial.read();

    if(incomingByte == '1'){
      digitalWrite(ledPin, HIGH);

    }
    else if (incomingByte == '0'){
      digitalWrite(ledPin, LOW); 
    }
    
      Serial.print("I received: ");
      Serial.println(incomingByte, DEC);
  }
  delay(10);
}

Часть кода нам уже знакома - мы используем встроенный светодиод под номером 13.

Сигнал от компьютера поступает в виде байта. Создаём новую переменную incomingByte для этих целей.

Последовательный порт включается командой begin() с указанием скорости.

Если с компьютера поступает сигнал, то функция available() вернёт количество байт, доступное для чтения. Таким образом, мы просто убеждаемся, что какой-то сигнал пришёл (больше нуля).

После первой проверки мы проверяем введённый символ, который может быть представлен и как байт. Если символ равен единице, то включаем светодиод, как мы делали раньше. Если символ равен 0, то выключаем.

Как это выглядит на практике. Заливаем скетч и запускаем Serial Monitor (Ctrl+Shift+M). В окне Serial Monitor наверху есть текстовое поле. Вводим в него числа 1 или 0 и нажимаем кнопку Send. Можно также нажать клавишу Enter для быстрого ввода.

Для общего развития в скетч добавлены также две строчки кода, определяющие код нажатой клавиши. Таким образом вы можете узнать код для клавиш 0 и 1. Вы также можете нажимать и на другие клавиши, они не повлияют на светодиод, но вы увидите коды клавиш.

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


#define ARRAY_SIZE 12 
//global variable definition 
char hello[ARRAY_SIZE] = {
  'h','e','l','l','o',' ','k','i','t','t','y','!'}; 
  
void setup() { 
  Serial.begin(9600); 
} 
void loop() { 
  //print characters from array to serial monitor 
  for(int x = 0; x < ARRAY_SIZE; x++) { 
    Serial.print(hello[x]); 
    delay(250); 
  } 
  Serial.println(); 
  delay(250); 
}

В различных уроках вы будете принимать сигналы от платы Arduino. Это полезно, например, для отладки приложения, когда вы выводите сообщения и по ним ориентируетесь, какая часть программа работает, а какая - нет. Способность общения между Arduino и компьютером очень важна. Вы можете принимать сигналы не только в Arduino IDE, но и в других приложениях на компьютере. Например, в связке с Arduino часто используют приложение Processing, в котором рисуют графики поступаемых сигналов.

Если вы больше не нуждаетесь в получении данных, то закрывайте окно Serial Monitor.

Реклама