это предложение поясняет то, от чего сигналы на INT0 считаются 1 за 2?
да: вы вошли в обработчик прерывания, что-то делаете, а в это время контакт дребезжит, т.е. проваливается в 0 и снова становится в 1. таким образом у вас возникает условие для возникновения того же самого прерывания сразу же после того, как вы завершите обработку. вам еще крупно повезло, что только 2 раза на одно нажатие из-за дребезга у вас прерывание обрабатывается - могло бы и 10 раз сработать...
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
Большое спасибо за столь поняьный ответ. Не подскажете как избавиться от дребезга, я так понимаю нужно исползовать таймер?
если вы начинающий - зачем вам сложности с таймером? я уже так много раз рассказывал про кнопки, что скоро тошнить будет... но все-таки повторюсь.
алгоритм опроса кнопки должен быть следующим: 1. считываем состояние кнопки (или кнопок, если их несколько) в какую-то переменную, пусть это будет key 2. делаем задержку на 10-15 миллисекунд, за которые дребезг обычно должен кончиться 3. снова считываем состояние кнопки и сравниваем его с key 4. если оба значения одинаковы - то key и будет соответствовать текущему состоянию кнопки (кнопок), можно его обрабатывать 5. если значения разные - то мы считаем, что дребезг еще не кончился и тогда вместо key выдаем 0, что должно означать отсутствие нажатия кнопок.
на языке Си это может выглядеть так:
Код:
// макрос для задержки подалвения дребезга в миллисекундах #define DEBOUNCE 15
uint8_t get_key_code(void); // эта функция вернет состояние кнопок
// функия опроса кнопок, вернет 0, если нет нажатий, не ноль - если есть uint8_t get_key(void){ uint8_t key;
вы всегда используете get_key(), если хотите определить состояние кнопки или кнопок. особо заострю ваше внимание на функции get_key_code(), для которой я не показал реализацию. дело в том, что эта функция может быть разной для одной кнопки, пяти-восьми кнопок, для матрицы 4х4 или даже более - в каждом случае она должна быть своя. можно заменить ее макросом, если работаем только с 1-8 кнопками. вот пример для опроса единственной кнопки, висящей на 0-ом пине PORTB:
так как обычно кнопки с порта вешают на землю, то нажатому состоянию соответствует 0 в соответствующем пине. чтобы не нарушать логику, я инвертирую это значение, чтобы не нажатому состоянию соответствовал 0, а нажатому 1.
если вы повесили 4 кнопки на PORTB, то поступаете вот так:
Код:
// определяем константы для каждой кнопки #define KEY1 _BV(PB0) #define KEY2 _BV(PB1) #define KEY3 _BV(PB2) #define KEY4 _BV(PB3) // а вот так мы обозначаем сразу все наши кнопки #define ALL_KEY (KEY1 | KEY2 | KEY3 | KEY4)
в этом случае в своей программе вы вот так обрабатываете все свои 4 кнопки:
Код:
// где-то в глубине своей программы
switch(get_key()){ case KEY1: // тут обработка кнопки 1 break; case KEY2: // тут обработка кнопки 1 break; case KEY3: // тут обработка кнопки 1 break; case KEY4: // тут обработка кнопки 1 break; case KEY1 | KEY3: // тут обработка одновременного нажатия сразу 2 кнопок break; default: // а тут обработка всех прочих вариантов, в том числе отсутствия нажатия }
как видите, все элементарно просто, и никакие таймеры не нужны. когда заматереете, как программист, тогда, возможно, начнете обрабатывать кнопки и с прерываниями и таймерами, но лично мне в огромном количестве поделок практически никогда это не требовалось...
P.S. да, примеры я привел с ориентацией на avr-gcc, если вы любитель CodeVision, вам нужно перед всем этим добавиь пару строчек:
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
я ведь понимаю как должна работать эта программа, вся проблема в том что я не знаю как это записать в код.
понимать как должна работать программа этого очень мало - это лишь техническое задание. Алгоритм - это решение техзадания и не зависит от языка его можно написать хоть на русском(блок-схемы, графическая форма, карта состояний), а уже алгоритм преобразуется в программу практически чисто механически с учетом возможностей конкретного языка.
Цитата:
- это как?
Берешь указательный палец правой руки и водишь им по программе предсказывая её поведение в каждый момент времени. Это возможно, поскольку программа работает строго определенным образом и не зависит от нашего желания - обычно когда за строгость принимаешь собственное желание возникает неожиданное поведение программы.
Про обход дребезга я уже написал(ниже). Единственное что отмечу - тебе надо считать именно количество моментов отпускания(или нажатия?) кнопки. Значит в кратце обрисуем алгоритм. У нас есть бесконечный цикл, внутри него первым шагом стоит задержка 10мс, потом считывание кнопки +сохранение его в переменную, и CASE на 4 состояния кнопки(текущее и предыдущее) из всех 4-х состояний нам интересно лишь одно - текущее:кнопка нажата прошлое:кнопка отпущена. Как обнаруживаем это состояние - прибавляем +1 к количеству нажатий. И делаем все что нам надо еще - проверяем какое нажатие, если 2-е то что-то делаем и т.д. Перед переходом к началу цикла копируем текущее состояние кнопки в предыдущее. Замечу еще раз: чтобы не нарваться на дребезг считывать кнопку надо только один раз за итерацию, а внутри цикла работать только с сохраненным значением.
Цитата:
я уже так много раз рассказывал про кнопки, что скоро тошнить будет... но все-таки повторюсь.
Чрезмерно усложненный алгоритм. Чтобы победить дребезг АБСОЛЮТНО ДОСТАТОЧНО считывать состояние кнопки ОДИН РАЗ на интервале минимум 10мс. Т.е. можно больше и даже немного меньше - зависит от качества кнопки(герконам, говорят, хватает 2мс). Но больший интервал уже может приводить к заметной человеком задержку реакции на нажатие.
Если алгоритм не критичен к скорости выполнения, то можно вставить такую задержку в главный цикл и в начале его считывать состояние кнопки и уже им пользоваться внутри цикла вполне безопасно. Тогда каждая итерация основного цикла будет занимать примерно 10мс, этот факт надо учитывать и использовать(для отсчета времени, например). Иногда нужно знать предыдущее состояние для отлова моментов нажатия/отпускания - тогда достаточно в конце цикла, сразу перед переходом на следующую итерацию сохранить текущее состояние в переменную прошлого состояния кнопки. Внутри цикла если сравнивать текущее значение и прошлое можно выделить 4 состояния: 1) момент нажатия, 2) кнопка нажата и удерживается 3) момент отпускания 4) кнопка отпущена.
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
обеспечить равномерную переодичность опроса в главном цикле намного сложнее, чем пользоваться моим вариантом кода. сомневаюсь, что от этого будет какой-то выигрыш... но если вы приведете свой вариант кода - с интересом погляжу: век живи, век учись
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
Это уже проблемы пользователя а не программы. Меньше интервал - начнется реакция на дребезг, больше интервал - будет недоволен пользователь. В обсуждаемом алгоритме, периодичность опроса будет варьироваться +- какая-то сотня микросекунд. Огромная разница, правда? Если есть такие части программы которые выполняются долго а опрос кнопок нужен - повесить анализ кнопок на прерывание от таймера который даст стабильный интервал независимо от основного алгоритма. Но кажется мне что при лагах в программе порядка 5 секунд уже пофиг будет сколько раз пользователь нажал кнопку за эти 5 секунд, тут подход другой нужен - фиксировать лишь сам факт нажатия т.е. повесить кнопку на прерывание и сбрасывать признак нажатия лишь после обработки нажатия, всеравно в эти 5 секунд программа занята очень важной обработкой и отреагировать на нажатие не может.
Если есть такие части программы которые выполняются долго а опрос кнопок нужен - повесить анализ кнопок на прерывание от таймера который даст стабильный интервал независимо от основного алгоритма.
и чем же это будет лучше (проще?) обычного периодического опроса кнопки, предлагаемому мной? использованием лишнего ресурса - таймера?
в сущнсти, все вами сказанное отторжения у меня не вызывает - варианты известные и применяемые по ситуации. мне приходилось вешать кнопки на линии вывода на ЖКИ - вот там пришлось поизвращаться с опросом, и то обошелся без таймеров и прерываний но надо ли так все усложнять начинающему?!
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
В чем именно усложнение? Простое чтение с одной задержкой, против двух считываний, задержки и сравнения результатов двух считываний в вашем алгоритме? Так все-таки что проще? А потом ведь будут введены еще понятия текущее состояние/прошлое состояние... так в пору и запутаться с тем что где и как представлено.
как изменится ваш код для 16 кнопок матрицей? для 3 кнопок на 3 разных портах? если таймер занят чем-то? если пинов с аппартными запросами прерываний нет свободных?
вы каждый раз будете изобретать новый костыль? я - нет
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
алгоритм опроса кнопки должен быть следующим: 1. считываем состояние кнопки (или кнопок, если их несколько) в какую-то переменную, пусть это будет key 2. делаем задержку на 10-15 миллисекунд, за которые дребезг обычно должен кончиться 3. снова считываем состояние кнопки и сравниваем его с key 4. если оба значения одинаковы - то key и будет соответствовать текущему состоянию кнопки (кнопок), можно его обрабатывать 5. если значения разные - то мы считаем, что дребезг еще не кончился и тогда вместо key выдаем 0, что должно означать отсутствие нажатия кнопок.
Универсальным решением я полагаю ВСЕГДА использовать один таймер как системный. И все относительно большие интервалы типа дребезга, миганий, интервалов регенерации и т.п. вешать на этот таймер как ПРОГРАММНЫЕ таймеры. А использовать в программе delay() - глупость какая то для любителей подрыгать ногой... Из серии printf ...
Есть кнопки, значит наверняка есть и индикация - вот туда и впендюрить опрос кнопок... всего-то один раз считать порты. У вас же опрос кнопок всегда будет сопряжен с задержками в программе даже когда в этом нет необходимости.
Универсальным решением я полагаю ВСЕГДА использовать один таймер как системный. И все относительно большие интервалы типа дребезга, миганий, интервалов регенерации и т.п. вешать на этот таймер как ПРОГРАММНЫЕ таймеры. А использовать в программе delay() - глупость какая то для любителей подрыгать ногой... Из серии printf ...
Cцепившись в споре, гуру забыли об бедном ТС. Если не жмут габариты и питание, на первых порах можно дребезг гасить аппаратно, отложив программное на потом, когда опыту поболе накопится. Два варианта на выбор. Что касается программного - мое мнение, согласованное с котом Мурзиком, через задержки - это через ОПУ. Но каждый делает "под себя" ( в лучшем смысле этих слов ) У меня, как у КРАМа, один системный таймер, который обслуживает все программные таймеры. С кнопками я обращаюсь так : есть 2-байтовый сдвиговый регистр. Получив прерывания от таймера, считываю состояние кнопок и сравниваю с 2-мя предыдущими. a) Если все 3 совпали - состояние статично, сравниваем его с предыдущим зафиксированным статусом кнопок.Если совпадает - ничего не делаем, не совпадает - выставляем флаг изменения состояния и фиксируем новый статус кнопок. b) Если не совпали - принятое состояние заталкиваем в сдвиговый регистр, выталкивая самое "давнее" значение. Все. На словах - сложно, а в коде это - десяток строк на асме.
Заголовок сообщения: Re: Обработка нажатия кнопки в AVR...
Добавлено: Сб апр 26, 2014 11:59:38
Нашел транзистор. Понюхал.
Зарегистрирован: Вс мар 30, 2014 21:41:24 Сообщений: 170 Откуда: Украина
Рейтинг сообщения:0
Честно говоря я не полностью разобрался с вашими советами и начал городить что-то своё. Посмотрите пожалуйста код и скажите что можно исправить, или заменить что-то? Эта программа в Proteus работает нормально. Но думаю может вы подскажете еще что нибудь?
Код:
#include <mega8.h> #include <delay.h>
volatile unsigned char per=0;
void main(void) { PORTB=0x00; DDRB=0x01;
PORTC=0x01; DDRC=0x00;
while (1) { unsigned char i, dr; if (PINC.0==0) // если кнопка нажата { dr=0; for (i=0;i<10;i++) // программный антидребезг контактов { delay_ms(10); if(PINC.0==0)
Фигня. У вас каждые N мс пока кнопка нажата будут считаться как отдельные нажатия кнопок.(похоже что N = 500).
В вашем-то случае, работа программы не критична к задержке в 10мс, значит можно главный цикл сделать с задержкой по 10мс на каждую итерацию. В таких условиях с дребезгом кнопки бороться уже не надо - один раз в начале цикла считываете состояние кнопки и сохраняете его. Внутри цикла нужно использовать это самое сохраненное. Тогда проблем с дребезгом никаких не будет.
Дальше, берем и сравниваем это значение с сохраненным в предыдущей итерации - если одинаковое ничего не делаем, если значения отличаются - значит произошло нажатие или отпускание а что именно определить можно из текущего состояния.
Заголовок сообщения: Re: Обработка нажатия кнопки в AVR...
Добавлено: Сб апр 26, 2014 19:27:35
Модератор
Карма: 90
Рейтинг сообщений: 1289
Зарегистрирован: Чт мар 18, 2010 23:09:57 Сообщений: 4510 Откуда: Планета Земля
Рейтинг сообщения:0 Медали: 1
sanyo.95, Вам бы книжечки по Си почитать. Вы даже не знаете что такое цикл, а сели писать программу. Стыдно должно быть такие вопросы задавать, имея интернет на компьютере...
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 11
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения