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

 
 
4 страниц V  < 1 2 3 4 >  
Reply to this topicStart new topic
> Управление контекстом БЕЗ RTOS
psL
сообщение Nov 28 2014, 08:26
Сообщение #31


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 5-08-05
Пользователь №: 7 390



Цитата(AlexandrY @ Nov 28 2014, 11:17) *
Забавно состояние ERROR по отношению к процессу управления светодиодом.
Что бы это могло значить? biggrin.gif

Враги украли плату индикации wink.gif
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Nov 28 2014, 09:09
Сообщение #32


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(psL @ Nov 28 2014, 10:26) *
Враги украли плату индикации wink.gif


Ни как ОНО узнает об этом без обратной связи то?
ERROR лишнее состояние, да и IDLE тоже.
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Nov 28 2014, 09:11
Сообщение #33


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



fsm->state можно и в прерывании сменить на ERROR чтобы вся схема перешла в это состояние.
таких автоматов может быть много. Еще хорошо бы состояние RESET или INIT, из которого схема в IDLE переходит.
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Nov 28 2014, 09:18
Сообщение #34


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(Golikov A. @ Nov 28 2014, 11:11) *
fsm->state можно и в прерывании сменить на ERROR чтобы вся схема перешла в это состояние.
таких автоматов может быть много. Еще хорошо бы состояние RESET или INIT, из которого схема в IDLE переходит.


Ага, еще нужны состояния ALARM, WARNING, FAULT, HARD FAULT, PANIC и т.д. wacko.gif
Go to the top of the page
 
+Quote Post
psL
сообщение Nov 28 2014, 09:25
Сообщение #35


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 5-08-05
Пользователь №: 7 390



Цитата(AlexandrY @ Nov 28 2014, 12:09) *
Ни как ОНО узнает об этом без обратной связи то?

откуда вообще взялся светодиод в энтом абстрактном примере?wink.gif Придираетесь, профессор?
Цитата(AlexandrY @ Nov 28 2014, 12:09) *
ERROR лишнее состояние, да и IDLE тоже.

да, даsm.gif назовем IDLE "константа 65535" и захардкодим, чтобы джедаи не догадались sm.gif
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Nov 28 2014, 09:57
Сообщение #36


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(psL @ Nov 28 2014, 11:25) *
откуда вообще взялся светодиод в энтом абстрактном примере?wink.gif Придираетесь, профессор?


Т.е. нынче принято обсуждать что угодно, но только не то, что спросил TC?

Цитата(psL @ Nov 28 2014, 11:25) *
да, даsm.gif назовем IDLE "константа 65535" и захардкодим, чтобы джедаи не догадались sm.gif


Боюсь вы термину IDLE придумали некое свое семантическое значение. Если оно вам помогает , ну и хорошо.
Только автоматов разных может быть много в программе и не упасётесь разными вариациями: IDLE1, IDLE2, IDLE3 ...
Go to the top of the page
 
+Quote Post
psL
сообщение Nov 28 2014, 10:55
Сообщение #37


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 5-08-05
Пользователь №: 7 390



Цитата(AlexandrY @ Nov 28 2014, 12:57) *
Т.е. нынче принято обсуждать что угодно, но только не то, что спросил TC?

ну ТС хотелось "контекста". В общем случае "контекст" может выглядеть так:
Код
struct job {
    void* data;              // "контекст"
    void  (*proc)(void*);
};

struct job jobs[] = {
   {.data=..., .proc=... }, ...
};

void job_proc(struct job* job){
   job->proc(job->data);
}

void main(){
  for(i=0; i<sizeof(jobs)/sizeof(struct job);i++)
     job_proc(&jobs[i]);
}

В качестве data и *proc м.б. struct fsm и fsm_proc из предыдущего примера с небольшой доработкой.
Или принципиально затачивать каждый пример для светодиода?
Go to the top of the page
 
+Quote Post
jcxz
сообщение Nov 28 2014, 11:06
Сообщение #38


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Golikov A. @ Nov 28 2014, 13:49) *
потому что при предложенном подходе каждая функция изначально критическая секция, с атомарным доступом ко всем используемым переменным до окончания своей работы. Функции не прерываются в середине, а только в определенных местах, и они должны правильно отрабатывать смену параметров на лету.

Это верно только в одном частном случае - когда границы критической секции не выходят за пределы таких коммутируемых функций.
А если выходят - как быть?
Также тут предполагается, что моменты переключения задач всегда на границах таких функций. Это корпоративная многозадачность.
А если длительность таких функций очень (на порядки различается)?
А если нужно выполнять функции, реагирующие на реалтайм-события, критичные к времени реакции. И в то же время среди функций есть тяжёлые (длительные) вычислительные функции, к тому же если время их выполнения заранее не известно.
Как в этом случае быть? wink.gif
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Nov 28 2014, 11:28
Сообщение #39


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(psL @ Nov 28 2014, 12:55) *
ну ТС хотелось "контекста". В общем случае "контекст" может выглядеть так:
Код
struct job {
    void* data;              // "контекст"
    void  (*proc)(void*);
};

struct job jobs[] = {
   {.data=..., .proc=... }, ...
};

void job_proc(struct job* job){
   job->proc(job->data);
}

void main(){
  for(i=0; i<sizeof(jobs)/sizeof(struct job);i++)
     job_proc(&jobs[i]);
}

В качестве data и *proc м.б. struct fsm и fsm_proc из предыдущего примера с небольшой доработкой.
Или принципиально затачивать каждый пример для светодиода?


А где здесь сохранение контекста?
Здесь изображен просто синхронный вызов функций с неким указателем неизвестно на что.
А если брать struct fsm как контекст задачи в применении к светодиоду, то это будет точно то же что я и продемонстрировал если вам дописать недостающий код, но будет более раздуто, так как состояниям будет выделяться дополнительная величина в управляющем шаблоне.
Go to the top of the page
 
+Quote Post
psL
сообщение Nov 28 2014, 11:48
Сообщение #40


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 5-08-05
Пользователь №: 7 390



Цитата(AlexandrY @ Nov 28 2014, 14:28) *
А где здесь сохранение контекста?

Указатель на "контекст" хранится в *data, не нужно ТС никаких downloadContext. Т.е.
Код
struct job jobs[] = {
   {.data=(void*)myfsm, .proc=fsm_proc }, ...
};

void fsm_proc(void* p){
   struct fsm* myfsm = (struct fsm*)p;
   ...
}

да, будет почти тоже самое. В этих примерах все абстрактно. Но, пмсм, так проще для понимания.

Насколько вообще понимаю суть вопроса, ТС просит обьяснить, как писать реентерабельные функции.
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Nov 28 2014, 11:58
Сообщение #41


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(psL @ Nov 28 2014, 13:48) *
Указатель на "контекст" хранится в *data, не нужно ТС никаких downloadContext. Т.е.


Вопрос был как сохранить контекст, а не где его хранить!

И ваш ответ по сути таков: превращать любую задачу в автомат состояний и состояние хранить в структуре, которую не надо сохранять потому как она у каждой задачи своя.

Мой пример тоже основан на этом.
Но! Только для светодиодов, соленоидов и прочей односигнальной мелочи.

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



Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Nov 28 2014, 14:07
Сообщение #42


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



Цитата
Это верно только в одном частном случае - когда границы критической секции не выходят за пределы таких коммутируемых функций.
А если выходят - как быть?

не могут выходить, функции так создаются

Цитата
Также тут предполагается, что моменты переключения задач всегда на границах таких функций. Это корпоративная многозадачность.
А если длительность таких функций очень (на порядки различается)?

опять же функции создаются так чтобы такого не было и переключение всегда на границе функций.
К примеру: есть функция обработки большого массива, функция при каждом вызове обрабатывает 1 элемент и выходит с кодом 1, а когда обработает последний вернет 0. В основной программе функция вызывается пока не вернет 0.

Цитата
А если нужно выполнять функции, реагирующие на реалтайм-события, критичные к времени реакции. И в то же время среди функций есть тяжёлые (длительные) вычислительные функции, к тому же если время их выполнения заранее не известно.
Как в этом случае быть? wink.gif

ну собственно вы сейчас называете все недостатки такого подхода и почему появились операционки. Отсюда ответ на ваш вопрос использовать операционку!
Go to the top of the page
 
+Quote Post
Slash
сообщение Nov 28 2014, 14:38
Сообщение #43


Местный
***

Группа: Участник
Сообщений: 202
Регистрация: 10-04-05
Из: Санкт-Петербург
Пользователь №: 4 011



Цитата(AlexandrY @ Nov 28 2014, 10:04) *
Этот автомат применяется мною и с RTOS и без.

Извините, но это жесть что влезаю из топика "С vs C++", но этот код можно сделать еще лучше.

Код
// Управляющая структура машины состояний управляемой шаблоном
typedef struct
{
  INT32U  init_state;
  INT32U  counter;
  INT32U *pattern_start_ptr;  // Указатель на массив констант int являющийся цепочкой состояний (шаблоном)
                              // Если значение в массиве = 0xFFFF, то процесс обработки завершается
                              // Если значение в массиве = 0x0000, то вернуть указатель на начало цепочки
  INT32U *pttn_ptr;           // Текущая позиция в цепочке состояний

} T_solnd_ptrn;

pattern_start_ptr и pttn_ptr нет ну никакого смысла делать указателями, только лишние разименовывания. По смыслу это индекс позиции. Дать им имена pos и startPos или index и startIndex.
Чистая вкусовщина - меня коробит от сочетания в именах больших букв и подчеркиваний ну и typedef struct туда-же. Выделять типы данных префиксом "T_" нет смысла - современный редактор цветом покажет, что данный символ - тип данных. Т.е. меняем на
Код
struct SolenoidPattern
{
  INT32U  init_state;
  INT32U  counter;
  INT32U startPos ;  // Указатель на массив констант int являющийся цепочкой состояний (шаблоном)
                              // Если значение в массиве = 0xFFFF, то процесс обработки завершается
                              // Если значение в массиве = 0x0000, то вернуть указатель на начало цепочки
  INT32U pos;           // Текущая позиция в цепочке состояний
};


Код
//  Шаблоны работы соленоидов
//  ----------------------------------------------------------------------
//  Шаблон состоит из массива пар слов.
//  Первое слово - значение напряжения (в процентах от максимального) на текущем интервале времени
//  Второе       - длительность интервала времени в мс
//  интервал равный 0     - означает возврат в начало шаблона
//  интервал равный 65535 - означает застывание состояния

const INT32U  SOLENOID1_ON[10] = { 100, 300, 25,  300, 100, 300, 25,  300, 25, 0xFFFF };
const INT32U  SOLENOID2_ON[10] = { 25,  300, 100, 300, 25,  300, 100, 300, 25, 0xFFFF };
const INT32U  SOLENOID_OFF[4] = { 0, 2000, 0, 0xFFFF };

Здорово бы комментарии поддержать кодом, введя тип данных
Код
struct Point
{
    uint32_t voltage;
    uint32_t time;
};
const Point SOLENOID1_ON[5] = { {100, 300}, {25,  300}, {100, 300}, {25,  300}, {25, 0xFFFF} };


Тогда такая комбинация
Код
    voltage = *solnd_cbl[n].pttn_ptr;
    solnd_cbl[n].pttn_ptr++;
    duration =  *solnd_cbl[n].pttn_ptr;
    solnd_cbl[n].pttn_ptr++;

сокращается до
Код
    voltage = solnd_cbl[n].at(pos).voltage;
    duration =  solnd_cbl[n].at(pos).time;
    solnd_cbl[n].pos++;


Тут мне не все понятно, вроде бы эта функция вроде конструктора SolenoidPattern. Не хватает определения функции Set_solenoids_voltage.
Код
/*-------------------------------------------------------------------------------------------------------------
  Инициализация машины состояний заданным шаблоном
  *pttn - указатель на начало шаблона
  n - индекс соленоида (0..1)
-------------------------------------------------------------------------------------------------------------*/
void Set_Solenoid_pattern(const INT32U *pttn, INT32U n)
{
  if ( pttn != 0 )
  {
    solnd_cbl[n].pattern_start_ptr = (INT32U *)pttn;
    solnd_cbl[n].pttn_ptr          = (INT32U *)pttn;
    Set_solenoids_voltage(*solnd_cbl[n].pttn_ptr, n);
    solnd_cbl[n].pttn_ptr++;
    solnd_cbl[n].counter     = *solnd_cbl[n].pttn_ptr;
    solnd_cbl[n].pttn_ptr++;
  }
}


Ну и может быть отказаться от конструкции
Код
for (int i = 0; i < n; ++i)
{}

в пользу
Код
for (const Point & point : pointsArray)
{}

тогда из цикла пропадает индекс, но так сделать не всегда можно, иногда он нужен.

Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Nov 28 2014, 15:04
Сообщение #44


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



чего то я видать безнадежно устарел
Код
for (const Point & point : pointsArray)

вот это что за на?
Go to the top of the page
 
+Quote Post
jcxz
сообщение Nov 28 2014, 15:34
Сообщение #45


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Golikov A. @ Nov 28 2014, 20:07) *
К примеру: есть функция обработки большого массива, функция при каждом вызове обрабатывает 1 элемент и выходит с кодом 1, а когда обработает последний вернет 0. В основной программе функция вызывается пока не вернет 0.

А если таких элементов миллион и обработка - одна простая операция?
Будет чудовищный оверхед - 10% времени будет выполняться полезная работа и 90% - входы/выходы в функцию и разные проверки.
Вы конечно скажете - "в таком случае нужно не по 1-му, а по 100 элементов за раз обрабатывать".
Но тогда получается программа привязывается к среде выполнения и кроме решения задачи каждый раз нужно учитывать ещё кучу условий.
А если длительность обработки каждого элемента заранее неизвестна?
А если вызываете функции некоей сторонней библиотеки, где тоже время выполнения заранее неизвестно?

Цитата(Golikov A. @ Nov 28 2014, 20:07) *
ну собственно вы сейчас называете все недостатки такого подхода и почему появились операционки. Отсюда ответ на ваш вопрос использовать операционку!

Конечно. Всё уместно на своём месте. И для суперлупа есть свой узкий круг задач, которые для него оптимальны, и своеобразное построение алгоритма. Я тоже его частенько использую (совместно с ОС), для экономии памяти (под стек).
Но ТС пишет о таком подходе как о панацее для всего. Что в корне не верно. Традиционная вытесняющая ОС гораздо более универсальна.
А для суперцикла есть только своя ниша.

Цитата(Golikov A. @ Nov 28 2014, 21:04) *
чего то я видать безнадежно устарел
Код
for (const Point & point : pointsArray)

вот это что за на?

Вся эта си-плюс-плюсная объектно-инкапсулированная хрень хороша только для тех, кто не заглядывает в файлы листинга компилятора.
А если Вы задумываетесь об оптимальности не исходников (как здесь), а результирующего кода (скорости выполнения и размера), то выбирайте наиболее стандартные конструкции, типа for (int i = 0; i < n; ++i). Оптимизаторы компиляторов на них наиболее "натасканы" и код будет оптимальным.

Я, после опыта оптимизации по скорости DSP-кода, взял это себе за правило - если хочется чтобы код был наиболее оптимален после компилятора, конструкции в исходнном коде должны быть наиболее простыми.
На входе у меня был вот такой вот весь правильный С++ код, со всеми конструкторами/деструкторами и т.п. и при этом он безбожно тормозил и алгоритм не успевал обработать поток данных. После убиения всей этой плюсовой красоты и полного переписывания на простой си-код, скорость выполнения того-же самого алгоритма увеличилась в несколько сотен раз!
Потому что оптимизатор простой код сумел многократно распараллелить.
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 21st July 2025 - 16:16
Рейтинг@Mail.ru


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