Пошаговая инструкция создания первого проекта с нуля до работоспособного скрипта

При первом запуске только что установленной программы будет отображено следующее окно:

Первый шаг - создание нового проекта (будем создавать скрипт для контроллера Motorola MC68HC11E9). Для этого кликнуть мышкой на кнопку Create new project или выбрать в главном меню Project -> Create new project. Откроется окно создания проекта.

Имя проекта - нужно ввести имя проекта. В имени проекта нельзя использовать пробелы и запрещенные в именах файлов символы: < > : " / \ | ? *.

Расположение - можно выбрать папку на диске, где будут располагаться проекты. По умолчанию программа предлагает папку "Projects" в папке, откуда была запущена среда. Что бы изменить папку, нужно нажать кнопку справа от поля "Location".

Создать папку для проекта - позволяет создать подпапку для проекта. Имя этой папки будет как имя проекта.

Создать "Motorola.e" и включить в проект - создается главный исходный файл проекта и включается в проект.

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

Создать копию выходного файла... - сделано для удобства. При создании скрипта программа располагает его файл в папке скрипта. Если же указать дополнительный путь, то программа будет создавать копию файла скрипта по этому пути (если активировать переключатель "Зашифровать эту копию", то создаваемая копия будет зашифрована).

После нажатия кнопки "OK" увидите окно программы.

Слева отображается дерево проекта. В нем будут отображаться все исходные файлы, включенные в проект. Сейчас в проекте один файл "Motorola.e". В остальной части окна отображается содержимое этого файла. Это содержимое сгенерила программа автоматически, потому что был актвироватн переключатель Create default "Motorola.e" and include to project при создании проекта. Программа запоминает последний открытый проект. Если сейчас закрыть и открыть программу, то при запуске этот проект уже будет открыт в программе.

Слева, вверху дерева проектов есть красная кнопка с белым крестиком. Эта кнопка закрывает текущий проект (не программу). Кликнем на эту кнопку (то же самое можно сделать через главное меню Project - Close project). Программа переспросит, действительно ли мы хотим закрыть проект.

Отвечаем "Yes". Видим окно программы без открытого проекта.

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

На панели инструментов программы есть кнопка Compile. Нажмем ее (или можно просто нажать F7 на клавиатуре). Получаем какую-то ошибку '[Error] User interface file not found' внизу, с красной иконкой:

Ошибка сообщает нам что не найден файл какого-то интерфейса пользователя. Дело в том, что скрипт в программаторе сам по себе работать не начнет. Его необходимо запустить, выбрав пункт меню в программе или нажав кнопку на панели инструментов или кнопку в скрипте. Пока что ничего этого в нашем скрипте нет, об этом и сообщает эта ошибка. Для создания интерфейса пользователя нажимаем F12 на клавиатуре (или выбираем в меню View - User interface).Видим следующее:

Появилась закладка редактора интерфейса пользователя. Все разделы (Window, Menu, Editors) пустые. Для активации раздела необходимо установить переключатель Use window (или Use menu, Use editors) вверху вкладки. Активируем Use window. Отображается редактор интерфейса скрипта:

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

Выберем на панели компонентов кнопку - кликнем на ней мышкой.

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

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

В левой части редактора отобразится список свойств кнопки. Если кликнуть мышкой на надпись Button1 в списке свойств, то включиться редактирование надписи на кнопке. Введите надпись "Пуск" и нажмите кнопку Enter на клавиатуре. Надпись на кнопке измениться на "Пуск".

Мышкой сократим размер панели, такая большая пока не нужна.

Посмотрим опять в список свойств кнопки. Найдем там строку OnClick и нажмем на пустую область справа от нее. Отобразится выпадающий список со строкой main внизу. Выберем эту строку.

Сохраним результаты редактирования - нажмем Ctr+S или выберем в главном меню File - Save.

Вернемся в закладку с текстом исходного файла и допишем в файл строку, как ниже:

Нажимаем F7 на клавиатуре. Смотрим сообщения об ошибках - их нет.

Можно попробовать запустить скрипт. Выбираем кнопку Load на панели инструментов или нажимаем F8 на клавиатуре. Не работает. Подключаем программатор. Нажимаем F8. Вроде ничего не изменилось. Смотрим в левый нижний угол программы - видим информацию о программаторе.

