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

 
 
 
Reply to this topicStart new topic
> Отслеживание нескольких событий по времени
SZ0
сообщение Mar 11 2009, 19:40
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 326
Регистрация: 14-02-06
Пользователь №: 14 331



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

Есть микроконтроллер, он управляет несколькими выходами. Их работа зависит
от состояние клавиш и времени. Т.е. при нажатии той или иной клавиши выход
переключается в заданное состояние и может запускаться отчёт по времени, по
прошествии которого выход изменит своё состояние. Или же выход может
срабатывать в зависимости от выставленного будильника по RTC.

В прерывания хочу вынести отчёт времени, периодическое чтение RTC и естественно
опрос клавиш.

А как правильнее проводить сравение выставленных будильников с RTC? В основной
части программы или по периодическим прерываниям (например раз в 1 сек) и
выставляя флаги сработки реагировать в основной части программы?

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

Как можно обеспечить нахождение в режиме программирования устройства
(выставление) пользователем условий сработки для одного выхода и при этом
чтобы одновременно продолжалась работа и управление другими выходами?
Go to the top of the page
 
+Quote Post
Methane
сообщение Mar 11 2009, 19:46
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 3 615
Регистрация: 12-01-09
Из: США, Главное разведовательное управление
Пользователь №: 43 230



Какая точность нужна?
Причина редактирования: Нарушение п.3.4 Правил форума. Удалено ненужное цитирование.
Go to the top of the page
 
+Quote Post
rezident
сообщение Mar 11 2009, 20:19
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Если не предполагается восстановление всех параметров работы после пропадания/появления питания и максимальный период отсчета времени не нужен более 1,5 месяцев, то для данной задачи RTC вообще не нужен. А нужен всего один таймер, работающий от кварцованной частоты и настроенный так, чтобы генерировать прерывания с периодом, с минимально требуемым разрешением. В АСУ и ТП редко когда требуются воздействия с длительностью менее 100мс. Но можно сделать период генерации прерываний даже 10мс или 1 мс. В прерывании от таймера нужно какую-то глобальную беззнаковую 32-х битную переменную целого типа инкрементировать на число равное периоду в единицах мс. Т.е. если период прерываний будет 100мс, то в каждом прерывании от таймера увеличиваем переменную счетчика тиков на число 100, при периоде 10мс - на число 10 и т.п. Таким образом в этой переменной будет храниться относительное время в единицах мс с периодом переполнения примерно 0xFFFFFFFF/(1000мс*60с*60мин*24ч*30дн)=1,65 месяца.
В main-е в "вечном цикле" пускай "крутится" две основные задачи, которые выполняются поочередно.
1. HUI (интерфейс пользователя)
2. управление выходами.
Первая задача обеспечивает взаимодействие с клавиатурой и дисплеем, а также редактирование значений переменных, определяющих параметры управления выходами (описание функций выходов). Клавиатуры и дисплея может и не быть, а все параметры могут загружаться через какой-либо интерфейс. Это не суть важно.
Вторая задача, в соответствии с описанием функций каждого выхода (нормально замкнут, нормально разомкнут, время на которое выход должен быть включен и т.п.) управляет ими. Для отсчета интервалов времени должна иметься для каждого выхода своя переменная "временнОй засечки" той же рамерности, что и переменная "миллисекундных тиков". Берем беззнаковую разность между значением глобальной переменной миллисекундных тиков и временной засечки и сравниваем с переменной из описания конкретного выхода. Если разность меньше, то переходим к следующему выходу. Если же разность "больше или равно", то выполняем действие с выходом в соответствии с его описанием (включить/выключить) и запоминаем новое значение "временнОй засечки" для данного выхода.
Это все, что требуется для данной задачи. Описание функций выходов нужно хранить в энергонезависимой памяти (EEPROM внутренней или внешней или во Flash). Если же нужно, чтобы прибор продолжал функционировать с отсчетом всех временных интервалов даже и при пропадании питания, либо нужны временные интервалы более 1,5 месяцев, только тогда нужна м/с RTC с резервным питанием.
Забыл еще уточнить, что обе основные задачи "общаются" через область глобальных переменных, в которые загружаются из энергонезависимой памяти при включении прибора описания функций выходов.
И второй момент. При считывании значения переменной миллисекундных тиков нужно специальными методами обеспечить атомарность доступа к ней, если архитектура МК не обеспечивает этого условия (разрядность МК меньше 32-х бит).
Go to the top of the page
 
+Quote Post
SZ0
сообщение Mar 11 2009, 20:28
Сообщение #4


Местный
***

Группа: Участник
Сообщений: 326
Регистрация: 14-02-06
Пользователь №: 14 331



Цитата(Methane @ Mar 12 2009, 00:46) *
Какая точность нужна?


1 секунда
Go to the top of the page
 
+Quote Post
Methane
сообщение Mar 11 2009, 20:35
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 3 615
Регистрация: 12-01-09
Из: США, Главное разведовательное управление
Пользователь №: 43 230



Цитата(SZ0 @ Mar 11 2009, 22:28) *
1 секунда

Сделайте одно прерывание, к примеру в 100гц, в котором и следите за кнопками, реагируйте на что-то итд.
Go to the top of the page
 
+Quote Post
SZ0
сообщение Mar 11 2009, 21:02
Сообщение #6


Местный
***

Группа: Участник
Сообщений: 326
Регистрация: 14-02-06
Пользователь №: 14 331



Благодарю за столь развёрнутый ответ!

Делал систему, когда пользователь всё программирует и только потом происходит запуск. Но здесь пока не знаю как правильно "выкрутиться" с одновременным программированием и продолжением работы. Наверное нужно запоминать номер меню/блока который обрабатывается в режиме программирования, и при каждом последовательном проходе заходить в него и выполнять соответствующие действия пользователся?
Go to the top of the page
 
+Quote Post
rezident
сообщение Mar 11 2009, 21:42
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(SZ0 @ Mar 12 2009, 02:02) *
Наверное нужно запоминать номер меню/блока который обрабатывается в режиме программирования, и при каждом последовательном проходе заходить в него и выполнять соответствующие действия пользователся?
Т.е. проблема все-таки лишь с организацией меню? Это не так сложно как кажется. Допустим нам нужно простейшее трехуровневое меню при четырехкнопочной клавиатуре (кнопки: вверх, вниз, ввод, отмена).
1-й уровень. Основной. Сюда пользователь попадает сразу после включения прибора. Ему соответствует индекс меню - 0.
2-й уровень. Выбор номера редактируемого параметра. Ему соответствует индекс меню - 1.
3-й уровень. Редактирование значение выбранного параметра. Ему соответствует индекс меню - 2.
Вызывается функция меню. По текущему индексу переходим к соответствующей ветке.
а) Вначале индекс 0 - вызываем 1-й уровень, где, например, отображаем состояния выходов и ждем нажатия кнопок. Т.е. при вызове по индексу 0 (в Си это можно оператором switch оформить) вызываем функцию отображения переменной и проверяем наличие в буфере клавиатуры скан-кодов. Если скан-код имеется, то извлекаем его из буфера, меняем индекс меню - 1 и выходим из функции меню. Проверка делается всего один раз.
б) В следующий раз при вызове функции меню по индексу 1 попадаем уже во второй уровень. Где отображаем число номера параметра и м.б. сопровождающую надпись (типа "параметр N"). Проверяем наличие в буфере клавиатуры скан-кода клавиши. Если есть скан-код, то извлекаем его из буфера и проверяем на совпадение с кодами клавиш. Если "вниз", то уменьшаем (проверяя на выход за границу допустимых значений, т.е. если уже равно нулю, то НЕ уменьшаем) значение переменной номера параметра. Если "вверх", то увеличиваем (если равно максимальному номеру, то НЕ увеличиваем) величину переменной номера параметра. Если "ввод", то увеличиваем индекс меню на число 2. Если "отмена", то уменьшаем индекс меню на число 1. Проверка делается всего один раз и после этого выходим из функции меню.
в) В следующий заход попадаем опять по индексу меню. Если в предыдущий раз клавиши не нажимались, то индекс не менялся и все то же самое, что в п.б. Если индекс изменился и стал 0, то происходит все то же, что в п.а. Если же попали в третий уровень, то отображаем локальную копию значения параметра, номер которого был выбран на предыдущем вызове функции меню. И опять проверяем буфер клавиатуры. Если имеются скан-коды "вверх" или "вниз", то соответственно увеличиваем или уменьшаем на заданный шаг (совсем не обязательно именно на 1 изменять) локальной копии значения параметра. Если код "ввод", то сохраняем значение локальной копии параметра (той, что редактировали) в переменную из которой копировали это значение, уменьшаем индекс меню на 1. Если же код клавиши "отмена", то НЕ сохраняя значения, уменьшаем индекс меню на 1. Выходим из функции меню.
В общих чертах как-то так. Основная суть в том, что НЕ нужно постоянно находится в функции меню. Вошли в нее, перешли по индексу на соответствующий уровень, если нужно, то отобразили что-то, проверили нажатие клавиши, если в буфере был код клавиши, то выполнили требуемое действие и вышли из функции меню. Все!
Go to the top of the page
 
