реклама на сайте
подробности

 
 
18 страниц V  < 1 2 3 4 5 > »   
Reply to this topicStart new topic
> Начало работы with scmRTOS, Несколько вопросиков
Сергей Борщ
сообщение Mar 10 2008, 16:52
Сообщение #31


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(alux @ Mar 10 2008, 18:00) *
Но это же за уши притянуто.. Хочется принципиально для себя решить этот вопрос.
Увы, IAR и GCC несколько по-разному описывают регистры:
Код
GCC:
#define _SFR_IO8(io_addr) ((io_addr) + __SFR_OFFSET)
#define TIMSK0  _SFR_MEM8 (0x6E)
IAR:
#define SFR_B_N(_ADDR, _NAME, _B7, _B6, _B5, _B4, _B3, _B2, _B1, _B0) \
                 SFR_B_BITS_N(_NAME, _ADDR, \
                              Bit0,Bit1,Bit2,Bit3,Bit4,Bit5,Bit6,Bit7, \
                              _B0,_B1,_B2,_B3,_B4,_B5,_B6,_B7)
#define SFR_B_BITS_N(_NAME, _ADDR, _A,_B,_C,_D,_E,_F,_G,_H, \
                                   _A2,_B2,_C2,_D2,_E2,_F2,_G2,_H2) \
    __io union { \
      unsigned char   _NAME;           /* The sfrb as 1 byte */ \
      struct {                        /* The sfrb as 8 bits */ \
        __BYTEBITS(_NAME, _A,_B,_C,_D,_E,_F,_G,_H) \
      };  \
      struct {                        /* The sfrb as 8 bits */ \
        __BYTEBITS(_NAME, _A2,_B2,_C2,_D2,_E2,_F2,_G2,_H2) \
      };  \
    } @ _ADDR;SFR_B_N(0x6E,TIMSK0,Dummy7,Dummy6,Dummy5,Dummy4,Dummy3,OCIE0B,OCIE0A,TOIE0)
Поэтому в GCC можно использовать #ifdef к именам регистров, а в IAR - увы, нет. Поэтому вам проще всего выкинуть лишние строчки условий и оставить только
Код
#define SPM_CONTROL_REG SPMCSR
#define TIMSK TIMSK0
или заменить SPM_CONTROL_REG на SPMCSR и TIMSK на TIMSK0 дальше в исходнике.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
alux
сообщение Mar 11 2008, 12:37
Сообщение #32


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Возникло пару вопросов. Допустим, есть три процесса: KeyMenu, EditTime, Blink. Порядок работы должен быть такой :
1) KeyMenu - навигация по пунктам меню. На этом этапе остальные два процесса находятся в ожидании.
2) Заходим в пункт меню "Настройка -> Время". После нажатия ENTER запускается функция, которая считывает время с RTC в переменные и выводит эти значения на ЖКИ. После этого необходимо запустить процессы EditTime и Blink. При этом необходимо перевести KeyMenu в ожидание, пока работают эти процессы. Процесс Blink - это просто инвертирование текущего знакоместа с периодом 1 сек.
3) После окончания ввода времени, EditTime и Blink снова переводятся в ожидание, а KeyMenu переходит в состояние готовности.

Первый вопрос. Как это лучше организовать?
И второй вопрос скорее по C++. Мой проект состоит из нескольких С-файлов. В tasks.c я вынес все процессы и объявления объектов. Как в другом С-файле использовать методы объекта?

PS. В другом С-файле, в котором необходимо вызвать ef.Signal(); просто объявил extern OS::TEventFlag ef; как это обычно делается с переменными и компилятора это устроило, хотя в учебнике С++ сказано, что данные-члены не могут определятся с модификаторами auto, extern, register
Go to the top of the page
 
+Quote Post
dxp
сообщение Mar 11 2008, 14:03
Сообщение #33


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(alux @ Mar 11 2008, 18:37) *
И второй вопрос скорее по C++. Мой проект состоит из нескольких С-файлов. В tasks.c я вынес все процессы и объявления объектов. Как в другом С-файле использовать методы объекта?