Теперь выбираем в главном меню пункт View - Script window

Отображается небольшое окно с заголовком Debug.

Берем его мышкой за заголовок и тянем к правому (или левому) краю главного окна программы. Когда появится голубой прямоугольник вдоль правой границы окна, отпускаем кнопку мыши и окно Debug пристыкуется к правой части окна программы. Должно получится примерно так

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

Теперь кликнем на кнопку Пуск в правой части окна. В нижнем правом окне должна появится надпись "Привет, программист".

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

Должно получится так:

Теперь немного разберемся, что написано в скрипте.

/**
* Original filename: "ColorTest.e"
* Created: 22.11.2017
* Author: Алекс
*/

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

void main(int id);

Это внешнее объявление функции main, что бы она отображалась в выпадающем списке в редакторе интерфейса пользователя. Если не сделать такое объявление, то в выпадающем списке не будет строки main, свойству OnClick кнопки "Пуск" не будет ничего назначено и кнопка не будет ничего запускать.

private

Эта директива означает завершение интерфейсной секции файла.

void main(int id)
{
    print("Привет, программист");
}

Это непосредственно выполняемый код скрипта. Функция print служит для вывода текста в окно сообщений программы.

Кода нажимается кнопка "Пуск" в окне скрипта, виртуальная машина выполняет код функции, имя которой было указано в свойстве OnClick кнопки в редакторе интерфейса.

Сейчас сделаем небольшую светодиодную мигалку.Будем мигать светодиодами питания программатора. Мигание оформим в цикле. Оператор цикла в скриптах называется for. Изменим код внутри нашей функции main следующим образом (можно прямо отсюда взять и скопировать в редактор)

void main(int id)
{
    print("Привет, программист");
    int i;
    for(i = 0; i < 10; i++)
    {
       print("\ni = "+i);
       POWER.VCC_5V;
       DelayMilli(500);
       POWER.Off;
       DelayMilli(500);
    }
    print("\nМигалка отработала.");
}

При наборе текста POWER и нажатии точки редактор будет предлагать выпадающий список автодополнения с возможными вариантами управления питанием (подробно о POWER здесь):

Можно клавишами курсора выбрать нужный вариант и нажать Enter. Выбранный вариант подставится в текущую позицию курсора. Так же можно вызывать список автодополнения нажатием клавиш Ctrl+пробел на клавиатуре. Например если набрать текст Del и затем нажать Ctrl+пробел, то редактор предложит возможные варианты автодополнения:

Про DelayMilli и DelayMicro.

Компилируем, запускаем. Видим, что красный светодиод на программаторе мигает 10 раз в течение 10 секунд. При каждом мигании в окно сообщений выводится строка i = 0, i = 1, i = 2 ... i = 9. После завершения работы окно сообщений будет иметь вид

i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
Мигалка отработала.

Учебный скрипт заработал.

Продолжим делать скрипт для проца MC68HC11. У этого процессора память можно разделить на две области - EEPROM и остальная память, назовем ее RO М. Вообще вся память у этого процессора в одном адресном пространстве, но мы условно отделим EEPROM, потому что в основном его надо читать/писать, сохранять.

Для отображения какого-нибудь содержимого файла нужно активировать редакторы. Нажимаем F12, что бы отобразился редактор интерфейса пользователя. Выбираем закладку "Editors" и активируем переключатель "Use editor".

Отображается состояние редакторов по умолчанию.

В редакторе "Memory size"вводим значение 512 и нажимаем Enter. Видим, что размер редактора стал 512 байт. Это будет редактор для содержимого EEPROM контроллера. Поэтому в редакторе "Tab caption" вводим EEPROM и нажимаем Enter. Заголовок закладки нашего редактора стал EEPROM.

Сейчас можно собрать скрипт (нажимаем F7 на клавиатуре) и загрузить в программатор (нажимаем F8). Программатор должен быть подключен для этого. И в правой части программы, там где отображается вид скрипта, должно появится отображение редактора с теми параметрами, что мы только что указали.

Возвращаемся в редактор. Видим выделенную область "Additional tab" и переключатель "Enabled " ниже его. Активируем его. Видим, что в редактор добавиласть вкладка и два строчных редактора "Memory size" и "Tab caption"стали активны. В редакторе "Memory size" вводим 12288 и нажимаем Enter, заголовок в Tab caption пишем ROM. Должно получится так:

