|
|
  |
Синхронное взаимодействие программных модулей |
|
|
|
Feb 7 2017, 12:47
|
Местный
  
Группа: Участник
Сообщений: 333
Регистрация: 19-12-13
Из: Новосибирск
Пользователь №: 79 709

|
Подбросьте идей, как реализовать синхронность программных модулей. Организация программ на данный момент у меня следующая. Модульность. Никаких долгих циклов. Модули, задачи, процессы дробятся условиями, флагами, состояниями конечных автоматов. Итерация основного цикла выполняется с запасом за один системный тик. В основном системный тик у меня - 1 мс. Использую программные таймеры. То есть, у меня псевдопараллельность процессов. Иногда бывают ситуации, когда несколько модулей после определенного события должны выполнить определенные действия. Речь идет не о быстром поочередном выполнении, а, скажем, в течении одной итерации основного цикла.
Сообщение отредактировал demiurg1978 - Feb 7 2017, 12:49
|
|
|
|
|
Feb 7 2017, 13:25
|
Знающий
   
Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153

|
Не совсем понял суть проблемы. Как вариант 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); } Если ставить флаг в прерывании, то чтение и сброс надо переделать на атомарное
|
|
|
|
|
Feb 7 2017, 14:45
|
Местный
  
Группа: Участник
Сообщений: 333
Регистрация: 19-12-13
Из: Новосибирск
Пользователь №: 79 709

|
Попробую поточнее выразиться. Событие генерируется по условию и времени. Скажем, подавление дребезга контактных датчиков и входов. Одни входы - это контактные датчики, другие - контактные группы пускателей. У пускателей свои времянки включения-выключения. И чтобы не произошло сбоя, нужно синхронизировать действия модулей. Повторяю, речь не быстро-быстро выполнить действия. А о синхронизации действий в заданных рамках. Возьмем за такую рамку и условие, к примеру, итерацию основного цикла. Обработали все времянки подавления дребезга, по условиям модуль генерирует событие (что-то). Другими модулями видится это что-то, и выполняются определенные действия. Скажем, за итерацию основного цикла. Прошла итерация, это что-то больше не выставлено. Главное условие, сохранить инкапсуляцию программных модулей. Хмм... Как такая идея. Берем за временную засечку системный таймер и очередность выполнения модулей основной цикл. В обработчике системного таймера будет определена глобальная переменная флаг. Определенный модуль выставляет этот флаг. Определяем также еще одну переменную-флаг. Когда происходит прерывание системного таймера, мы сбрасываем первый флаг и выставляем следующий. В начале основного цикла, если установлен этот флаг, выполняем действия в пределах итерации основного цикла. При следующей итерации так как первый флаг сброшен, больше ничего не выставляется. Подсмотрено у ЛИ. Код //----------------------------- Переменные: ----------------------------------
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); //обслуживание измерителя } }
Сообщение отредактировал demiurg1978 - Feb 7 2017, 14:49
|
|
|
|
|
Feb 7 2017, 15:02
|
Местный
  
Группа: Участник
Сообщений: 333
Регистрация: 19-12-13
Из: Новосибирск
Пользователь №: 79 709

|
Цитата(gte @ Feb 7 2017, 20:51)  Не ручаюсь за то что правильно понял. В пром. контроллерах текущие состояние входов считывают в буфер в начале программного цикла, работают с буфером в пределах одного программного цикла, в конце цикла записывают значения из буфера в выходы. Что считаем входами?
|
|
|
|
|
Feb 7 2017, 16:13
|
Местный
  
Группа: Участник
Сообщений: 333
Регистрация: 19-12-13
Из: Новосибирск
Пользователь №: 79 709

|
Я понимаю, что каждый разумеет в меру своего понимания и опыта. Общаясь на подобных форумах, каждый спрашивает в меру своего понимания и опыта, каждый отвечает в меру своего понимания и опыта. Есть такое понятие, как допустимое время реакции системы. Также нужно учитывать в расчетах время реакции исполнительных механизмов и время реакции датчиков. Исходим из этого. Соответственно, отбрасываем в этом обсуждении ответы начинающих, которые оперируют только байтами и тактами. И "быстрой-быстрой" реакцией. Прерывания и все такое прочее. Хотя надо признать, что некоторое время назад я именно так и рассуждал...  Эти байтики, такты, быстро-быстро обработать...
Сообщение отредактировал demiurg1978 - Feb 7 2017, 16:20
|
|
|
|
|
Feb 7 2017, 19:13
|
Гуру
     
Группа: Свой
Сообщений: 2 318
Регистрация: 13-02-05
Из: Липецкая область
Пользователь №: 2 613

|
Цитата(demiurg1978 @ Feb 7 2017, 18:02)  Что считаем входами? Ну это Вам видней. "Одни входы - это контактные датчики, другие - контактные группы пускателей." Так как это Ваш контроллер, то что назначите. Если интересны подробности того о чем я написал, то стоит почитать описания на тот же Симатик.
|
|
|
|
|
Feb 7 2017, 23:05
|
Частый гость
 
Группа: Участник
Сообщений: 168
Регистрация: 14-02-10
Пользователь №: 55 490

|
По коду в сообщении #4: Не затрагивая способы организации очерёдности вызовов, замечу, что нет необходимости в переменной fTick, обработчике прерывания, разрешении прерывания таймера. Просто настраиваем и запускаем таймер и в основном цикле проверяем аппаратный флаг: Код if ( TIFR1 & (1<<OCF1A) ) { TIFR1 = (1<<OCF1A); // не забыть сбросить флаг
{/*полезные действия*/} }
--------------------
#define TRUE (4==(2*2))
|
|
|
|
|
Feb 8 2017, 08:10
|

Знающий
   
Группа: Участник
Сообщений: 756
Регистрация: 14-11-14
Пользователь №: 83 663

|
Цитата(demiurg1978 @ Feb 7 2017, 20:13)  Я понимаю, что каждый разумеет в меру своего понимания и опыта. Общаясь на подобных форумах, каждый спрашивает в меру своего понимания и опыта, каждый отвечает в меру своего понимания и опыта. Есть такое понятие, как допустимое время реакции системы. Также нужно учитывать в расчетах время реакции исполнительных механизмов и время реакции датчиков. Исходим из этого. Соответственно, отбрасываем в этом обсуждении ответы начинающих, которые оперируют только байтами и тактами. И "быстрой-быстрой" реакцией. Прерывания и все такое прочее. Хотя надо признать, что некоторое время назад я именно так и рассуждал...  Эти байтики, такты, быстро-быстро обработать... Так вы диаграммку временнУю нарисовали бы и всём стало бы понятнее…
--------------------
Пролетарий умственного труда.
|
|
|
|
|
Feb 8 2017, 08:25
|
Знающий
   
Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153

|
Цитата(demiurg1978 @ Feb 7 2017, 19:13)  Я понимаю, что каждый разумеет в меру своего понимания и опыта. Общаясь на подобных форумах, каждый спрашивает в меру своего понимания и опыта, каждый отвечает в меру своего понимания и опыта. Есть такое понятие, как допустимое время реакции системы. Также нужно учитывать в расчетах время реакции исполнительных механизмов и время реакции датчиков. Исходим из этого. Соответственно, отбрасываем в этом обсуждении ответы начинающих, которые оперируют только байтами и тактами. И "быстрой-быстрой" реакцией. Прерывания и все такое прочее. Хотя надо признать, что некоторое время назад я именно так и рассуждал...  Эти байтики, такты, быстро-быстро обработать... Вы бы все таки сформулировали задачу Я так понял, что вы хотите, чтобы все модули, которые заинтересованы в некотором событии, уведомлялись о его наступлении. При этом модули не знаю друг про друга, а источник события не знает список заинтересованных в нем модулей ("не знает" в том смысле, что эти модули не прописаны в нем явно). Или задача звучит по другому?
|
|
|
|
|
Feb 23 2017, 15:39
|
Местный
  
Группа: Участник
Сообщений: 333
Регистрация: 19-12-13
Из: Новосибирск
Пользователь №: 79 709

|
Цитата(Непомнящий Евгений @ Feb 8 2017, 14:25)  Я так понял, что вы хотите, чтобы все модули, которые заинтересованы в некотором событии, уведомлялись о его наступлении. При этом модули не знаю друг про друга, а источник события не знает список заинтересованных в нем модулей ("не знает" в том смысле, что эти модули не прописаны в нем явно). Поднимаю тему. Опять столкнулся с этим. Да, вы точно описали мою проблему. Запутался уже как это реализовать.
|
|
|
|
|
Feb 23 2017, 17:35
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(demiurg1978 @ Feb 23 2017, 18:39)  Запутался уже как это реализовать. Создаете переменную СОБЫТИЕ, в которой 8 бит, по числу модулей. Если событие происходит, то приравниваете СОБЫТИЕ = 0xFF Эту переменную читают все модули. Прочитав, и выполнив действия, которые нужно выполнить, модуль сбрасывает соответствующий "свой" бит, поэтому действия выполняются каждым модулем один раз. Если система спроектирована правильно, то все модули обрабатывают событие раньше, чем произойдет новое событие.
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Jun 5 2017, 19:05
|
Частый гость
 
Группа: Участник
Сообщений: 121
Регистрация: 15-04-05
Из: Краснодар
Пользователь №: 4 185

|
Программы систем реального времени, по моему мнению, следует строить по принципу - на каждое событие есть свой обработчик. Завершилось преобразование АЦП, сработало прерывание, нужно сохранить данные и вызывать обработчик фоновой задачи, который преобразует сырые данные АЦП в формат с плавающей точкой. После завершения математики можно разрешать новое преобразование. Запускать новое преобразование АЦП, до того, как процессор завершит обработку, смысла нет. Чтобы программа так работала нужен диспетчер многозадачности. Вытесняющая многозадачность для одной единственной программы, которую пишешь сам - перебор. Кооперативной вполне достаточно. Есть два заблуждения. Заблуждение первое - кооперативная многозадачность создаёт множество неудобств. Заблуждение второе - вытесняющая многозадачность эти удобства решает. По степени важности обработчики делятся на три уровня - аппаратные прерывания (срочно, срочнее некуда), программные прерывания (не так срочно, как аппаратное прерывание, но срочнее, чем фоновая задача), фоновая задача (по остаточному принципу - сложная математика). Обработчик аппаратного прерывания инициирует либо программное прерывание, либо фоновую задачу. Системный таймер - надстройка над механизмом программного прерывания.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|