Яндекс.Метрика

    Песочница

    Внешние прерывания у 8-bit avr, использование кнопок

    Здравствуйте, на днях решил поэксперементировать с внешними прерываниями на attiny2313A. Думаю тем кто занимался программированием микроконтроллеров известно, что МК не всегда быстро может реагировать на нажатие кнопки, т.к. проверка PINа стандартно осуществляется в бесконченом цикле и если программа доостаточно большая — это может затормозить опрос ножки.
    Код ниже написан для WinAVR.

    image

    Стандартный опрос:


    • DDRxy|=(0<<y); PORTxy|=(0<<y)
      с одной стороны кнопка подключена к плюсу (VCC), а с другой стороны к ножке.
      В таком случае провод который подключен к ножке выступает в роли антены и любое возмущение электрическо-магнитного поля вокруг проводка вызывает срабатываение кнопки, что неприемлимо.

    • DDRxy|=(0<<y); PORTxy|=(1<<y)
      С одной стороны кнопка подключена к минусу (GND), а с другой стороны к ножке.
      Это наиболее примелимый вариант, наводок не возникает и кнопка срабатывает стабильно


    Во втором способе, обычный опрос в цикле будет выглядеть:
    if (!(PINB & (1<<PINB6))){ // если нажата кнопка на ноге PORTB6, то выполнить:
    моргнуть;
    }
    if (PINB & (1<<PINB7)){ // если ненажата кнопка на ноге PORTB7, то выполнить:
    моргнуть;
    }

    если инвертировать, то получиться и для первого способа, но не думаю что это кому-то надо.

    Итак сами Внешние прерывания


    В даташите на Мк attiny2313A
    есть прерывания INT0 (нога PD2), INT1(нога PD3), и PCINT0..7 (весь порт B и хотя ножек у него 8, но прерывание одно на всех, что лично меня не радует )
    Прерывания INT0 и INT1 их приоритет выше других прерываний.

    Итого мы можем настроить всего три кнопки без использования стандартного опроса.
    У меня была мысль, что т.к. я задействую внешние прерывания то регистры DDR и PORT ничего не изменят в поведение МК, но это не так… выход так же надо настраивать как при стандартной обработке.
    Сразу оговорюсь, что я пишу про ножки, настроенные на пдотягивающие резистор т.е. DDRxy|=(0<<y); PORTxy|=(1<<y). иначе смысла нет, срабатывание от прикосновения пальца, как мне кажется, никого не интересует.

    Регистры управления


    Итак даташит страница 58 External Interrupts

    MCU Control Register– MCUCR:
    image

    image
    image

    Если стоит по дефолту, The low level of INT0 generates an interrupt request, то нажав кнопку мы получим срабатвыание вектора, если ее не отпускать, то программа снова и снова будет уходить на прерывание.

    Если Any logical change on INT1 generates an interrupt request, то нажав кноку и не отпуская ее, функция прерывания сработает один раз и дальше программа пойдет по стандартной схеме, но когда мы подождав отпутим кнопку — это опять же будет изменение логики, то вектор опять запуститься.

    The falling edge of INT1 generates an interrupt request — тоже самое что и дефолт, во всяком случае по эксперементам, только работает мене стабильно, пока отжимаешь кнопку может сработать.

    The rising edge of INT1 generates an interrupt request — кнопка работает только когда ее отжимаешь.

    General Interrupt Mask Register – GIMSK:
    Глобально разрешает нужные нам прерывания.
    image

    External Interrupt Flag Register – EIFR:
    Регситр отвечающий за испольнение прервыания, если логика на ножке изменилась, то в регистре появляется запись, и вектор прервыания начинает обрабатываться.
    image

    Pin Change Mask Register – PCMSK:
    Разрешает прерывание на той или иной ноге Порта B
    image

    отдельно про PCINT

    Это ненастраиваемое внешнее прерывание, в отличие от других и всегда работает по принципу Any logical change что несколько затруднит его использование, хотя и ему применение найдется в разумных руках.
    И еще беда одна — наблюдается ложное срабатывание при подключении МК к питанию, уходит один раз на прерывание и больше не сбоит, работая в штатном режиме

    Вектора прерываний затрагивающие нашу тему


    image

    void preriv() //функция инициализации прерываний
    {
    GIMSK=(1<<PCIE)|(1<<INT0);
    PCMSK=(1<<PCINT0);
    MCUCR=(0<<ISC00)|(0<<ISC01);
    }
    preriv();// вызов функции инициализации в теле цикла

    ISR(INT0_vect){ // прерывание по вектору INT0
    PORTD|=(1<<PORTD4);
    _delay_ms(1000);
    }

    ISR(PCINT_vect){ // прерывание по вектору PCINT
    PORTD|=(1<<PORTD4);
    _delay_ms(1000);
    }


    Проект для Win AVR, attiny2313 PORTD4 — на нем стоит анодом(плюсом) светодиод и моргает когда кнопка на POTRD2 замыкается на землю.

    Чтобы использовать другой МК смотрите соответствующий Даташит.

    Самому мне помогла статья Dmitry.