Главная » Статьи » Полезные материалы |
В качестве рабочей среды я, по привычке, возьму Proton+. В нем организация прерываний производится проще и по структуре своей правильно. Под словом «правильно» я понимаю так, как рекомендует производитель микроконтроллера. Что такое прерывание в отношении к PIC микроконтроллеру? Ответ лежит в основе самого этого слова. Это временный останов выполнения программы для того, чтобы выполнить специальную подпрограмму. Эта подпрограмма находится по определенному адресу в адресном пространстве микроконтроллера. В ней выполняются действия, вызванные необходимостью, возникновение которой предусмотрел программист. Такой необходимостью может быть выдача в порт импульса в определенный момент времени, или по сигналу с внешнего устройства, тик таймера для подсчета времени или вывод на индикатор какой-то информации – все, что угодно, любое действие, которое надо выполнить во что бы то ни стало. Структурно работа прерывания выглядит как показано на рисунке ниже. Описать ее можно просто: В начале программы мы настраиваем микроконтроллер, манипулируя битами регистров специального назначения, отвечающими за прерывания от тех или иных источников. Указываем адрес, по которому будет находиться подпрограмма обработки прерывания. После этого выполняем основную программу(на схеме это условные инструкции Оператор 1, Оператор 2 и т. д.). Как только наступит момент прерывания, программа закончит текущую инструкцию и перейдет на подпрограмму обработки прерывания. Естественно, источников прерывания может быть несколько и на первый взгляд может показаться, что мы не в силах определить, что вызвало прерывание. Но это не так. Мы всегда можем проверить, чем вызвано прерывание, опросив флаги, которые устанавливаются при прерывании и которые, собственно и вызывают само прерывание. Кроме того, хочу отметить сразу – нам совсем не обязательно выполнять нужные нам действия прямо в обработчике. Чем меньше времени мы находимся в обработчике, тем качественней программа. Достаточно просто зафиксировать факт того, что прерывание было, а после, по выходу из обработчика, зная, что прерывание было, выполнить нужные нам действия. Это зависит от ситуации – нужно ли нам, чтобы действие было выполнено моментально, или можно выполнить его чуть позже. Мы рассмотрим на нескольких примерах организацию и обработку прерываний. Точнее, рассмотрим обработку прерываний от нескольких разных источников. Для начала поставим задачу. Пусть нам требуется переключать состояние порта PORTB.4 каждые 300 мСек на противоположное. Что нам для этого нужно? Отсчет времени – это первое и главное. Нам нужно отсчитывать 300 миллисекунд. Для этого лучше всего подойдет таймер TMR1, так как он без проблем позволит организовать такой период. Определимся с микроконтроллером и частотой генератора. Пусть это будет PIC16F877, работающий на частоте 4 МГц. Это не важно. Ну, пусть будет так, тем более, он имеет три таймера, в том числе и TMR1. Тщательно разберем алгоритм будущей программы. 1). Выбираем микроконтроллер – здесь мы уже определились. 2). Указываем частоту – здесь тоже определились. 3). Настроим порты на нужные нам режимы работы. Мы коснемся PORTB и PORTD (чтобы не усложнять статью лишним материалом, я решил, что в теле основной программы мы будем вести счет от нуля до 255 и выводить это число в порт PORTD с некоторой задержкой). 4). Настраиваем прерывание от TMR1 через каждые 300 мСек. Для этого нам нужно, во-первых, разрешить прерывание именно от переполнения этого таймера. Это делается установкой бита TMR1IE. Он находится в регистре PIE1 в нулевой позиции. Таким образом, чтобы разрешить это прерывание, мы напишем PIE1.0 = 1. Во-вторых нам требуется разрешить прерывания от периферийных устройств микроконтроллера, так как таймер TMR1 является периферийным устройством. В-третьих, нам нужно, по аналогии с нашей бюрократией (J), разрешить обработку прерываний вообще, установив бит глобального разрешения прерываний. Этот бит – как последняя инстанция – если он не установлен, то все запрещено, даже если нижние уровни все разрешили. Чтобы разрешить прерывания от периферии, нужно установить в единицу бит 6 регистра INTCON. Называется он PEIE. А чтобы разрешить все прерывания (последняя инстанция) – нужно установить бит 7 регистра INTCON. Он называется GIE (Global Interrupt Enable). Вообще, стоит познакомиться с документацией на микроконтроллер, тем более, на этот есть документ полностью на русском языке. 5). Указываем адрес подпрограммы обработчика прерывания. 6). Пишем главную программу. В ней мы программируем основные функции, которые должен выполнять микроконтроллер. Оперируем данными, обрабатываем информацию, выводим ее на индикатор и т.д. В общем, это дело лично каждого, что там делать, и что он хочет от микроконтроллера. 7). Пишем подпрограмму, ответственную за обработку прерываний. В этом пункте следует соблюдать несколько простых правил. Первое – сохранение контекста. Что это, спросите вы? Если вы хоть немного знакомы с PIC микроконтроллерами или с микроконтроллерами вообще, то вы должны знать, что есть специальные, так сказать, системные регистры. В PIC это два самых важных регистра – регистр STATUS и аккумулятор W. Эти регистры участвуют практически во всех операциях, выполняемых микроконтроллером. Сохранение их значений (текущего состояния этих регистров) при переходе на обработчик прерываний очень важно. Поясню. Например, в какой-то момент времени микроконтроллер вычисляет объем воздуха, подаваемого пациенту, подключенному к аппарату искусственной вентиляции легких, используя данные – время хода штока меха и объем. Во время вычислений обязательно фигурируют два системных регистра – W и STATUS, так как регистр W присутствует везде, где оперируют числами более одного байта, да и с однобайтными операндами – тоже, а STATUS – он независим ни от кого и устанавливает биты в зависимости от результата операций (и не только). И тут происходит прерывание – врач нажал кнопку (ну, например, для увеличения дыхательного объема или для смены режима работы аппарата). Если не сохранить содержимое системных регистров, то по выходу из прерывания, они будут иметь значения, отличные от тех, что были при входе в прерывание. Соответственно, результаты математических операций по вычислению объема воздуха будут неверны. Для того, чтобы этого избежать и предусмотрено сохранение контекста. Здесь подразумевается контекст исполняемой программы – логичность и последовательность ее выполнения. Второе – это проверка на правильность реакции. Это значит, что при неправильной организации, мы можем среагировать не на то прерывание. Поясню. Мы ожидали прерывание от переполнения TMR1, а произошло прерывание от TMR0 (допустим, каким-то образом было разрешено прерывание от TMR0 – вариантов много? Все мы люди, в конце концов). В обработчике мы просто сбросили бит глобального разрешения прерываний GIE (нам больше не требуются прерывания). После этого мы не попадем в прерывания по TMR1, которое, собственно, нам и нужно было. Это чревато, так называемыми, случайными ошибками, которые возникают, как бы случайно, непонятно от чего, а на самом деле – это результат взаимодействия определенных обстоятельств в данный момент. Чтобы избежать такой ситуации, рекомендуется проверять источник запроса прерывания. То есть, если мы предполагаем, что должно быть прерывание от переполнения TMR1, то в обработчике опрашиваем флаг, который устанавливается при переполнении TMR1. Если мы предполагали, что будет прерывание по фронту импульса на PORTB.0, то и опрашиваем флаг, отвечающий за это прерывание – INTF. Третье – это сброс флага источника прерывания. То есть после того, как мы обработали прерывание, мы должны указать системе, что мы это сделали, так как система не такая уж интеллектуальная, чтобы понять, что мы закончили обработку прерывания, а, тем более, что мы вообще были в подпрограмме обработки. После того как мы проверили флаг, вызвавший прерывание, мы его просто-напросто сбрасываем в ноль. При выходе из прерывания это укажет системе, что запросов на прерывание – нет. И программа продолжит выполнение с прерванного места. Четвертое – восстановление контекста. Логично, не правда ли? При входе мы сохранили значения системных регистров, так как они все равно изменятся при обработке прерываний, при выходе – вернули прежние значения. Программа вернется к выполнению с того места, где была прервана, причем, на данные, с которыми работала программа до вход в прерывание, никак не повлияет остановка. Это важно помнить и использовать, если вы хотите, чтобы ваши программы были надежны. Возвращаются из обработчика прерываний с помощью команды Retfie. C помощью этой инструкции из стека извлекается адрес команды, следующей за той, при которой возникло прерывание. Это все. Вот сама программа:
Это был один из вариантов организации прерываний. Другой вариант - это фиксирование факта прерывания и выход из обработчика. Этот метод можно использовать, когда время выполнения программы не сильно критично. В этом случае используется искусственный флаг - переменная типа бит, чтобы засвидетельствовать установкой ее в единицу факт прерывания. Попробуйте сами написать программу, используя приведенную выше за основу, только обработку прерывания проводите не в самом обработчике, а чуть позже, выйдя из него. Это ваше домашнее задание. Хотелось бы увидеть комментарии и оценить ваш интерес к моим статьям вообще. Материалы статьи вы можете скачать здесь. Архив содержит проект MPLAB, с помощью которого легко отследить время выполнения программы. | ||
Просмотров: 27945 | Комментарии: 14 | | |
Всего комментариев: 14 | ||||||||||||||
| ||||||||||||||