FLProg – Самостоятельная интеграция в программу кастомных контроллеров +11




На Хабре достаточно давно не освещался проект FLProg. Это связанно с отсутствием времени на написание статей, да и моими собственными личными проблемами. Но проект не умер, он живёт и развивается. В среднем раз в месяц выходит очередная версия программы. Со времени последней публикации была полностью переделана отрисовка схемы (благодаря этому были устранены фризы при отрисовке), появилась система Cross Reference для проекта, и система анализа проекта на ошибки. Непосредственно сам код программы, был перенесён на более свежую версию языка программирования. Благодаря этому в положительную (с моей точки зрения конечно, ну и пользователи меня поддерживают) сторону изменился интерфейс программы. Добавились многие интересные блоки. Реализовано масштабирование схемы и поиск блоков.

Но все равно основной проблемой проекта остаётся то, что разработчиком программы является один человек (это я), а количество различных плат контроллеров, сенсоров, датчиков, плат расширения выпускаемых как китайскими, так в последнее время и нашими производителями растет постоянно. И пользователям хочется их попробовать, или использовать в своих проектах. Для периферийных устройств, в своё время, эта проблема более менее была решена мной с помощью создания редактора пользовательских блоков. Данный шаг как говорится «стрельнул», и теперь, практически на большинство существующих периферийных плат, в интернете, или на форуме программы, можно найти соответствующий пользовательский блок. Ну, или на том же форуме (или в группе в Контакте) попросить у местных гуру написать такой. Обычно можно, так или иначе, договорится.

Теперь пришла пора решать вторую проблему – это платы контроллеров.

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

Этим постом я начинаю серию как минимум из двух постов, в которых рассмотрим, как пользоваться этим редактором. В первой статье я с разрешения shiotiny попробую описать его плату ShIoTiny. Во второй статье попробуем виртуально придумать аналог настоящего промышленного контроллера, и описать его.

Итак, начнём.

Открываем программу FLProg. В меню «Инструменты» выбираем пункт «Редактор пользовательских описаний контроллеров».



Открывается окно редактора описаний.

Пользовательские описания можно объединять в библиотеке с любой глубиной вложенности. Поэтому сначала создадим библиотеку описаний.



Зададим имя библиотеки.



После чего создадим в библиотеке описание контроллера.



И назначим ему имя:



При создании описания контроллера мы сразу попадаем на ветку общих параметров.



Здесь мы можем изменить имя, задать тип центрального процессора, задать размер EEPROM, изменить номер версии описания.

Поскольку плата ShloTiny сделана на базе контроллера ESP8266 то его и выбираем. При выборе контроллера автоматически проставляется соответствующий ему объём EEPROM. При необходимости это значение можно изменить. Номер версии по умолчанию для нового описания устанавливается 1.

В будущем при изменении существующих описаний, рекомендуется изменять его в сторону увеличения. При использовании данного описания в проекте, программа будет сравнивать версию описания в проекте и в библиотеке. Если номер версии описания в библиотеке больше чем в проекте, в меню «Проект» программы появится пункт для обновления описания в программе. Если наоборот – то появится пункт для обновления описания в библиотеке. Ну а если в библиотеке вообще не будет найдено описания контроллера применяющегося в проекте – в том же меню появится пункт для внесения описания из проекта в библиотеку.

Так же в этой ветке можно написать текстовое описание контроллера, помогающее при его выборе.

Для применения внесённых изменением перед переходом на другую ветку параметров контроллера необходимо нажать кнопку «Применить». Если этого не сделать, изменения не будут сохранены.

Теперь рассмотрим принципиальную схему платы ShloTiny.



У платы имеется три цифровых входа, три цифровых выхода, аналоговый вход, и вход для сенсора. Итого восемь выводов платы.

Переходим в редакторе на ветку «Выводы контроллера» и задаём количество выводов, не забывая после этого нажать кнопку «Применить».



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



