FLProg + Nextion HMI Enhanced

89dd2736e88945caabb83f1ff96fd3ac.JPG

Компания ITEAD выпустила новую линейку Enhanced своих панелей Nextion HMI. Представители компании предоставили мне экземпляр этой линейки для интеграции новых возможностей панели в программу FLProg. В версии 2.2 это было реализовано. В данном уроке мы рассмотрим новые возможности панели, и для примера создадим программируемый таймер на пять каналов.
Для начала рассмотрим характеристики панели. В линейке Enhanced появились встроенные часы реального времени, 1024 байта энергонезависимой памяти, 8 цифровых входов/выходов. Каждый них может быть настроен как вход, так и как выход. Четыре из них (с 4-го по 7) могут быть настроены как выходы ШИМ.

67b8013701ed4c9592ac313a40a27e9f.JPG

Кроме непосредственно самой линейки «Nextion HMI Enhanced» была выпущена плата «Expansion Board»

df4974c5c35d4f909f3bc441771a3254.jpg

На ней установлены органы управления и индикации, привязанные к GPIO панели.

115b52b6a05e49f085511cd667fe4004.jpg
Такие возможности позволяют на базе этой панели сделать практически законченное устройство. В данном уроке я основной упор сделаю на программирование самой панели, поскольку информации по этому поводу мало, а подводных камней много. Ссылка на проект для программы Nextion Editor есть в конце поста.

Начало работы с редактором Nextion Editor, его запуск, начальный выбор кодировки, типа панели рассмотрено в моих предыдущих постах тыц, тыц , и тыц. Поэтому не будем на этом останавливаться.
Программа панели состоит из трёх экранов Главного (Main), Настройка таймера (SetTimer) и Установка времени (SetCurrentTime).

Начнём с главного экрана.

6a8c8c671fa44f48b89274f4f2bc39d2.PNG

На этом экране отображаются уставки включения, выключения, состояния каждого канала, кнопки изменения состояния каналов, и кнопка перехода на экран настройки текущего времени. При клике на текст, отображающий уставки канала, происходит переход на настройку данного канала. Кроме того на этом экране находятся четыре скрытые кнопки необходимые для привязки к физическим кнопкам находящихся на Expansion Board..

c9315952439f428ebb7c0a1035590e71.PNG

Рассмотрим код, содержащийся на главном экране.

Событие Preinitialilize Event (вызывается перед инициализацией экрана).

cfgpio 0,1,b0 //Кнопка Esc (IO0) привязывается к виртуальной кнопке b0 "Установить время"
cfgpio 2,1,b8 //Кнопка Right (IO2) привязывается к виртуальной кнопке b8 -"Редактировать выбранный канал"
cfgpio 3,1,b7 //Кнопка Down (IO3) привязывается к виртуальной кнопке b7 -"Перейти на следующий канал"
cfgpio 4,1,b6 //Кнопка Up (IO4) привязывается к виртуальной кнопке b6 -"Перейти на предыдущий канал"
cfgpio 5,1,b9 //Кнопка Left (IO5) привязывается к виртуальной кнопке b9 -"Переключить состояние канала"
SelTim.val=1 //Выбор первого канала


Здесь мы привязываем физические кнопки, находящиеся на Expansion Board, к виртуальным кнопкам на экране.

Подробнее о команде cfgpio — настройка физических входов — выходов панели (данная команда есть только у панелей линейки Enhanced).
Синтаксис:
cfgpio id, state, cmp
где:
id: номер входа/выхода (0–7)
state: режим работы (0–4)
cmp: имя привязываемого компонента (актуально только режиме работы 1, в остальных случаях — 0).
Обратите внимание на наличие пробелов. Обязательный пробел после команды cfgpio дальше в тексте команды пробелы не допустимы.

Возможные режима работы:

