Главная » Программирование » PIC - микроконтроллеры » Дребезг контактов кнопки или вред прерываний - INT0 в PIC18

Дребезг контактов кнопки или вред прерываний — INT0 в PIC18

Цикл статей – PIC начинающим или основы основ

INT0 в PIC18 — про внешние прерывания

В этой статье наглядно покажем к чему приводит дребезг контактов, почему обрабатывая кнопки нужно учитывать этот эффект, а заодно разберемся с внешними прерываниями PIC18 на примере INT0.

Внешние прерывания (External interrupt) в PIC18

Помните, в прошлой статье я рассказал о прерываниях таймера TMR1? На схеме используемой демоплаты видно, что кнопка SW1 подключена к порту RB0. Порт RB0 примечателен тем, что на него выведена замечательная альтернативная функция — внешнее прерывание INT0.

PIC18F45К20 - распиновка

PIC18F45К20 — распиновка

Если требуется, чтобы микроконтроллер сразу же обрабатывал внешние воздействия в виде перепадов 0 и 1 на входах RB0, RB1, RB2, необходимо воспользоваться прерываниями INT0, INT1, INT2 соответственно. Каждое из прерываний INT можно настроить независимо друг от друга. Поскольку в нашей демоплатке кнопка подключена на RB0, то рассматривать буду прерывание INT0.

Прерывание INT происходит при изменении логического уровня входного сигнала. INT можно настроить так, чтобы событие прерывания происходило либо по фронту, т.е. сигнал меняется с лог. 0 на лог. 1, либо наоборот — по спаду, т.е. сигнал на меняется с лог. 1 на лог. 0. Эту настройку можно делать в любой момент программы битом INTEDG0 в регистре INTCON2.

Биты регистра INTCON2

Биты регистра INTCON2

INTCON2bits.INTEDG0 = 1; // Прерывание по фронту
INTCON2bits.INTEDG0 = 0; // Прерывание по спаду

Возникшее прерывание необходимо сбросить:

INTCONbits.INT0IF = 0; // Сбросили флаг прерывания по INT0

Если этого не сделать, прерывание будет выполняться в бесконечном цикле и программа зависнет.

Кнопка SW1 подключена так, что при нажатии сигнал на RB0 изменяется из состояния 1 в состояние 0, при отпускании из 0 в 1.

Изменение логического уровня в зависимости от состояния кнопки

Изменение логического уровня в зависимости от состояния кнопки

Теперь можно дополнить комментарии в приведенном выше коде:

INTCON2bits.INTEDG0 = 1; // Прерывание по фронту (при отпускании кнопки)
INTCON2bits.INTEDG0 = 0; // Прерывание по спаду (при нажатии на кнопку)
Для INT1, INT2
Для настройки INT1 и INT2 нужно изменять соответственно биты INTEDG1 и INTEDG2 в регистре INTCON2.

Для наглядности срабатывания кнопки напишем программу с эффектом двоичный счетчик, в которой счет прибавляется при нажатии на кнопку. Код файла main_intv2.c:

/*
 * File:   main_intv2.c
 * Author: PRO-DIOD.RU
 *
 */

#include <xc.h> // В этом проекте можно заменить строкой #include <pic18f45k20.h>
#include "config_bits.h"

/*######################################################################################################################
 * Г Л А В Н А Я   Ф У Н К Ц И Я
 */
int main(void)
{
/* Переменные. Действуют внутри функции main() */
// Нет переменных

/* Включаем кварц */
OSCCON = 0b01110001; // Internal; 16MHz;
OSCTUNEbits.PLLEN = 1; // PLL включен! 16MHz * 4 = 64MHz;

/* Настройки прерываний */
INTCONbits.PEIE = 1;            // Периферийные прерывания разрешены
INTCONbits.GIE  = 1;            // Глобальные прерывания разрешены
RCONbits.IPEN   = 1;            // Разрешить двуприоритетные прерывания

/* Настройка портов I/O */
TRISD = 0x00;// Порт D как выход
LATD = 0x00; // Гасим все светодиоды на PORTD
// INTCONbits.RBIE = 1;

TRISB = 0x00000001; // RB0 как вход (для кнопки)

/* Настройка прерывания INT0 */
//INTCON2bits.INTEDG0 = 1; // Прерывание по фронту (при отпускании кнопки)
INTCON2bits.INTEDG0 = 0; // Прерывание по спаду (при нажатии на кнопку)
INTCONbits.INT0IE   = 1;  // Включить прерывание (interrupt) TMR1
INTCONbits.INT0IF   = 0; // Очищаем флаг прерывания (чтобы сразу не свалиться в прерывание)

while(1)
  {
	// ничего нет =)
  } // while(1) end
} // main end

/*######################################################################################################################
 * ОБРАБОТЧИК ПРЕРЫВАНИЙ с НИЗКИМ ПРИОРИТЕТОМ
 */
void interrupt low_priority low_isr (void)
{

} // low_isr END

/*######################################################################################################################
 * ОБРАБОТЧИК ПРЕРЫВАНИЙ с ВЫСОКИМ ПРИОРИТЕТОМ
 */
void interrupt high_isr (void)
{
if (INTCONbits.INT0IF && INTCONbits.INT0IE)
  {
	INTCONbits.INT0IF = 0; // Сбросили флаг прерывания по INT0
	LATD = PORTD + 1;   // Прибавляем единичку к значению на PORTD (см. двоичный счетчик)
  }

// Поскольку в проекте используется только один источник прерывания (INT0),
// можно обойтить без оператора IF:

//INTCONbits.INT0IF = 0; // Сбросили флаг прерывания по INT0
//LATD = PORTD + 1;   // Прибавляем единичку к значению на PORTD (см. двоичный счетчик)

} // high_isr END

Обратите внимание на строчку 20:

OSCTUNEbits.PLLEN = 1; // PLL включен! 16MHz * 4 = 64MHz;

В прошлых проектах микроконтроллер работал на частоте 16МГц, теперь, для ускорения реакции МК, включен PLL, который умножает частоту на четыре. В результате МК работает на частоте 64МГц. Это максимальная по документации частота МК.

Подключенный файл config_bits.h аналогичен прошлому проекту.

Скачать готовый проект по ссылке:

Кнопка (INT0 при нажатии)
125.3 KiB
62 Downloads
Детали

Чтобы двоичный счетчик прибавлялся при отпускании кнопки, нужно раскомментировать строчку 36 и закомментировать строчку 37. Должно получиться так:

INTCON2bits.INTEDG0 = 1; // Прерывание по фронту (при отпускании кнопки)
//INTCON2bits.INTEDG0 = 0; // Прерывание по спаду (при нажатии на кнопку)

Скачать готовый проект по ссылке:

Кнопка (INT0 при отпускании)
125.3 KiB
55 Downloads
Детали

Результаты применения INT0 для обработки кнопки

По идее, при нажатии или отжатии кнопки — в зависимости от загруженной программы в МК, к значению порта B (RB) будет прибавляться единица, а светодиоды будут показывать состояние порта. Но в реальности, во время коммутации кнопки из-за несовершенства контактной группы, коммутация будет происходить с дребезгом. Это будет выражаться в том, что при нажатии или отжатии кнопки к значению порта B (RB) будет прибавляться два или три. На самом деле прибавляется по единице, но этот процесс происходит очень быстро, поэтому кажется, что прибавляется больше, чем по единице.

Эффект дребезга может появляться не всегда!
У кого-то этот эффект может быть очень хорошо выражен, у кого не быть совсем — все зависит от поганости кнопки, влажности, температуры и кучи других параметров, которые и делают этот процесс случайным.

Как бороться с дребезгом кнопок?

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

1) Способ на аппаратном уровне заключается в установке конденсатора параллельно кнопке емкостью примерно 0,01 мкФ (10 нФ).

2) Способ программный заключается в том, что опрос кнопок производится редко, примерно 10…100 раз в секунду, например, в прерывании таймера.

Метки::

1 отзыв Ваш отзыв

  1. il86md #

    подскажите если я правильно понял. мне надо поймать импульс на ноге (int0 RB0) и замерить его длину счетчиком.
    ________
    ___/ \___
    импульс из низкого уровня в высокий и с высокого в низкий.
    до прерывания я должен установить
    INTCON2bits.INTEDG0 = 1; // Прерывание по фронту
    произошло прерывание
    в прерывании я должен выставить
    INTCON2bits.INTEDG0 = 0; // Прерывание по спаду
    стартануть таймер
    ждать снова прерывания по спаду
    останавливаем таймер.

    p.s. в прерывании GIE=0

Ваш отзыв