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

Продолжаем разбираться с Arduino в рамках «выходного» цикла статей #МастеримДома. Итак, на сегодняшний день у нас имеется устройство на платформе Arduino Uno для измерения концентрации CO2 в помещении и, соответственно, небольшой скетч для преобразования сигнала с датчика MQ135 в эту самую концентрацию. А сегодня мы перейдем непосредственно к теме управления устройством Arduino с помощью программы, написанной в Delphi 10.3 Rio.

Если Вы уже ознакомились со всеми предыдущими статьями (раз, два, три), то вам должно уже быть понятно в чем заключается суть управления Arduino из какой-либо сторонней программы, написанной вообще на любом языке будь то Delphi, Python или любой другой язык. Суть работы будет всегда одна — научиться читать и отправлять данные по средствам COM-порта (RS-232).

Таким образом, сегодня мы сделаем следующее:

  1. Напишем небольшую программку в Delphi, которая будет читать данные с COM-порта и отправлять команды для Arduino
  2. Доработаем наш скетч для того Arduino «умела» принимать и обрабатывать отправленные ей команды.

Работа с COM-портом в Delphi

Конечно, было бы намного интереснее (с точки зрения обучения программированию) написать свои собственные методы работы с COM-портом, расписать то, как работать с этими портами и так далее, но я решил просто воспользоваться уже готовыми решениями для Delphi коих тысячи.

В качестве основных компонентов для работы с COM-портами в Delphi я выбрал библиотеку ComPort Library. Несмотря на то, что эта библиотека не обновлялась довольно давно, версия для Delphi XE вполне спокойно скомплировалась и установилась в Delphi 10.3.

После установки на панели компонентов появится новая вкладка CPortLib, содержащая следующие компоненты для работы с RS-232 в Delphi:

Теперь, прежде, чем приступать к разработке приложения, определимся с алгоритмом работы. Итак, наша программа будет:

  1. Считывать числовые значения из COM-порта. Здесь в качестве числовых значений я подразумеваю, во-первых, значение концентрации в ppm и, во-вторых, калибровочные данные с датчика (R0).
  2. Отсылать Arduino следующие команды:
    1. «1» — начать передачу калибровочных данных
    2. «2» — прекратить передачу всех данных
    3. «любой символ» — начать или возобновить передачу данных о концентрации
Учитывая то, что, используя только COM-порт для работы с Arduino, мы не можем вносить изменения в скетч и, тем более, его перезагружать в Arduino, в перспективе можно будет продумать вариант получения «сырых» данных с Arduino и их обработку в Delphi, что, на мой взгляд, может облегчить работу с датчиком и избавит от ковыряния в исходниках библиотек для Arduino. Но это только в перспективе.

Итак, интерфейс программы будет вот таким:

На форме расположена кнопка для настройки и подключения к COM-порту, список (TComboBox) для выбора одной из трех команд, описанных выше, метки (TLabel) для вывода среднего значения передаваемой величины и количества передач, Memo для вывода всего потока данных и, собственно, сам компонент TComPort для работы с портом.

Код события OnClick для кнопки подключения следующий:

procedure TfrmMain.Button1Click(Sender: TObject);
begin
  ArduinoCom.ShowSetupDialog;//вызываем диалог настройки порта
  ArduinoCom.Open; //пробуем открыть порт
  if ArduinoCom.Connected then
    lbConnect.Caption:='Подключен на '+ArduinoCom.Port
  else
    lbConnect.Caption:='Не подключен';
end;

Сам клик по кнопке вызовет вот такой диалог настройки для компонента (форма диалога входит в библиотеку):
После того, как подключение к порту прошло успешно мы можем считывать данные и проводить необходимые вычисления. Для этого в секции private формы я объявил две переменные:

 private
    aCount: integer;
    aAvg: double;

aCount — количество измерений; aAvg — среднее значение измеряемой величины.
У компонента TComPort пишем вот такой обработчик события OnRxChar:

procedure TfrmMain.ArduinoComRxChar(Sender: TObject; Count: Integer);
var Str: string;
    aNext: double;
begin
  ArduinoCom.ReadStr(Str, Count);//читаем строку от Arduino
  memData.Text:=memData.Text+Str;//записываем строку в Memo
  aNext:=StrToFloat(Trim(str),FS);//полученное числовое значение
  if aCount=0 then //если это первое значение - оно же и будет средним
    aAvg:=aNext
  else //иначе рассчитываем среднее значение
    aAvg:=aAvg*(aCount/(aCount+1))+aNext/(aCount+1);
  inc(aCount);//наращиваем счётчик
  UpdateForm;//обновляем метки на форме