На этой ветке, можно прописать альтернативное имя вывода, которое будет выводится в программе. В случае его отсутствия, в программе будет выводится надпись PinN где N номер вывода в списке выводов. Я рекомендую записывать в поле альтернативного имени надпись к нему на плате. Это облегчит понимание, к какому выводу производится обращение. Для описываемой платы занесём туда значение Input1 в соответствие с принципиальной схемой. Так в этой ветке можно прописать индивидуальное описание вывода, например для указания особенностей его применения. При необходимости, так же можно задать псевдоним вывода, который будет выводится в программе в скобках после названия вывода.

После внесения изменений не забываем нажать кнопку «Применить». По такому же принципу поименуем остальные выводы.



В той же ветке основных параметров вывода к нему добавляются выполняемые им функции.



Каждому выводу можно назначить следующие функции.



  • I2C – функция одного из выводов шины I2C (SDA или SCL).
  • SPI – функция одного из выводов шины SPI (MISO, MOSI, SCK, SS).
  • UART – функция одного из выводов интерфейса UART (RX или TX).
  • Функция аналогового входа
  • Функция аналогового выхода (в программе FLProg пока не используется, задел на будущее).
  • Функция цифрового входа/выхода.

Назначим выводу 1 функцию цифрового входа/выхода. При назначении выводу новой функции (ещё не настроенной) в дереве контроллера появится ветка «Ошибки» и весь путь до ветки некорректной функции окрасится красным. На ветке «Ошибки» можно посмотреть список ошибок найденных в описании контроллера.



В данном случае на вводе 1 в функции «Цифровой вход/выход» не задан номер этого ввода как цифрового. Переходим на ветку данной функции (в будущем я планирую сделать прямой переход на нужную ветку при клике на ошибку).



Согласно принципиальной схеме платы вывод «Input1» подключен к пину GPIO2 контроллера. Это значение вводим в поле «Номер цифрового входа». При компиляции проекта это значение будет вставляться в код. Поскольку использование данного ввода в качестве вывода не предусмотрено, то снимаем чекбокс «Может использоваться как выход». Как всегда нажимаем кнопку «Применить». Таким же образом настраиваем остальные два цифровых входа. Затем переходим к выводу аналогового входа «ADC1» и добавляем ему функцию «Аналоговый вход».



В настройках этой функции необходимо указать номер данного вывода как аналогового входа. В соответствии со схемой это 0 (в ESP8266 он один).



Затем переходим к настройке вывода «1WIRE». Здесь добавляем к нему функцию цифрового входа/выхода, но запрещаем его использование как входа, так и как выхода. В результате он будет доступен для выбора только в блоках сенсоров, и не доступен при создании входов, выходов.



Настройка выходов «К1» — «К3» аналогична настройкам входов «Input1» – «Input3» только в случае выходов мы запрещаем им использоваться в качестве входа.





Переходим к ветке «Изображения». В ней мы можем добавить загружаемые в описание контроллера изображения, например с внешним видом контроллера, распиновкой и т.д.

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

Изображение добавляется с помощью кнопки «Добавить изображение».



После выбора и загрузки изображения (поддерживается только формат PNG), для каждого изображения создается отдельная ветка в дереве. В этой ветке можно задать имя для загруженного изображения, которое будет показываться в информации о контроллере.



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





Переходим к ветке «Стандартные блоки».



На этой ветке показаны блоки, которые могут быть представлены в библиотеке стандартных блоков программы в соответствии с текущими настройками программы. Что это значит. Часть стандартных блоков программы предназначены только для определённых видов ЦП. И их наличие зависит от выбранного процессора. Так же блоки, рассчитанные на работу с SPI, I2C, UART появятся в этом списке, только если на выводах контроллера будут добавлены соответствующие функции. Блоки, рассчитанные на работу с EEPROM, появятся, только если размер EEPROM заданный на ветке общих параметров контроллера будет больше нуля, или на выводах контроллера будет добавлена функция I2C. По умолчанию, все блоки в библиотеке запрещены к использованию (отмечены оранжевым цветом). Разрешить к использованию можно как отдельный блок, так и целиком папку блоков, выделив необходимую ветку и нажав кнопку «Разрешить», или из контекстного меню.



При разрешении блока или папки блоков к показу в программе они окрашиваются в черный цвет.

Запрещение к показу блока или отдельной папки производится аналогично.



В папке, в которой разрешены к показу не все блоки, отмечаются тремя звездочками перед именем и после.

Запретим к использованию в программе моторы, часы реального времени, дисплеи, блоки ИК управления, датчики (кроме датчиков DS18B20 и DHT22 –поскольку разработчик платы пока заявил только об их поддержке), микросхемы расширений и пьезо динамик.



То же самое сделаем и для языка LAD



Не забываем после внесения изменений применять их.

Остальные ветки описания контроллера мы рассмотрим в следующем посту, пока текущих настроек достаточно для использования конкретно этой платы в программе FLProg.

Пока только коротко скажу что ветка «Специальные блоки» служит для загрузки в описание пользовательских блоков, которые будут показаны в библиотеке стандартных блоков в программе при использовании данного контроллера. Ветка «Специальный код» служит для записи кода, который всегда будет вставляться в компилируемы код, а ветка «Специальные библиотеки», служит для загрузки в описание контроллера библиотек, которые будут, выгружается в папку \libraries ArduinoIDE, с которой работает программа.

После всех изменений, сохраняем библиотеку описаний контроллера.



Теперь попробуем использовать созданное нами описание контроллера.
В программе FLProg создаем новый проект для контроллера.



Открываем окно выбора контроллера.



И выбираем созданное нами описание.



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





Так же можно посмотреть и остальные параметры



После выбора контроллера подтверждаем его выбор:



В результате откроется основное рабочее окно проекта, настроенное в соответствии с выбранным контроллером.



В цели данного поста не входит задача обучения работы с программой FLProg. Это достаточно хорошо описано в моих предыдущих постах, на сайте проекта, и на форуме проекта. Кроме того сейчас на ютубе уже достаточно много каналов, где выложены видео уроки по работе с программой. Например, очень хороший канал «Ключь к Ардуино», как раз сейчас ведёт серию уроков, с очень хорошей подачей материала.

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



Для выбора в качестве входа доступны только те выводы, которым мы разрешили работать в этом качестве.



Затем создаем цифровой выход. Здесь так же доступны только разрешённые выводы.



Собираем схему что бы при нажатии кнопки на Input1 (Вход 1) включалось реле К1 (Реле1).
Так же вытаскиваем на схему в отдельную плату блок для чтения информации с датчика DS18B20.



Заходим в настройки блока. При создании новой шины OneWire мы видим, что для выбора доступны все цифровые входы/выходы. Это недоработка в версии 6.0. Но поскольку, эта версия всё таки имеет статус бэта, то это простительно. В версии 6.1 будет дана возможность запрета использования пина в качества датчика, сенсора или для микросхем расширения. Кроме того в следующем посту я расскажу другой способ решения этой проблемы. Пока выбираем вывод 1WIRE.



Настраиваем датчик для задания адреса через массив.



Вставляем новую плату перед первой, и вытаскиваем на неё блок «Сканирование шины OneWire».



Настраиваем его на ту же шину OneWire, и на тот же массив, на которые настроен блок чтения с датчика DS18B20.



Собираем схему однократного запуска сканирования шины при запуске контроллера, используя блок R триггера (выделение переднего фронта).



На плате с блоком чтения данных с датчика DS18B20 собираем схему включения/отключения реле с гистерезисом. Для этого используем два компаратора, и SR триггер. Благодаря этой схеме, реле 2 будет включатся при понижении температуры ниже 10 градусов, и выключаться при повышении температуры выше 20 градусов.