Номер режима Описание Пример
0 Вход с подтяжкой к + 5 вольтам (встроенный резистор 50 кОм). Текущее состояние можно прочитать из системной переменной pio0 — pio7 (для 0- 7 входа/выхода соответственно cfgpio 0,0,0
Вход/выход GPIO0 настраивается как вход, подтянутый к +5В. Текущее состояние можно прочитать так:
n0.val = pio0
1 Вход с подтяжкой к + 5 вольтам (встроенный резистор 50 кОм) и привязкой к виртуальному элементу. Текущее состояние прочитать из системной переменной pio0 — pio7 (для 0- 7 входа/выхода соответственно). Так же при состоянии входа в лог. 1 привязанному элементу присваивается нажатое состояние, при лог. 0 привязанному элементу присваивается отпущенное состояние. Данный режим необходимо включать в событии Preinitialilize Event окна, поскольку после инициализации страницы, привязка не происходит. cfgpio 2,1, b0
Вход/выход GPIO2 настраивается как вход, подтянутый к +5В с привязкой к виртуальной кнопке b0.
По переднему фронту на этом входе, кнопка b0 переводится в нажатое состояние, по заднему фронту — в отпущенное.
2 Двухтактный выход. Задать значение на выходе можно через системную переменную pio0 — pio7 (для 0- 7 входа/выхода соответственно). cfgpio 1,2,0
Вход/выход GPIO1 настраивается как двухтактный выход. Запись высокого выходного уровня:
pio1=1
3 Выход ШИМ. Только для 4–7 входа/выхода. Значения от 0 до 100. По умолчанию — 50. Значение задаётся с помощью системных переменных pwm4- pwm7 (для 4- 7 входа/выхода соответственно). Частота ШИМ для всех выходов задается с помощью системной переменной pwmf в герцах. Значения от 1 до 65536. По умолчанию — 1000. cfgpio 4,3,0
Вход/выход GPIO4 настраивается как выход ШИМ.
Запись значения:
pwm4=20
Задание частоты ШИМ — 2000 Гц.
pwmf=2000
4 Выход с открытым коллектором. Задать значение на выходе можно через системную переменную pio0 — pio7 (для 0- 7 входа/выхода соответственно). cfgpio 5,4,0
Вход/выход GPIO5 настраивается как двухтактный выход. Запись высокого выходного уровня:
pio5=1

Событие Touch Press Event кнопки b0 — «Установить время»

page 2 // Переход на страницу установки текущего времени


Тут всё понятно без объяснений

Событие Touch Press Event кнопки b1 — «Переключить состояние первого канала»

repo TempB.val,0 // Читаем из EEPROM в переменную TempB активность канала 1
if(TempB.val==1) // Если канал активен - переключаем его состояние
{
  if(tsr1.val==1)// если канал включён
  {
    tsr1.val=2 // выключаем его
  }else
  {
    tsr1.val=1 // иначе - включаем
  }
}


Сначала мы читаем из EEPROM активность канала. Каждый канал можно выключить из работы на странице настройки канала. Команду repo — «чтение из EEPROM» мы рассмотрим поподробнее ниже. Затем, если канал активен, переключаем его состояние. Текущее состояние каналов хранится в переменных tsr1 — tsr5 для каждого из каналов соответственно.

Особенности в синтаксисе выражения if else

if (TempB.val==1) — пробелы нигде не допускаются.
Все открывающие и закрывающие скобки обязательно с новой строки. Никакие команды кроме скобок в этой строке не допускаются. Исключение составляет выражение
}else
Вот оно должно быть написано именно так, в одну строку и без пробелов. Осознание этого заняло у меня прилично времени, я всё время ставил пробел перед else и не мог понять, почему ругается компилятор.


Для остальных кнопок изменения состояния канала (b2 — b5) код события Touch Press Event аналогичны. Изменяется только адрес в EEPROM и переменная состояния канала.

Событие Touch Press Event кнопки b6 — «Выбрать предыдущий канал». Кнопка невидимая. Режим отрисовки (sta) — crop image (вырезанное изображение). В качестве картинки в не нажатом состоянии (picc) и нажатом состоянии (picc2) выбрано фоновое изображение окна. За счёт этого кнопка не отображается, но работает. Эта кнопка на этом экране привязана к физической кнопке Up (IO4) на Expansion Board.

if(SelTim.val<2)//Если выбран канал 1
{
  SelTim.val=5 // выбираем канал 5
}else
{
  SelTim.val=SelTim.val-1 //иначе переходим на предыдущий канал
}


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

Событие Touch Press Event кнопки b7 — «Выбрать следующий канал». Кнопка невидимая. Эта кнопка на этом экране привязана к физической кнопке Down (IO3) на Expansion Board.

if(SelTim.val>4) //Если выбран канал 5
{
  SelTim.val=1 //переходим на канал 1
}else
{
  SelTim.val=SelTim.val+1 // иначе переходим на следующий
}


Тут я думаю то же всё понятно.

Событие Touch Press Event кнопки b8 — «Редактировать выбранный канал». Кнопка невидимая. Эта кнопка на этом экране привязана к физической кнопке Right (IO2) на Expansion Board.

if(SelTim.val==1) // Если выбран канал 1
{
  click TimerText1,1 // то имитируем нажатие на поле отображения состояния канала 1
}
if(SelTim.val==2) // Если выбран канал 2
{
  click TimerText2,1 // то имитируем нажатие на поле отображения состояния канала 2
}
if(SelTim.val==3) // Если выбран канал 3
{
  click TimerText3,1 // то имитируем нажатие на поле отображения состояния канала 3
}
if(SelTim.val==4) // Если выбран канал 4
{
  click TimerText4,1 // то имитируем нажатие на поле отображения состояния канала 4
}
if(SelTim.val==5) // Если выбран канал 5
{
  click TimerText5,1 // то имитируем нажатие на поле отображения состояния канала 1
}

Подробнее о команде click — имитация нажатия или отпускания элемента

Синтаксис:
click cmpID, event
где:
cmpID: имя или ID элемента.
event: событие 0 — отпускание; 1 — нажатие
Обратите внимание на наличие пробелов. Обязательный пробел после команды click дальше в тексте команды пробелы не допустимы.

Событие Touch Press Event кнопки b9 — «Переключить состояние выбранного канала». Кнопка невидимая. Эта кнопка на этом экране привязана к физической кнопке Left (IO5) на Expansion Board.

if(SelTim.val==1) // Если выбран канал 1
{
  click b1,1 // Имитируем нажатие на кнопку b1
}
if(SelTim.val==2) // Если выбран канал 2
{
  click b2,1 // Имитируем нажатие на кнопку b2
}
if(SelTim.val==3) // Если выбран канал 3
{
  click b3,1 // Имитируем нажатие на кнопку b3
}
if(SelTim.val==4) // Если выбран канал 4
{
  click b4,1 // Имитируем нажатие на кнопку b4
}
if(SelTim.val==5) // Если выбран канал 5
{
  click b5,1 // Имитируем нажатие на кнопку b5
}

Событие Touch Press Event текстового поля TimerText1 — «Отображение состояния канала 1».

sys0=1 // заносим в системную переменную sys0  номер редактируемого канала
sys1=1 // заносим в системную переменную sys1  стартовый номер для выделения необходимого поля редактирования
page 1 //переходим на страницу редактирования канала (SetTimer - ID = 1).


Для других текстовых полей (TimerText2 — TimerText5) код события Touch Press Event аналогичен. Только в системную переменную sys0 заносится соответствующий номер канала.
sys0, sys1, sys2-глобальные числовые переменные, которые не нужно создавать или определять. Их можно использовать на любом экране. Значение по умолчанию для этих трех переменных равны 0, их можно читать и писать, их диапазон значений 0~4294967295. Рекомендуется для передачи значений между страницами.

На этом экране установлен таймер tm0. Этот таймер срабатывает каждые 200 миллисекунд (параметр tim), при активности страницы. Код контроля состояния таймеров и перерисовки компонентов, находящихся на странице находится в событии Timer Event этого таймера.

Код под сполером
//Отображение текущего времени в поле CurrentTime1
//----Отображение текущего дня----
temp.val=rtc2 // Получаем значение текущего дня из системной переменной rtc2 - "день в часах реального времени"
tempText.txt="" //Во временную строковую переменную tempText кладём пустую строку
if(temp.val<10)// Если день меньше 10
{
  tempText.txt="0" // то во временную строковую переменную tempText кладём символ "0"
}
cov temp.val,TT1.txt,0 //конвертим значения дня (числовое) в строковое значение в строковую переменную TT1
CurrentTime1.txt=tempText.txt+TT1.txt //значение из переменной tempText и TT1 заносим в поле отображения CurrentTime1
//----Отображение текущего месяца----
temp.val=rtc1 // Получаем значение текущего месяца из системной переменной rtc1 - "месяц в часах реального времени"
tempText.txt="" //Во временную строковую переменную tempText кладём пустую строку
if(temp.val<10) // Если месяц меньше 10
{
  tempText.txt="0" // то во временную строковую переменную tempText кладём символ "0"
}
cov temp.val,TT1.txt,0 //конвертим значения месяца (числовое) в строковое значение в строковую переменную TT1
CurrentTime1.txt=CurrentTime1.txt+"-"+tempText.txt+TT1.txt // к тексту в поле отображения CurrentTime1 добавляем разделитель даты "-" и значения из переменных tempText и TT1
//----Отображение текущего года----
temp.val=rtc0 // Получаем значение текущего года из системной переменной rtc0 - "год в часах реального времени"
cov temp.val,TT1.txt,0 //конвертим значения года (числовое) в строковое значение в строковую переменную TT1
CurrentTime1.txt=CurrentTime1.txt+"-"+TT1.txt // к тексту в поле отображения CurrentTime1 добавляем разделитель даты "-" и значения из переменной TT1
//----Отображение текущего часа----
temp.val=rtc3 // Получаем значение текущего часа из системной переменной rtc3 - "час в часах реального времени"
tempText.txt="" //Во временную строковую переменную tempText кладём пустую строку
if(temp.val<10) // Если час меньше 10
{
  tempText.txt="0" // то во временную строковую переменную tempText кладём символ "0"
}
cov temp.val,TT1.txt,0 //конвертим значения часа (числовое) в строковое значение в строковую переменную TT1
CurrentTime1.txt=CurrentTime1.txt+" "+tempText.txt+TT1.txt  // к тексту в поле отображения CurrentTime1 добавляем разделитель даты и времени " " и значения из переменных tempText и TT1
//----Отображение текущей минуты----
temp.val=rtc4 // Получаем значение текущей минуты из системной переменной rtc4 - "минута в часах реального времени"
tempText.txt="" //Во временную строковую переменную tempText кладём пустую строку
if(temp.val<10) // Если минута меньше 10
{
  tempText.txt="0"// то во временную строковую переменную tempText кладём символ "0"
}
cov temp.val,TT1.txt,0 //конвертим значения минуты (числовое) в строковое значение в строковую переменную TT1
CurrentTime1.txt=CurrentTime1.txt+":"+tempText.txt+TT1.txt  // к тексту в поле отображения CurrentTime1 добавляем разделитель времени ":" и значения из переменных tempText и TT1
//----Отображение текущей секунды----
temp.val=rtc5 // Получаем значение текущей секунды из системной переменной rtc5 - "секунда в часах реального времени"
tempText.txt=""  //Во временную строковую переменную tempText кладём пустую строку
if(temp.val<10) // Если секунда меньше 10
{
  tempText.txt="0" // то во временную строковую переменную tempText кладём символ "0"
}
cov temp.val,TT1.txt,0 //конвертим значения секунды (числовое) в строковое значение в строковую переменную TT1
CurrentTime1.txt=CurrentTime1.txt+":"+tempText.txt+TT1.txt  // к тексту в поле отображения CurrentTime1 добавляем разделитель времени ":" и значения из переменных tempText и TT1
//Отрисовка времени срабатывания каналов и определение событий срабатывания/отключения каналов
for(i.val=0;i.val<5;i.val++)//перебор каналов. в переменной i находится номер обрабатываемого канала (счёт с нуля)
{
  temp.val=i.val*52 // определение стартового адреса в EEPROM для обрабатываемого канала
  //----Обработка дня включения----
  temp2.val=temp.val+4 //Определяем адрес в EEPROM уставки дня включения канала
  Var0txt.txt=""// в текстовую переменную  Var0txt записываем пустую строку
  repo temp1.val,temp2.val // вычитываем из EEPROM в переменную temp1.val уставку дня включения канала
  if(temp1.val==10000) // если уставка дня не учитываеся (значение 10000)
  {
    ts1.val=1 //считаем что уставка совпала с текущим днём
    tempText.txt="X" // в строковую переменную   tempText для отображения пишем символ "X"
  }else // Иначе
  {
    if(temp1.val==rtc2) //если  уставка совпала с текущим днём
    {
      ts1.val=1 //запоминаем что совпала в переменную  ts1
    }else //иначе
    {
      ts1.val=2 // запоминаем что не совпала в переменную  ts1
    }
    cov temp1.val,tempText.txt,0 //конвертим уставку дня включения канала (числовое значение) во  строковую переменную  tempText
    if(temp1.val<10)//Eсли значение уставки дня включения канала меньше 10
    {
      Var0txt.txt="0" //в текстовую переменную  Var0txt записываем символ "0"
    }
  }
  TT1.txt=Var0txt.txt+tempText.txt+"-"//в текстовую переменную TT1 записываем значения переменных Var0txt, tempText и разделитель даты "-"
  //----Обработка месяца включения----
  temp2.val=temp.val+8 //Определяем адрес в EEPROM уставки месяца включения канала
  Var0txt.txt="" // в текстовую переменную  Var0txt записываем пустую строку
  repo temp1.val,temp2.val // вычитываем из EEPROM в переменную temp1.val уставку месяца включения канала
  if(temp1.val==10000)// если уставка месяца не учитываеся (значение 10000)
  {
    ts2.val=1 //считаем что уставка совпала с текущим месяцем
    tempText.txt="X"// в строковую переменную   tempText для отображения пишем символ "X"
  }else // Иначе
  {
    if(temp1.val==rtc1)//если  уставка совпала с текущим месяцем
    {
      ts2.val=1 //запоминаем что совпала в переменную  ts2
    }else //иначе
    {
      ts2.val=2 // запоминаем что не совпала в переменную  ts2
    }
    cov temp1.val,tempText.txt,0 //конвертим уставку месяца включения канала (числовое значение) во  строковую переменную  tempText
    if(temp1.val<10) //Eсли значение уставки месяца включения канала меньше 10
    {
      Var0txt.txt="0" //в текстовую переменную  Var0txt записываем символ "0"
    }
  }
  TT1.txt=TT1.txt+Var0txt.txt+tempText.txt+"-" //К значению текстовой переменной TT1 добавляем значения переменных Var0txt, tempText и разделитель даты "-"
  //----Обработка года включения----
  temp2.val=temp.val+12 //Определяем адрес в EEPROM уставки года включения канала
  repo temp1.val,temp2.val// вычитываем из EEPROM в переменную temp1.val уставку года включения канала
  if(temp1.val==10000) // если уставка месяца не учитываеся (значение 10000)
  {
    ts3.val=1 //считаем что уставка совпала с текущим годом
    tempText.txt="X"// в строковую переменную   tempText для отображения пишем символ "X"
  }else // Иначе
  {
    if(temp1.val==rtc0) //если  уставка совпала с текущим годом
    {
      ts3.val=1 //запоминаем что совпала в переменную  ts3
    }else //иначе
    {
      ts3.val=0 // запоминаем что не совпала в переменную  ts3
    }
    cov temp1.val,tempText.txt,0 //конвертим уставку года включения канала (числовое значение) во  строковую переменную  tempText
  }
  TT1.txt=TT1.txt+tempText.txt+" " //К значению текстовой переменной TT1 добавляем значения переменной  tempText и разделитель даты и времени " "
  //----Обработка часа включения----
  temp2.val=temp.val+16 //Определяем адрес в EEPROM уставки часа включения канала
  Var0txt.txt=""  // в текстовую переменную  Var0txt записываем пустую строку
  repo temp1.val,temp2.val // вычитываем из EEPROM в переменную temp1.val уставку часа включения канала
  if(temp1.val==10000)// если уставка часа не учитываеся (значение 10000)
  {
    ts4.val=1 //считаем что уставка совпала с текущим часом
    tempText.txt="X" // в строковую переменную   tempText для отображения пишем символ "X"
  }else // Иначе
  {
    if(temp1.val==rtc3) //если  уставка совпала с текущим часом
    {
      ts4.val=1 //запоминаем что совпала в переменную  ts4
    }else //иначе
    {
      ts4.val=0  // запоминаем что не совпала в переменную  ts4
    }
    cov temp1.val,tempText.txt,0 //конвертим уставку часа включения канала (числовое значение) во  строковую переменную  tempText
    if(temp1.val<10) //Eсли значение уставки часа включения канала меньше 10
    {
      Var0txt.txt="0" //в текстовую переменную  Var0txt записываем символ "0"
    }
  }
  TT1.txt=TT1.txt+Var0txt.txt+tempText.txt+":" //К значению текстовой переменной TT1 добавляем значения переменных Var0txt, tempText и разделитель времени ":"
  //----Обработка минуты включения----
  temp2.val=temp.val+20 //Определяем адрес в EEPROM уставки минуты включения канала
  Var0txt.txt="" // в текстовую переменную  Var0txt записываем пустую строку
  repo temp1.val,temp2.val // вычитываем из EEPROM в переменную temp1.val уставку минуты включения канала
  if(temp1.val==10000)// если уставка минуты не учитываеся (значение 10000)
  {
    ts5.val=1 //считаем что уставка совпала с текущей минутой
    tempText.txt="X" // в строковую переменную   tempText для отображения пишем символ "X"
  }else // Иначе
  {
    if(temp1.val==rtc4) //если  уставка совпала с текущей минутой
    {
      ts5.val=1//запоминаем что совпала в переменную  ts5
    }else //иначе
    {
      ts5.val=0 // запоминаем что не совпала в переменную  ts5
    }
    cov temp1.val,tempText.txt,0 //конвертим уставку минуты включения канала (числовое значение) во  строковую переменную  tempText
    if(temp1.val<10) //Eсли значение уставки минуты включения канала меньше 10
    {
      Var0txt.txt="0"//в текстовую переменную  Var0txt записываем символ "0"
    }
  }
  TT1.txt=TT1.txt+Var0txt.txt+tempText.txt+":"//К значению текстовой переменной TT1 добавляем значения переменных Var0txt, tempText и разделитель времени ":"
  //----Обработка секунды включения----
  temp2.val=temp.val+24 //Определяем адрес в EEPROM уставки секунды включения канала
  Var0txt.txt="" // в текстовую переменную  Var0txt записываем пустую строку
  repo temp1.val,temp2.val // вычитываем из EEPROM в переменную temp1.val уставку секунды включения канала
  if(temp1.val==10000) // если уставка секунды не учитываеся (значение 10000)
  {
    ts6.val=1 //считаем что уставка совпала с текущей секундой
    tempText.txt="X" // в строковую переменную   tempText для отображения пишем символ "X"
  }else // Иначе
  {
    if(temp1.val==rtc5) //если  уставка совпала с текущей секундой
    {
      ts6.val=1 //запоминаем что совпала в переменную  ts6
    }else //иначе
    {
      ts6.val=0 // запоминаем что не совпала в переменную  ts6
    }
    cov temp1.val,tempText.txt,0 //конвертим уставку секунды включения канала (числовое значение) во  строковую переменную  tempText
    if(temp1.val<10) //Eсли значение уставки секунды включения канала меньше 10
    {
      Var0txt.txt="0" //в текстовую переменную  Var0txt записываем символ "0"
    }
  }
  TT1.txt=TT1.txt+Var0txt.txt+tempText.txt+" / " //К значению текстовой переменной TT1 добавляем значения переменных Var0txt, tempText и разделитель уставки включения и выключения "/"
  //----Обработка дня отключения----
  temp2.val=temp.val+28 //Определяем адрес в EEPROM уставки дня отключения  канала
  Var0txt.txt=""  // в текстовую переменную  Var0txt записываем пустую строку
  repo temp1.val,temp2.val // вычитываем из EEPROM в переменную temp1.val уставку дня отключения канала
  if(temp1.val==10000) // если уставка дня не учитываеся (значение 10000)
  {
    ts7.val=1 //считаем что уставка совпала с текущим днём
    tempText.txt="X" // в строковую переменную   tempText для отображения пишем символ "X"
  }else // Иначе
  {
    if(temp1.val==rtc2) //если  уставка совпала с текущим днём
    {
      ts7.val=1  //запоминаем что совпала в переменную  ts7
    }else //иначе
    {
      ts7.val=0 // запоминаем что не совпала в переменную  ts7
    }
    cov temp1.val,tempText.txt,0 //конвертим уставку дня выключения канала (числовое значение) во  строковую переменную  tempText
    if(temp1.val<10)//Eсли значение уставки дня выключения канала меньше 10
    {
      Var0txt.txt="0"//в текстовую переменную  Var0txt записываем символ "0"
    }
  }
  TT1.txt=TT1.txt+Var0txt.txt+tempText.txt+"-" //К значению текстовой переменной TT1 добавляем значения переменных Var0txt, tempText и разделитель даты "-"
  //----Обработка месяца отключения----
  temp2.val=temp.val+32 //Определяем адрес в EEPROM уставки дня отключения  канала
  Var0txt.txt="" // в текстовую переменную  Var0txt записываем пустую строку
  repo temp1.val,temp2.val// вычитываем из EEPROM в переменную temp1.val уставку месяца отключения канала
  if(temp1.val==10000)// если уставка месяца не учитываеся (значение 10000)
  {
    ts8.val=1//считаем что уставка совпала с текущим месяцем
    tempText.txt="X" // в строковую переменную   tempText для отображения пишем символ "X"
  }else // Иначе
  {
    if(temp1.val==rtc1) //если  уставка совпала с текущим месяцем
    {
      ts8.val=1 //запоминаем что совпала в переменную  ts8
    }else //иначе
    {
      ts8.val=0 // запоминаем что не совпала в переменную  ts8
    }
    cov temp1.val,tempText.txt,0 //конвертим уставку месяца выключения канала (числовое значение) во  строковую переменную  tempText
    if(temp1.val<10) //Eсли значение уставки месяца выключения канала меньше 10
    {
      Var0txt.txt="0"//в текстовую переменную  Var0txt записываем символ "0"
    }
  }
  TT1.txt=TT1.txt+Var0txt.txt+tempText.txt+"-"//К значению текстовой переменной TT1 добавляем значения переменных Var0txt, tempText и разделитель даты "-"
  //----Обработка года отключения----
  temp2.val=temp.val+36 //Определяем адрес в EEPROM уставки дня отключения  канала
  repo temp1.val,temp2.val // вычитываем из EEPROM в переменную temp1.val уставку года отключения канала
  if(temp1.val==10000)// если уставка года не учитываеся (значение 10000)
  {
    ts9.val=1 //считаем что уставка совпала с текущим месяцем
    tempText.txt="X" // в строковую переменную   tempText для отображения пишем символ "X"
  }else // Иначе
  {
    if(temp1.val==rtc0) //если  уставка совпала с текущим годом
    {
      ts9.val=1 //запоминаем что совпала в переменную  ts9
    }else //иначе
    {
      ts9.val=0 // запоминаем что не совпала в переменную  ts9
    }
    cov temp1.val,tempText.txt,0 //конвертим уставку года выключения канала (числовое значение) во  строковую переменную  tempText
  }
  TT1.txt=TT1.txt+Var0txt.txt+tempText.txt+" " //К значению текстовой переменной TT1 добавляем значения переменной tempText и разделитель даты и времени " "
  //----Обработка часа отключения----
  temp2.val=temp.val+40 //Определяем адрес в EEPROM уставки часа отключения  канала
  Var0txt.txt="" // в текстовую переменную  Var0txt записываем пустую строку
  repo temp1.val,temp2.val // вычитываем из EEPROM в переменную temp1.val уставку часа отключения канала
  if(temp1.val==10000) // если уставка часа не учитываеся (значение 10000)
  {
    ts10.val=1//считаем что уставка совпала с текущим часом
    tempText.txt="X" // в строковую переменную   tempText для отображения пишем символ "X"
  }else // Иначе
  {
    if(temp1.val==rtc3)  //если  уставка совпала с текущим часом
    {
      ts10.val=1 //запоминаем что совпала в переменную  ts10
    }else  //иначе
    {
      ts10.val=0 // запоминаем что не совпала в переменную  ts10
    }
    cov temp1.val,tempText.txt,0  //конвертим уставку часа выключения канала (числовое значение) во  строковую переменную  tempText
    if(temp1.val<10) //Eсли значение уставки часа выключения канала меньше 10
    {
      Var0txt.txt="0" //в текстовую переменную  Var0txt записываем символ "0"
    }
  }
  TT1.txt=TT1.txt+Var0txt.txt+tempText.txt+":"//К значению текстовой переменной TT1 добавляем значения переменных Var0txt, tempText и разделитель времени ":"
 //----Обработка минуты отключения----
  temp2.val=temp.val+44 //Определяем адрес в EEPROM уставки минуты отключения  канала
  Var0txt.txt="" // в текстовую переменную  Var0txt записываем пустую строку
  repo temp1.val,temp2.val  // вычитываем из EEPROM в переменную temp1.val уставку минуты отключения канала
  if(temp1.val==10000)  // если уставка минуты не учитываеся (значение 10000)
  {
    ts11.val=1 //считаем что уставка совпала с текущей минутой
    tempText.txt="X" // в строковую переменную   tempText для отображения пишем символ "X"
  }else // Иначе
  {
    if(temp1.val==rtc4) //если  уставка совпала с текущей минутой
    {
      ts11.val=1  //запоминаем что совпала в переменную  ts11
    }else //иначе
    {
      ts11.val=0 // запоминаем что не совпала в переменную  ts11
    }
    cov temp1.val,tempText.txt,0 //конвертим уставку минуты выключения канала (числовое значение) во  строковую переменную  tempText
    if(temp1.val<10) //Eсли значение уставки минуты выключения канала меньше 10
    {
      Var0txt.txt="0"//в текстовую переменную  Var0txt записываем символ "0"
    }
  }
  TT1.txt=TT1.txt+Var0txt.txt+tempText.txt+":" //К значению текстовой переменной TT1 добавляем значения переменных Var0txt, tempText и разделитель времени ":"
  //----Обработка секунды отключения----
  temp2.val=temp.val+48 //Определяем адрес в EEPROM уставки секунды отключения  канала
  Var0txt.txt="" // в текстовую переменную  Var0txt записываем пустую строку
  repo temp1.val,temp2.val // вычитываем из EEPROM в переменную temp1.val уставку секунды отключения канала
  if(temp1.val==10000)  // если уставка секунды не учитываеся (значение 10000)
  {
    ts12.val=1 //считаем что уставка совпала с текущей секундой
    tempText.txt="X" // в строковую переменную   tempText для отображения пишем символ "X"
  }else // Иначе
  {
    if(temp1.val==rtc5) //если  уставка совпала с текущей минутой
    {
      ts12.val=1 //запоминаем что совпала в переменную  ts12
    }else //иначе
    {
      ts12.val=0 // запоминаем что не совпала в переменную  ts12
    }
    cov temp1.val,tempText.txt,0 //конвертим уставку секунды выключения канала (числовое значение) во  строковую переменную  tempText
    if(temp1.val<10)  //Eсли значение уставки секунды выключения канала меньше 10
    {
      Var0txt.txt="0" //в текстовую переменную  Var0txt записываем символ "0"
    }
  }
  TT1.txt=TT1.txt+Var0txt.txt+tempText.txt //К значению текстовой переменной TT1 добавляем значения переменных Var0txt, tempText
  //----Определение события включения----
  repo temp1.val,temp.val // вычитываем из EEPROM в переменную temp1.val состояние активности канала
  tsrOn.val=0 //в переменную tsrOn (произошло событие включения) записываем 0 (нет события)
  if(temp1.val==1)// Если канал активен
  {
    if(ts1.val==1)// и если совпал день включения
    {
      if(ts2.val==1)// и если совпал месяц включения
      {
        if(ts3.val==1)// и если совпал год включения
        {
          if(ts4.val==1)// и если совпал час включения
          {
            if(ts5.val==1)// и если совпала минута включения
            {
              if(ts6.val==1)// и если совпала секунда включения
              {
                tsrOn.val=1//в переменную tsrOn (произошло событие включения) записываем 1 (естьсобытие включения)
              }
            }
          }
        }
      }
    }
  }
  //----Определение события выключения----
  tsrOf.val=0 //в переменную tsrOf (произошло событие выключения) записываем 0 (нет события)
  if(temp1.val==1)// Если канал активен
  {
    if(ts7.val==1)// и если совпал день выключения
    {
      if(ts8.val==1)// и если совпал месяц выключения
      {
        if(ts9.val==1)// и если совпал год выключения
        {
          if(ts10.val==1)// и если совпал час выключения
          {
            if(ts11.val==1)// и если совпала минута выключения
            {
              if(ts12.val==1)// и если совпала секунда выключения
              {
                tsrOf.val=1//в переменную tsrOf (произошло событие выключения) записываем 1 (есть событие отключения)
              }
            }
          }
        }
      }
    }
  }else//Иначе
  {
    tsrOf.val=1//в переменную tsrOf (произошло событие выключения) записываем 1 (есть событие отключения)
  }
  //----Обработка событий для канала 1----
  if(i.val==0)// если обрабатывается канал 1
  {
    if(tsr1.val==1)//если текущее состояние канала - включён (состояние канала 1 - переменная tsr1)
    {
      if(tsrOf.val==1)// и если произошло событие отключения
      {
        tsr1.val=2 //переводим канал в отключённое состояние 
      }
    }else //Иначе (если состояние канала отключенное )
    {
      if(tsrOn.val==1) // и если произошло событие включения
      {
        tsr1.val=1  //переводим канал во включенное состояние состояние 
      }
    }
    if(tsr1.val==1)//если текущее состояние канала - включён (состояние канала 1 - переменная tsr1)
    {
      TimerText1.pco=63488// тектовому полю  TimerText1 задаём цвет текста - красный 
    }else //иначе
    {
      if(temp1.val==1) // если канал активен
      {
        TimerText1.pco=65504 // тектовому полю  TimerText1 задаём цвет текста - жёлтый
      }else // иначе(если канал не активен)
      {
        TimerText1.pco=50712 // тектовому полю  TimerText1 задаём цвет текста - серый
      }
    }
    TimerText1.txt=TT1.txt //в текстовое поле TimerText1 в качестве текста задаем значение текстовой переменной TT1
  }
   //----Обработка событий для канала 2----
  if(i.val==1) // если обрабатывается канал 2
  {
    if(tsr2.val==1)//если текущее состояние канала - включён (состояние канала 2 - переменная tsr2)
    {
      if(tsrOf.val==1)// и если произошло событие отключения
      {
        tsr2.val=2 //переводим канал в отключённое состояние 
      }
    }else //Иначе (если состояние канала отключенное )
    {
      if(tsrOn.val==1)// и если произошло событие включения
      {
        tsr2.val=1 //переводим канал во включенное состояние состояние 
      }
    }
    if(tsr2.val==1)//если текущее состояние канала - включён (состояние канала 2 - переменная tsr2)
    {
      TimerText2.pco=63488// тектовому полю  TimerText2 задаём цвет текста - красный 
    }else //иначе
    {
      if(temp1.val==1) // если канал активен
      {
        TimerText2.pco=65504 // тектовому полю  TimerText2 задаём цвет текста - жёлтый
      }else  // иначе(если канал не активен)
      {
        TimerText2.pco=50712 // тектовому полю  TimerText2 задаём цвет текста - серый
      }
    }
    TimerText2.txt=TT1.txt //в текстовое поле TimerText2 в качестве текста задаем значение текстовой переменной TT1
  }
  //----Обработка событий для канала 3----
  if(i.val==2) // если обрабатывается канал 3
  {
    if(tsr3.val==1)//если текущее состояние канала - включён (состояние канала 3 - переменная tsr3)
    {
      if(tsrOf.val==1)// и если произошло событие отключения
      {
        tsr3.val=2  //переводим канал в отключённое состояние 
      }
    }else //Иначе (если состояние канала отключенное )
    {
      if(tsrOn.val==1)// и если произошло событие включения
      {
        tsr3.val=1 //переводим канал во включенное состояние состояние 
      }
    }
    if(tsr3.val==1)//если текущее состояние канала - включён (состояние канала 3 - переменная tsr3)
    {
      TimerText3.pco=63488 // тектовому полю  TimerText3 задаём цвет текста - красный 
    }else //иначе
    {
      if(temp1.val==1) // если канал активен
      {
        TimerText3.pco=65504  // тектовому полю  TimerText3 задаём цвет текста - жёлтый
      }else // иначе(если канал не активен)
      {
        TimerText3.pco=50712// тектовому полю  TimerText3 задаём цвет текста - серый
      }
    }
    TimerText3.txt=TT1.txt //в текстовое поле TimerText3 в качестве текста задаем значение текстовой переменной TT1
  }
  //----Обработка событий для канала 4----
  if(i.val==3) // если обрабатывается канал 4
  {
    if(tsr4.val==1)//если текущее состояние канала - включён (состояние канала 4 - переменная tsr4)
    {
      if(tsrOf.val==1)// и если произошло событие отключения
      {
        tsr4.val=2//переводим канал в отключённое состояние 
      }
    }else //Иначе (если состояние канала отключенное )
    {
      if(tsrOn.val==1)// и если произошло событие включения
      {
        tsr4.val=1//переводим канал во включенное состояние состояние 
      }
    }
    if(tsr4.val==1)//если текущее состояние канала - включён (состояние канала 4 - переменная tsr4)
    {
      TimerText4.pco=63488 // тектовому полю  TimerText4 задаём цвет текста - красный 
    }else//иначе
    {
      if(temp1.val==1)// если канал активен
      {
        TimerText4.pco=65504 // тектовому полю  TimerText4 задаём цвет текста - жёлтый
      }else // иначе(если канал не активен)
      {
        TimerText4.pco=50712// тектовому полю  TimerText4 задаём цвет текста - серый
      }
    }
    TimerText4.txt=TT1.txt //в текстовое поле TimerText4 в качестве текста задаем значение текстовой переменной TT1
  }
  //----Обработка событий для канала 5----
  if(i.val==4) // если обрабатывается канал 5
  {
    if(tsr5.val==1)//если текущее состояние канала - включён (состояние канала 5 - переменная tsr5)
    {
      if(tsrOf.val==1)// и если произошло событие отключения
      {
        tsr5.val=2//переводим канал в отключённое состояние 
      }
    }else //Иначе (если состояние канала отключенное )
    {
      if(tsrOn.val==1)// и если произошло событие включения
      {
        tsr5.val=1 //переводим канал во включенное состояние состояние 
      }
    }
    if(tsr5.val==1)//если текущее состояние канала - включён (состояние канала 5 - переменная tsr5)
    {
      TimerText5.pco=63488 // тектовому полю  TimerText5 задаём цвет текста - красный 
    }else //иначе
    {
      if(temp1.val==1)// если канал активен
      {
        TimerText5.pco=65504 // тектовому полю  TimerText5 задаём цвет текста - жёлтый
      }else // иначе(если канал не активен)
      {
        TimerText5.pco=50712 // тектовому полю  TimerText5 задаём цвет текста - серый
      }
    }
    TimerText5.txt=TT1.txt //в текстовое поле TimerText5 в качестве текста задаем значение текстовой переменной TT1
  }
}
//Отрисовка значка выбранного канала
if(SelTim.val==1) //если выбран канал 1 (переменная SelTim)
{
  b1.txt="+" // на кнопке переключения состояния канала 1 (b1) рисуем "+"
}else //иначе
{
  b1.txt="" // на кнопке переключения состояния канала 1 (b1) стираем "+"
}
if(SelTim.val==2) //если выбран канал 2 (переменная SelTim)
{
  b2.txt="+" // на кнопке переключения состояния канала 2 (b2) рисуем "+"
}else//иначе
{
  b2.txt="" // на кнопке переключения состояния канала 2 (b2) стираем "+"
}
if(SelTim.val==3)//если выбран канал 3 (переменная SelTim)
{
  b3.txt="+" // на кнопке переключения состояния канала 3 (b3) рисуем "+"
}else//иначе
{
  b3.txt="" // на кнопке переключения состояния канала 3 (b3) стираем "+"
}
if(SelTim.val==4)//если выбран канал 4 (переменная SelTim)
{
  b4.txt="+" // на кнопке переключения состояния канала 4 (b4) рисуем "+"
}else//иначе
{
  b4.txt="" // на кнопке переключения состояния канала 4 (b4) стираем "+"
}
if(SelTim.val==5)//если выбран канал 5 (переменная SelTim)
{
  b5.txt="+" // на кнопке переключения состояния канала 5 (b5) рисуем "+"
}else//иначе
{
  b5.txt="" // на кнопке переключения состояния канала 5 (b5) стираем "+"
}



Особенности в синтаксисе выражения for

for (n0.val=0; n0.val<100; n0.val++) — пробелы нигде не допускаются.
Все открывающие и закрывающие скобки обязательно с новой строки. Никакие команды кроме скобок в этой строке не допускаются.


Подробнее о команде cov — конвертация между строковыми и числовыми данными.

Синтаксис:
cov att1, att2, lenth
где:
att1: исходное значение
att2: целевое значение
lenth: длинна строки (0 — авто определение)
Пример:
cov number.val, text.txt,0
Значение числовой переменной number будет преобразовано в строку и занесено в значение строковой переменной text.
cov text.txt, number.val,5
Обратное преобразование первых пяти символов из строковой переменной text.
Обратите внимание на наличие пробелов. Обязательный пробел после команды cov дальше в тексте команды пробелы не допустимы.


Рассмотрим расположение данных в EEPROM панели. На каждый канал отведено 52 байта. На каждое значение — 4 байта.

<

© Geektimes




Адрес в EEPROM
Стартовое смещение = (номер канала начиная с 0)*52
Значение
Стартовое смещение Активность канала (0 — канал отключен, 1- канал включён)
Стартовое смещение + 4