end;

Процедура UpdateForm простая:

procedure TfrmMain.UpdateForm;
begin
  lbAvg.Caption:=FloatToStrF(aAvg, fffixed, 6,2);
  lbCount.Caption:=IntToStr(aCount);
end;

Соответственно, при выборе значения в ComboBox мы должны обнулить все значения, отправить Arduino команду и начать отсчёт заново:

procedure TfrmMain.cbCommandChange(Sender: TObject);
begin
  //отправляем команду Arduino
  case cbCommand.ItemIndex of
    0:ArduinoCom.WriteStr('3');//ppm
    1:ArduinoCom.WriteStr('1');//ro
    2:ArduinoCom.WriteStr('2');//----
  end;
  memData.Text:=EmptyStr;
  aCount:=0;
  aAvg:=0;
  UpdateForm;
end;

А при запуске программы не забыть выставить первоначальные значения всех переменных:

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  aAvg:=0;
  aCount:=0;
  FS.DecimalSeparator:='.';
  UpdateForm;
end;

В принципе, на сегодня это и всё, что нам необходимо, чтобы научиться управлять Arduino из Delphi. Теперь перейдем к скетчу Arduino и научим наше устройство «понимать» отправленные ей команды.

Скетч Arduino

Как я говорил, ещё в первой статье посвященной Arduino и Delphi, необходимо чуть-чуть разобраться с С++. Я не скажу, что представленный ниже скетч — это идеальный код (уверен, что можно всё сделать короче и понятнее), но скетч работает и даёт ожидаемый результат. Итак, код скетча для Arduino следующий:

#include  <MQ135.h>//подключаем библиотеку для работы с MQ135
#define analogPin A0 // аналоговый выход MQ135 подключен к пину A0 Arduino
 
MQ135 gasSensor = MQ135(analogPin);
bool Zero = false; //если True - с датчика читается значение Ro
bool Conc = true; //если True - с датчика читается концентрация
float Value = 0; //значение с датчика
 
void setup() {
  Serial.setTimeout(1000); //настраиваем тай-маут для порта
  Serial.begin(9600); // инициализация последовательного порта
  pinMode(analogPin, INPUT);  // режим работы аналогового пина
  delay(1000); // даём датчику небольшое время на разогрев
}
 
void loop() {
 
 if (Serial.available() &gt; 0) {  //если есть доступные данные
        // считываем строку
        String incomingStr = Serial.readString();
        //пробуем преобразовать строку в число
        int Command = incomingStr.toInt();
        switch (Command) { //выбираем, что передавать в порт и передавать ли вообще
           case 1: Zero = true;
                   Conc = false;
                   break;
           case 2: Zero = false;
                   Conc = false;
                   break;
           default:
                  Zero = false; 
                  Conc = true;
       }
    }
 
if (Zero) 
   Value = gasSensor.getRZero(); // чтение R0 
else if (Conc)
   Value = gasSensor.getPPM(); //чтение концентрации
 
 if (Zero || Conc) //стоит ли что-то передавать
   Serial.println(Value); // выдача в последовательный порт
 
 delay(1000); // задержка перед выводом следующего значения
}

В принципе, по комментариям в коде должна стать понятной логика скетча, а именно:
1. По умолчанию стартуем с чтением концентрации
2. Если в порт пришло что-либо, то пробуем прочитать строку
3. Если строка представляет собой число 1 или 2, то либо передаем R0, либо прерываем какую-либо передачу вообще
4. Если пришла непонятная строка или, как в случае с нашей программой в Delphi — значение 3, то начинаем передавать значение концентрации.

Теперь можно загрузить скетч в Arduino, запустить нашу Delphi-программку и посмотреть на её работу.

Результат

Передача данных о концентрации CO2 в помещении

Аналогичным образом передаются калибровочные данные:

Таким образом, можно констатировать, что управлять Arduino с помощью программ, написанных в Delphi вполне возможно и делается это относительно просто. Более того, если необходимо, то на «плечи» Delphi можно перенести и все необходимые расчёты (всё же на борту Arduino не так уж и много памяти).

5 5 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
1 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
Маша Иванова
Маша Иванова
31/05/2021 21:49

Здравствуйте! Пожалуйста, покажите подробнее этапы работы с библиотекой ComPort Library (а можно с сопроводительными иллюстрациями) вплоть до появления вкладки CPortLib на панели компонентов. Благодарю!