Нажимаем F7 и F8 (или Compile и затем Load на панели инструментов) и проверяем, что в панели скрипта редакторы выглядят так же.

Теперь выключим переключатель "Use editor", нажимаем F7 и F8 и видим, что отображение редакторов в панели скрипта пропало, осталась только кнопка "Пуск".

Активируем переключатель "Use editor", нажимаем F7 и F8 и видим, что отображение редакторов в панели скрипта вернулось.

Теперь нам надо создать меню для нашего скрипта и активировать кнопки на панели инструментов. Для работы с процессором понадобятся следующие операции: Чтение, запись, проверка и инициализация. Инициализация нужна конкретно для этого процессора, для других типов процессоров может быть по другому.

Выбираем вкладку "Menu" в редакторе интерфейса. И активируем переключатель "Use menu". Здесь у нас будет схематично отображаться меню для скрипта. Будем его настраивать.

Нажимаем кнопку "Add item", видим что в таблице добавилась строка. Нажимаем F7, F8, смотрим в панель скрипта. Видим надпись "Device" вверху панели. Кликаем на нее мышкой и видим выпавшее меню с одной стокой "New item". Вот это то меню, которое мы только что создали.

Возвращаемся в редактор, кликаем мышкой в ячейку с надписью New item в столбце Caption. Ячейка переходит в режим редактирования, пишем там текст Инициализация и нажимаем Enter. Текст в ячейке меняется на "Инициализация". Нажимаем F7, F8, проверяем меню в панели скрипта, видим, что текст стал Инициализация.

Нажимаем кнопку "Add item". В таблицу меню добавляется еще строка. Заменяем в ней текст New item на знак минуса. Нажимаем F7, F8, проверяем меню в панели скрипта, видим, что внизу меню добавился разделитель.

Если текстом в ячейке в столбце Caption будет знак минуса, то в реальном меню в этом пункте будет отображаться разделитель.

Нажимая кнопку "Add item" и редактируя текст пунктов меню, заполняем таблицу как на картинке, собираем скрипт (F7), грузим в программатор (F8) и проверяем, что меню в панели скрипта отображается как надо.

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

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

Теперь нужно назначить кнопки на панели инструментов пунктам меню. Если дважды кликнуть мышкой в столбец "Toolbar button", там отобразится выпадающий список с кодами кнопок на панели инструментов.

Коды кнопок:

Назначим коды кнопок так:

Нажимаем F7 и F8. В панели скрипта некоторые кнопки стали активными. Если навести на них курсор мыши, то будет появляться подсказка с текстом соответствующего пункта меню. В панели скрипта эти кнопки можно нажимать и можно выбирать пункты меню. При выборе меню или нажатии на кнопку в окне сообщений будет выскакивать надпись No proc. Это происходит потому, что кнопкам и меню не назначены никакие функции. В таблице редактирования меню в столбце OnClick выбираем все ячейки и выбираем там строку c "main":

После этого нажимаем F7 и F8, нажимаем все кнопки на панели скрипта или выбираем любой пункт в меню скрипта - всегда в окне сообщений скрипта будет добавляться строка "Привет, программист!". Это в нормальном скрипте обычно не нужно, здесь мы сделали это для демонстрации, что одна и та же функция может вызываться разными методами.

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

Объявим некоторые полезные константы. После строки private допишем:

private


const
   EEPROM_BEGIN = 0xB600,
   EEPROM_SIZE  = 512,
   ROM_BEGIN    = 0xD000,
   ROM_SIZE     = 12288;

Так мы числовым значениям присваиваем символьные имена. Это облегчает их запоминание, возможное нахождение их в тексте скрипта, и автоподстановка будет их предлагать в своем списке, если набрать первые пару символов названия и нажать Ctrl+пробел. И если вдруг понадобится поменять значение, нужно будет поменять его только в этом объявлении, а не пересматривать весь текст скрипта.

   EEPROM_BEGIN = 0xB600,
   EEPROM_SIZE  = 512,

Это адрес начала области EEPROM (EEPROM_BEGIN) и ее размер (EEPROM_SIZE) в контроллере 68HС11E9.

   ROM_BEGIN    = 0xD000,
   ROM_SIZE     = 12288;

Это адрес начала области ROM (ROM_BEGIN) и ее размер (ROM_SIZE) в контроллере 68HС11E9.

Немного теории, как работает программирование у контроллеров моторола серии 68HC11. Если после сброса у процессора определенные выводы подключены к земле, то запускается внутренний загрузчик. Этот загрузчик принимает через последовательный порт 256 байт и сохраняет их в ОЗУ процессора. Эти 256 байт являются исполняемым кодом для процессора. Можно подставить любой свой код и после загрузки в контроллер он запустится на выполнение. Обычно этот код ждет команд и данных через последовательный порт, и выполняет эти команды - пишет EEPROM или читает и передает через тот же порт наружу.

Значит в скрипт нам нужно подставить код загрузчика. Это просто массив байт. Допишем его в текст скрипта после объявления констант (лучше просто скопировать отсюда):

uchar Boot[]= { 0xCE,0x10,0x00,0x6F,0x2C,0x86,0x30,0xA7,0x2B,0x86,0x0C,0xA7,0x2D,0x6F,0x35,0x86, 0x07,0x8D,0x41,0x4A,0x26,0xFB,0x86,0xA5,0xA7,0x2F,0x1F,0x2E,0x20,0xFC,0xA6,0x2F, 0x81,0x52,0x27,0x4C,0x81,0x57,0x27,0x02,0x20,0xF0,0x8D,0x4A,0x1F,0x2E,0x20,0xFC, 0xA6,0x2F,0xC6,0x16,0xE7,0x3B,0x18,0xE7,0x00,0xC6,0x17,0xE7,0x3B,0x8D,0x15,0x6F, 0x3B,0xC6,0x02,0xE7,0x3B,0x18,0xA7,0x00,0xC6,0x03,0xE7,0x3B,0x8D,0x06,0x6F,0x3B, 0x8D,0x14,0x20,0xC6,0x36,0xEC,0x0E,0xC3,0x9C,0x40,0xED,0x1C,0x86,0x10,0xA7,0x23, 0x1F,0x23,0x10,0xFC,0x32,0x39,0x1F,0x2E,0x80,0xFC,0x18,0xA6,0x00,0xA7,0x2F,0x39, 0x8D,0x04,0x8D,0xF2,0x20,0xA4,0x1F,0x2E,0x20,0xFC,0xA6,0x2F,0x1F,0x2E,0x20,0xFC, 0xE6,0x2F,0x18,0x8F,0x39,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };

Возвращаем содержимое функции main к первоначальному варианту.

void main(int id)
{
    print("Привет, программист");
}

Теперь можно нажать F7 и скомпилировать скрипт. Сообщений об ошибках быть не должно, должно быть два предупреждения.

Для облегчения навигации по ошибкам и предупреждениям можно активировать переключатель "Show hints in editor", тогда по клику мышкой на строку с предупреждением или ошибкой курсор в исходом тексте установиться на место ошибки и будет отображаться всплывающая подсказка с текстом предупреждения или ошибки.

"[Warning] Motorola.e(37,17): Variable 'id' declared, but never used" - сообщает о том, что переменная с именем id объявлена в процедуре, но в коде процедуры нигде не используется. Теоретически можно убрать объявление этой переменной, но именно для этой функции main делать это нельзя, потому что эта функция вызывается из интерфейса пользователя, и в этой переменной id будет передан идентификатор кнопки или пункта меню, который вызвал эту функцию. Далее мы будем использовать эту переменную в тексте и это предупреждение исчезнет.

[Warning] Motorola.e(17,11): Variable 'Boot' declared, but never used - то же самое, только про только что записанный массив Boot. Мы его объявили, но пока в тексте скрипта к нему обращения нет. Потом мы допишем код, и это предупреждение исчезнет.

Нам понадобится управлять выводом Reset контроллера. Вообще вот такая схема подключения к контроллеру используется:

Схема приведена для внутрисхемного подключения. Предполагается, что кварц уже подключен к контроллеру. Здесь он не нарисован.

Ввод RESET контроллера подключен к выводу 1 разъема программатора. Для удобства присвоим выводу 1 символическое имя, что бы легче было писать код. Имя пину присваивается так:

pin RESET = PIN1;

pin -означает, что далее будет присвоение имени пину. RESET - это имя которое вы хотите присвоить, может быть любым идентификатором. Дальше знак равенства и PIN1 - предопределенное имя пина (зарезервированное слово), завершается присвоение точкой с запятой.

Допишем

pin RESET = PIN1;

перед процедурой main.

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

Для выбора частоты кварца переходим в редактор интерфейса (нажимаем F12). Мышкой расширяем панель компонентов скрипта. Мышкой перетаскиваем кнопку пуск ближе к правой границе панели. Мышкой нажимаем на кнопку с изображением цифр 123 в рамочке (при наведении на него появляется подсказка Digit editor).

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

Заходим в редактор свойств и исправляем название только что созданного редактора на Частота кварца, а значение Value на 4000. Сделанные изменения должны тут же отобразится в нашем редакторе. Если название редактора уехало за границы панели, то мышкой поправляем его положение, что бы все было видно. Также заменим имя Digit1 на Crystal, то бы было понятнее в тексте, что это за значение.

Теперь можно попробовать как работает наш числовой редактор. Обязательно сохраним изменения в визуальном редакторе (нажмем Ctrl+S), это нужно для правильной работы автодополнения текста и перейдем в редактор текста. В тело функции main запишем:

void main(int id)
{
    print("\nЧастота кварца: "+ Crystal.Value);
}

При наборе текста можно использовать автодополнение, например если набрать текст pr и нажать Ctr+пробел, то автодополнение предложит возможные варианты, которые начинаются с "pr":

Клавишами курсора можно выбрать строку с "print" и нажать Enter. Слово print подставится в текст вместо pr.

Если вызвать автодополнение (Ctr+пробел) после набора Di, то Di сразу дополнится до Digit1, потому что это единственное слово в проекте, начинающееся на Di.

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

Собираем скрипт по F7 (ошибок быть не должно), загружаем по F8. Теперь нажимаем на кнопку Пуск в скрипте. В окне сообщений видим:

Частота кварца: 4000

Изменяем значение 4000 на другое в редакторе "Частота кварца", нажимаем Пуск - и в окне сообщений должно отображаться

Частата кваца: и новое значение.

Мы сделали возможность ввода пользователем частоты кварца контроллера. Частота указывается в килогерцах, поэтому лучше зайти в визуальный редактор (F12), выбрать редактор Частота кварца и подкорректировать ему название на Частота кварца (кГц).

В скрипте у нас будет процедура начальной инициализации контроллера, назовем ее Init. Запишем ее в скрипт перед функцией main:

pin RESET = PIN1;

int Init(void)
{
}

void main(int id)
{

    print("\nЧастота кварца: " + Crystal.Value);
}

Заодно можно проверить работу автоподстановки. Если набрать текст int Init(void) и нажать Enter, то редактор сам подставит две фигурные скобки снизу и установит курсор между ними.

В процедуре Init нам надо:

Про управление питанием мы уже знаем.

POWER.VCC_5V;

После включения питания сделаем задержку, что бы оно успело стабилизироваться. Например, если контроллер установлен на какой-то плате, где по питанию стоят большие электролиты, то их начальная зарядка потребует времени. Сделаем задержку 0.1 секунды = 100 миллисекунд.

DelayMill(100);

Про DelayMilli.

После подачи питания нужно на вывод RESET контроллера подать импульс "0". Это делается просто.

RESET = 0;
RESET = 1;

RESET - это имя которое мы присвоили выводу 1 программатора. Если выводу присваивается любое ненулевое значение (1, 10, 5000), то на этом выводе программатора установится уровень логической "1", если присвоить ноль - то уровень "0".

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

RESET = 0; DelayMilli(50);
RESET = 1; DelayMilli(50);

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

UART.Open(скорость, параметры);

Скорость - скорость порта, параметры - параметры работы порта (количество бит, паритет, количество стоп-бит).

Скорость в нашем случае вычисляется так: Частота кварца в килогерцах * 0.16

Так как скрипты не поддерживают числа с плавающей запятой, заменим вычисление на целочисленное: Частота кварца в килогерцах * 1000 / 6250 (1000/6250 = 0.16)

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

uses UARTConstants;

