Что такое прерывание в микроконтроллере
Что такое прерывание в микроконтроллере
Под системой прерываний мы будем понимать совокупность аппаратных и программных средств, реализующих механизм прерываний в микроконтроллере. Хотя существуют большое множество различных вариантов построения систем прерываний, тем не менее, можно выделить несколько основных способов организации систем прерываний. Они отличаются между собой объемом аппаратных средств, необходимых для реализации такой системы и соответственно имеют различное быстродействие. Рассмотрим эти варианты.
Одноуровневые прерывания
Данная система прерываний реализована таким образом, что при возникновении прерывания процессор аппаратно переходит к подпрограмме обработки прерываний, расположенной по некоторому фиксированному адресу. Чтобы упростить аппаратную часть системы прерываний, этот адрес обычно располагается либо в начале, либо в конце адресного пространства программной памяти. Поскольку для обработки ВСЕХ прерываний используется только ОДНА точка входа, то такая система прерываний получила название одноуровневой. В такой системе выявление источника прерываний путем опроса состояния флажков признаков прерываний в начале программы обработки прерываний. При обнаружении установленного флажка происходит переход к соответствующему участку процедуры. Чем больше возможных источников прерываний, тем больше времени необходимо для обнаружения источника прерывания. Такой метод обнаружения источника прерывания называется программным опросом или поллингом ( polling ). Его недостатком является довольно большое время, затрачиваемое на поиск источника прерывания и, как следствие, замедленная реакция системы на внешние события. Его достоинство – простота реализации системы прерываний.
Векторные прерывания
Чтобы значительно уменьшить время реакции на внешние события, используются многоуровневые или, что то же самое, векторные прерывания. В векторных прерываниях КАЖДОМУ источнику прерывания соответствует СВОЙ, вполне определенный, адрес процедуры обработки прерывания, который принято называть вектором прерывания.
Вообще, в качестве вектора прерывания могут быть использованы любые данные (адрес подпрограммы, адрес перехода, значение смещения относительно начала таблицы прерываний, специальные инструкции и т.д.), которые позволяют непосредственно перейти к процедуре обработки прерывания, не затрачивая времени на поиск источника прерывания. Какие данные используются в качестве вектора прерывания и каким именно образом они используются зависит от способа реализации системы прерываний в соответствующем процессоре.
В семействе PIC 18 используется как одноуровневая (в режиме совместимости с PIC 16), так и двухуровневая система прерываний. В режиме совместимости при возникновении прерывания процессор переходит к процедуре обработки прерывания по адресу 0 x 000008 и далее все происходит аналогично PIC 16. При двухуровневой системе прерывания имеются два вектора перехода 0 x 000008 и 0 x 000018. Присвоение уровня каждому из имеющихся источников прерывания задается программным путем, с помощью соответствующих признаков. Способ организации системы прерывания (одно- или двухуровневая ) также определяется значением соответствующего разряда в регистре управления прерываниями.
В контроллерах семейства AVR реализована векторная система прерываний. При обнаружении прерывания, процессор сразу переходит по вектору прерывания к процедуре обработки прерываний от данного источника. Вектора прерываний расположены в начальных адресах программной памяти и представляют из себя команду перехода на обработчик прерывания. Количество векторов прерываний соответствует числу возможных источников прерываний, которые зависят от конкретного типа контроллера. Следует добавить, что сброс флажков запроса на прерывания происходит автоматически при переходе по вектору прерывания и выполнение каких-либо инструкций для этого не требуется.
В контроллерах семейства mcs 51 система прерываний также является векторной, но для вектора прерывания зарезервирован довольно большой обьем памяти (8 байт), что иногда бывает достаточно для его обработчика. Флаги прерывания сбрасываются автоматически при переходе к обработчику прерываний, если у прерывания возможен только один источник и несбрасываются если у прерывания может быть два и более источников. В последнем случае необходимо программно сбросить флаг вызвавший прерывание после выяснения причины прерывания ( поллинга ). Вектора располагаются в начальных адресах программной памяти.
Приоритетные прерывания
Обычно, значимость тех или иных событий в системе неодинакова. Одни события более важны и требуют немедленной реакции, другие менее важны, и с ответом на них можно подождать. Естественно, что и соответствующие этим событиям прерывания должны иметь разный приоритет. При одновременном возникновении нескольких прерываний, процессор должен перейти к обработке прерывания, имеющего более высокий приоритет. Этот процесс происходит на аппаратном уровне ядра процессора и называется последовательностью опроса прерываний ( interrupt polling sequence ).
В контроллерах PIC 18 при двухуровневой системе прерывания более высокий уровень приоритета имеют прерывания с вектором 0 x 000008. В пределах одного уровня приоритетность прерывания определяется программно, так же как и у PIC 16.
В семействе AVR приоритета опроса жестко фиксирован и не может быть изменен. Чем меньше адрес вектора прерывания, тем выше уровень опроса прерывания ему соответствующего.
В семействе MSP 430 приоритет опроса также жестко фиксирован и неизменяем, но зависимость приоритета опроса прерывания обратная – чем выше адрес вектора прерывания, тем выше приоритет опроса данного прерывания.
Вложенные прерывания
В контроллерах PIC 18 при двухуровневой системе прерывания возможно прерывание процедур прерывания с низким уровнем приоритета прерываниями, имеющими более высокий уровень.
В семействе AVR в процедурах обработки прерываний глобальные прерывания автоматически запрещаются, и процедура обработки прерывания не может быть прервана. Тем не менее, если это необходимо, то можно в процедуре обработки прерывания использовать инструкцию разрешения прерываний, разрешая тем самым вложенность прерываний. Естественно, что в этом случае сама эта процедура может быть прервана любым прерыванием, даже если оно имеет меньший уровень приоритета, по сравнению с текущим уровнем.
Программирование микроконтроллеров. Прерывание
Очередная тема для новичков: прерывание.
Многие новички слышали об этом, но понять, что это такое и с чем это едят и как это применять и зачем это нужно — незнают. А когда понимают, что это такое и как это нужно применять, то планка знаний и решений готовых реализаций поднимается на много выше.
Рассмотрим микроконтроллер от Атмел ATtiny13A, как самый простой и доступный. Среда разработки — CodeVisionAVR.
Если описать простым языком, то прерывание, это останов общего цикла программы по какому либо событию и выполнения после этого куска кода программы в рамках прерывания.
Из жизненной ситуации можно описать так:
Сидит офисный работник, выполняет определенную ежедневную задачу каждый день, например пишет отчеты, составляет графики — обычная рутинная работа. И тут звонит телефон — сработал сигнал прерывания для работника. Работник сразу откладывает в сторонку документы (микроконтроллер в это время подготавливается и сохраняет нужные данные и запоминает место остановки) и начинает разговаривать по телефону (микроконтроллер при этом выполняет подпрограмму, описанную в прерывании). Дальнейшие действия сотрудника зависят от самого разговора. Но в итоге он опять возвращается к выполнению своей рутинной ежедневной работы ( у микроконтроллера это выполнение основного цикла while(1)).
У микроконтроллера есть много разных прерываний. срабатывающих от разных условий. Когда есть много прерываний, то необходимы правила их выполнения при одновременном срабатывании условий их выполнения — приоритет. Если одновременно наступают события одновременно вызывающие разные прерывания, то выполняться начнет то, у которого выше приоритет — которое главнее. Приоритет прерываний описывается цифрой. Чем меньше число приоритета пррывания, тем приоритетней выполнение прерывания. По-английски это называется Interrupt Vectors — вектор прерываний.
Из жизненной ситуации можно описать так:
Сидит офисный работник, выполняет определенную ежедневную задачу каждый день, например пишет отчеты, составляет графики — обычная рутинная работа. И тут звонит телефон и заходит б** директор одновременно. У телефона приоритет прерывания равен 3, у директора единице. Телефон идет лесом — директор во внимании, выполняются его указания.
В даташите подробно описан принцип работы в режиме прерывания, что выполняется при входе в прерывание, что делается с регистрами и с памятью и за сколько тактов процессора.
Вектор прерываний описывается в таблице Interrupt Vectors, заодно опишем, что они значат:
Самое главное прерывание нулевое — RESET. Адрес его нулевой — вектор номер один. Источник прерывания — сброс микроконтроллера по ресету от входа RESET, от провала напряжения по питанию, если ативен фьюз Brown-out Reset и от срабатывания сторожевого таймера. Тут все и так понятно.
Вектор два: INT0 — прерывание по внешнему входу INT0. У ATTiny13 это пятая ножка PB0.
Ножку INT0 можно настроить на срабатывание на выполнение прерывания, насколько я помню, по фронту сигнала, по спаду или по изменению сигнала — и фронт и спад. Я, например, применяю это прерывание при необходимости выполнить точный подсчет длительности импульса для выполнения алгоритма деления или умножения частоты.
Вектор три: PCINT0 — прерывание по изменению состояния по входам PB0 — PB5( PCINT0 — PCINT5), короче говоря все ножки микроконтроллера при этом можно применить для выполнения этого прерывания. Один из моих любимых прерываний, использую его в основном для пробуждения из сна по изменению на входах, когда микроконтроллер спит.
Прерывания
Прерывания – это специальный механизм, позволяющий остановить выполнение основной программы и переключить процессор на выполнение другой задачи по определенному внешнему или внутреннему событию. Фактически прерывания являются обыкновенными подпрограммами, которые в тот или иной момент времени микропроцессор может вызывать аппаратно. Такие подпрограммы принято называть обработчиками прерываний.
В большинстве случаев прерывания позволяют очень сильно разгрузить ЦПУ от той работы, которую самостоятельно могут выполнять отдельные его модули. Например, любой таймер-счетчик, отсчитав необходимое число тактов генератора, может сгенерировать прерывание и вызвать подпрограмму, в которой будет находиться код для отчета различных временных интервалов. Точно таким же образом при наступлении определенного события (отсылка или прием слова данных, изменение состояния на линии и мн. др.) способны оповещать процессор модули USART, SPI, TWI, ADC и т.д. Различные модели AVR могут содержать от 4 до 56 таких источников прерываний.
Табл.5. Таблица векторов прерываний:
Номер
Адрес в памяти программ
Бит разрешение прерывания
Флаг прерывания
Описание события
Внешнее прерывание 0
Внешнее прерывание 1
Cовпадение TCNT2 и OCR2
Совпадение TCNT1 и OCR1A
Совпадение TCNT1 и OCR1B
Прерывание от модуля SPI
Получение байта по USART
Опустошение UDR в USART
Передача байта по USART
Завершение записи в EEPROM
Прерывание от компаратора
Прерывание от модуля TWI
Завершение выполнения spm
За каждым обработчиком прерывания жестко закреплен определенный адрес (вектор прерывания) в начале памяти программ. Положения векторов прерываний для ATmega8 сведены табл.5. Обычно по адресу вектора прерывания находится инструкция перехода, которая передает управление подпрограмме обработчика:
В моделях AVR с объемом FLASH ≤8 кбайт, для векторов отводится по 1 слову памяти программ, как раз для инструкций rjmp. Во всех остальных микроконтроллерах каждый вектор прерывания занимает уже 2 слова, а в качестве инструкции перехода используются jmp.
Управление прерываниями производится индивидуально. За разрешение каждого из них отвечают специальные разряды соответствующих РВВ, а о наступлении события микроконтроллер может судить по состоянию флагов прерывания (см. табл.5). Например, если прерывание по переполнению таймера-счетчика 2 разрешено (установлен бит TOIE2 из TIMSK), то при изменении содержимого счетного регистра TCNT2 c 0xFF на 0x00 в регистре TIFR аппаратно будет установлен флаг прерывания TOV2 и микроконтроллер вызовет подпрограмму по адресу 0x0004.
За общее управление прерываний у AVR отвечает флаг I из регистра SREG. При I=0 все прерывания, независимо от состояния битов разрешения, запрещены.
При вызове обработчика прерывания адрес текущей команды в основной программе копируется в стек, как и при обычном вызове подпрограммы. Но вместе с этим микроконтроллер аппаратно сбрасывает на нуль флаг I и флаг, который явился источником прерывания. Обработчик должен заканчиваться командой возврата из прерывания reti. После ее выполнения адрес возврата восстанавливается в PC и при этом одновременно устанавливается флаг I.
Ниже рассмотрен пример использования обработчика внешнего прерывания INT0.
Инструкция перехода, размещенная по нулевому адресу (вектор сброса у всех моделей AVR), передает управление на начало основной программы main, где и происходит инициализация микроконтроллера. В качестве условия возникновения прерывания выбрано изменение состояния вывода INT0 с уровня лог.1 на лог.0 (момент нажатия кнопки). При возникновении указанного события произойдет вызов подпрограммы по адресу 0x0001 (вектор прерывания INT0) и, далее, обработчика service_INT0. В обработчике нужно сохранить содержимое SREG и, если это необходимо, остальных регистров, которые используются в контексте основной программы.
Возможна такая ситуация, что в процессе работы одновременно возникнут сразу несколько запросов на прерывания (одновременно будут установлены несколько флагов прерывания). В этом случае первым будет вызван тот обработчик, чей адрес в таблице векторов прерывания находится выше. Например, при возникновении запросов от АЦП (адрес 0x000E) и компаратора (адрес 0x0010), первым будет обработан запрос от АЦП. Таким образом, каждое прерывание у AVR имеет свой собственный неизменный приоритет, который зависит от его местоположением в таблице векторов.
Здесь возможны две проблемы. Во-первых, обработка отдельных прерываний может быть достаточно длительной процедурой и другие запросы окажутся отложенными на недопустимо большой срок. А во-вторых, прерывание с низким приоритетом может иметь намного большее значение для данного устройства. В обоих случаях можно выйти из положения, если допустить в программе вложенные прерывания. Для этого после сохранения контекста в обработчике прерывания нужно вручную установить флаг I командой sei:
Вложенные прерывания могут оказаться недопустимыми при малом размере стека.
Перейти к следующей части: Порты ввода-вывода
AVR Урок 10. Таймеры-счетчики. Прерывания
Урок 10
Таймеры-счетчики. Прерывания
Сегодня мы узнаем, что такое таймеры-счётчики в микроконтроллерах и для чего они нужны, а также что такое прерывания и для чего они тоже нужны.
Таймеры-счётчики – это такие устройства или модули в микроконтроллере, которые, как видно из названия, постоянно что-то считают. Считают они либо до определённой величины, либо до такой величины, сколько они битности. Считают они постоянно с одной скоростью, со скоростью тактовой частоты микроконтроллера, поправленной на делители частоты, которые мы будем конфигурировать в определённых регистрах.
И вот эти таймеры-счётчики постоянно считают, если мы их инициализируем.
Таймеров в МК Atmega8 три.
Два из них – это восьмибитные таймеры, то есть такие, которые могут максимально досчитать только до 255. Данной величины нам будет маловато. Даже если мы применим максимальный делитель частоты, то мы не то что секунду не отсчитаем, мы даже полсекунды не сможем посчитать. А у нас задача именно такая, чтобы досчитывать до 1 секунды, чтобы управлять наращиванием счёта светодиодного индикатора. Можно конечно применить ещё наращивание переменной до определенной величины, но хотелось бы полностью аппаратного счёта.
Но есть ещё один таймер – это полноправный 16-битный таймер. Он не только 16-битный, но есть в нём ещё определённые прелести, которых нет у других таймеров. С данными опциями мы познакомимся позже.
Вот этот 16-битный таймер мы и будем сегодня изучать и использовать. Также, познакомившись с данным таймером, вам ничего не будет стоить самостоятельно изучить работу двух других, так как они значительно проще. Но тем не менее 8-битные таймеры в дальнейшем мы также будем рассматривать, так как для достижения более сложных задач нам одного таймера будет недостаточно.
Теперь коротко о прерываниях.
Прерывания (Interrupts) – это такие механизмы, которые прерывают код в зависимости от определённых условий или определённой обстановки, которые будут диктовать некоторые устройства, модули и шины, находящиеся в микроконтроллере.
В нашем контроллере Atmega8 существует 19 видов прерываний. Вот они все находятся в таблице в технической документации на контроллер
Какого типа могут быть условия? В нашем случае, например, досчитал таймер до определённой величины, либо например в какую-нибудь шину пришёл байт и другие условия.
На данный момент мы будем обрабатывать прерывание, которое находится в таблице, размещённой выше на 7 позиции – TIMER1 COMPA, вызываемое по адресу 0x006.
Теперь давайте рассмотрим наш 16-битный таймер или TIMER1.
Вот его структурная схема
Мы видим там регистр TCNTn, в котором постоянно меняется число, то есть оно постоянно наращивается. Практически это и есть счётчик. То есть данный регистр и хранит число, до которого и досчитал таймер.
А в регистры OCRnA и OCRnB (буквы n – это номер таймера, в нашем случае будет 1) – это регистры, в которые мы заносим число, с которым будет сравниваться чило в регистре TCNTn.
Например, занесли мы какое-нибудь число в регистр OCRnA и как только данное число совпало со значением в регистре счёта, то возникнет прерывание и мы его сможем обработать. Таймеры с прерываниями очень похожи на обычную задержку в коде, только когда мы находимся в задержке, то мы в это время не можем выполнять никакой код (ну опять же образно «мы», на самом деле АЛУ). А когда считает таймер, то весь код нашей программы в это время спокойно выполняется. Так что мы выигрываем колоссально, не давая простаивать огромным ресурсам контроллера по секунде или даже по полсекунды. В это время мы можем обрабатывать нажатия кнопок, которые мы также можем обрабатывать в таймере и многое другое.
Есть также регистр TCCR. Данный регистр – это регистр управления. Там настраиваются определенные биты, отвечающие за конфигурацию таймера.
Также у таймера существует несколько режимов, с которыми мы также познакомимся немного позденее.
Он состоит из двух половинок, так как у нас конотроллер 8-битный и в нем не может быть 16-битных регистров. Поэтому в одной половинке регистра (а физически в одном регистре) хранится старшая часть регистра, а в другом – младшая. Можно также назвать это регистровой парой, состоящей из двух отдельных регистров TCCR1A и TCCR1B. Цифра 1 означает то, что регистр принадлежит именно таймеру 1.
Даный регист TCCR отвечает за установку делителя, чтобы таймер не так быстро считал, также он отвечает (вернее его определённые биты) за установку определённого режима.
За установку режима отвечают биты WGM
Мы видим здесь очень много разновидностей режимов.
Normal – это обычный режим, таймер считает до конца.
PWM – это ШИМ только разные разновидности, то есть таймер может играть роль широтно-импульсного модулятора. С данной технологией мы будем знакомиться в более поздних занятиях.
CTC – это сброс по совпадению, как раз то что нам будет нужно. Здесь то и сравнивются регистры TCNT и OCR. Таких режима два, нам нужен первый, второй работает с другим регистром.
Все разновидности режимов мы в данном занятии изучать не будем. Когда нам эти режимы потребуются, тогда и разберёмся.
Ну давайте не будем томить себя документацией и наконец-то попробуем что-то в какие-нибудь регистры занести.
Код, как всегда, был создан из прошлого проекта. Для протеуса также код был скопирован и переименован с прошлого занятия, также в свойствах контроллера был указан путь к новой прошивке. Проекты мы назовем Test07.
Попробуем как всегда скомпилировать код и запустить его в протеусе. Если всё нормально работает, то начинаем добавлять новый код.
Добавим ещё одну функцию, благо добавлять функции мы на прошлом занятии научились. Код функции разместим после функции segchar и до функции main. После из-за того, что мы будем внутри нашей новой функции вызывать функцию segchar.
Мало того, мы создадим не одну функцию, а целых две. В одну функцию мы разместим весь код инициализации нашего таймеру, а другая функция будет являться обработчиком прерывания от таймера, а такие функции они специфичны и вызывать их не требуется. Когда возникнет необходимость, они вызовутся сами в зависимости от определённых условий, которые были оговорены выше.
Поэтому первую функцию мы назвовём timer_ini
void timer_ini ( void )
Также давайте наши функции, а также какие-то законченные блоки с объявлением глобальных переменных, с прототипами функций будем отделять друг от друга вот такими чёрточками, которые за счет наличия двух слешей впереди компилятор обрабатывать не будет и примет их за комментарии. За счёт этих отчерчиваний мы будем видеть, где заканчивается одна функция и начинается другая.
Данная функция, как мы видим не имеет ни каких аргументов – ни входных, не возвращаемых. Давайте сразу данную функцию вызовем в функции main()
unsigned char butcount=0, butstate=0;
timer_ini ();
Теперь мы данную функцию начнём потихонечку наполнять кодом.
Начнем с регистра управления таймером, например с TCCR1B. Используя нашу любимую операцию «ИЛИ», мы в определённый бит регистра занесём единичку
void timer_ini ( void )
TCCR1B |= (1 WGM12 ); // устанавливаем режим СТС (сброс по совпадению)
Из комментария мы видим, что мы работает с битами режима, и установим мы из них только бит WGM12, остальные оставим нули. Исходя из этого мы сконфигурировали вот такой режим:
Также у таймера существует ещё вот такой регистр – TIMSK. Данный регистр отвечает за маски прерываний – Interrupt Mask. Доступен данный регистр для всех таймеров, не только для первого, он общий. В данном регистре мы установим бит OCIE1A, который включит нужный нам тип прерывания TIMER1 COMPA
TCCR1B |= (1 WGM12 ); // устанавливаем режим СТС (сброс по совпадению)
TIMSK |= (1 OCIE1A ); //устанавливаем бит разрешения прерывания 1ого счетчика по совпадению с OCR1A(H и L)
Теперь давайте поиграемся с самими регистрами сравнения OCR1A(H и L). Для этого придётся немного посчитать. Регистр OCR1AH хранит старшую часть числа для сравнения, а регистр OCR1AL – младшую.
Но прежде чем посчитать, давайте пока напишем код с любыми значениями данного регистра и потом поправим, так как дальше мы будем инициализировать делитель и он тоже будет учавствовать в расчёте требуемого времени счёта. Без делителя таймер будет слишком быстро считать.
TIMSK |= (1 OCIE1A ); //устанавливаем бит разрешения прерывания 1ого счетчика по совпадению с OCR1A(H и L)
OCR1AH = 0b10000000; //записываем в регистр число для сравнения
OCR1AL = 0b00000000;
TCCR1B |= ( ); //установим делитель.
Пока никакой делитель не устанавливаем, так как мы его ещё не посчитали. Давайте мы этим и займёмся.
Пока у нас в регистре OCR1A находится число 0b1000000000000000, что соответствует десятичному числу 32768.
Микроконтроллер у нас работает, как мы договорились, на частоте 8000000 Гц.
Разделим 8000000 на 32768, получим приблизительно 244,14. Вот с такой частотой в герцах и будет работать наш таймер, если мы не применим делитель. То есть цифры наши будут меняться 244 раза в секунду, поэтому мы их даже не увидим. Поэтому нужно будет применить делитель частоты таймера. Выберем делитель на 256. Он нам как раз подойдёт, а ровно до 1 Гц мы скорректируем затем числом сравнения.
Вот какие существуют делители для 1 таймера
Я выделил в таблице требуемый нам делитель. Мы видим, что нам требуется установить только бит CS12.
Так как делитель частоты у нас 256, то на этот делитель мы поделим 8000000, получится 31250, вот такое вот мы и должны занести число в TCNT. До такого числа и будет считать наш таймер, чтобы досчитать до 1 секунды. Число 31250 – это в двоичном представлении 0b0111101000010010. Занесём данное число в регистровую пару, и также применим делитель
OCR1AH = 0b01111010; //записываем в регистр число для сравнения
OCR1AL = 0b00010010;
TCCR1B |= (1 CS12 ); //установим делитель.
С данной функцией всё.
Теперь следующая функция – обработчик прерывания от таймера по совпадению. Пишется она вот так
ISR ( TIMER1_COMPA_vect )
И тело этой функции будет выполняться само по факту наступления совпадения чисел.
Нам нужна будет переменная. Объявим её глобально, в начале файла
unsigned char i ;
Соответственно, из кода в функции main() мы такую же переменную уберём
Также закомментируем весь код в бесконечном цикле. Его роль теперь у нас будет выполнять таймер, и, я думаю, он с этим справится не хуже, а даже лучше, «никому» при этом не мешая.
while (1)
// for(i=0;i
// while (butstate==0)
// if (!(PINB&0b00000001))
// if(butcount
// butcount++;
// else
// butstate=1;
// else
// if(butcount > 0)
// butcount–;
// else
// butstate=1;
// segchar(i);
// _delay_ms(500);
// butstate=0;
Теперь, собственно, тело функции-обработчика. Здесь мы будем вызывать функцию segchar. Затем будем наращивать на 1 переменную i. И чтобы она не ушла за пределы однозначного числа, будем её обнулять при данном условии
if ( i >9) i =0;
segchar ( i );
Теперь немного исправим код вначале функции main(). Порт D, отвечающий за состояние сегментов, забьём единичками, чтобы при включении у нас не светился индикатор, так как он с общим анодом. Затем мы здесь занесём число 0 в глобавльную переменную i, просто для порядка. Вообще, как правило, при старте в неициализированных переменных и так всегда нули. Но мы всё же проинициализируем её. И, самое главное, чтобы прерывание от таймера работало, её недостаточно включить в инициализации таймера. Также вообще для работы всех прерываний необходимо разрешить глобальные прерывания. Для этого существует специальная функция sei() – Set Interrupt.
Теперь код будет вот таким
PORTD = 0b11111111;
sei ();
Также ещё мы обязаны подключить файл библиотеки прерываний вначале файла
Также переменные для кнопки нам пока не потребуются, так как с кнопкой мы сегодня работать не будем. Закомментируем их
//unsigned char butcount=0, butstate=0;
Соберём наш код и проверим его работоспособность сначала в протеусе. Если всё нормально работает, то проверим также в живой схеме
Всё у нас работает. Отлично!
Вот такой вот получился секундомер. Но так как у нас даже нет кварцевого резонатора, то данный секундомер нельзя назвать точным.
Тем не менее сегодня мы с вами много чему научились. Мы узнали о прерываниях, также научились их обрабатывать, Научились работать с таймерами, конфигурировать несколько новых регистров микроконтроллера, до этого мы работали только с регистрами портов. Также за счёт всего этого мы значительно разгрузили арифметическо-логическое устройство нашего микроконтроллера.
Купить программатор можно здесь (продавец надёжный) USBASP USBISP 2.0