В каком-нибудь загововке, который всем виден:

Код
typedef OS::process<OS::pr0, 768>  TMainProc;
typedef OS::process<OS::pr1, 768>  TFPGAProc;
typedef OS::process<OS::pr2, 1024> TControlsProc;
typedef OS::process<OS::pr3, 1024> TGUIProc;

extern TMainProc     MainProc;
extern TFPGAProc     FPGAProc;
extern TControlsProc ControlsProc;
extern TGUIProc      GUIProc;


В исходных файлах объявить сами объекты:

Код
TMainProc     MainProc;
...
TFPGAProc     FPGAProc;
...



Цитата(alux @ Mar 11 2008, 18:37) *
PS. В другом С-файле, в котором необходимо вызвать ef.Signal(); просто объявил extern OS::TEventFlag ef; как это обычно делается с переменными и компилятора это устроило, хотя в учебнике С++ сказано, что данные-члены не могут определятся с модификаторами auto, extern, register


extern OS::TEventFlag ef;

где тут данное-член? И вообще, где тут член класса? Тут объект ef типа OS::TEventFlag объявлен как extern. Все в норме.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 11 2008, 16:48
Сообщение #34


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(alux @ Mar 11 2008, 14:37) *
3) После окончания ввода времени, EditTime и Blink снова переводятся в ожидание, а KeyMenu переходит в состояние готовности.
А смысл делать EditTime отдельным процессом? Мне кажется он просится функцией (возможно - функцией-членом класса TTimer), вызываемой из KeyMenu, но никак не отдельным процессом. Что касается Blink - он может ожидать некое сообщение (скажем, BLINK_ON) и получив его - мигать, пока не получит сообщение BLINK_OFF. Он может также получать сообщения SHORT_FLASH (одна короткая вспышка), LONG_FLASH (одна длинная вспышка) и другие, или сообщение может представлять из себя структуру, в которой записаны частота мигания, скважность, длительность.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
alux
сообщение Mar 11 2008, 20:31
Сообщение #35


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Цитата(Сергей Борщ @ Mar 11 2008, 20:48) *
А смысл делать EditTime отдельным процессом? Мне кажется он просится функцией (возможно - функцией-членом класса TTimer), вызываемой из KeyMenu, но никак не отдельным процессом.

Так изначально у меня ф-ция EditTime вызывалась из функции пункта меню "Настройка -> Время" . В этой ф-ции в вечном цикле опрашивались кнопки и происходило редактирование времени. Естественно, контроллер больше ничего не делал, кроме прерываний. Только ждал нажатия ESC, которое вывело бы его из вечного цикла. Это было до использования ОС. Поэтому я решил сделать EditTime отдельным процессом. Scan_code нажатой кнопки получаю в прерывании таймера 2, который запускается в обработчике внешнего прерывания от нажатия кнопки.
Код
OS_PROCESS void TKeyMenu::Exec()    
{
  for(;;)
  {
    if(key_code.scan & KEY_PRESSED)
    {
      key_code.scan &= (0xff-KEY_PRESSED);   // Clear MSB of scan_code (key_pressed)
    
      switch(key_code.scan)      
      {
         case UP:
              SET_MENU(PREVIOUS);
              break;
         case DOWN:
              SET_MENU(NEXT);
              break;
         case LEFT:
              SET_MENU(PARENT);
              break;
         case RIGHT:
              SET_MENU(SIBLING);
              break;
      }
    }
    Sleep(10);
  }
}

//-----------------------------------------------------
OS_PROCESS void TEditTime::Exec()  
{
  for(;;)
  {
    ef.Wait();
    
    if(key_code.scan & KEY_PRESSED)
    {
      key_code.scan &= (0xff-KEY_PRESSED);   // Clear MSB of scan_code (key_pressed)
    
      switch(key_code.scan)    
      {
        case LEFT:        //k_esc
             // выйти из редактирования. Возврат к предыдущему пункту меню
             break;
            
        case RIGHT:       //k_enter
            // переход к следующему параметру
             break;
            
        case DOWN:        //k_left
            // перевод курсор на один символ влево
             break;
            
        case UP:          //k_right
             // перевод курсора на один символ вправо
             break;  
            
        default:          // 0...9
             //цифровые кнопки
             break;            
      }
    }
    Sleep(3);
  }
}

//---------------------------------------------------------------------------
OS_PROCESS void TBlink::Exec()    
{
    for(;;)
    {
      ef.Wait();
      ks0108InvertRect(x, y, w, 9);
      Sleep(500);
    }
}
EditTime и Blink ждут сигнала от функции, которая вызывается при входе в пункт меню. Это мой первый опыт работы с ОС. Предложите что-нибудь лучше. А что такое функция-член класса TTimer ? Можно поподробней? Желательно с примером. Заранее спасибо.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 11 2008, 22:31
Сообщение #36


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(alux @ Mar 11 2008, 22:31) *
Так изначально у меня ф-ция EditTime вызывалась из функции пункта меню "Настройка -> Время" . В этой ф-ции в вечном цикле опрашивались кнопки и происходило редактирование времени. Естественно, контроллер больше ничего не делал, кроме прерываний... Поэтому я решил сделать EditTime отдельным процессом.
Так ведь и теперь у вас он во время EditTime не делает ничего в TKeyMenu. При этом у вас получилось, что EditTime работает изредка, а память под свой стек занимает всегда. Если бы вы сделали его функцией и вызывали из TKeyMenu - в остальное время этот стек мог бы быть использован другими частями TKeyMenu.
Цитата(alux @ Mar 11 2008, 22:31) *
А что такое функция-член класса TTimer ? Можно поподробней?
Это я прочитал рекомендовавшуюся здесь книжку Гради Буча "Объектно-ориентированный анализ и проектирование" и пытаюсь применять полученные там знания. Он рекомендует вычленять в предметной области законченные абстракции и облекать их в вид классов. Вот у вас в системе судя по описанию есть некие часы, которые можно выделить в отдельную абстракцию. Они умеют считать время, их можно спросить "который час", их можно установить. Их можно реализовать в виде класса (обозвать его TTimer), который будет иметь только две открытые функции GetTime(), SetTime(). Внутрь этого класса спрятать (сделать private) счетчик времени и тем самым гарантировать, что никто его случайно не испортит - только вызвав явно SetTime(). Применяя в системе разные внешние микросхемы часов или программные часы, вам придется переписать только реализацию этого класса, вся остальная часть программы не будет зависеть от физической реализации часов.
Вот изложил все это и понял, что функция EditTime имеет отношение скорее к интерфейсу пользователя, чем к часам, ее нет смысла делать членом класса TTimer, скорее она должна в конце своей работы вызвать SetTime().


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
alux
сообщение Mar 12 2008, 06:48
Сообщение #37


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Цитата(Сергей Борщ @ Mar 12 2008, 02:31) *
Так ведь и теперь у вас он во время EditTime не делает ничего в TKeyMenu. При этом у вас получилось, что EditTime работает изредка, а память под свой стек занимает всегда. Если бы вы сделали его функцией и вызывали из TKeyMenu - в остальное время этот стек мог бы быть использован другими частями TKeyMenu.
Согласен. Мой способ мне самому не нравится. Процессов не хватит на каждый пункт меню. В TEditTime и TKeyMenu используются одинаковые конструкции
Код
  for(;;)
  {
    if(key_code.scan & KEY_PRESSED)
    {
      key_code.scan &= (0xff-KEY_PRESSED);   // Clear MSB of scan_code (key_pressed)
    
      switch(key_code.scan)      
      {
         case UP:
              .........
              break;
         case DOWN:
              .........
              break;
         case LEFT:
              .........
              break;
         case RIGHT:
              .........
              break;
      }
    }
    Sleep(...);
  }
Как бы использовать один процесс TKey, только для редактирования времени выполнять одно действие, а для навигации меню - другое.? Подозреваю, что здесь напрашивается создать класс... Но пока не знаю, как это реализовать. Опыта с ++ маловато.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 12 2008, 08:06
Сообщение #38


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(alux @ Mar 12 2008, 08:48) *
Как бы использовать один процесс TKey, только для редактирования времени выполнять одно действие, а для навигации меню - другое.? Подозреваю, что здесь напрашивается создать класс...
Могу предложить сделать абстрактный базовый класс с виртуальными функциями (методами) ActionUp(), ActionDown(), ActionLeft() ....От него унаследовать TMainMenu, TEditTime и остальные, в которых переопределить эти методы. Посмотрите пример 3 из комплекта ОСи - там как раз такой подход реализован при кормлении слонов.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
dxp
сообщение Mar 12 2008, 09:06
Сообщение #39


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(alux @ Mar 12 2008, 12:48) *
Согласен. Мой способ мне самому не нравится. Процессов не хватит на каждый пункт меню. В TEditTime и TKeyMenu используются одинаковые конструкции
...
Как бы использовать один процесс TKey, только для редактирования времени выполнять одно действие, а для навигации меню - другое.? Подозреваю, что здесь напрашивается создать класс... Но пока не знаю, как это реализовать. Опыта с ++ маловато.

Вы тут углубились в вещи, которые к осям имеют очень опосредованное отношение - проектирование и разработка пользовательского интерфейса. Для пользовательского интерфейса идеально подходит та часть С++, которая реализует ООП. Вкратце: чтобы не городить мегатонны кода и запутаться в конце концов, применяется тот самый ОО подход - создается абстрактрый класс пункта меню, например, TMenuItem, в нем определяется интерфейс - набор чисто виртуальных функций, которые и будут реализовывать функциональность. Далее, от этого абстрактного класса наследуете уже конкретные классы пунктов меню, в которых определяете конкретное наполнение тех виртуальных функций.

Код
    class TMenuItem // абстрактрый базовый класс пункта меню
    {
    public:
        TMenuItem(const char * str);
        virtual void draw() = 0;      // чисто виртуальная фукнция
        virtual void change(int x) = 0;
    
    private:
        const char* caption;
        ...
    };


    class TMenuItem1 : public TMenuItem
    {
    public:
        TMenuItem1(const char * str) : TMenuItem(str)  { ... }
        ...
    };

    ...


Таких классов надо родить столько, сколько у вас разных пунктов меню. В каждом из этих классов переопределяете фукнции draw и change (или какие там у вас будут функции).

Код
void TMenuItem1::draw() { ... } // конкретная реализация данной функции - отрисовка этого конкретного пункта меню.

void TMenuItem1::change(int x) { ... } // изменение данного конкретного пункта меню


Для остальных классов тоже определить точно так же эти функции. Если есть одинаковые куски кода, то можно их использовать - например, у меня все пункты меню отрисовываются одинаково, поэтому у меня функция draw() невиртуальная и общая для всех классов потомков. А change() - виртуальная, т.к. содержимое пункта меню в каждом случае индивидуально и изменяется, соответственно, тоже индивидуально (к примеру, часть пунктов задает числовые параметры, а часть - строковые).

Теперь организуете сами пункты меню в группы - например, создав массив указателей на объекты этих типов.
Код
TMenuItem1 MenuItem1;
TMenuItem2 MenuItem2;
...
TMenuItemN MenuItemN;

TMenuItem *Menu[] =
{
    &MenuItem1,
    &MenuItem1,
    ...
    &MenuItemN,
}


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

Код
byte index;

if( RIGHT )
{
    Menu[++index]->draw(); // проверка перехода границы массива для простоты опущена
}
else if( LEFT )
{
    Menu[--index]->draw(); // проверка перехода границы массива для простоты опущена
}
else if ( UP )
{
    Menu[index]->change(1);  
}
else if ( DOWN )
{
    Menu[index]->change(-1);  
}


Т.е. тут события LEFT/RIGHT задают перемещение по пунктам меню, UP/DOWN - изменение значения пункта. Конечно, это все кратко, для иллюстрации только. На практике, обычно, все сложнее - все упирается в конкретную организацию меню и требуемую функциональность. Но схема построения будет та же и она, как видно, достаточно проста.

В каждом случае будут вызываться разные функции draw и change - для каждого объекта своя. Для всех пунктов меню общим является то, что они являются пунктами меню и то, что с ними можно делать - а именно: отображать и изменять. Но уже сами эти фукнции (отображение и изменение) для каждого пункта разные. Все это реализуется на основе полиморфизма (поведение, получаемое с помощью виртуальных фукнций), что вышеприведенный пример и иллюстрирует.

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

Вообще, наверное, GUI - одна из самых подходящих областей для применения ООП, где преимущества ООП перед процедурным программированием являются просто гиганскими. smile.gif

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


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
alux
сообщение Mar 12 2008, 10:45
Сообщение #40


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Реализация меню - это отдельная тема для разговора. Если бы я сейчас начинал свой проект, то, возможно, и применил бы ОО подход в создании меню. Правда, пока не понятно, как это усложнится в случае иерархического меню. У меня меню создается макросом MAKE_MENU (Name, Next, Previous, Parent, Sibling, SelectFunc, EnterFunc, Text). Структура меню видна, как на ладони. И главное, что это уже отлажено и работает.
Цитата(dxp @ Mar 12 2008, 13:06) *
вот этот код обработки пунктов меню имеет смысл поместить в один процесс (как правило, низкоприоритетный)

Этот процесс должен обрабатывать не только пункты меню, но и другие функции, в частности EditTime. По совету Сергея я создал от базового абстрактного класса TKey два новых класса: TMainMenu и TEditTime , которые имеют собственные реализации виртуальных методов Up, Down, Right, Left. Теперь мне надо, чтобы процесс, который получает сообщение в виде scan_code нажатой кнопки от ISR Timer2 отрабатывался по-разному, в зависимости от того, что в данный момент нужно: навигация по пунктам меню или редактирование времени. Как это сделать?

PS. Ничего лучшего, кроме как при входе в меню "Настройка -> Время" установить обычный глобальный флаг (не OS::EventFlag), по которому в процессе TKey определять какие действия необходимо делать при нажатии на кнопки, не придумал. Спрашивается. Зачем было городить виртуальные функции с абстрактными классами? 05.gif
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 12 2008, 12:30
Сообщение #41


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(alux @ Mar 12 2008, 12:45) *
PS. Ничего лучшего, кроме как при входе в меню "Настройка -> Время" установить обычный глобальный флаг (не OS::EventFlag), по которому в процессе TKey определять какие действия необходимо делать при нажатии на кнопки, не придумал. Спрашивается. Зачем было городить виртуальные функции с абстрактными классами? 05.gif
Мимо. Заводите объекты ваших классов-потомков, заводите указатель на абстрактный класс TKey:
Код
TMainMenu MainMenu;
TEditTime  EditTime;
TKey *CurrentMode = &MainMenu; // начинаем с меню.
enum TKeyCode { KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN };
OS::message<TKeyCode> Keyboard;

Указателю вы можете присвоить адрес любого класса-потомка этого базового класса. Т.е. надо меню - CurrentMode = &MainMenu. Надо редактировать время - CurrentMode = &EditTime; Теперь в потоке, который собственно организует управление делаете вызов виртуальных функций:
Код
for(;;)
  {
    if(!Keyboard.Wait(timeout))
    {
         CurrentMode = &MainMenu;  // пользователь ушел, выход в основной режим по таймауту
         // или CurrentMode->Timeout();
    }
    TKeyCode Key = Keyboard;
    switch (Key)
    {
    case LEY_LEFT:
          CurrentMode->Left();
          break;
    case LEY_RIGHT:
          CurrentMode->Right();
          break;
    .....................
    }
  }
Примерно так... Потом увидете, что все пункты меню можно построить точно так же как и TMainMenu, а красивую и понятную таблицу переходов между ними можно продолжать генерить макросом.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
alux
сообщение Mar 12 2008, 13:24
Сообщение #42


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Спасибо, Сергей. Сам бы до этого не додумался. beer.gif
Я думаю достаточно будет EventFlag вместо message. Скан-код хранится в глобальной переменной.
Еще один момент. В функции EditTime используются цифровые кнопки (0...9), а для навигации по пунктам меню - нет. В конструкции switch в ветке default при редактировании времени вводятся цифры. В базовом абстрактном классе необходимо создавать все виртуальные функции, которые используются потомками? Если да, то в TMainMenu нужно просто создать вирт. ф-цию Default {} с пустым телом?
Цитата(Сергей Борщ @ Mar 12 2008, 16:30) *
Потом увидете, что все пункты меню можно построить точно так же как и TMainMenu, а красивую и понятную таблицу переходов между ними можно продолжать генерить макросом.
Это к разговору о создании иерархического меню?

PS.
Цитата(Сергей Борщ @ Mar 12 2008, 16:30) *
if(!Keyboard.Wait(timeout))
wait нужно писать с маленькой буквы wink.gif

PS2. А на счет функции Blink, которая нужна при редактировании времени, то на мой взгляд будет проще ее запускать отдельным таймером. К проекту подключен timer.c, в котором задан массив системных таймеров, с помощью которых можна запускать функции с заданным интервалом времени.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 12 2008, 16:26
Сообщение #43


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(alux @ Mar 12 2008, 15:24) *
В конструкции switch в ветке default при редактировании времени вводятся цифры. В базовом абстрактном классе необходимо создавать все виртуальные функции, которые используются потомками? Если да, то в TMainMenu нужно просто создать вирт. ф-цию Default {} с пустым телом?
Думаю, да. Обозвать ее как-то вроде Numeric(). Причем если система попискивает на нажатие кнопки, то можно в базовом классе определить пару невиртуальных функций, BeepOk() и BeepError() и в реализации Numeric() для TMainMenu вызывать BeepError(), а в "правильных" обработчиках - BeepOk().

Цитата(alux @ Mar 12 2008, 15:24) *
Это к разговору о создании иерархического меню?
Да.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
alux
сообщение Mar 12 2008, 16:57
Сообщение #44


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Сделал так как Сергей сказал. За исключением того, что вместо message из ISR посылается TEventFlag::SignalISR(). Теперь наблюдаю следующее: При удержании кнопки при навигации по пунктам меню курсор постоянно "бегает". Никак не пойму из-за чего. Скан-код нажатой клавиши передается через глобальную переменную scan_code. В ней же старшим битом передается информация о нажатии кнопки. При обработке старший бит сбрасывается и таким образом избегаем повторной обработки нажатия кнопки. А на самом деле происходит повтор. :/ Если нет нажатия, то scan_code=0, и это состояние не обрабатывается.
Код
if(key_code.scan & KEY_PRESSED)
    {
      key_code.scan &= (0xff-KEY_PRESSED);   // Clear MSB of scan_code (key_pressed)
    
      switch(key_code.scan)      
      {
.............
Коротко о том, как у меня устроена клавиатура. При нажатии попадаем в ISR PCINT, запрещаем PCINT. Там запускаем таймер2. Через 35 мс в ISR Timer2 останавливаю таймер2, вычисляю скан-код, разрешаю прерывание PCINT. До этого все работало замечательно 05.gif

PS. Проверил этот же проект без ОС и с ОС(jacOS) - все работает нормально: отрабатывает одно нажатие. Значит проблема в этой системе. Возможно, я в упор не вижу слона, а со стороны вам будет виднее. wink.gif Так в чем же может быть проблема? Второй день копаю... sad.gif
Go to the top of the page
 
+Quote Post
alux
сообщение Mar 14 2008, 08:55
Сообщение #45


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Проблема с повтором решена. Спасибо Сергею Борщу. Проблема была в разрешении вложенных прерываний в ISR Timer2.
Go to the top of the page
 
+Quote Post

18 страниц V  < 1 2 3 4 5 > » 
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th April 2024 - 18:40
Рейтинг@Mail.ru


Страница сгенерированна за 0.01911 секунд с 7
ELECTRONIX ©2004-2016