Теперь после строки RESET=1 Записываем UART, ставим точку, выпадает список автодополнения

Выбираем Open(), нажимаем Enter. В скобках после Open дописываем:

UART.Open(Crystal.Value * 1000/6250);

Ставим запятую, затем пишем UA и нажимаем Ctrl+пробел, и из списка автодополнения выбираем UART_8N1

После закрывающей скобки ставим точку с запятой. Должно получится

UART.Open(Crystal.Value * 1000/6250,UART_8N1);

Crystal - это имя визуального редактора, где пользователь вводит частоту кварца контроллера. Value - числовое значение этого редактора.

Теперь устанавливаем тайм-аут чтения UART:

UART.Timeout = 50;

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

PBAR_POS = 0;
PBAR_MAX = 255;

Загрузчик имеер размер 256 байт, максимальное значение индикатора прогресса 255. Индикатор прогресса мы будем устанавливать по текущему индексу байта загрузчика, а он может быть 0...255. Если сделать размер индикатора 256, то в конце он не дорисуется до конца и индикатор процентов будет 99, а не 100.

Дальше следует цикл передачи байт загрузчика. Сначала передается байт 255, затем сам загрузчик. Контроллер выдает обратно каждый принятый байт, и по этой обратной передаче можно определить, работает контроллер или нет.

int a;
for(a = 0; a < 256;a++)
{
    UART.Write(Boot[a]);
    if(UART.ReadByte != Boot[a])
    {
        POWER.Off;
        print("Ошибка.\nНет эха от контроллера.");
        return 0;
    }
    PBAR_POS = a;
}

int a - объявление переменной целого типа с именем a

for(a = 0; a < 256; a++) - цикл, в начале цикла переменной a присваивается значение 0, цикл выполняется пока а меньше 256, на каждом обороте цикла переменная а увеличивается на 1

UART.Write(Boot[a])); - через последовательный порт передается элемент массива Boot с индексом а

if(UART.ReadByte != Boot[a]) - читается принятый байт из последовательного порта и сравнивается с элементом а массива Boot. Если байт не совпал, то ошибка, выключаем питание (POWER.Off), выдаем сообщение (print("Ошибка.\nКонтроллер не отвечает.")), выходим и фукции и возвратом нуля (return 0)

Если же принятый байт совпадает с принятым, передвигаем ползунок индикатора прогресса (PBAR_POS = a) и продолжаем цикл.

По завершении приема загрузчика контроллер запускает его. В коде загрузчика зашито следущее начало:

Перключение скорости UART контроллера в 8 раз быстрее, чем при передаче загрузчика. Пауза примерно 100 миллисекунд (зависит от частоты кварца контроллера), затем выдача байта 0xA5. Скрипт должен сделать: переключить скорость UART в 8 раз выше, установить тайм-аут 200 миллисекунд, и ждать байт на прием. Делаем:

UART.Open(8 * Crystal.Value * 1000/6666,UART_8N1);
UART.TimeoutValue = 200;
if(0xA5 != UART.ReadByte)
{
   
POWER.Off;
   
print("Ошибка.\nНет эха от загрузчика.");
    
return 0;
}
print(" OK");
return 1;

И код функции InitBootloader целиком:

int InitBootloader(void)
{
   
print("\nИнициализация загрузчика... ");
   
POWER.VCC_5V; DelayMilli(100);
   
RESET = 0; DelayMilli(50);
   
RESET = 1; DelayMilli(50);
   
UART.Open(Crystal.Value * 1000/6250,UART_8N1);
   
UART.TimeoutValue = 50;
   
UART.Write(255);
   
PBAR_POS = 0; PBAR_MAX = 255;
   
int a;
   
for(a = 0; a < 256;a++)
    {
       
UART.Write(Boot[a]);
       
if(UART.ReadByte != Boot[a])
        {
           
POWER.Off;
           
print("Ошибка.\nНет эха от контроллера.");
           
return 0;
        }
       
PBAR_POS = a;
    }
   
UART.Open(8 * Crystal.Value * 1000/6250,UART_8N1);
   
UART.TimeoutValue = 200;
   
if(0xA5 != UART.ReadByte)
    {
       
POWER.Off;
       
print("Ошибка.\nНет эха от загрузчика.");
       
return 0;
    }
   
print(" OK");
   
return 1;
}

Теперь можно запустить скрипт. Нажимам F7 и F8. Нажимаем в окне скрипта кнопку Пуск или любую кнопку на панели инструментов - что то не то. Появляется сообщение "Привет, программист". А наша процедура InitBootloader никак себя не проявляет. Ну и правильно, она же в нашем коде никак не не вызывается. Исправим это. В теле функции main удаляем строку print ("Привет программист"); а записываем:

void main(int id)
{
    int a = InitBootloader();   
    print(("\nInitBootloader() = "+a);
    POWER.Off;
}

Нажимаем F7, затем F8 и в окне скрипта нажимаем любую кнопку. Если контроллер подключен к программатору, должен произойти процесс инициализации загрузчика и результат будет такой:>

Инициализация загрузчика... OK
InitBootloader() = 1

Если же контроллер не подключен или что-то не так, то результат будет

Инициализация загрузчика... Ошибка.
Нет эха от контроллера.
InitBootloader() = 0

Скрипт работает..

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

void Read(int id);

А в конце скрипта

void Read(int id)
{

}

Сохраняем скрипт (Ctrl+S). Переходим в редактор интерфейса (F12) и в таблице меню в строке Read в столбце OnClick вызываем выпадающий список. Там должна добавиться строка Read

Выбираем ее для этого пункта меню.

Теперь нам надо написать код этой функции Read. Чтение памяти работает таким образом: программатор передает загрузчику в контроллере символ 'R' и два байта адреса, загрузчик читает этот адрес в памяти и выдает через последовательный порт.

Объявляем переменные, которые будем использовать

int adr,Counter,temp;

Настраиваем индикатор прогресса:

PBAR_POS = 0;
PBAR_MAX = EEPROM_SIZE-1;

Сообщение о процессе:

print("\nЧтение EEPROM... ");

Устанавливаем переменной адреса начальное значение

adr = EEPROM_BEGIN;

Цикл чтения, читаются EEPROM_SIZE байт

for(Counter = 0; Counter < EEPROM_SIZE;Counter++)
{

Передаем командный байт 'R' и два байта адреса - сначала старшие 8 бит, потом младшие 8 бит

UART.Write('R',adr >> 8,adr);

Принимаем прочитанный байт. Если вдруг примем 0x80000000, то это ошибка, связь отвалилась или пропало питание или еще что. Тогда сообщаем об этом, выключаем питание и выходим.

if((temp = UART.ReadByte) == 0x80000000)
{
    print("Ошибка. Адрес "+adr+" (0x"+adr.toHex(4)+')');
    POWER.Off;
    return;
}

Байт прочитался, кладем его в редактор

EDITOR[Counter] = temp;

EDITOR - зарезервированное слово, означает обращение к первому (в левой вкладке) редактору. В квадратных скобках записывается адрес ячейки редактора.

Следующий адреc

adr++;

Передвигаем индикатор прогресса

PBAR_POS = Counter;
}

Чтение завершено, сообщаем количество прочитанных байт

print(" Готово. "+Counter+" байт прочитано.");

Окончательный вид функции Read такой:

void Read(int id)
{
   
int adr,Counter,temp;
   
PBAR_POS = 0;
   
PBAR_MAX = EEPROM_SIZE-1;
   
print("\nЧтение EEPROM... ");
   
adr = EEPROM_BEGIN;
   
for(Counter = 0; Counter < EEPROM_SIZE;Counter++)
    {
       
UART.Write('R',adr >> 8,adr);
       
if((temp = UART.ReadByte) == 0x80000000)
        {
           
print("Ошибка. Адрес "+adr+" (0x"+adr.toHex(4)+')');
           
POWER.Off;
           
return;
        }
       
EDITOR[Counter] = temp;
       
adr++;
       
PBAR_POS = Counter;
    }
   
print(" Готово. "+Counter+" байт прочитано.");
   
return;
}

Теперь собираем скрипт (F7), грузим в программатор. Нажимаем в панели скрипта кнопку со знаком вопроса - должна произойти инициализация загрузчика. После этого нажимаем кнопку с зеленой кнопкой вверх - должно произойти чтение EEPROM контроллера и его содержимое отобразится в редакторе.