Кнопки прерывания таймеры

Обсуждаем контроллеры компании Atmel.
Ответить
Вымогатель припоя
Аватара пользователя
Сообщения: 508
Зарегистрирован: Пт фев 22, 2013 18:00:43
Откуда: Беларусь, г. Гомель

Сообщение rxstart1 »

Доброго времени всем. Опрос кнопки через порт известен всем тут нет ничего сложного
if (!PIND.1)
{
delay_ms(10);
if (!PIND.1)
{<...событие>}
}.
Но иногда возникает необходимость экстренно опросить кнопку, т. е. несмотря на, то что выполняется кусок программы при нажатии на кнопку управление должно передаться обработчику кнопки из любого места программы. Чтобы реализовать это необходимо использовать обработчик прерывания на ноге к которой подключена кнопка.
Я написал такую программу, может для кого будет интересно, кому то поможет. Для начала нужно завести переменную, в которой будет находится вся информация о кнопке. Почему переменную, а не новый тип - типа структуры, в которой для каждого состояния будет своя переменная, потому, что это микроконтроллер, а не CORE I7 :))) . Нужно экономно использовать память. Вот описание бит переменной типа unsigned integer.
|-|-|-|-| |-|10|9|8| |7|6|5|4| |3|2|1|0|
0-7 - счетчик времени удержания кнопки максимальное значение 256 в десятичной системе или FF в HEX
8-9 - состояние кнопки: 00 - Сброс
01 - Нажата
10 - Отпущена
11 - Удерживается
10 - флаг разрешения на включение таймера: 0 - Запретить включение таймера
1 - Разрешить включение таймера
11-15 - не используются
Прогу на си прикрепляю. Далее хочу добавить, кому это интересно. Как видите биты с 11 по 15 не используются, а их можно использовать скажем для определение комбинаций нажатий кнопки, типа короткий + короткий + длинный(как в известной игрушке mortal combat :))) ) и т. п. Или же увеличить за счет них определение время удержания кнопки.
Вложения
button.rar
(1.54 КБ) 230 скачиваний
Реклама
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Сообщение uk8amk »

Почему переменную, а не новый тип - типа структуры, в которой для каждого состояния будет своя переменная, потому, что это микроконтроллер, а не CORE I7
Спорное утверждение.
Тип структуры с битовыми полями обычно работает не хуже. К тому же если использовать перечислители кодов состояний кнопок, то можно отказаться от магических чисел с непонятными логическими масками. Выйдет проще и прозрачней.

Вы зачем-то используете внешнее прерывание с кнопкой. При этом всё равно на кнопку завязан таймер с вектором TIM0_OVF. Логичнее было туда свалить всё, и подсчёт интервалов, и определение нажатий.

Далее код в основном цикле потенциально не безопасен. Вы выполняете некие действия с переменной int как будто процесс синхронный. На самом деле эти данные меняются асинхронно по отношению к основному циклу. Результат может быть непредсказуем, работа с периодическими ошибками. Выход - синхронизировать/буферизовать состояние переменной кнопки только в одном месте программы. Часто это делается отдельными функциями getter-setter. Там же реализуется атомарный доступ к длинным данным.
Реклама
Вымогатель припоя
Аватара пользователя
Сообщения: 508
Зарегистрирован: Пт фев 22, 2013 18:00:43
Откуда: Беларусь, г. Гомель

Сообщение rxstart1 »

uk8amk писал(а): Далее код в основном цикле потенциально не безопасен. Вы выполняете некие действия с переменной int как будто процесс синхронный. На самом деле эти данные меняются асинхронно по отношению к основному циклу. Результат может быть непредсказуем, работа с периодическими ошибками. Выход - синхронизировать/буферизовать состояние переменной кнопки только в одном месте программы. Часто это делается отдельными функциями getter-setter. Там же реализуется атомарный доступ к длинным данным.

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

По поводу вектора на таймер не совсем Вас понял, что и как на него завязывать?
Модератор
Аватара пользователя
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

rxstart1 писал(а):По поводу вектора на таймер не совсем Вас понял, что и как на него завязывать?
Имелось в виду, можно повесить всю обработку кнопок на таймер, без всяких внешних прерываний. Ибо это лишние ресурсы + кнопки должны висеть на определённых выводах.
А плюсов никаких.
Реклама
Эиком - электронные компоненты и радиодетали
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

А мне вот этот алгоритм больше нравиться
http://kit-e.ru/articles/circuit/2007_08_170.php
Плюсы:
1) хоть 1 хоть 2 кнопки да хоть подключение матричной клавиатуры,алгоритм не меняется.
2) кнопки можно подключать к любым выводам.
Минусы:
Структура программы должна быть в виде Switch, и в майне категорически не должно быть delay_ms и любых других задержек.
Реклама
Вымогатель припоя
Аватара пользователя
Сообщения: 508
Зарегистрирован: Пт фев 22, 2013 18:00:43
Откуда: Беларусь, г. Гомель

Сообщение rxstart1 »

Да согласен переписал код, вместо прерывания использую захват таймера. Код получился еще короче, правда есть и минус, нельзя использовать этот таймер для других целей. Благо есть еще один :)))
Структура программы должна быть в виде Switch, и в майне категорически не должно быть delay_ms и любых других задержек.
Это совсем разные вещи. В Вашем случае опрос происходит линейно в основном цикле, в моем асинхронно, т. е. В моем случае, кнопка сработает теоретически даже при "зависании" основной программы. Ну и в основной программе иногда требуются задержки. :)))
Реклама
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Сообщение uk8amk »

правильно написанная программа не будет глючить. Пробовал использовать в своих устройствах все работает без ошибок и зависаний.
В том и дело.
Поясню что у вас не так.

Код: Выделить всё

volatile unsigned int StartStop;
...
if (StartStop==RELEASE)
...
#define HOLD    (StartStop&(1<<8))&&(StartStop&(1<<9))
Как вы думаете, за сколько маш.циклов будет происходить процесс обращения к данным(копирование/сравнение) StartStop? Является ли он атомарным? Здесь я полагаю что вы работаете на 8-битном процессоре AVR.

И то что у вас оно где-то как-то работает вовсе не гарантирует правильную работу в других программах при других условиях.
Вымогатель припоя
Аватара пользователя
Сообщения: 508
Зарегистрирован: Пт фев 22, 2013 18:00:43
Откуда: Беларусь, г. Гомель

Сообщение rxstart1 »

Вы имеете ввиду , что переменная изменяется внутри обработчика прерывания и при передаче управления у нее новое значение. Я это прекрасно понимаю и соответственно зная эту особенность и писал основной код. :)))
Кстати у меня возник вопрос по структурам. Верно ли, что такая структура занимает 8 бит и если это так, то почему я могу свободно записать t.A=5; И реально в дебаге t.A=5. Вот это мне действительно непонятно? :shock:
typedef struct
{
unsigned A : 1;
unsigned B : 1;
unsigned C : 1;
unsigned D : 1;
unsigned E : 1;
unsigned F : 1;
unsigned G : 1;
unsigned H : 1;
} t8;

t8 t;
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Сообщение uk8amk »

Одиночный спецификатор unsigned резервирует область размером int. Поэтому вся структура должна занять не менее sizeof(int) байт.
Если же писать unsigned char A:1, то по идее да, на структуру 8 бит. Правда в некоторых системах и компиляторах возможна иная упаковка и выравнивание данных.
t.A=5; это выражение должно взять только младший бит. Попробуйте в отладке взять адрес структуры и вставить в окно Memory. Возможно что отладка шалит.
Вымогатель припоя
Аватара пользователя
Сообщения: 508
Зарегистрирован: Пт фев 22, 2013 18:00:43
Откуда: Беларусь, г. Гомель

Сообщение rxstart1 »

Попробую, я просто никогда не использовал такого вида переменные, нашел в нете описание и как мне показалось директива :1 после переменной указывает на ее размер. Т. е. правильно записать unsigned char A : 1; ?
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

rxstart1 писал(а):Это совсем разные вещи. В Вашем случае опрос происходит линейно в основном цикле, в моем асинхронно, т. е. В моем случае, кнопка сработает теоретически даже при "зависании" основной программы. Ну и в основной программе иногда требуются задержки. :)))
А зачем нужна реакция от кнопки если, дальнейший алгоритм обработки завис ? :)
В Вашем случае опрос происходит линейно в основном цикле, в моем асинхронно
А кто мешает перенести мой алгоритм с некоторыми доработками в таймер?
Ответить

Вернуться в «AVR»