Использование прерываний в микроконтроллере PIC


В данной статье мы рассмотрим работу с внешними прерываниями в микроконтроллере PIC и почему в этом возникает необходимость. Перед началом изучения данной статьи рекомендуем ознакомиться с общими принципами программирования микроконтроллеров PIC с помощью программы MPLABX и подключения к микроконтроллеру PIC ЖК дисплея.

Внешний вид проекта для демонстрации использования прерываний в микроконтроллере PIC

Также на нашем сайте вы можете посмотреть статьи про использование прерываний в плате Arduino и плате STM32 Blue Pill.

Необходимые компоненты

  1. Микроконтроллер PIC16F877A (купить на AliExpress).
  2. Держатель микросхем на 40 контактов (купить на AliExpress).
  3. Программатор PICkit 3 (купить на AliExpress).
  4. Кварцевый генератор 20 МГц (купить на AliExpress).
  5. Конденсаторы 22 пФ (2 шт.) и 0,1 мкФ (купить на AliExpress).
  6. Конденсатор 10 мкФ (купить на AliExpress).
  7. Регулятор напряжения 7805 (купить на AliExpress).
  8. ЖК дисплей 16х2 (купить на AliExpress).
  9. Макетная плата.
  10. Соединительные провода.

Что такое прерывания и зачем они нужны

В микроконтроллере PIC16F877A можно использовать 15 типов прерываний. Так зачем они нужны?

Как мы знаем, все микроконтроллеры программируются на выполнение определенной последовательности действий, задаваемой программой. Но достаточно часто в реальных проектах возникают ситуации, в которых требуется немедленное (первоочередное) выполнение каких либо действий. В этом случае на помощь и приходят прерывания.

Прерывания постоянно анализируют ситуацию на предмет появления определенных событий и когда эти события наступают, они исполняют небольшой фрагмент кода, после чего основная программа продолжает свое нормальное функционирование. Этот небольшой фрагмент кода называется процедурой обработки (обслуживания) прерывания (Interrupt Service Routine, ISR). На нашем сайте мы уже рассматривали один пример использования прерываний в микроконтроллере PIC – в проекте цифрового спидометра и одометра.

В микроконтроллерах существует два основных типа прерываний: внешние и внутренние. Внутренние прерывания происходят непосредственно внутри микроконтроллера, к из примерам можно отнести прерывания от таймеров, модулей АЦП и т.д. Эти прерывания срабатывают программным способом, то есть непосредственно в программе.

Срабатывание внешних прерываний могут вызывать какие-либо внешние устройства или действия пользователя. В данном проекте для срабатывания внешнего прерывания мы будем использовать обычную кнопку. Мы будем производить на экране ЖК дисплея счет от 0 до 1000 и когда будет происходить внешнее прерывание, мы будем выводить сообщение об этом на ЖК дисплей и затем продолжать счет.

Схема проекта

Схема проекта для демонстрации возможностей использования прерываний в микроконтроллере PIC представлена на следующем рисунке.

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

Для определения контакта, на котором микроконтроллером PIC16F877A возможна обработка внешнего прерывания, необходимо обратиться к даташиту на данный микроконтроллер. Из данного даташита можно узнать, что 33-й контакт микроконтроллера с названием RBO/INT может использоваться для обработки сигнала внешнего прерывания. Другой контакт нельзя будет использовать для этой цели.

Схема соединений микроконтроллера PIC приведена в следующей таблице.

№ п/п № контакта микроконтроллера Наименование контакта микроконтроллера Куда подключен
1 21 RD2 RS of LCD
2 22 RD3 E of LCD
3 27 RD4 D4 of LCD
4 28 RD5 D5 of LCD
5 29 RD6 D6 of LCD
6 30 RD7 D7 of LCD
7 33 RBO/INT кнопка

На порту PORT B мы будем использовать внутренние подтягивающие резисторы, поэтому мы непосредственным образом можем замкнуть контакт RB0 на землю (общий провод) через кнопку. Таким образом, всегда, когда на этом контакте будет появляться уровень LOW, будет срабатывать прерывание.

Внешний вид собранной на макетной плате конструкции проекта показан на следующем рисунке.

Внешний вид собранной на макетной плате конструкции проекта

Моделирование работы проекта

Перед проверкой работы схемы на "реальном железе" мы протестировали ее работу в симуляторе Proteus. Схема проекта в данном симуляторе показана на следующем рисунке.

Схема проекта в симуляторе Proteus

Во время тестирования работы схемы в симуляторе Proteus вы должны увидеть как на экране ЖК дисплея будет последовательно инкрементироваться счетчик. А когда пользователь будет нажимать кнопку, будет происходить выполнение процедуры обработки прерывания (ISR).

Объяснение программы для микроконтроллера PIC

Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.

Первым делом в программе настроим биты конфигурации. После этого необходимо указать, что на контакте RB0/INT мы будем производить обработку сигнала внешнего прерывания, то есть он не будет обычным цифровым входом или выходом. Следующая строка кода подключает внутренние подтягивающие резисторы к контактам порта portB при помощи установки 7-го бита регистра OPTION_REG в 0.

Структура регистра OPTION_REG в микроконтроллере PIC

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

