Рубрики
Схемы на PIC

Руководство по таймерам в микроконтроллерах PIC для начинающих

Ранее на нашем сайте мы рассмотрели основы работы с микроконтроллерами PIC с помощью MPLABX IDE, отладку программы мигания светодиодом для них в симуляторе и на «реальном» железе, а также мигание с их помощью последовательностью светодиодов. В этой же статье на основе предыдущего проекта мигания последовательностью светодиодов мы рассмотрим основы работы с таймерами в микроконтроллерах PIC. По сравнению с предыдущим проектом мигания последовательностью светодиодов в данном проекте мы добавим одну дополнительную кнопку.

Ранее на нашем сайте мы достаточно подробно рассматривали работу с таймерами в платах Arduino.

Зачем нужны таймеры

Таймеры играют важную роль в большинстве проектов встраиваемой электроники. Они позволяют отмерять заданные интервалы времени. Но вы можете спросить зачем нам нужны таймеры если мы можем делать то же самое с помощью функции задержки (__delay_ms())?

Здесь дело в том, что во время задержки, организованной с помощью функции __delay_ms()), микроконтроллер не может больше делать ничего: ни считывать значения со входов АЦП, ни проверять состояние контактов, ни записывать какие либо значения в свои регистры и т.д.

Также у задержек, организуемых с помощью функции __delay_ms()), есть и другие недостатки:

  1. Значение задержки задается константой и его нельзя изменить во время исполнения программы.
  2. Значение задержки не такое точное как в случае использования для этой цели таймеров.
  3. Невозможно организовать очень длительные задержки, к примеру, полчаса и более. Максимальная величина задержки зависит от используемой частоты кварцевого генератора.

Таймеры в микроконтроллерах PIC

На физическом уровне таймер представляет собой регистр, значение в котором непрерывно увеличивается до 255, и затем счет в нем начинается сначала: 0, 1, 2, 3, 4…255….0, 1, 2, 3……и т. д.

Микроконтроллер PIC16F877A содержит три таймера, с именами Timer0, Timer1 и Timer2. Timer0 и Timer2 являются 8-битными, а Timer1 – 16-битным. В нашем проекте мы рассмотрим работу с Timer0. Если вы поймете принцип его работы, то по аналогии с ним вы сможете работать и с таймерами Timer1 и Timer2

Таймер/счетчик Timer0 имеет следующие особенности:

  • 8-битный;
  • можно записывать и считывать информацию;
  • 8-битный программируемый предварительный делитель частоты (предделитель, prescaler);
  • выбор внешней или внутренней частоты синхронизации;
  • прерывание при переполнении от FFh до 00h;
  • выбор спада или нарастания импульса для сигнала внешней синхронизации.

Для начала разберемся с рядом терминов, оказывающих влияние на функционирование таймера.

Предварительный делитель частоты (предделитель, prescaler) – это компонент микроконтроллера, который делит частоту задающего генератора перед тем как она достигает логического уровня, увеличивающего состояние таймера. Коэффициент деления предделителя для микроконтроллеров PIC лежит в диапазоне от 1 до 256, он устанавливается с помощью регистра OPTION (этот же регистр используется и для управления подтягивающими резисторами). К примеру, если значение (его коэффициент деления) предделителя равно 64, то с каждым 64-м импульсом частоты генератора значение таймера будет увеличиваться на 1.

Когда при инкрементировании таймера его значение достигает 255 (максимальное его значение) он инициализирует прерывание и сбрасывает свое значение снова до 0. Этот прерывание называется прерыванием от таймера. Оно информирует микроконтроллер что истек определенный промежуток времени.

Обозначим за Fosc частоту тактового генератора (Frequency of the Oscillator), то есть частоту используемого кристалла. Интервал времени, отсчитываемый таймером, зависит от значения предделителя (Prescaler) и значения частоты Fosc.

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

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

В нашем проекте мы будем использовать 2 кнопки и 8 светодиодов, которые подключены к 8 контактам микроконтроллера PIC. С помощью 1-й кнопки мы будем устанавливать временную задержку (500ms на каждое нажатие), а 2-й кнопкой будем запускать процесс мигания последовательности светодиодов. К примеру, если первую кнопку мы нажмем трижды (500*3 = 1500ms), то задержка составит 1,5 секунды и при нажатии второй кнопки светодиоды будут включаться и выключаться с этим значением задержки. Более подробно работу проекта вы можете посмотреть на видео, приведенном в конце статьи.

Первым делом в программе мы зададим значение битов конфигурации, но этот фрагмент программы мы здесь рассматривать не будем поскольку мы его подробно рассмотрели в соответствующей статье. Поэтому перейдем сразу к функции main, в которой мы будем задавать параметры работы таймера Timer0.

Вначале посмотрим на структуру регистра OPTION в даташите нашего микроконтроллера PIC.

Как мы уже рассмотрели в предыдущей статье, бит 7 используется для управления внутренними подтягивающими резисторами порта PORTB. Как видно из представленного рисунка, если бит 3 установить в 0, то предделитель будет устанавливаться для нашего таймера, а не для сторожевого таймера (WatchDogTimer, WDT). Режим работы таймера устанавливается при помощи установки бита 5 (T0CS) в 0 (OPTION_REG<5>).

Биты 2-0 используются для установки значения предделителя. Как видно из представленной таблицы, чтобы установить значение предделителя равным 64, в эти биты нужно записать 101.

Теперь посмотрим на регистры, ассоциированные с Timer0.

Таймер при своей установке начинает счет и переполняется при достижении значения 256, чтобы разрешить срабатывание прерывания от таймера в этой точке регистр TMR0IE необходимо установить в high. Поскольку Timer 0 по своей сути является периферийным устройством, мы также должны разрешить прерывания от периферийных устройств установив PEIE=1. И, наконец, мы должны установить глобальное разрешение прерываний для микроконтроллера, это делается при помощи установки GIE=1.

Задержку, отсчитываемую таймером, можно определить по формуле:

Delay = ((256-REG_val)*(Prescal*4))/Fosc

Если
REG_val = 100,
Prescal = 64,
Fosc = 20000000,

То по данной формуле получим значение задержки равное Delay = 0.0019968s

Далее в программе сконфигурируем работу портов ввода/вывода.

Конфигурация работы портов такая же, как и в нашей предыдущей статье поскольку мы используем одно и то же «железо», за исключением того, что мы добавили в схему проекта еще одну дополнительную кнопку – она конфигурируется с помощью строки TRISB1=1.

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

Переменная get_scnds инкрементируется с каждым нажатием первой кнопки. Переменная flag (определяемая программно) используется для удержания процесса инкрементирования пока пользователь не удалит свой палец с кнопки.

Следующий блок программы начинает работать при нажатии второй кнопки. Значение заданной пользователем задержки в результате работы первого блока сохранилось у нас в переменной get_scnds. В этом же блоке программы мы будем использовать переменную hscnd, которая будет управлять процедурой обработки прерывания (Interrupt service routine, ISR).

Данная процедура будет вызываться каждый раз при переполнении Timer0. Как мы уже указывали ранее, значение задержки должно увеличиваться на полсекунды при каждом нажатии первой кнопки, поэтому мы должны инкрементировать переменную hscnd для каждой полсекунды. Поскольку ранее мы запрограммировали задержку для нашего таймера равную 0.0019968s (~ 2ms), то чтобы отсчитать полсекунды значение переменной должно быть равно 250 поскольку 250*2ms = 0.5 секунды. Поэтому когда значение переменной count достигает 250 (250*2ms = 0.5 секунды) это будет означать что прошло полсекунды, поэтому увеличиваем значение переменной hscnd на 1 и сбрасываем значение переменной count в 0.

В дальнейшем мы переключаем состояние светодиодов, основываясь на заданной задержке.

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

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

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

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

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

3 ответа к “Руководство по таймерам в микроконтроллерах PIC для начинающих”

Не компилируется файл, пишет ошибку…

из за вот это строчки void interrupt timer_isr()

слово interrupt убираешь, комплируется, в протеусе не работает, пишет оверфлоу интеррупт.
всю голову сломал, так и не понял в чем проблема…

2 errors generated.
(908) exit status = 1
nbproject/Makefile-default.mk:107: recipe for target ‘build/default/production/main.p1’ failed
make[2]: Leaving directory ‘C:/Users/Dream/MPLABXProjects/Timer Crank.X’
nbproject/Makefile-default.mk:91: recipe for target ‘.build-conf’ failed
make[1]: Leaving directory ‘C:/Users/Dream/MPLABXProjects/Timer Crank.X’
nbproject/Makefile-impl.mk:39: recipe for target ‘.build-impl’ failed

BUILD FAILED (exit value 2, total time: 205ms)

К сожалению, с протеусом уже давно не работал, не могу подсказать здесь что то конкретное. А оверфлоу это означает переполнение в общем случае. У вас другие проекты (без использования прерываний) нормально компилируются?

Я не пробовал. Я только учусь.

Может подскажете как решить такую задучу.

Мне нужно что бы с выхода контроллера выходили импульсы, обычные прямоугольные импульсы.

Надо зайдествовать 2 порта. На одном генерируется 24 импульса, на другом 1. И так до бесконечности.

Не могу сообразить как написать код. сижу изучаю таймеры уже весь день.

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

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