+Quote Post
Vavan4ik
сообщение Mar 24 2009, 07:23
Сообщение #8





Группа: Участник
Сообщений: 13
Регистрация: 23-12-08
Из: Украина, Днепропетровск
Пользователь №: 42 690



Спасибо мужики за тему, я тоже сейчас борюсь с временными интервалами от несколько секунд до 24 часов, причем одновременно нужно и отображать, и расчитывать, и опрашивать, и выводить, уже хотел спрашивать про многозадачность, но идея с большой переменной очень клевая, только вот нужно придумать чтобы ее обнулять безболезненно, чтобы не получилось переполнения (в случае если устройство будет включено более времени переполнения).
Спасибо!
Go to the top of the page
 
+Quote Post
rezident
сообщение Mar 24 2009, 18:28
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Vavan4ik @ Mar 24 2009, 12:23) *
только вот нужно придумать чтобы ее обнулять безболезненно, чтобы не получилось переполнения (в случае если устройство будет включено более времени переполнения).
Вы видимо не поняли сути, раз опасаетесь переполнения и собираетесь принудительно обнулять переменную. cranky.gif Я же не зря выделял слова про беззнаковую разность. Допустим, что переменная "системных тиков" 8-ми разрядная и изменяется на 1 каждую секунду. С помощью такой переменной можно отмерить интервал времени 4 с четвертью минуты. Допустим нам нужно отмерить 10 секунд, а текущее значение переменной "тиков" timeTick равно 250. Запомним это значение во временной статической переменной. С первого взгляда может показаться что возникнет ошибка, ведь 250+10=260 и превышает разрядность выбранной переменной (255 max). Но в этом нет ничего страшного! Мы ведь берем беззнаковую разность. А при таком счислении условие типа
Код
if ((timeTick-time)>=10)

будет истинно тогда, когда значение переменной timeTick достигнет значения 4. Т.е. при беззнаковом вычитании 8-ми разрядных переменных 4-250=10. Проверяем действительно ли 10 секунд? Счетчик timeTick принимает последовательно такие значения
0 - 250 <<--- исходное значение, от которого начинаем отсчет/сравнение
1 - 251
2 - 252
3 - 253
4 - 254
5 - 255
6 - 0 <<--- вот это "естественное" переполнение, которого вы почему-то боитесь smile.gif
7 - 1
8 - 2
9 - 3
10 - 4
Видим, что интервал между 250 и 4 действительно из 10 отсчетов состоит, а каждый отсчет у нас по условию это 1 секунда. 10*1 сек=10 секунд, хоть при этом произошло совсем не опасное переполнение счетчика. smile.gif
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 23rd June 2025 - 23:45
Рейтинг@Mail.ru


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