Когда контакт RB0 сконфигурирован для обработки внешнего прерывания то каждый раз, когда на нем будет уровень low, будет устанавливаться в 1 флаг внешнего прерывания INTF и будет вызываться функция обработки прерывания.

Как вы можете видеть, мы назвали функцию обработки прерывания ISR_example. Вы можете дать ей любое другое имя. Внутри данной функции мы будем проверять установлен ли флаг INTF и выполнять необходимые действия. Также внутри этой функции очень важно очистить флаг INTF, только после этого произойдет переход (возврат) в основную функцию программы (main). Очистить флаг INTF можно с помощью команды:

Внутри основной функции программы (main) мы будем инкрементировать значение счетчика каждые 500 ms и отображать его значение на экране ЖК дисплея. Прерывание всегда будет оставаться активным, всегда при нажатии кнопки оно будет срабатывать и при этом будет происходить переход к выполнению функции обработки прерывания (ISR).

Тестирование работы проекта

После сборки схемы проекта на макетной плате и загрузки кода программы в микроконтроллер PIC вы можете приступить к тестированию его работы. При нажатии кнопки будет осуществляться вызов функции обработки прерывания и на экране ЖК дисплея будет показываться соответствующее сообщение.

Тестирование работы проекта

Более подробно работу проекта вы можете посмотреть на видео, приведенном в конце статьи.

Исходный код программы

Видео, демонстрирующее работу проекта

(Проголосуй первым!)
Загрузка...
1 580 просмотров

Комментарии

Использование прерываний в микроконтроллере PIC — 10 комментариев

  1. Получилось, слава Богу, добиться работы прерывания. Как я и предполагал, проблема в схеме была. И синатксис обработчика прерываний void __interrupt() ISR_example()
    {
    if(GPIF==1)
    {
    Code....
    GPIF=0;
    }
    }

    • Ну вот, мы рады что у вас все таки получилось. И вам спасибо за ценные комментарии по данному проекту

  2. Сколько смотрю уроки по pic контроллерам, возникают вопросы касательно:
    1. Прерываний. У pic один вектор прерываний, в отличие от avr и при этом прерывание по флагу можно определить. Вопрос, откуда в коде берут название обработчика прерываний "void interrupt ISR_example()"? Если для avr я могу взять название из даташита, то тут неясно.
    2. Установка отдельного бита. Именно в статьях где pic, там делают так, "GP4=1;", а avr, например, бит PD4 в 1 будет "PORTD|=(1<<4);" Как я знаю в си, в отличие от ассемблера, нельзя выставить отдельный бит, поэтому применяется битовая маска. А в pic получается можно? Самое интересное работает такая конструкция.

    • 1. Ну с таким названием функции обработчика прерывания у вас заработал данный проект или нет?
      2. Да, в микроконтроллерах AVR при работе в языке С необходимо использовать битовую маску, ну а в PIC, наверное, установка отдельного бита работает из-за того что для них написан более продвинутый компилятор, который понимает что делать с такой конструкцией

      • 1. Нет, не работает, компилятор ругается, при этом, в мануале к компилятору правильный синтаксис показан. Я переписал, но теперь почему-то код в обработчике не выполняется.

        • А в мануале к компилятору какой синтаксис этой команды приведен? У меня такое ощущение что в программе пропущена одна строчка, в которой компилятору указывается имя функции обработчика прерывания, по крайней мере, так в платах Ардуино делается. Если нужно я могу вам ссылку на статью-оригинал привести, но вряд ли там будет что то отличающееся от моей статьи. Статья от индийского энтузиаста, как видно из видео у него все заработало. Но вот опечатки в своих программах в статьях они иногда делают, это я уже неоднократно замечал. Но что поделать, программисты часто народ рассеянный

          • Спасибо, за ответ. Синтаксис на который компилятор не ругается, такой: "void __interrupt() ISR_example()", причем, после "ISR_" ,по-моему, неважно какое слово стоит. Но вот дела, несколько форумов пересмотрел, а в моем случае контроллер pic12f683, все регистры вроде нормально выставлены, но переывание по выводам GPIO не работает. А в этом контроллере даже есть регистр который позволяет разрешить прерывание с конкретного вывода, регистр "IOC".
            Оригинал статьи, возможно, видел.
            В моем случае, идёт отслеживание перехода через ноль, для управления семистором и где-то схематическая ошибка, как вариант, могла попасть.

            • И вам спасибо за конструктивный комментарий. Если все таки у вас получится обработку этого прерывания запустить буду признателен если отпишитесь потом о своих успехах

    • 1. Тоже сегодня весь день искал это.
      Нашелся в моем даташите вот такой пример:Example 11-4. Setting up Vectored Interrupts using XC8.
      Из него стал ясен синтаксис функции для прерывания:
      void __interrupt(irq(IRQ_SW), base(0x3008)) SW_ISR(void)
      Где __interrupt(irq(IRQ_SW), base(0x3008)) - макрос для компилятора, который разворачивается в __attribute__((picinterrupt(("irq(31), base(0x3008)")))) (что делает picinterrupt найти уже не смог.)
      А SW_ISR - уже произвольное название функции.
      2. "PORTD|=(1<<4);" - такая конструкция и даст вам выставление определенного бита в единицу.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *