Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Синхронное взаимодействие программных модулей
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
demiurg1978
Подбросьте идей, как реализовать синхронность программных модулей. Организация программ на данный момент у меня следующая. Модульность. Никаких долгих циклов. Модули, задачи, процессы дробятся условиями, флагами, состояниями конечных автоматов. Итерация основного цикла выполняется с запасом за один системный тик. В основном системный тик у меня - 1 мс. Использую программные таймеры. То есть, у меня псевдопараллельность процессов.
Иногда бывают ситуации, когда несколько модулей после определенного события должны выполнить определенные действия. Речь идет не о быстром поочередном выполнении, а, скажем, в течении одной итерации основного цикла.
Непомнящий Евгений
Не совсем понял суть проблемы. Как вариант

CODE
struct Action {
bool todo = false;
Action *next = 0;
};

Action *event1;

void registerAction(Action **event, Action *a) {
a->next = *event;
*event = a;
}

void setOn(Action *event) {
while(event) {
event->todo = true;
event = event->next;
}
}

// модуль 1
Action mod1_event1;
registerAction(event1, mod1_event1);

void loop() {
if (mod1_event.todo) {
mod1_event.todo = false;
// ...
}
}

// модуль 2
Action mod2_event1;
registerAction(event1, mod2_event1);

void loop() {
if (mod2_event.todo) {
mod2_event.todo = false;
// ...
}
}

// где-то еще

ISR(isr) {
setOn(event1);
}


Если ставить флаг в прерывании, то чтение и сброс надо переделать на атомарное
demiurg1978
Попробую поточнее выразиться. Событие генерируется по условию и времени. Скажем, подавление дребезга контактных датчиков и входов. Одни входы - это контактные датчики, другие - контактные группы пускателей. У пускателей свои времянки включения-выключения. И чтобы не произошло сбоя, нужно синхронизировать действия модулей. Повторяю, речь не быстро-быстро выполнить действия. А о синхронизации действий в заданных рамках. Возьмем за такую рамку и условие, к примеру, итерацию основного цикла. Обработали все времянки подавления дребезга, по условиям модуль генерирует событие (что-то). Другими модулями видится это что-то, и выполняются определенные действия. Скажем, за итерацию основного цикла. Прошла итерация, это что-то больше не выставлено. Главное условие, сохранить инкапсуляцию программных модулей.

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

Подсмотрено у ЛИ.
Код
//----------------------------- Переменные: ----------------------------------

volatile bool fTick;               //флаг обновления системного таймера
static bool tick;                  //флаг начала нового системного интервала

//------------------ Инициализация системного таймера ------------------------

void Main_Timer_Init(void)
{
// bla-bla
  fTick = 1;                       //принудительное обновление
}

//--------------------- Проверка системного таймера: -------------------------

__monitor bool Main_GetTick(void)
{
  if(!fTick) return(0);            //проверка нового системного интервала
  fTick = 0;                       //очистка флага
  return(1);                       //новый системный интервал
}

//------------------- Прерывание системного таймера: -------------------------

#pragma vector = TIMER1_COMPA_vect
__interrupt void Timer(void)
{
  fTick = 1;                       //новый системный интервал
}

//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
//-------------------------- Основная программа: -----------------------------
//----------------------------------------------------------------------------

void main(void)
{  Main_Timer_Init();               //инициализация системного таймера
  __enable_interrupt();            //разрешение прерываний

  while(1)                         //основной цикл
  {
    tick = Main_GetTick();         //опрос системного таймера
    Meter_Exe(tick);               //обслуживание измерителя
  }
}
gte
Цитата(demiurg1978 @ Feb 7 2017, 17:14) *
Попробую поточнее выразиться. Событие генерируется по условию и времени.

Не ручаюсь за то что правильно понял. В пром. контроллерах текущие состояние входов считывают в буфер в начале программного цикла, работают с буфером в пределах одного программного цикла, в конце цикла записывают значения из буфера в выходы.
demiurg1978
Цитата(gte @ Feb 7 2017, 20:51) *
Не ручаюсь за то что правильно понял. В пром. контроллерах текущие состояние входов считывают в буфер в начале программного цикла, работают с буфером в пределах одного программного цикла, в конце цикла записывают значения из буфера в выходы.

Что считаем входами?
zombi
Цитата(demiurg1978 @ Feb 7 2017, 16:47) *
как реализовать синхронность программных модулей

нужно на нескольких выходах, в зависимости от входов, формировать состояние синхронно каждую мс?
Или нужно нечто другое?
«Правильно заданный вопрос – половина ответа»(с)
demiurg1978
Я понимаю, что каждый разумеет в меру своего понимания и опыта. Общаясь на подобных форумах, каждый спрашивает в меру своего понимания и опыта, каждый отвечает в меру своего понимания и опыта.
Есть такое понятие, как допустимое время реакции системы. Также нужно учитывать в расчетах время реакции исполнительных механизмов и время реакции датчиков. Исходим из этого. Соответственно, отбрасываем в этом обсуждении ответы начинающих, которые оперируют только байтами и тактами. И "быстрой-быстрой" реакцией. Прерывания и все такое прочее. Хотя надо признать, что некоторое время назад я именно так и рассуждал... sm.gif Эти байтики, такты, быстро-быстро обработать...
gte
Цитата(demiurg1978 @ Feb 7 2017, 18:02) *
Что считаем входами?

Ну это Вам видней.
"Одни входы - это контактные датчики, другие - контактные группы пускателей."
Так как это Ваш контроллер, то что назначите.
Если интересны подробности того о чем я написал, то стоит почитать описания на тот же Симатик.

zombi
Цитата(demiurg1978 @ Feb 7 2017, 15:47) *
Речь идет не о быстром поочередном выполнении, а, скажем, в течении одной итерации основного цикла.

Т.е. Вам нужно медленно и параллельно?
Попробуйте переписать Ваше сообщение после первой запятой понятнее, так что бы "дошло" до всех участников форума независимо от опыта и квалификации.
Владивольт
По коду в сообщении #4:
Не затрагивая способы организации очерёдности вызовов, замечу,
что нет необходимости в переменной fTick, обработчике прерывания,
разрешении прерывания таймера.

Просто настраиваем и запускаем таймер и в основном цикле проверяем аппаратный флаг:
Код
if ( TIFR1 & (1<<OCF1A) )
{
  TIFR1 = (1<<OCF1A); // не забыть сбросить флаг

  {/*полезные действия*/}
}
Obam
Цитата(demiurg1978 @ Feb 7 2017, 20:13) *
Я понимаю, что каждый разумеет в меру своего понимания и опыта. Общаясь на подобных форумах, каждый спрашивает в меру своего понимания и опыта, каждый отвечает в меру своего понимания и опыта.
Есть такое понятие, как допустимое время реакции системы. Также нужно учитывать в расчетах время реакции исполнительных механизмов и время реакции датчиков. Исходим из этого. Соответственно, отбрасываем в этом обсуждении ответы начинающих, которые оперируют только байтами и тактами. И "быстрой-быстрой" реакцией. Прерывания и все такое прочее. Хотя надо признать, что некоторое время назад я именно так и рассуждал... sm.gif Эти байтики, такты, быстро-быстро обработать...


Так вы диаграммку временнУю нарисовали бы и всём стало бы понятнее…
Непомнящий Евгений
Цитата(demiurg1978 @ Feb 7 2017, 19:13) *
Я понимаю, что каждый разумеет в меру своего понимания и опыта. Общаясь на подобных форумах, каждый спрашивает в меру своего понимания и опыта, каждый отвечает в меру своего понимания и опыта.
Есть такое понятие, как допустимое время реакции системы. Также нужно учитывать в расчетах время реакции исполнительных механизмов и время реакции датчиков. Исходим из этого. Соответственно, отбрасываем в этом обсуждении ответы начинающих, которые оперируют только байтами и тактами. И "быстрой-быстрой" реакцией. Прерывания и все такое прочее. Хотя надо признать, что некоторое время назад я именно так и рассуждал... sm.gif Эти байтики, такты, быстро-быстро обработать...


Вы бы все таки сформулировали задачу rolleyes.gif

Я так понял, что вы хотите, чтобы все модули, которые заинтересованы в некотором событии, уведомлялись о его наступлении. При этом модули не знаю друг про друга, а источник события не знает список заинтересованных в нем модулей ("не знает" в том смысле, что эти модули не прописаны в нем явно).

Или задача звучит по другому?
demiurg1978
Цитата(Непомнящий Евгений @ Feb 8 2017, 14:25) *
Я так понял, что вы хотите, чтобы все модули, которые заинтересованы в некотором событии, уведомлялись о его наступлении. При этом модули не знаю друг про друга, а источник события не знает список заинтересованных в нем модулей ("не знает" в том смысле, что эти модули не прописаны в нем явно).

Поднимаю тему. Опять столкнулся с этим. Да, вы точно описали мою проблему. Запутался уже как это реализовать.
Dog Pawlowa
Цитата(demiurg1978 @ Feb 23 2017, 18:39) *
Запутался уже как это реализовать.

Создаете переменную СОБЫТИЕ, в которой 8 бит, по числу модулей.
Если событие происходит, то приравниваете СОБЫТИЕ = 0xFF
Эту переменную читают все модули. Прочитав, и выполнив действия, которые нужно выполнить, модуль сбрасывает соответствующий "свой" бит, поэтому действия выполняются каждым модулем один раз.
Если система спроектирована правильно, то все модули обрабатывают событие раньше, чем произойдет новое событие.

Д_М
Программы систем реального времени, по моему мнению, следует строить по принципу - на каждое событие есть свой обработчик. Завершилось преобразование АЦП, сработало прерывание, нужно сохранить данные и вызывать обработчик фоновой задачи, который преобразует сырые данные АЦП в формат с плавающей точкой. После завершения математики можно разрешать новое преобразование. Запускать новое преобразование АЦП, до того, как процессор завершит обработку, смысла нет. Чтобы программа так работала нужен диспетчер многозадачности. Вытесняющая многозадачность для одной единственной программы, которую пишешь сам - перебор. Кооперативной вполне достаточно. Есть два заблуждения. Заблуждение первое - кооперативная многозадачность создаёт множество неудобств. Заблуждение второе - вытесняющая многозадачность эти удобства решает. По степени важности обработчики делятся на три уровня - аппаратные прерывания (срочно, срочнее некуда), программные прерывания (не так срочно, как аппаратное прерывание, но срочнее, чем фоновая задача), фоновая задача (по остаточному принципу - сложная математика). Обработчик аппаратного прерывания инициирует либо программное прерывание, либо фоновую задачу. Системный таймер - надстройка над механизмом программного прерывания.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.