Arduino:Примеры/SendandReceiveArguments

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Перевод: Максим Кузьмин (Cubewriter) Контакты:</br>* Skype: cubewriter</br>* E-mail: cubewriter@gmail.com</br>* Максим Кузьмин на freelance.ru
Проверка/Оформление/Редактирование: Мякишев Е.А.


Получение и отправка команд с аргументами[1]

Этот пример является расширенной версией примера «Получение и отправка команд», то есть демонстрирует, как сделать на PC переключатель светодиода, встроенного в Arduino, а также как отправлять обратно на PC статус, в котором в данный момент находится светодиод, но вдобавок к этому – как отправлять и принимать несколько аргументов в виде значений типа float.

Код

// *** Получение и отправка команд с аргументами ***

// Это расширенная версия примера «Получение и отправка команд». 
// В него добавлено то, что Arduino теперь отправляет и принимает
// несколько float-значений.
//
// Этот скетч демонстрирует, как:
// - возвращать разные статусы (команды подтверждения и ошибки)
// - получать несколько аргументов
// - отправлять несколько аргументов
// - вызывать функцию периодически

#include <CmdMessenger.h>  //  подключаем библиотеку CmdMessenger

// переменные для мигающего светодиода: 
unsigned long previousToggleLed = 0;   // то, когда светодиод был переключен в последний раз
bool ledState                   = 0;   // текущее состояние светодиода
const int kBlinkLed             = 13;  // контакт для встроенного светодиода

// привязываем экземпляр класса CmdMessenger к последовательному порту:
CmdMessenger cmdMessenger = CmdMessenger(Serial);

// Это список распознаваемых команд, и эти команды могут быть 
// либо получены, либо отправлены. Чтобы получить команду, к этому 
// событию нужно привязать функцию внешнего вызова.
enum
{
  // Команды:
  kAcknowledge         , // команда, подтверждающая получение команды
  kError               , // команда, сообщающая об ошибках
  kFloatAddition       , // команда, запрашивающая суммировать два float-значения
  kFloatAdditionResult , // команда, сообщающая о результате суммирования
};

// команды, отсылаемые от PC и получаемые на Arduino; в скетче Arduino 
// нужно задать функцию внешнего вызова для каждой записи из списка ниже:
void attachCommandCallbacks()
{
  // подключаем функции внешнего вызова:
  cmdMessenger.attach(OnUnknownCommand);
  cmdMessenger.attach(kFloatAddition, OnFloatAddition);
}

// ------------------  ФУНКЦИИ ВНЕШНЕГО ВЫЗОВА -----------------------

// эта функция вызывается, когда к присланной команде не привязано никакой функции:
void OnUnknownCommand()
{
  cmdMessenger.sendCmd(kError,"Command without attached callback");  //  "Команда без функции внешнего вызова" 
}

// функция внешнего вызова, сообщающая о готовности Arduino (т.е. о ее загрузке):
void OnArduinoReady()
{
  cmdMessenger.sendCmd(kAcknowledge,"Arduino ready");  //  "Arduino готова"
}

// функция внешнего вызова, рассчитывающая сумму двух присланных float-значений:
void OnFloatAddition()
{
  // извлекаем первый аргумент как float:
  float a = cmdMessenger.readFloatArg();
  
  // извлекаем второй аргумент как float:
  float b = cmdMessenger.readFloatArg();
  
  // отсылаем обратно результат суммирования:
  //cmdMessenger.sendCmd(kFloatAdditionResult,a + b);
  cmdMessenger.sendCmdStart(kFloatAdditionResult);
  cmdMessenger.sendCmdArg(a+b);
  cmdMessenger.sendCmdArg(a-b);
  cmdMessenger.sendCmdEnd();
}

// ------------------ ГЛАВНАЯ ЧАСТЬ СКЕТЧА ----------------------

// блок исходных операций:
void setup() 
{
  // прослушиваем последовательное соединение на предмет сообщений от PC:
  Serial.begin(115200); 

  // добавляем каждой команде символ новой строки:
  cmdMessenger.printLfCr();   

  // подключаем функции внешнего вызова, заданные пользователем:
  attachCommandCallbacks();

  // отсылаем на PC сообщение, что Arduino загрузилась:
  cmdMessenger.sendCmd(kAcknowledge,"Arduino has started!");  //  "Arduino запущена!"

  // режим работы светодиода выставляем на OUTPUT:
  pinMode(kBlinkLed, OUTPUT);
}

// возвращаем «true», если время превысило заданный интервал 
// (в миллисекундах); используется для периодических действий:
bool hasExpired(unsigned long &prevTime, unsigned long interval) {
  if (  millis() - prevTime > interval ) {
    prevTime = millis();
    return true;
  } else     
    return false;
}

// блок повторяющихся операций:
void loop() 
{
  // обрабатываем данные, пришедшие по последовательному соединению,
  // и выполняем функции внешнего вызова:
  cmdMessenger.feedinSerialData();

  // периодически переключаем светодиод; если светодиод
  // не переключается каждые 2000 миллисекунд, это значит, что работа 
  // cmdMessenger требует больше времени: 
  if (hasExpired(previousToggleLed,2000)) // переключаем каждые 2 секунды:
  {
    toggleLed();  
  } 
}

// состояние переключаемого светодиода: 
void toggleLed()
{  
  ledState = !ledState;
  digitalWrite(kBlinkLed, ledState?HIGH:LOW);
}

См.также

Внешние ссылки