Запускаем схему на компилирование.



В результате полученный код откроется в Arduino IDE. В качестве платы, выбираем NodeMCU, на которой установлен тот же чип, что и на ShloTiny. Проверка кода показывает, что он корректен, и его можно загружать.



Код, полученный в результате компиляции
#include <OneWire.h>
extern "C" {
#include "user_interface.h";
}
OneWire  _ow13(13);
byte _FLPArray133289689[9];
unsigned long _d18x2x1Tti = 0UL;
float _d18x2x1O = 0.00;
bool _trgr1 = 0;
bool _bounseInputD2S = 0;
bool _bounseInputD2O = 0;
unsigned long _bounseInputD2P = 0UL;
bool _trgrt1 = 0;
bool _trgrt1I = 0;
bool _sowb1_needScan = 0;
bool _sowb1_ost = 0;
bool _sowb1_Out_1 = 0;

void setup()
{

  pinMode(2, INPUT);
  pinMode(12, OUTPUT);
  pinMode(14, OUTPUT);

  _bounseInputD2O =  digitalRead(2);

}
void loop()
{


  bool  _bounceInputTmpD2 =  (digitalRead (2));

  if (_bounseInputD2S)
  {
    if (millis() >= (_bounseInputD2P + 40))
    {
      _bounseInputD2O = _bounceInputTmpD2;
      _bounseInputD2S = 0;
    }
  }
  else
  {
    if (_bounceInputTmpD2 != _bounseInputD2O )
    {
      _bounseInputD2S = 1;
      _bounseInputD2P = millis();
    }
  }




  //Плата:1
  if (1) {
    if (_trgrt1I) {
      _trgrt1 = 0;
    } else {
      _trgrt1 = 1;
      _trgrt1I = 1;
    }
  } else {
    _trgrt1 = 0;
    _trgrt1I = 0;
  };
  if (_sowb1_needScan) {
    if ( _oneWireSeach (_FLPArray133289689, _ow13)) {
      _sowb1_Out_1 = 1;
    }
    _ow13.reset_search();
    _sowb1_needScan = 0;
  }
  if (_trgrt1) {
    if (! _sowb1_ost) {
      _sowb1_ost = 1;
      _sowb1_needScan = 1;
      _sowb1_Out_1 = 0;
    }
  } else {
    _sowb1_ost = 0;
  }

  //Плата:2
  digitalWrite(12, !(_bounseInputD2O));

  //Плата:3
  if (_isTimer(_d18x2x1Tti, 1000)) {
    _d18x2x1Tti = millis();
    _d18x2x1O =  _readDS18_ow13(_FLPArray133289689, _FLPArray133289689[8]);
  }
  if (((_d18x2x1O)) > (20)) _trgr1 = 0;
  if (((_d18x2x1O)) < (10)) _trgr1 = 1;
  digitalWrite(14, _trgr1);






}

bool _isTimer(unsigned long startTime, unsigned long period )
{
  unsigned long currentTime;
  currentTime = millis();
  if (currentTime >= startTime) {
    return (currentTime >= (startTime + period));
  } else {
    return (currentTime >= (4294967295 - startTime + period));
  }
}
float _convertDS18x2xData(byte type_s, byte data[12])
{
  int16_t raw = (data[1] << 8) | data[0];
  if (type_s)
  {
    raw = raw << 3;
    if (data[7] == 0x10) {
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  }
  else
  {
    byte cfg = (data[4] & 0x60);
    if (cfg == 0x00) raw = raw & ~7;   else if (cfg == 0x20) raw = raw & ~3;  else if (cfg == 0x40) raw = raw & ~1;
  }
  return  (float)raw / 16.0;
}
float _readDS18_ow13(byte addr[8], byte type_s)
{ byte data[12];
  byte i;
  _ow13.reset();
  _ow13.select(addr);
  _ow13.write(0xBE);
  for ( i = 0; i < 9; i++) {
    data[i] = _ow13.read();
  }
  _ow13.reset();
  _ow13.select(addr);
  _ow13.write(0x44, 1);
  return _convertDS18x2xData(type_s, data);
}
bool _oneWireSeach (byte array[], OneWire ow )
{
  byte temp[8];
  byte i;
  if ( !ow.search(temp)) {
    return false;
  }
  if (OneWire::crc8(temp, 7) != temp[7]) {
    return false;
  }

  switch (temp[0]) {
    case 0x10:
      array[8] = 1;
      break;
    case 0x28:
      array[8] = 0;
      break;
    case 0x22:
      array[8] = 0;
      break;
    default:
      return false;
  }

  for ( i = 0; i < 8; i++) {
    array[i] = temp[i];
  }
  return true;
}


> Описание контроллера ShloTiny для программы FLProg

На этом, данный урок закончим, в следующем посту попробуем описать что-то более серьёзное и приближенное к «настоящим» промышленным контроллерам.

Вы можете помочь и перевести немного средств на развитие сайта



Комментарии (18):

  1. Shtucer
    /#20610675

    Теперь рассмотрим принципиальную схему платы ShloTiny.

    Давайте. Как на схеме включить свет?

    • totuin
      /#20610723

      Ну не знаю, я всё прекрасно разглядел (в отдельном окне конечно). Хотя может это сказывается мой многолетний опыт рисования принципиальных схем в автокаде, и такой фон мне привычен))))

      • FDA
        /#20612447

        Много лет работал в P-CAD. Сейчас в DipTrace. Везде чёрный фон. Для глаз самое то! Но вот коллега на работе использует белый фон, а при разводке чёрные проводники. Ему так очень нравится

        • totuin
          /#20613093

          Я пробовал белый фон. Глазу сильнее устают. Поэтому я сделал в программе возможность изменять цветовые темы. Судя по скриншотам пользователей популярностью пользуются оттенки серого или черный в качестве фона.

  2. shiotiny
    /#20610703

    К сожалению, не могу поставить плюс, но статья понравилась.

    Теперь у моего контроллера аж две среды визуального программирования — встроенная и FLPROG. Обалдеть:)

    Давайте. Как на схеме включить свет?


    Открыть её в отдельном окне. О небольших ошибках я в курсе.

  3. roboter
    /#20611477

    основной проблемой проекта остаётся то, что разработчиком программы является один человек (это я)

    А ссылкой на GitHub или другой репозиторий не поделитесь?

    • totuin
      /#20611581

      Нет не поделюсь, поскольку её не существует. Программа FLProg — это не комерческая свободно распостраняемая программа. Но не Open Software. Возможно это мой личный таракан (большой и жирный), но я негативно отношусь к Open Software. С моей точки зрения над нормальным проектом должна работать «спитая» команда, с одинаковыми виденьем результата, и одинаковым подходом к программированию. Когда куча народу, совершенно незнакомых друг с другом, со своим виденьем что и как должно быть, со своими патернами, пытается собрать что то единое, получается такая каша, которую практически нереально расхебать. Но ещё раз повторюсь — это лично моё мнение, которое не претендует на истину в последней инстанции.
      Ну и есть ещё одна причина по которой просто не имеет смысла выкладывать исходники — это язык програмирования. Программа написана на языке SmallTalk, а смолтолкеров в России единицы. Так что просто некому будет писать реквесты.

      • roboter
        /#20612125

        Если у программы есть основной владелец, то он вправе решать стили и подходы и никто не сможет без вашего мнения/одобрения что то менять. Так и сложится команда.
        С открытыми исходниками если автор программы забъёт на её развитие хотя бы формат файла посмотреть можно будет, даже если это на SmallTalk.

        • totuin
          /#20613071

          Оно конечно так, но на все эти просмотры кода, одобрение/неодобрения надо тратить достаточно большое количество времени. И вообще это административная по большому счету работа, которую я просто ненавижу. И просто не умею её делать. Форум, группу я отдал в управление тем людям, у которых это получается намного лучше, и ни грамма об этом не жалею. Для меня намного интереснее заниматься непосредственно разработкой программы. Естественно, если что то случится в моей жизни, что я не смогу дальше заниматься программой, я передам доступ к своему хранилищу кода в руки доверенным лицам, и они уже будут решать дальнейшую судьбу программы. Но на ближайшие несколько лет дорожная карта развития программы у меня уже есть. Так что пока есть силы и возможности — программа будет развиваться.

  4. shiotiny
    /#20611643

    Но не Open Software.


    Наверное, вы хотели сказать «не Open Source»?

    То есть сама то программа у вас свободно доступна. Но исходников открытых нет. Так?

    • totuin
      /#20611663

      Наверное, вы хотели сказать «не Open Source»?

      Да именно это я хотел сказать. Что то голова к вечеру болит))). И Вы правы — программа свободно доступна, но исходников открытых нет, и не будет, пока я занимаюсь её разработкой.

      • alex-open-plc
        /#20613047

        Каким образом вы гарантируете отсутствие «тараканов» и черных ходов в программе?

        • totuin
          /#20613075

          А я не гарантирую. Зачем? Программа не лезет в сеть, если не ставить галочку «Отправлять отчет об ошибке на сервер». По умолчанию она не стоит. Всё легко проверяется с помощью специальных программ. Портативная версия не лезет никуда, что опять таки проверяется самой виндой (если что — она верещит). Да и создана портативная версия, которая в принципе ничем не отличается от устанавливаемой через инсталятор была так что бы ее можно было запускать даже на залоченных политиками компах. У меня у самого такой рабочий комп. Она не лезет ни в системные файлы, ни в реестр. Какие бэкдоры? За семь лет существования проекта пока никто не обнаружил ничего что подпортило бы репутацию FLProg как честной программы. А вот теперь скажите — винда которой Вы наверное пользуетесь даёт вам исходники? И сколько раз она была замечена в шпионстве? Но большинство людей всё равно ею пользуются…

  5. seri0shka
    /#20623249

    Самостоятельная интеграция в программу кастомных контроллеров
    Давно хотел такую возможность в FLProg. Для себя внедрил с помощью тех же пользовательских блоков. Вот так выглядит один и тот же проект для двух разных контроллеров (под контроллерами подразумевается микроконтроллер в комплекте с микросхемами расширения, схемами входов и выходов, по сути ПЛК или программируемое реле с суммарным количеством входов и выходов от 50 штук)
    скрины
    imageimage

    • totuin
      /#20623261

      В описании контроллера есть ветки «Специальный код», и «Специальные блоки». В первой можно прописать код, который всегда будет вставляться в скетч, а во второй ветке загрузить пользовательские блоки которые появятся в стандартной библиотеке. Думаю Вам это будет интересно. Подробнее о них я напишу в следующем посте.

    • totuin
      /#20623267

      Ещё одна фича от применения пользовательских блоков- с их помощью можно лёгким движением руки перейти с ненавистного многим Виринга на настоящий Си.

      Я уже над этим думаю, и есть идеи. Скорее всего будет прямая запись в регистры (если они прописанны в свойствах вывода). Но это немного попозже

      • seri0shka
        /#20623283

        будет прямая запись в регистры
        Главное, чтобы не «вместо», а «в дополнение».

        • totuin
          /#20623289

          Главное, чтобы не «вместо», а «в дополнение».


          Это конечно. Скорее всего, если прописанны адреса регистров для выводов, в меню «Проект» будет появлятся чекбокс что ни будь вроде «При компиляции использовать запись в регистры». Ещё до конца не продумал)))) И эта опция будет привязыватся к конкретному проекту.