Перейти к содержанию
    

Непонятное поведение программы. MicroMenu

Всем привет. Есть проект 2012-2013 года. Небольшая партия блоков управления термоформовочными станками. Станки исправно работают круглосуточно все это время. Недавно обратились. Всплыли проблемки. Я открыл проект, и понял, что программу лучше переписать заново. Я тогда только перешёл на си. Сейчас у меня другие подходы, наработки.

Итак, столкнулся с проблемой. Меню. Давно применяю MicroMenu. Отличный вариант для МК. Других вариантов пока так и не нашел. И именно с MicroMenu вылезло непонятное поведение программы. В железе нажимаю кнопки следующий пункт, предыдущий. Если доходит до конца, до начала, несколько нажатий туда-сюда, и мк перестаёт реагировать на кнопки NEXT, PREV. На кнопку Esc реакция есть. Возврат на исходное состояние. В таблицах переходов криминала не вижу.

Сделал в лоб. Без MicroMenu. Switch-case. Все чётко работает.

Сделал тестовые куски кода. Вывод на символьный дисплей коды кнопок, счётчик пунктов, некоторые переменные, содержимое указателя на таблицу. При затыке значение счётчика пунктов при нажатии на кнопки NEXT, PREV не меняется. Коды кнопок верные. Состояние остальных переменных без криминала. Указатель на таблицу переходов показывает верные адреса. Было подозрение на срыв стека. Увеличил. Не помогло.

Проект делаю дома. IAR. Си. Сейчас я на работе. Накидываю план действий. Заменить мк. Возможен контрафакт. Раньше проблем с MicroMenu не было. Стек увеличивал. Не помогло. Куда копать дальше, пока мыслей нет.

Все остальное в программе, где используются таблицы (не micromenu) работает чётко.

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

Если проблема в стеке, то на данный момент я не знаю, в какие настройки IAR соваться.

Возможное воздействие прерываний проверил. На данный момент прерывание только одно. Timer2. Программные таймеры. В библиотеке есть два варианта работы программных таймеров. С прерыванием таймера и без. Изменений нет. Программа сбоит.

Попробую ещё поэтапно урезать проект, оставить только клавиатуру и меню.

МК ATMEGA32A.

Что подскажете?

Изменено пользователем demiurg1978

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

99.99%, что МК не виноват. А факт нажатия проблемной кнопки точно доходит до нужного места программы? Я бы для начала сделал самое простое - переключал светодиод в момент получения нужного кода кнопки соответствующей функцией MicroMenu. А потом это переключение светодиода двигал бы туда-сюда по программе от этой точки в зависимости от результата. Еще версия (более правдоподобная) - значение какого-то из счетчиков  выходит за допустимые границы и меню перестает обновляться. А кнопка ESC этот счетчик сбрасывает.

Чудес не бывает. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

К примеру, если опрос кнопок реализован как матрица - надо проверять корректность работы драйвера кнопковвода.

В частности, время задания-опроса строки-столбца напредмет емкостных х-к заряд-разряда и помех. Увеличьте таймауты на опрос/сканирование. + устранение дребезга / повторного ввода.

При очень быстром сканировании считываться может предыдущий "скан" из-за емкостей монтажа.

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

Используйте отладку (не знаю, есть ли аппаратная отладка на мегу), или вставьте свои отладочные блоки кода, которые выводят лог-статус

при неверной отработке меню.

и т д

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

Повторяю. На Switch-case все работает идеально. Но это увеличение, разбухания кода.

Есть одна мысль. Тогда, 2013 году, когда писал проект, выяснилось, что IAR некорректно выдал выхлоп на запись EEPROM у ATMEGA32, 32A. ATMEGA8535 нормально. Возможно, здесь и сейчас есть та же проблема. Проверю, отпишусь.

Сергей Борщ, приветствую! Рад видеть в обсуждении.

Изменено пользователем demiurg1978

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 часа назад, demiurg1978 сказал:

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

. . . .

Я бы перепроверил (пару-тройку раз, и еще раз) блоки кода MENU_ITEM( ) - макрос.  Там заданы "цепочки" переходов между пунктами и уровнями.

Может что-то удалили или наоборот, добавили новое, без коррекции связности пунктов. При этом компилятор может и не выдать ошибку. Тк это не ошибка для компилятора - что задал, то и получил фашист гранату.

А также почитал листинг компиляции на-предмет warning почитать. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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 все работало. А эта функция работает поверх и совершает нужные действия насильно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ааааа!!! Посыпаю голову пеплом! Банальный и беспощадный копипаст! В обработчиках кодов кнопок NEXT и PREV  у PREV стоял параметр функции NEXT. Епрст. Еклмн. Гребаный стыд и позор!

Вычислил по тестовому отображению адресов таблицы MicroMenu. Нажимая на кнопки поочерёдно NEXT и PREV адреса устанавливались при PREV как при NEXT. Полез разбираться и увидел. Матерился долго и смачно. Полночи вчерашнюю убил на разбирательство.

Исправил. Всё чётко работает. И синхронизацию процессов заодно поправил.

Благодарю за внимание, прастыте, что отвлек, побеспокоил. 🙂

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

58 минут назад, demiurg1978 сказал:

  . . . Рассинхронизация навигации по меню и Blink пунктов меню. . . .

Похоже, у Вас еще реализована "визуализация" состояния меню (на одной строке) или даже его структурный вид на многострочном дисплее.

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

Если нет отладки - выводите на UART на любую терминалку текущий статус работы Вашего кода, в виде "Go menu1", "Menu1 proceed ".

40 минут назад, demiurg1978 сказал:

Что то не так. Продолжаю разбираться.... 

Хьюстон уже охренел :crazy:

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)
 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 minutes ago, k155la3 said:

... 

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

Но, нужно аккуратно работать. Так как указатели на указатели на указатели. Я когда начал разбираться, да ещё тогда на асме писал, мой моск чуть не взорвался. Держать у уме все это. После этого я перешёл на си. Стало проще. Более объектно стало.

В MicroMenu можно использовать только один слой. Если слой будет завернут ещё в один слой, случится бесконечная рекурсия. То есть. При использовании нужно заходить в MicroMenu 1 раз. Если в callback будет ещё один вход, программа зациклится.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Видео

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;
      }
   }
}
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Как-то так. Пока черновые наброски

 

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, demiurg1978 said:

В MicroMenu можно использовать только один слой.

Я делал меню на 3 уровня.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Just now, x893 said:

... 

Речь не об уровнях меню. Уровней меню может быть сколько угодно. Главное - памяти чтобы хватило.

Речь о входе в MicroMenu. Вход должен быть только один. Зашли, вышли. Если в callback будет ещё один вход, программа зациклится.

Пример. Пусть мы зашли по CHILD, в callback будет ещё один вход по PARENT, CHILD, NEXT, PREV. Программа зациклится. Будет постоянный переход по указанному макросу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ничего не понял, но если есть голова с мозгом, то разобраться можно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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);

} 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...