demiurg1978 1 10 ноября, 2022 Опубликовано 10 ноября, 2022 (изменено) · Жалоба Всем привет. Есть проект 2012-2013 года. Небольшая партия блоков управления термоформовочными станками. Станки исправно работают круглосуточно все это время. Недавно обратились. Всплыли проблемки. Я открыл проект, и понял, что программу лучше переписать заново. Я тогда только перешёл на си. Сейчас у меня другие подходы, наработки. Итак, столкнулся с проблемой. Меню. Давно применяю MicroMenu. Отличный вариант для МК. Других вариантов пока так и не нашел. И именно с MicroMenu вылезло непонятное поведение программы. В железе нажимаю кнопки следующий пункт, предыдущий. Если доходит до конца, до начала, несколько нажатий туда-сюда, и мк перестаёт реагировать на кнопки NEXT, PREV. На кнопку Esc реакция есть. Возврат на исходное состояние. В таблицах переходов криминала не вижу. Сделал в лоб. Без MicroMenu. Switch-case. Все чётко работает. Сделал тестовые куски кода. Вывод на символьный дисплей коды кнопок, счётчик пунктов, некоторые переменные, содержимое указателя на таблицу. При затыке значение счётчика пунктов при нажатии на кнопки NEXT, PREV не меняется. Коды кнопок верные. Состояние остальных переменных без криминала. Указатель на таблицу переходов показывает верные адреса. Было подозрение на срыв стека. Увеличил. Не помогло. Проект делаю дома. IAR. Си. Сейчас я на работе. Накидываю план действий. Заменить мк. Возможен контрафакт. Раньше проблем с MicroMenu не было. Стек увеличивал. Не помогло. Куда копать дальше, пока мыслей нет. Все остальное в программе, где используются таблицы (не micromenu) работает чётко. Вечером проверю питание. Фьюзы контроля питания, заменю мк. Также попробую использовать обычные таблицы. Если проблема в стеке, то на данный момент я не знаю, в какие настройки IAR соваться. Возможное воздействие прерываний проверил. На данный момент прерывание только одно. Timer2. Программные таймеры. В библиотеке есть два варианта работы программных таймеров. С прерыванием таймера и без. Изменений нет. Программа сбоит. Попробую ещё поэтапно урезать проект, оставить только клавиатуру и меню. МК ATMEGA32A. Что подскажете? Изменено 10 ноября, 2022 пользователем demiurg1978 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 10 ноября, 2022 Опубликовано 10 ноября, 2022 · Жалоба 99.99%, что МК не виноват. А факт нажатия проблемной кнопки точно доходит до нужного места программы? Я бы для начала сделал самое простое - переключал светодиод в момент получения нужного кода кнопки соответствующей функцией MicroMenu. А потом это переключение светодиода двигал бы туда-сюда по программе от этой точки в зависимости от результата. Еще версия (более правдоподобная) - значение какого-то из счетчиков выходит за допустимые границы и меню перестает обновляться. А кнопка ESC этот счетчик сбрасывает. Чудес не бывает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
k155la3 27 10 ноября, 2022 Опубликовано 10 ноября, 2022 · Жалоба Для начала исключите возможные аппаратные проблемы. К примеру, если опрос кнопок реализован как матрица - надо проверять корректность работы драйвера кнопковвода. В частности, время задания-опроса строки-столбца напредмет емкостных х-к заряд-разряда и помех. Увеличьте таймауты на опрос/сканирование. + устранение дребезга / повторного ввода. При очень быстром сканировании считываться может предыдущий "скан" из-за емкостей монтажа. Если кнопки работают напрямую, по опросу - смотрите дребезг, возможно меню залипает по причине двойной обработки из-за дребезга. Используйте отладку (не знаю, есть ли аппаратная отладка на мегу), или вставьте свои отладочные блоки кода, которые выводят лог-статус при неверной отработке меню. и т д Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg1978 1 10 ноября, 2022 Опубликовано 10 ноября, 2022 (изменено) · Жалоба Все что может меняться, я вывел на дисплей. Коды кнопок и все остальное выводится в требуемом состоянии конечного автомата. Все выводимые переменные показывают корректные данные. Возможно, что то упустил. Сегодня буду дальше ковырять. Аппаратных средств отладки мк на данный момент нет. Всё эти годы все косяки и ошибки выявлял в симуляторе AVR Studio, текстовыми кусками кода. Окончательный прогон на железе. Повторяю. На Switch-case все работает идеально. Но это увеличение, разбухания кода. Есть одна мысль. Тогда, 2013 году, когда писал проект, выяснилось, что IAR некорректно выдал выхлоп на запись EEPROM у ATMEGA32, 32A. ATMEGA8535 нормально. Возможно, здесь и сейчас есть та же проблема. Проверю, отпишусь. Сергей Борщ, приветствую! Рад видеть в обсуждении. Изменено 10 ноября, 2022 пользователем demiurg1978 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
k155la3 27 10 ноября, 2022 Опубликовано 10 ноября, 2022 · Жалоба 3 часа назад, demiurg1978 сказал: . . . . Все выводимые переменные показывают корректные данные. Возможно, что то упустил. Сегодня буду дальше ковырять. . . . . Я бы перепроверил (пару-тройку раз, и еще раз) блоки кода MENU_ITEM( ) - макрос. Там заданы "цепочки" переходов между пунктами и уровнями. Может что-то удалили или наоборот, добавили новое, без коррекции связности пунктов. При этом компилятор может и не выдать ошибку. Тк это не ошибка для компилятора - что задал, то и получил фашист гранату. А также почитал листинг компиляции на-предмет warning почитать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg1978 1 10 ноября, 2022 Опубликовано 10 ноября, 2022 · Жалоба 1 hour ago, k155la3 said: ... Отчёт. У меня используются в этих блоках управления ионисторы. Алгоритм работы: при подаче питания считываются параметры из EEPROM SRAM. На питании 24 вольта стоит оптрон. Когда питание сняли, за счёт ёмкостей блока питания мк успевает определить, что снято питание 24 V, переходит в урезанный цикл, и за счёт ионистора перегоняет все параметры в EEPROM. Из за ионистора и пониженного напряжения фьюзы BODEN нужно выставить 2,7 вольта. Проверил. Есть. Заменил МК на ATMEGA8535. Такая же картина. Перенастроил сторожевой на 2 с. Мало ли, вдруг где то зациклился. Хотя не вариант. Точно этого не может быть. Системный тик 1 мс. Но мало ли. Не помогло. Урезал проект до минимума. Не помогло. И тут я понял. Рассинхронизация программных модулей. Ведь по кнопке ESC возврат в исходное происходит исправно. И по нажатию ENTER заходит. Рассинхронизация навигации по меню и Blink пунктов меню. С MicroMenu я сделал общую функцию опроса кодов кнопок и действий. И эта функция работает поверх КА меню. А если Switch-case, то это в нужных состояниях. И потому со Switch-case все работало. А эта функция работает поверх и совершает нужные действия насильно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg1978 1 10 ноября, 2022 Опубликовано 10 ноября, 2022 · Жалоба Что то не так. Продолжаю разбираться.... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg1978 1 10 ноября, 2022 Опубликовано 10 ноября, 2022 · Жалоба Ааааа!!! Посыпаю голову пеплом! Банальный и беспощадный копипаст! В обработчиках кодов кнопок NEXT и PREV у PREV стоял параметр функции NEXT. Епрст. Еклмн. Гребаный стыд и позор! Вычислил по тестовому отображению адресов таблицы MicroMenu. Нажимая на кнопки поочерёдно NEXT и PREV адреса устанавливались при PREV как при NEXT. Полез разбираться и увидел. Матерился долго и смачно. Полночи вчерашнюю убил на разбирательство. Исправил. Всё чётко работает. И синхронизацию процессов заодно поправил. Благодарю за внимание, прастыте, что отвлек, побеспокоил. 🙂 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
k155la3 27 10 ноября, 2022 Опубликовано 10 ноября, 2022 · Жалоба 58 минут назад, demiurg1978 сказал: . . . Рассинхронизация навигации по меню и Blink пунктов меню. . . . Похоже, у Вас еще реализована "визуализация" состояния меню (на одной строке) или даже его структурный вид на многострочном дисплее. Есть такая гипотеза, что само микро-меню работает нормально, а проблемы с кодом визуализации. Если нет отладки - выводите на UART на любую терминалку текущий статус работы Вашего кода, в виде "Go menu1", "Menu1 proceed ". 40 минут назад, demiurg1978 сказал: Что то не так. Продолжаю разбираться.... Хьюстон уже охренел 7 минут назад, demiurg1978 сказал: . . . . обработчиках кодов кнопок NEXT и PREV у PREV стоял параметр функции NEXT. . . . . Это что, здесь ? /** Relative navigational menu entry for \ref Menu_Navigate(), to move to the previous linked menu item. */ #define MENU_PREVIOUS MENU_ITEM_READ_POINTER(&Menu_GetCurrentMenu()->Previous) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg1978 1 10 ноября, 2022 Опубликовано 10 ноября, 2022 · Жалоба 4 minutes ago, k155la3 said: ... В очередной раз убеждаюсь, что на данный момент лучше MicroMenu пока ничего нет. Но, нужно аккуратно работать. Так как указатели на указатели на указатели. Я когда начал разбираться, да ещё тогда на асме писал, мой моск чуть не взорвался. Держать у уме все это. После этого я перешёл на си. Стало проще. Более объектно стало. В MicroMenu можно использовать только один слой. Если слой будет завернут ещё в один слой, случится бесконечная рекурсия. То есть. При использовании нужно заходить в MicroMenu 1 раз. Если в callback будет ещё один вход, программа зациклится. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg1978 1 10 ноября, 2022 Опубликовано 10 ноября, 2022 · Жалоба Видео Spoiler //======================================================================== #ifndef MENU_H #define MENU_H #include "menu.h" #include "main_def_func.h" //======================================================================== //======================================================================== // Typedefs: typedef void (*FuncPtr)(void); //======================================================================== //======================================================================== typedef struct menu_item { void *Parent; void *Child; void *Next; void *Prev; FuncPtr EnterFunc; FuncPtr PlusFunc; FuncPtr MinusFunc; FuncPtr MenuInitFunc; char __flash *Text; } menu_item; //======================================================================== // Externs: //======================================================================== extern menu_item __flash Null_Menu; //======================================================================== // Defines and Macros: //======================================================================== #define NULL_ENTRY Null_Menu #define NULL_FUNC (void*)0 #define NULL_TEXT "" //======================================================================== //======================================================================== #define MAKE_MENU(Name, Parent, Child, Next, Prev, EnterFunc, PlusFunc, MinusFunc, MenuInitFunc, Text) \ extern menu_item __flash Parent; \ extern menu_item __flash Child; \ extern menu_item __flash Next; \ extern menu_item __flash Prev; \ menu_item __flash Name = \ { \ (menu_item*) &Parent, \ (menu_item*) &Child, \ (menu_item*) &Next, \ (menu_item*) &Prev, \ EnterFunc, \ PlusFunc, \ MinusFunc, \ MenuInitFunc, \ {Text} \ } //======================================================================== //======================================================================== #define PARENT *((menu_item __flash*) (CurrMenuItem->Parent)) #define CHILD *((menu_item __flash*) (CurrMenuItem->Child)) #define NEXT *((menu_item __flash*) (CurrMenuItem->Next)) #define PREV *((menu_item __flash*) (CurrMenuItem->Prev)) #define ENTER_FUNC *((FuncPtr) (CurrMenuItem->EnterFunc)) #define PLUS_FUNC *((FuncPtr) (CurrMenuItem->PlusFunc)) #define MINUS_FUNC *((FuncPtr) (CurrMenuItem->MinusFunc)) #define MENU_INIT_FUNC *((FuncPtr) (CurrMenuItem->MenuInitFunc)) //======================================================================== //======================================================================== #define SET_MENU_LEVEL(x) \ Set_Menu_Level(&x) #define SET_MENU_ITEM(x) \ Set_Menu_Item(&x) #define GO_MENU_FUNC(x) \ MenuFunc((FuncPtr*)&x) #define EXTERN_MENU(Name) \ extern menu_item __flash Name; //======================================================================== // Prototypes: //======================================================================== bool Set_Menu_Level (menu_item __flash *NewMenu); bool Set_Menu_Item (menu_item __flash *NewMenu); bool MenuFunc (FuncPtr* Function); //======================================================================== //======================================================================== bool proc_menu_keys (void); //======================================================================== //======================================================================== u08 Get_Quant_Items (void); //======================================================================== //======================================================================== menu_item __flash * Get_CurrMenuItem (void); //======================================================================== #endif Spoiler //======================================================================== #include "menu.h" //======================================================================== //======================================================================== static u08 quant_items; //======================================================================== //============================================================================================================================================== static menu_item __flash *CurrMenuItem; // Текущий пункт меню. menu_item __flash Null_Menu = {(void*)0, (void*)0, (void*)0, (void*)0, NULL_FUNC, NULL_FUNC, NULL_FUNC, NULL_FUNC, NULL_TEXT}; //============================================================================================================================================== //======================================================================== bool Set_Menu_Level (menu_item __flash *NewMenu) { if ((void*)NewMenu == (void*)&NULL_ENTRY) return false; else { CurrMenuItem = NewMenu; GO_MENU_FUNC (MENU_INIT_FUNC); return true; } } //======================================================================== //======================================================================== bool Set_Menu_Item (menu_item __flash *NewMenu) { if ((void*)NewMenu == (void*)&NULL_ENTRY) return false; else { CurrMenuItem = NewMenu; GO_MENU_FUNC (MENU_INIT_FUNC); return true; } } //======================================================================== //======================================================================== bool MenuFunc (FuncPtr* Function) { if ((void*) Function == (void*) NULL_FUNC) return false; else { ((FuncPtr) Function)(); return true; } } //======================================================================== //======================================================================== //--------------------- Навигация по меню. ------------------------------- // Кнопки: // Esc. Выход из меню. Переход на родительский уровень. Отмена. // Enter. Вход в меню. Переход на пункт меню. Вход в режим редактирования параметра. Сохранение параметра. // Plus. Следующий пункт меню. Изменение параметра. Увеличить значение параметра. // Minus. Предыдущий пункт меню. Изменение параметра. Уменьшить значение параметра. //------------------------------------------------------------------------ // Esc. Parent Level. // Enter. Child Level. Func. // Plus. Next Item. Func. // Minus. Prev Item. Func. //------------------------------------------------------------------------ bool proc_menu_keys (void) { bool a = false; if (Get_Event (EV_ID_KEY_PRESSED)) { switch (Get_Key_Code ()) { case KEY_ESC_COD: if (SET_MENU_LEVEL (PARENT)) a = true; break; case KEY_ENTER_COD: if (CurrMenuItem -> EnterFunc != NULL_FUNC) { GO_MENU_FUNC (ENTER_FUNC); a = true; } if (SET_MENU_LEVEL (CHILD)) a = true; break; case KEY_NEXT_COD: if (SET_MENU_ITEM (NEXT)) { inc_cnt_blink_str (); a = true; } break; case KEY_PREV_COD: if (SET_MENU_ITEM (PREV)) { dec_cnt_blink_str (); a = true; } break; case KEY_PLUS_COD: if (CurrMenuItem -> PlusFunc != NULL_FUNC) { GO_MENU_FUNC (PLUS_FUNC); a = true; } break; case KEY_MINUS_COD: if (CurrMenuItem -> MinusFunc != NULL_FUNC) { GO_MENU_FUNC (MINUS_FUNC); a = true; } break; } } return a; } //======================================================================== //======================================================================== u08 Get_Quant_Items (void) { return quant_items; } //======================================================================== //======================================================================== menu_item __flash * Get_CurrMenuItem (void) { return CurrMenuItem; } //======================================================================== Spoiler //======================================================================================================================================================================================================================================================= // NAME PARENT CHILD NEXT PREV PLUS_FUNC MINUS_FUNC ENTER_FUNC MENU_INIT_FUNC TEXT //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- MAKE_MENU (L_OUT_MODE, NULL_ENTRY, L1_L1_I1, NULL_ENTRY, NULL_ENTRY, NULL_FUNC, NULL_FUNC, NULL_FUNC, Info_Service_Default_Init, NULL_TEXT); //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- MAKE_MENU (L1_L1_I1, L_OUT_MODE, NULL_ENTRY, L1_L1_I2, NULL_ENTRY, NULL_FUNC, NULL_FUNC, NULL_FUNC, Change_Main_Parameters_Init, NULL_TEXT); MAKE_MENU (L1_L1_I2, L_OUT_MODE, NULL_ENTRY, L1_L1_I3, L1_L1_I1, NULL_FUNC, NULL_FUNC, NULL_FUNC, Change_Main_Parameters_Init, NULL_TEXT); MAKE_MENU (L1_L1_I3, L_OUT_MODE, NULL_ENTRY, L1_L1_I4, L1_L1_I2, NULL_FUNC, NULL_FUNC, NULL_FUNC, Change_Main_Parameters_Init, NULL_TEXT); MAKE_MENU (L1_L1_I4, L_OUT_MODE, NULL_ENTRY, L1_L1_I5, L1_L1_I3, NULL_FUNC, NULL_FUNC, NULL_FUNC, Change_Main_Parameters_Init, NULL_TEXT); MAKE_MENU (L1_L1_I5, L_OUT_MODE, NULL_ENTRY, L1_L1_I6, L1_L1_I4, NULL_FUNC, NULL_FUNC, NULL_FUNC, Change_Main_Parameters_Init, NULL_TEXT); MAKE_MENU (L1_L1_I6, L_OUT_MODE, NULL_ENTRY, NULL_ENTRY, L1_L1_I5, NULL_FUNC, NULL_FUNC, NULL_FUNC, Change_Main_Parameters_Init, NULL_TEXT); //======================================================================================================================================================================================================================================================= Spoiler //======================================================================== EXTERN_MENU (L_OUT_MODE); //======================================================================== //======================================================================== static info_service_t _info_service; static u08 _info_service_slave; static soft_timer_t ST_PROC_INFO_SERVICE; static soft_timer_t ST_BLINK_ITEM; static bool blink_str_flag; static u08 cnt_blink_str; __flash FUNC info_service_func [INFO_SERVICE_STATES] = { #define STATE(name, func) func, #include "_info_service.h" #undef STATE }; void Info_Service (void) { Kbd_Drv (); Proc_Fsm_Func (info_service_func, _info_service); } //======================================================================== //======================================================================== void Info_Service_Init (void) { if (Get_Event (EV_ID_CHAR_DSP_RUN)) { SET_MENU_LEVEL (L_OUT_MODE); Info_Service_Default_Init (); } } //------------------------------------------------------------------------ void Info_Service_Default_Init (void) { _info_service = INFO_SERVICE_DEFAULT; _info_service_slave = 0; } //------------------------------------------------------------------------ void Change_Main_Parameters_Init (void) { Set_Soft_Timer (ST_PROC_INFO_SERVICE, 0, 25); // Перезапуск обновления дисплея. Set_Soft_Timer (ST_BLINK_ITEM, 0, 500); _info_service_slave = 1; } //------------------------------------------------------------------------ void Info_Service_Default (void) { static u08 cnt_debug; // !!!!!!!!!!!!!!!! Шаги тестов !!!!!!!!!!!!!!!!!!!!! if (proc_menu_keys ()) return; switch (_info_service_slave) { case 0: Clr_Dsp_Buf (); Set_Soft_Timer (ST_PROC_INFO_SERVICE, 0, 25); Reset_Soft_Timer (ST_BLINK_ITEM); blink_str_flag = false; cnt_blink_str = 0; _info_service_slave = 1; break; case 1: break; case 2: break; case 3: break; case 4: Show_State_All_Inputs (); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! break; } if (Handle_Soft_Timer (ST_BLINK_ITEM)) { if (!blink_str_flag) blink_str_flag = true; else blink_str_flag = false; } if (Handle_Soft_Timer (ST_PROC_INFO_SERVICE)) { Clr_Dsp_Buf (); Show_Mode (); Show_Parameters (); show_addr (Get_Keys_Curr (), 1, 1); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! if (!blink_str_flag) // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Print_Char (1, 4, ARROW_RIGHT); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! else // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Print_Char (1, 4, ARROW_LEFT); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! u16 a = (u16) Get_CurrMenuItem (); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! u08 b = (a >> 8); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! show_addr (b, 1, 14); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! a = (u16) Get_CurrMenuItem (); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! b = (a & 0x00FF); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! show_addr (b, 1, 16); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Print_u08 (1, 18, cnt_blink_str); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! } } //======================================================================== //======================================================================== void Menu_Init (void) { _info_service = INFO_SERVICE_OUT_MENU; _info_service_slave = 0; } //======================================================================== //======================================================================== void Info_Service_Out_Menu (void) { } //======================================================================== //======================================================================== void Info_Service_Emerg_Mode_Init (void) { Clr_Dsp_Buf (); _info_service = INFO_SERVICE_EMERG_MODE; _info_service_slave = 0; } //------------------------------------------------------------------------ void Info_Service_Emerg_Mode (void) { } //======================================================================== //======================================================================== void Show_Mode (void) { switch (Get_Proc_Eds_Mode ()) { case MODE_STOP: Clr_sStatus (); Print_Buf (sStatus, 9, "СТОП"); break; case MODE_MANUAL: Clr_sStatus (); Print_Buf (sStatus, 8, "НАЛАДКА"); break; case MODE_AUTOMAT: Clr_sStatus (); Print_Buf (sStatus, 8, "АВТОМАТ"); break; case MODE_STOPPING: Clr_sStatus (); Print_Buf (sStatus, 7, "ОСТАНОВКА"); break; case MODE_EMERG_STOP: Clr_sStatus (); Print_Buf (sStatus, 4, "АВАРИЙНЫЙ СТОП!"); break; } } //======================================================================== //======================================================================== void Show_Parameters (void) { bool flag = false; for (u08 i = 0; i < QTY_WORK_PARAMETERS; i++) { if ((blink_str_flag) && (i == cnt_blink_str)) flag = true; else flag = false; switch (i) { case 0: Show_Heat (flag); // Нагрев break; case 1: Show_Formovka (flag); // Формовка break; case 2: Show_Pnevmosyem (flag); // Пневмосъем break; case 3: Show_Tirag (flag); // Тираж break; case 4: Show_Curr_Quant (flag); // Счетчик изделий. break; case 5: Show_Part (flag); // Партия break; } } } //======================================================================== //======================================================================== void Show_Heat (bool f) // Нагрев { if (!f) Print_Buf (2, 1, "НАГР"); else Set_Str (2, 1, 4, ' '); Print_Val_xx_x (2, 6, tim_heat_val); } //======================================================================== //======================================================================== void Show_Formovka (bool f) // Формовка { if (!f) Print_Buf (3, 1, "ФОРМ"); else Set_Str (3, 1, 4, ' '); Print_Val_xx_x (3, 6, tim_formovka_val); } //======================================================================== //======================================================================== void Show_Pnevmosyem (bool f) { if (!f) Print_Buf (4, 1, "ПНЕВ"); else Set_Str (4, 1, 4, ' '); Print_Val_xx_x (4, 6, tim_pnevmosyem_val); } //======================================================================== //======================================================================== void Show_Tirag (bool f) { if (!f) Print_Buf (2, 11, "УСТ"); else Set_Str (2, 11, 3, ' '); Print_Val_xxxxxx (2, 15, sett_quant); } //======================================================================== //======================================================================== void Show_Curr_Quant (bool f) { if (!f) Print_Buf (3, 11, "ТЕК"); else Set_Str (3, 11, 3, ' '); Print_Val_xxxxxx (3, 15, curr_quant); } //======================================================================== //======================================================================== void Show_Part (bool f) { if (!f) Print_Buf (4, 11, "ПАР"); else Set_Str (4, 11, 3, ' '); Print_Val_xxxx (4, 17, quant_products); } //======================================================================== //======================================================================== void inc_cnt_blink_str (void) { if (cnt_blink_str < 5) cnt_blink_str++; } void dec_cnt_blink_str (void) { if (cnt_blink_str) cnt_blink_str--; } //======================================================================== // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void Show_State_All_Inputs (void) { u08 *ptr_1 = inputs_buf; char *ptr_2; for (u08 cnt_bytes = 0; cnt_bytes < IN_OUT_BYTES; cnt_bytes++) { switch (cnt_bytes) { case 0: ptr_2 = dsp_buf + (((1)-1)*POSITION_MAX_X+((1)-1)); break; case 1: ptr_2 = dsp_buf + (((2)-1)*POSITION_MAX_X+((1)-1)); break; case 2: ptr_2 = dsp_buf + (((3)-1)*POSITION_MAX_X+((1)-1)); break; } u08 a = *ptr_1++; for (u08 cnt_bits = 0; cnt_bits < 8; cnt_bits++) { if (a & (1<<0)) *ptr_2++ = '1'; else *ptr_2++ = '0'; a >>= 1; } } } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Как-то так. Пока черновые наброски Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
x893 60 10 ноября, 2022 Опубликовано 10 ноября, 2022 · Жалоба 1 hour ago, demiurg1978 said: В MicroMenu можно использовать только один слой. Я делал меню на 3 уровня. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg1978 1 10 ноября, 2022 Опубликовано 10 ноября, 2022 · Жалоба Just now, x893 said: ... Речь не об уровнях меню. Уровней меню может быть сколько угодно. Главное - памяти чтобы хватило. Речь о входе в MicroMenu. Вход должен быть только один. Зашли, вышли. Если в callback будет ещё один вход, программа зациклится. Пример. Пусть мы зашли по CHILD, в callback будет ещё один вход по PARENT, CHILD, NEXT, PREV. Программа зациклится. Будет постоянный переход по указанному макросу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
x893 60 10 ноября, 2022 Опубликовано 10 ноября, 2022 · Жалоба Ничего не понял, но если есть голова с мозгом, то разобраться можно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg1978 1 10 ноября, 2022 Опубликовано 10 ноября, 2022 · Жалоба 9 minutes ago, x893 said: ... case KEY_ENTER_COD: if (CurrMenuItem -> EnterFunc != NULL_FUNC) { GO_MENU_FUNC (ENTER_FUNC); a = true; } if (SET_MENU_LEVEL (CHILD)) a = true; break; void Callback_Func (void) { SET_MENU_LEVEL (KAKOE_TO_MENU); } В этом случае будет рекурсия. Скажу честно, не разбирался с этой особенностью. Просто учитываю этот нюанс. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться