Добрый день!
Возникла потребность реализации древовидного меню.Очень помогли пояснения уважаемой Cirno_9 Константы, указатели на переменные и процедуры в операторе DATA по операторам ADR2 и DATA, чем ей очень благодарен!
Еще статьи easyelectronics.ru и rn-wissen.de
В статьях куски кода, отображение и обработка параметров отдана на откуп пользователя. Я решил добить вывод на LCD меню и конечных параметров/переменных. От того код получился раздутым, но желающим можно подчерпнуть нужное.
Структура меню:
Пара слов о коде.
1. Начинаем с создания структуры меню через таблицу данных DATA. Для каждого пункта описывается адрес следующего и предыдущего пункта в пределах одного уровня вложенности, родитель и дочерний уровни вложенности. Это адреса меток типа WORD. Имея одинаковую структуру таблиц данных, перемещаясь между метками, попадаем на нужную метку и извлекаем из поля DATA константу с именем выбранного пункта меню.
2. 5-й столбец в таблице данных - так называемый параметр. В моём случае здесь содержится порядковый номер элемента массива параметров. Т.к. в таблице данных DATA можно хранить только адреса переменных, подпрограмм или константы, то, получив адрес переменной, мы не можем привязаться к ее имени, что непрактично, на мой взгляд. Поэтому я выбрал решение с номерами индексов массива параметров.
3. Для опроса кнопок (UP, DOWN, OK, CANCEL) настроен TIMER0 с периодом превышающим время дребезга контактов. Реализация опроса без обработки удержания кнопки, т.е. только однократное нажатие.
4. При входе в меню по нажатию кн. "OK" инициализация меню. Процедура, которой передается адрес метки пункта меню, заполняет массив данных из таблицы DATA. Массив типа WORD, но содержит строковую переменную через Overlay. Т.о. имеем все данные по текущему пункту.
5. Для навигации по меню созданы константы 1 - Next; 2 - Previous; 3 - Parent; 4 - Child. Через ту же процедуру инициализации, передавая ей адрес метки по порядковому номеру массива данных, осуществляется навигация по меню.
6. Собственно, на этом основной объем стаей на тему меню и заканчивается. Не описываются методы изменения параметров, вывод на дисплей меню.
7. В своем примере добавил инициализацию переменных из EEPROM, сохранение в EEPROM при записи параметра и его восстановление в случае отмены записи.
8. Для определения границ значений параметров и шага их изменения созданы отдельные массивы с таким же числом элементов как и основной массив с параметрами. Т.к. в моем проекте задействованы параметры с типом WORD, пришлось весь массив делать типа WORD.
9. Вывод на LCD. 3 режима отображения: основной режим, режим отображения пунктов меню с курсором, режим отображения названия параметра и его значения.
10. Интересен способ организации списка относительного смещения. В зависимости от положения курсора в области видимости LCD рассчитывается массив/список с номерами пунктов для каждой строки LCD. Т.о. список пунктов меню является динамическим, а не постраничным. Бонусом, сохранение позиции курсора Parent при выходе из Child.
11. Экспериментировал на 2*16 и 4*16 LCD.
'*******************************************************************************
'* Filename : Menu
'* Revision : 1.0
'* Controller : ATMEGA8
'* Compiler : BASCOM-AVR 2.0.7.8
'* Author : MACTEPok
'* WWW : https://bascomavr.bbok.ru/
'* Comment : Menu + ADR2
'*******************************************************************************
$map ' Получаем карту распределения памяти компилятором Bascom
$regfile = "m8def.dat" ' Используемый контроллер
$crystal = 1000000 '
$framesize = 32 ' Размер области используемой и необходимой для преобразований
$hwstack = 64 ' Размер аппаратного стека. Требуется бОльший объем, т.к. много преходов
$swstack = 64 ' Размер программного стека.
$lib "lcd4busy_anypin.lbx" ' Библиотека LCD
$lib "mcsbyteint.lbx" ' Библиотека для преобразования чисел в строки
'-------------------------------------------------------------------------------
' Конфигурация WatchDog
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
' Настройка портов
'-------------------------------------------------------------------------------
Ddrc = Ddrc And &B11100001 : Portc = Portc Or &B00011110
Button_pins Alias Pinc
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
' Конфигурация таймеров
'-------------------------------------------------------------------------------
Config Timer0 = Timer , Prescale = 256 , Clear Timer = 1
On Timer0 Handler_timer0_ovf ' Прерывание по переполнению
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
' Используемые переменные
'-------------------------------------------------------------------------------
Const Con_lcd_lines = 4 ' Крайнее положение курсора в меню. Номер строки по типу LCD (2 или 4)
Const Buttons_null = &B0011110 ' Маска состояние порта при отжатых кнопках
Const Con_increment = 1 ' Аргумент для процедуры Menu_change_parametr_sub
Const Con_decrement = 0 ' Аргумент для процедуры Menu_change_parametr_sub
Const Con_menuitem_next = 1 ' Идентификаторы для навигации в пределах массива данных пункта меню
Const Con_menuitem_previous = 2
Const Con_menuitem_parent = 3
Const Con_menuitem_child = 4
Const Con_menuitem_parametr = 5
Const Con_menuitem_text = 6
Const Con_n_index_parametr = 12 ' Кол-во параметров
Const Con_n_index_menu_item = 13 ' Кол-во элементов массива данных
Const Con_str_version = "v1.0 06.2025" ' Не более 15 символов
Const Con_cursor_begin = 1 ' Начальное положение курсора в меню. Номер строки
Const Con_lcd_character = 16 ' Кол-во символов в строке LCD
Const Con_table_depth = 4 ' Максимальная глубина вложенности меню
Dim B_debounce_flag As Byte
Dim B_lcd_flag As Byte
Dim B_buttons_stat As Byte ' Переменная состояния кнопок
Dim Int_cursor_shift(con_lcd_lines) As Integer ' Массив типа Integer, хранящий значение смещения относительно текущего пункта меню для каждой строки LCD
Dim Str_cursor_position As String * Con_table_depth ' Строковый формат массива B_cursor_position()
Dim B_cursor_position(con_table_depth) As Byte At Str_cursor_position Overlay ' Текущая позиция курсора (1 индекс). Каждый следующий индекс - предыдущее положение в Parent и т.д. по уровню вложенности
Dim Y As Byte
Dim B_var As Byte
Dim W_selected_menu_item(con_n_index_menu_item) As Word ' Массив с адресами меток текущего пункта меню:2хNext_2хPrevious_2хParent_2хChild_2хParametr_15xText_1x00
Dim Str_menu_text As String * 15 At W_selected_menu_item(1) + 10 Overlay ' Текстовое поле в массиве выделено в составную переменную
Dim W_temp_menu_item(con_n_index_menu_item) As Word ' Временный массив с адресами меток пункта меню:2хNext_2хPrevious_2хParent_2хChild_2хParametr_15xText_1x00
Dim Str_temp_menu_text As String * 15 At W_temp_menu_item(1) + 10 Overlay ' Текстовое поле в временном массиве выделено в составную переменную
Dim W_parametrs(con_n_index_parametr) As Word ' Числовые параметры в меню
Dim W_parametrs_lim_min(con_n_index_parametr) As Word ' Минимальный предел значений параметров
Dim W_parametrs_lim_max(con_n_index_parametr) As Word ' Максимальный предел значений параметров
Dim B_step_size(con_n_index_parametr) As Byte ' Шаг изменения значений параметров
Dim W_adr As Word ' Переменная для работы с адресами
Dim Str_version_parametr As String * 15
Dim Str_var As String * 16
Dim Str_cursor As String * 1
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
' Подпрограммы, функции
'-------------------------------------------------------------------------------
Declare Sub Menu_change_sub(byval Adr_label As Word) ' Инициализация выбранного пункта меню
Declare Sub Menu_save_parametr_sub(byval Index_parametr As Word) ' Сохранение параметра из SRAM в EEPROM
Declare Sub Menu_recovery_parametr_sub(byval Index_parametr As Word) ' Восстановление параметра из EEPROM в SRAM
Declare Sub Menu_change_parametr_sub(byval Index_parametr As Word , Byval Way As Byte) ' Инкремент/декремент выбранного параметра с определенным шагом
Declare Sub Cursor_change_sub(byval Way As Byte , Byval Start_position As Byte) ' Управление позицией курсора в режиме меню. Заполнение массива смещения. Инкремент/декремент, стартовая позиция
Declare Function Text_menuitem_func(byval Menu_shift As Byte)as String ' Получение имени пункта меню для навигации
Declare Function Text_list_func(byval Cursor_shift As Integer)as String ' Получение имени пункта меню для отображения в виде списка на LCD
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
' Конфигурация LCD
'-------------------------------------------------------------------------------
Config Lcdpin = Pin , Rs = Portb.0 , E = Portb.2 , Db4 = Portb.3 , Db5 = Portb.4 , Db6 = Portb.5 , Db7 = Portc.0 , Wr = Portb.1
#if Con_lcd_lines = 2
Config Lcd = 16 * 2 ' Используемый LCD
#else
Config Lcd = 16 * 4 ' Используемый LCD
#endif
Initlcd ' Инициализируем LCD
Waitms 50 ' Ждем пока все запустится
Cursor Off Noblink ' Выключаем неморгающий курсор
Cls ' Очистка экрана
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
' З А П У С К И П Р Е Д В А Р И Т Е Л Ь Н Ы Е Н А С Т Р О Й К И
'-------------------------------------------------------------------------------
Str_version_parametr = Con_str_version ' Версия ПО
W_parametrs_lim_min(1) = 10 ' Fnom min = 10
W_parametrs_lim_min(2) = 10 ' Fmin min = 10
W_parametrs_lim_min(3) = 20 ' Fmax min = 20 '
W_parametrs_lim_min(4) = 1 ' PPR
W_parametrs_lim_min(5) = 0 ' In2 enable
W_parametrs_lim_min(6) = 0 ' In2 invert
W_parametrs_lim_min(7) = 0 ' In3 enable
W_parametrs_lim_min(8) = 0 ' In3 invert
W_parametrs_lim_min(9) = 0 ' In3 delay
W_parametrs_lim_min(10) = 0 ' Out1 delay
W_parametrs_lim_min(11) = 0 ' Out2 delay
W_parametrs_lim_min(12) = 0 ' Brightness
W_parametrs_lim_max(1) = 10000 ' Fnom max = 10000
W_parametrs_lim_max(2) = 9900 ' Fmin max = 9900
W_parametrs_lim_max(3) = 10000 ' Fmax max = 10000
W_parametrs_lim_max(4) = 16 ' PPR
W_parametrs_lim_max(5) = 1 ' In2 enable
W_parametrs_lim_max(6) = 1 ' In2 invert
W_parametrs_lim_max(7) = 1 ' In3 enable
W_parametrs_lim_max(8) = 1 ' In3 invert
W_parametrs_lim_max(9) = 60 ' In3 delay
W_parametrs_lim_max(10) = 60 ' Out1 delay
W_parametrs_lim_max(11) = 60 ' Out2 delay
W_parametrs_lim_max(12) = 250 ' Brightness
B_step_size(1) = 10
B_step_size(2) = 10
B_step_size(3) = 10
B_step_size(4) = 1
B_step_size(5) = 1
B_step_size(6) = 1
B_step_size(7) = 1
B_step_size(8) = 1
B_step_size(9) = 1
B_step_size(10) = 1
B_step_size(11) = 1
B_step_size(12) = 10
For Y = 1 To Con_n_index_parametr
Menu_recovery_parametr_sub Y ' Заполнение массива параметров из EEPROM
Next
'-------------------------------------------------------------------------------
' Разрешаем работу необходимых прерываний
'-------------------------------------------------------------------------------
Enable Timer0 ' Разрешение прерывания по переполнению Timer1
'------------ Разрешаем работу всех включенных прерываний --------------------
Enable Interrupts
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
' Г Л А В Н Ы Й Ц И К Л
Main:
'-------------------------------------------------------------------------------
If B_debounce_flag = 1 Then Gosub Key_even ' Обработчик клавиатуры
If B_lcd_flag = 1 Then Gosub Lcd_even ' Обработчик LCD
'-----------
!jmp main
End
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
' Обработчик клавиатуры
'-------------------------------------------------------------------------------
' Навигация по меню.
' Проверка наличия текста в названии соответствующего пункта.
Key_even:
Select Case B_buttons_stat
Case &B00010110 ' Кнопка "OK"
If Str_menu_text = "" Then ' Если в рабочем массиве адресов нет данных, значит основном режиме отображения (не в меню)
Menu_change_sub Loadlabel(menu_1) ' Инициализация меню
Cursor_change_sub 0 , 2 ' Установка позиции курсора в первую строку
Else
If W_selected_menu_item(con_menuitem_parametr) <> 0 Then ' Если в текущем пункте меню есть параметры. Переход из Child в Parent с сохранением параметра
Menu_save_parametr_sub W_selected_menu_item(con_menuitem_parametr) ' Процедура сохранения параметра из SRAM в EEPROM
Cursor_change_sub 0 , 1 ' Установка позиции курсора для Parent
Else ' Если Child пункт меню без параметра
Cursor_change_sub 0 , 2 ' Установка позиции курсора в первую строку
End If
Menu_change_sub W_selected_menu_item(con_menuitem_child) ' Инициализация Child пункта меню. Для Child пункта с параметром Child = Parent в таблице DATA
End If
Case &B00001110 ' Кнопка "Cancel"
If W_selected_menu_item(con_menuitem_parametr) <> 0 Then ' Если в текущем пункте меню есть параметр
Menu_recovery_parametr_sub Con_menuitem_parametr ' Восстановление параметра из EEPROM
End If
If Str_menu_text <> "" Then ' Если в рабочем массиве адресов есть данные, значит режиме отображения меню
Menu_change_sub W_selected_menu_item(con_menuitem_parent) ' Инициализация Parent пункта меню
Cursor_change_sub 0 , 1 ' Установка позиции курсора для Parent
End If
Case &B00011100 ' Кнопка "UP"
If Str_menu_text <> "" And W_selected_menu_item(con_menuitem_parametr) = 0 Then ' Если в режиме отображения меню и в текущем пункте нет параметра
If Text_menuitem_func(con_menuitem_previous) <> "" Then ' Если есть Previous пункт меню
Menu_change_sub W_selected_menu_item(con_menuitem_previous) ' Инициализация Previous пункта меню
Cursor_change_sub 0 , 0 ' Декремент позиции курсора
End If
End If
If Str_menu_text <> "" And W_selected_menu_item(con_menuitem_parametr) <> 0 Then ' Если в режиме отображения меню и в текущем пункте есть параметр
Menu_change_parametr_sub W_selected_menu_item(con_menuitem_parametr) , Con_increment ' Процедура инкремента выбранного параметра
End If
Case &B00011010 ' Кнопка "DOWN"
If Str_menu_text <> "" And W_selected_menu_item(con_menuitem_parametr) = 0 Then ' Если в режиме отображения меню и в текущем пункте нет параметра
If Text_menuitem_func(con_menuitem_next) <> "" Then ' Если есть Next пункт меню
Menu_change_sub W_selected_menu_item(con_menuitem_next) ' Инициализация Next пункта меню
Cursor_change_sub 1 , 0 ' Инкремент позиции курсора
End If
End If
If Str_menu_text <> "" And W_selected_menu_item(con_menuitem_parametr) <> 0 Then ' Если в режиме отображения меню и в текущем пункте есть параметр
Menu_change_parametr_sub W_selected_menu_item(con_menuitem_parametr) , Con_decrement ' Процедура декремента выбранного параметра
End If
End Select
B_debounce_flag = 2 ' Установить флага нажатия кнопки. Нажатие кнопки обработано
'-------------------------------------------------------------------------------
Return
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
' Обработчик LCD
'-------------------------------------------------------------------------------
Lcd_even:
If Str_menu_text = "" Then ' Основной режим
For Y = Con_cursor_begin To Con_lcd_lines ' Цикл по кол-ву строк LCD
Select Case Y
Case 1
Str_var = "Fnom = " + Str(w_parametrs(1)) ' 1 параметр
Str_var = Str_var + " Hz"
Case 2
Str_var = "PPR = " + Str(w_parametrs(4)) ' 4 параметр
Case 3
Str_var = "Out1 del = " + Str(w_parametrs(10)) ' 10 параметр
Str_var = Str_var + " s"
Case 4
Str_var = "Brightness = " + Str(w_parametrs(12)) ' 12 параметр
End Select
B_var = Con_lcd_character - Len(str_var)
Str_var = Str_var + Space(b_var) ' Заполнение пробелами до конца строки
Locate Y , 1
Lcd Str_var
Next
End If
If Str_menu_text <> "" And W_selected_menu_item(con_menuitem_parametr) = 0 Then ' Режим меню. Пункты без параметров
For Y = Con_cursor_begin To Con_lcd_lines ' Цикл по кол-ву строк LCD
If B_cursor_position(1) = Y Then Str_cursor = Chr(&Hc9) Else Str_cursor = Space(1) ' Первый символ в строке для курсора
Str_var = Str_cursor + Text_list_func(int_cursor_shift(y)) ' Курсор + имя пункта в текущей позиции списка
B_var = Con_lcd_character - Len(str_var)
Str_var = Str_var + Space(b_var) ' Заполнение пробелами до конца строки
Locate Y , 1
Lcd Str_var
Next
End If
If Str_menu_text <> "" And W_selected_menu_item(con_menuitem_parametr) <> 0 Then ' Режим меню. Пункты с параметрами
For Y = Con_cursor_begin To Con_lcd_lines ' Цикл по кол-ву строк LCD
Select Case Y
Case 1
Str_var = Text_list_func(0) ' Имя пункта в текущей позиции списка
Case 2
If W_selected_menu_item(con_menuitem_parametr) <= Con_n_index_parametr Then ' Костыль для вывода статических данных в качестве параметра. По метке DATA значение параметра превышает размер массива параметров
Str_var = Str(w_parametrs(w_selected_menu_item(con_menuitem_parametr))) ' Получение значения параметра из массива параметров по индексу из 5-го элемента массива данных пункта меню
Else
Str_var = ""
End If
Case Else
Str_var = ""
End Select
B_var = Con_lcd_character - Len(str_var)
Str_var = Str_var + Space(b_var) ' Заполнение пробелами до конца строки
Locate Y , 1
Lcd Str_var
Next
End If
B_lcd_flag = 0 ' Сброс флага
'-------------------------------------------------------------------------------
Return
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
' Обработчик прерывания по переполнению TIMER0
'-------------------------------------------------------------------------------
Handler_timer0_ovf:
B_buttons_stat = Button_pins And Buttons_null ' Чтение состояния кнопок
If B_buttons_stat < Buttons_null And B_debounce_flag = 0 Then B_debounce_flag = 1 ' Установка флага нажатия кнопок. Если нажата кнопка, не было удержания, не была вызвана процедура обработки нажатия кнопки
If B_buttons_stat = Buttons_null And B_debounce_flag = 2 Then B_debounce_flag = 0 ' Сброс флага нажатия кнопок. Если кнопки отжаты, нажатие было обработано в процедуре
B_lcd_flag = 1 ' Установка флага для обработки LCD
'--------
Return
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
' Процедура инициализации массива данных выбранного пункта меню
'-------------------------------------------------------------------------------
Sub Menu_change_sub(byval Adr_label As Word)
Local B_step As Byte
W_adr = Adr_label ' Получение адреса метки
!lds R8, {W_adr} ' Установить указатель DATA на метку по указанному адресу
!lds R9, {W_adr+1}
For B_step = 1 To 5
Read W_selected_menu_item(b_step) ' Чтение 5 слов в массив
Next
Read Str_menu_text ' Чтение данных Text
'-------------------------------------------------------------------------------
End Sub
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
' Процедура сохранения параметра из SRAM в EEPROM
'-------------------------------------------------------------------------------
Sub Menu_save_parametr_sub(byval Index_parametr As Word)
Local Adr_eeprom As Word
Adr_eeprom = Index_parametr * 2 ' Массив с параметрами типа WORD
Writeeeprom W_parametrs(index_parametr) , Adr_eeprom
'-------------------------------------------------------------------------------
End Sub
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
' Процедура восстановления параметра из EEPROM в SRAM
'-------------------------------------------------------------------------------
Sub Menu_recovery_parametr_sub(byval Index_parametr As Word)
Local Adr_eeprom As Word
Adr_eeprom = Index_parametr * 2 ' Массив с параметрами типа WORD
Readeeprom W_parametrs(index_parametr) , Adr_eeprom
'-------------------------------------------------------------------------------
End Sub
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
' Процедура изменения выбранного параметра с определенным шагом
'-------------------------------------------------------------------------------
Sub Menu_change_parametr_sub(byval Index_parametr As Word , Byval Way As Byte)
Select Case Index_parametr ' Костыль для вывода статических данных в качестве параметра
Case Is <= Con_n_index_parametr ' Изменение параметров доступно только в пределах размера массива. Статичные параметры в этот диапазон не входят
Select Case Way
Case 0 ' Декремент
If W_parametrs(index_parametr) > W_parametrs_lim_min(index_parametr) Then W_parametrs(index_parametr) = W_parametrs(index_parametr) - B_step_size(index_parametr)
Case 1 ' Инкремент
If W_parametrs(index_parametr) < W_parametrs_lim_max(index_parametr) Then W_parametrs(index_parametr) = W_parametrs(index_parametr) + B_step_size(index_parametr)
End Select
End Select
'-------------------------------------------------------------------------------
End Sub
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
' Процедура управления позицией курсора в режиме меню. Заполнение массива смещения
'-------------------------------------------------------------------------------
Sub Cursor_change_sub(byval Way As Byte , Byval Start_position As Byte)
Local I As Byte
' Изменение позиции курсора в пределах области видимости LCD
' Way = 0 - Previous, Way = 1 - Next: перемещение курсора в пределах одного уровня вложенности меню
' Start_position = 0 - на текущем уровне вложенности, Start_position = 1 - Parent, Start_position = 2 - Child: переход между уровнями меню
' Через переменную Str_cursor_position и массив B_cursor_position() реализовано сохранение позиции курсора перед входом в Child, при возврате курсор устанавливается на пункт Parent
Select Case Start_position
Case 0
If Start_position = 0 Then
If Way = 0 And B_cursor_position(1) > Con_cursor_begin Then Decr B_cursor_position(1) ' Декремент позиции курсора
If Way = 1 And B_cursor_position(1) < Con_lcd_lines Then Incr B_cursor_position(1) ' Инкремент позиции курсора
End If
Case 1
Str_cursor_position = Mid(str_cursor_position , 2 , Con_table_depth) ' Сдвиг элементов массива влево.
Case 2
Str_cursor_position = Chr(1) + Str_cursor_position ' Первый элемент массива со значением 1, остальные элементы сдвинуть вправо. Во 2 элементе хранится позиция для выхода в Parent и т.д.
End Select
For I = Con_cursor_begin To Con_lcd_lines ' Смещение для текущей позиции курсора.
Int_cursor_shift(i) = I - B_cursor_position(1) ' Например для B_cursor_position(1) = 3: (-2) (-1), (0), (+1) для 4 строчного LCD
Next
'-------------------------------------------------------------------------------
End Sub
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
' Функция получения имени пункта меню для навигации
'-------------------------------------------------------------------------------
Function Text_menuitem_func(byval Menu_shift As Byte)as String
Local Str_text As String * 15
Select Case Menu_shift
Case 1 To 4
W_adr = W_selected_menu_item(menu_shift) + 10 ' Установить указатель DATA на метку по адресу из W_selected_menu_item(1..4) + сместить на 10 байт к полю Text
!lds R8, {W_adr} ' 1 - Next; 2 - Previous; 3 - Parent; 4 - Child;
!lds R9, {W_adr+1} '
Read Str_text ' Чтение данных Text из памяти программы
Case 6
Str_text = Str_menu_text ' Имя текущего пункта уже имеется в массиве
End Select
Text_menuitem_func = Str_text
'-------------------------------------------------------------------------------
End Function
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
' Функция получения имени пункта меню для отбражения в виде списка на LCD
'-------------------------------------------------------------------------------
Function Text_list_func(byval Cursor_shift As Integer)as String
Local I As Byte
Local K As Integer
K = Cursor_shift
For I = 1 To Con_n_index_menu_item
W_temp_menu_item(i) = W_selected_menu_item(i) ' Заполнение временного массива данными текущего пункта
Next
If W_temp_menu_item(1) = 0 Then Goto Exit_text_list_func ' Дополнительная проверка, если функция вызвана не в режиме отображения меню
If K < 0 Then ' Пункт меню над текущим, т.е. Previous
While K <> 0
W_adr = W_temp_menu_item(con_menuitem_previous) ' Получение адреса Previous относительно текущего пункта меню из временного массива
!lds R8, {W_adr} ' Установить указатель DATA на метку по адресу Previous относительно текущего пункта меню
!lds R9, {W_adr+1} '
For I = 1 To 5 ' Заполнение временного массива данными Previous пункта
Read W_temp_menu_item(i) ' Чтение 5 слов в массив
Next
Read Str_temp_menu_text ' Чтение данных Text
If Str_temp_menu_text = "" Then Exit While ' Выход из цикла, если нет данных
Incr K
Wend
End If
If K > 0 Then ' Пункт меню под текущим, т.е. Next
While K <> 0
W_adr = W_temp_menu_item(con_menuitem_next) ' Получение адреса Next относительно текущего пункта меню из временного массива
!lds R8, {W_adr} ' Установить указатель DATA на метку по адресу Next относительно текущего пункта меню
!lds R9, {W_adr+1} '
For I = 1 To 5 ' Заполнение временного массива данными Next пункта
Read W_temp_menu_item(i) ' Чтение 5 слов в массив
Next
Read Str_temp_menu_text ' Чтение данных Text
If Str_temp_menu_text = "" Then Exit While ' Выход из цикла, если нет данных
Decr K
Wend
End If
Exit_text_list_func:
Text_list_func = Str_temp_menu_text
'-------------------------------------------------------------------------------
End Function
'-------------------------------------------------------------------------------
$eeprom
Eep_parametrs:
Data 0% , 2000% , 1000% , 3000% , 2% , 1% , 0% , 1% , 0% , 5% , 5% , 5% , 0% ' Данные с 2-го байта. Адрес &H0002
$data
M_nothing: ' Нет действий в меню
Data 0% , 0% , 0% , 0% , 0% , ""
' Имя метки
' Следующий / Предыдущий / Родитель / Дочерний / Параметр / Имя пункта
' Next / Previous / Parent / Child / Parametr / Text
Menu_1:
Adr2 Menu_2 : Adr2 M_nothing : Adr2 M_nothing : Adr2 Menu_11 : Data 0% , "1. Inputs"
Menu_2:
Adr2 Menu_3 : Adr2 Menu_1 : Adr2 M_nothing : Adr2 Menu_21 : Data 0% , "2. Outputs"
Menu_3:
Adr2 Menu_4 : Adr2 Menu_2 : Adr2 M_nothing : Adr2 Menu_31 : Data 0% , "3. LED"
Menu_4:
Adr2 M_nothing : Adr2 Menu_3 : Adr2 M_nothing : Adr2 Menu_41 : Data 0% , "4. Version"
Menu_11:
Adr2 Menu_12 : Adr2 M_nothing : Adr2 Menu_1 : Adr2 Menu_111 : Data 0% , "1.1 Input 1"
Menu_12:
Adr2 Menu_13 : Adr2 Menu_11 : Adr2 Menu_1 : Adr2 Menu_121 : Data 0% , "1.2 Input 2"
Menu_13:
Adr2 M_nothing : Adr2 Menu_12 : Adr2 Menu_1 : Adr2 Menu_131 : Data 0% , "1.3 Input 3"
Menu_21:
Adr2 Menu_22 : Adr2 M_nothing : Adr2 Menu_2 : Adr2 Menu_211 : Data 0% , "2.1 Output 1"
Menu_22:
Adr2 M_nothing : Adr2 Menu_21 : Adr2 Menu_2 : Adr2 Menu_221 : Data 0% , "2.2 Output 2"
Menu_31:
Adr2 M_nothing : Adr2 M_nothing : Adr2 Menu_3 : Adr2 Menu_311 : Data 0% , "3.1 Brightness"
Menu_111:
Adr2 Menu_112 : Adr2 M_nothing : Adr2 Menu_11 : Adr2 Menu_1111 : Data 0% , "1.1.1 F nom"
Menu_112:
Adr2 Menu_113 : Adr2 Menu_111 : Adr2 Menu_11 : Adr2 Menu_1121 : Data 0% , "1.1.2 F min"
Menu_113:
Adr2 Menu_114 : Adr2 Menu_112 : Adr2 Menu_11 : Adr2 Menu_1131 : Data 0% , "1.1.3 F max"
Menu_114:
Adr2 M_nothing : Adr2 Menu_113 : Adr2 Menu_11 : Adr2 Menu_1141 : Data 0% , "1.1.4 PPR"
Menu_121:
Adr2 Menu_122 : Adr2 M_nothing : Adr2 Menu_12 : Adr2 Menu_1211 : Data 0% , "1.2.1 Enable"
Menu_122:
Adr2 M_nothing : Adr2 Menu_121 : Adr2 Menu_12 : Adr2 Menu_1221 : Data 0% , "1.2.2 Invert"
Menu_131:
Adr2 Menu_132 : Adr2 M_nothing : Adr2 Menu_13 : Adr2 Menu_1311 : Data 0% , "1.3.1 Enable"
Menu_132:
Adr2 Menu_133 : Adr2 Menu_131 : Adr2 Menu_13 : Adr2 Menu_1321 : Data 0% , "1.3.2 Invert"
Menu_133:
Adr2 M_nothing : Adr2 Menu_132 : Adr2 Menu_13 : Adr2 Menu_1331 : Data 0% , "1.3.3 Delay"
Menu_211:
Adr2 M_nothing : Adr2 M_nothing : Adr2 Menu_21 : Adr2 Menu_2111 : Data 0% , "2.1.1 Delay"
Menu_221:
Adr2 M_nothing : Adr2 M_nothing : Adr2 Menu_22 : Adr2 Menu_2211 : Data 0% , "2.2.1 Delay"
' В пунктах меню с параметрами адреса Parent и Child равны
' При отмене - возврат на адрес Parent
' При сохранении параметра - перед возвратом на адрес Parent проверка адреса параметра W_selected_menu_item(5) <> 0
' и переход в процедуру сохранения параметра
Menu_1111:
Adr2 M_nothing : Adr2 M_nothing : Adr2 Menu_111 : Adr2 Menu_111 : Data 1% , "F nom, Hz"
Menu_1121:
Adr2 M_nothing : Adr2 M_nothing : Adr2 Menu_112 : Adr2 Menu_112 : Data 2% , "F min, Hz"
Menu_1131:
Adr2 M_nothing : Adr2 M_nothing : Adr2 Menu_113 : Adr2 Menu_113 : Data 3% , "F max, Hz"
Menu_1141:
Adr2 M_nothing : Adr2 M_nothing : Adr2 Menu_114 : Adr2 Menu_114 : Data 4% , "PPR"
Menu_1211:
Adr2 M_nothing : Adr2 M_nothing : Adr2 Menu_121 : Adr2 Menu_121 : Data 5% , "Enable"
Menu_1221:
Adr2 M_nothing : Adr2 M_nothing : Adr2 Menu_122 : Adr2 Menu_122 : Data 6% , "Invert"
Menu_1311:
Adr2 M_nothing : Adr2 M_nothing : Adr2 Menu_131 : Adr2 Menu_131 : Data 7% , "Enable"
Menu_1321:
Adr2 M_nothing : Adr2 M_nothing : Adr2 Menu_132 : Adr2 Menu_132 : Data 8% , "Invert"
Menu_1331:
Adr2 M_nothing : Adr2 M_nothing : Adr2 Menu_133 : Adr2 Menu_133 : Data 9% , "Delay, s"
Menu_2111:
Adr2 M_nothing : Adr2 M_nothing : Adr2 Menu_211 : Adr2 Menu_211 : Data 10% , "Delay, s"
Menu_2211:
Adr2 M_nothing : Adr2 M_nothing : Adr2 Menu_221 : Adr2 Menu_221 : Data 11% , "Delay, s"
Menu_311:
Adr2 M_nothing : Adr2 M_nothing : Adr2 Menu_31 : Adr2 Menu_31 : Data 12% , "Brightness"
Menu_41:
Adr2 M_nothing : Adr2 M_nothing : Adr2 Menu_4 : Adr2 Menu_4 : Data 100% , "v1.0 06.2025"
Картинки из проекта:
Ссылка на проект disk.yandex.ru



