Вы находитесь на странице: 1из 8

Лабораторная работа №3

Курс: «Микропроцессорная техника в мехатронике и робототехнике»

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

Временные интервалы в программе можно задавать используя вложенные циклы. При этом
процессор не может выполнять никаких других функций. Более правильно для формирования
временных интервалов использовать таймеры. Это позволяет более точно формировать интервалы
времени, но главное – позволяет разгрузить центральный процессор.
Пока таймер формирует задержку, программа может выполнять любые другие действия.
Сформулируем задачу следующим образом:
«Разработать автомат «Бегущие огни» для управления составной гирляндой из восьми отдельных
гирлянд. Устройство должно обеспечивать «движение» огня в двух разных направлениях. Переключение
направления «движения» должно осуществляться при помощи переключателя (кнопки). Задание
временного интервала 200 мс должно обеспечиваться с использованием прерываний по таймеру».
На рис. 1 показана принципиальная схема устройства. Управление светодиодами
осуществляется портом PB микроконтроллера. Светодиод горит, когда на выходе порта
присутствует сигнал логического нуля. Переключатель управления направлением движения
подключен к нулевому выводу порта PD. Схема тактируется внешним кварцевым резонатором
4 МГц.

Рис. 1 Схема автомата «Бегущие огни»

Алгоритм
В данной задаче удобнее всего использовать режим совпадения. Точнее, его подрежим «сброс
при совпадении». В этом режиме таймер сам периодически вырабатывает запросы на прерывание с
заранее заданным периодом.
Все функции управления «движением огней» выполняет процедура обработки прерывания. При
каждом вызове прерывания процедура производит сдвиг «огней» на один шаг в нужном направлении.
1
В микроконтроллере ATtiny2313 имеются два встроенных таймера-счетчика. Поэтому
сначала нам нужно выбрать, какой из них будет использоваться. Исходить будем из заданного
времени задержки 200 мс. Для формирования временных интервалов таймер/счетчик просто
подсчитывает тактовые импульсы от системного генератора.
Частота сигнала этого генератора в нашем случае равна 4 МГц . А период импульсов 1/4=0,25
мкс. Для того, чтобы получить на выходе 200 мс, необходимо иметь коэффициент деления, равный
200 103
 800 103 (восемьсот тысяч раз).
0,25 10 6

Микросхема ATtiny2313 содержит два таймера. Один восьмиразрядный и один


шестнадцатиразрядный. Восьмиразрядный таймер имеет максимальный коэффициент пересчета
28  256 , а шестнадцатиразрядный 216  65536 . В таком случае, даже шестнадцатиразрядного
таймера не хватит для формирования требуемой задержки. Будем использовать предварительный
делитель. Этот делитель производит предварительное деление тактового сигнала перед тем, как тот
поступит на вход таймера/счетчика.
Программным путем можно выбрать один из четырех фиксированных коэффициентов
деления. Выберем самый большой возможный коэффициент деления предделителя (1024). Тогда на
его выходе мы получим сигнал с частотой 4 106 / 1024  3906 Гц Период такого сигнала будет

равен 1/ 3906  0,256 103 с или 0,256 мс. Именно этот сигнал поступает на вход нашего таймера,
который обеспечивает окончательное деление. Посчитаем коэффициент деления, который наш
таймер должен нам обеспечить: 200 / 0,256  780 . Такой коэффициент пересчета нам может
обеспечить только таймер Т1. Поэтому в программе необходимо вначале включить
предварительный делитель и выбрать для него коэффициент деления 1/1024.
Второй коэффициент деления (780) мы помещаем в специальный системный регистр – регистр
совпадения. Сравнение содержимого счетного регистра с содержимым регистра совпадения будет
происходить на аппаратном уровне. В режиме «сброс при совпадении» таймер работает следующим
образом. Сразу после запуска, значение счетного регистра начнет увеличиваться. Когда это значение
окажется равным значению регистра совпадения, таймер автоматически сбросится и продолжит работу
с нуля. В момент сброса таймера формируется запрос на прерывание.
Для задания движения бегущих огней в программе будут использоваться операции сдвига. При этом
понадобится специальный рабочий регистр. То есть один из регистров общего назначения, в котором
будет храниться текущее состояние наших «огней». В начале программы в рабочий регистр
необходимо записать исходное значение. То есть число, один из разрядов которого равен единице, а
остальные – нулю. В результате операций сдвига эта единица будет перемещаться вправо или влево,
создавая эффект бегущего огня. Проверка состояния кнопки и сдвиг на один шаг будет
производиться при каждом вызове процедуры обработки прерывания.
Алгоритм работы программы состоит из двух независимых алгоритмов. Во-первых, это
алгоритм основной программы, а во-вторых, алгоритм процедуры обработки прерывания.
Рассмотрим их по порядку.
2
Алгоритм основной программы:
1. Настроить стек и порты ввода-вывода микроконтроллера.
2. Настроить таймер и систему прерываний.
3. Записать в рабочий регистр исходное значение.
4. Разрешить работу таймера.
5. Разрешить прерывания.
6. Перейти к выполнению основного цикла.
Так как все операции, связанные с движением огней, выполняет процедура обработки
прерываний, в основном цикле программы нам ничего делать не нужно, поэтому оставим основной
цикл пустым.
Алгоритм процедуры обработки прерывания.
1. Проверить состояние переключателя режимов.
2. Если контакты переключателя разомкнуты, произвести сдвиг всех разрядов рабочего
регистра на один разряд вправо. Если в результате этого сдвига единичный бит выйдет за
пределы байта, создать новый единичный бит в крайней левой позиции.
3. Если контакты переключателя замкнуты, произвести сдвиг всех разрядов рабочего регистра
на один разряд влево. Если в результате этого сдвига единичный бит выйдет за пределы байта,
создать новый единичный бит в крайней правой позиции.
4. Вывести содержимое рабочего регистра в порт РВ, предварительно проинвертировав его.
5. Закончить процедуру обработки прерывания.

Программа на языке СИ
При разработке программы средствами системы CodeVisionAVR в подобной ситуации
целесообразнее воспользоваться мастером, при помощи которого удобно создать новую заготовку
программы.
Запустим программу CodeVisionAVR и запустим мастер.
После запуска мастера все его управляющие элементы будут находиться в исходном состоянии.
То есть иметь значения по умолчанию. Теперь нам нужно восстановить настройки из лабораторной
работы №1.

Рис. 2 Загрузка параметров мастера

3
Для этого в меню «File» мастера выберем пункт «Open», как показано на рис. 2. Появится стандартное
окно открытия файла. Найдите на вашем диске файл Prog1.cwp и откройте его. После того, как вы его
откроете, все органы управления во всех вкладках мастера примут те значения, какие они имели при
создании программы Progl (Лабораторная работа №1).
Теперь нужно сохранить этот пример с другим именем. Для этого при помощи пункта меню «File / Save
As» сделайте копию только что загруженного файла. Копию поместите в новую директорию с именем
Prog2. В этой директории будет храниться наш новый проект. Теперь можно приступать к изменениям
настроек под новые требования.
Исходя из задания, потребуется изменить лишь настройки нашего таймера. Для этого сначала
откройте вкладку «Timers». На этой вкладке вы увидите еще три вкладки поменьше (рис. 3). Эти
вкладки предназначены для настройки двух системных таймеров (Timer 0 и Timer 1), а также
охранного таймера (Watchdog). Открываем вкладку «Timer l», как показано на рис. 3. При помощи
расположенных там элементов управления выставляем следующие настройки.
 Поле «Clock Source» (Источник Тактового Сигнала) оставляем в положении «System Clock»
(Тактовый сигнал от системного генератора).
 В поле «Clock Value» (Значение тактовой частоты) выбираем значение 3,906 кГц. На самом деле
мы выбираем коэффициент деления предварительного делителя. Но для удобства программиста
показаны получаемые при этом частоты сигнала. Значения этих частот вычисляются исходя из
выбранной частоты тактового генератора (см. вкладку «Chip»). Как вы помните, тактовая частота в
нашем случае равна 4 МГц.
 В поле «Mode» выбираем режим работы таймера. В нашем случае мы должны выбрать режим
«СТС top = OCRlA» (режим сброса при совпадении с регистром OCR1A). Два поля «Out. А» и «Out. В»
оставляем без изменений. При помощи этих полей можно включить и настроить параметры вывода
сигнала совпадения на внешние контакты микроконтроллера. В данном случае нам это не нужно.
 Поле «Input Capt.» (Вход Захвата) используется при работе в режиме захвата. Мы не используем
режим захвата, поэтому и это поле тоже оставим без изменения.
 Поле «Interrupt On» (Прерывание От) нам нужно изменить. Это поле предназначено для
разрешения или запрета различных видов прерываний от таймера. В правой части поля имеются две
маленькие кнопочки, при помощи которых вы можете листать его содержимое. В процессе
перелистывания в окошке появляются названия видов прерываний. Слева от названия каждого вида
прерывания имеется поле выбора («Check Box»), при помощи которого вы можете включить либо
выключить данное прерывание. Путем перелистывания найдите прерывание, которое называется
«Compare A Mach» (при совпадении с А). Поставьте знак в соответствующем поле «Check Box». Теперь
нужное прерывание будет включено.
 Поля «Value» и «Inp. Capture» оставим без изменений. Эти поля предназначены для задания
начальных значений счетного регистра и содержимого регистра захвата.
И, наконец, два поля под общим названием «Comp.» позволяют выставить значения,
записываемые в регистры совпадения А и В. Мы будем использовать регистр А. Запишем в поле «А:»
значение нужного нам коэффициента деления (3D0). В данном случае допускается только
4
шестнадцатеричный формат.
В результате всех этих манипуляций окно настройки таймера должно выглядеть так, как показано
на рис. 3.

Рис. 3 Настройка таймера

Сохраните новое значение параметров при помощи меню «File/Save» мастера.


Теперь можно приступать к процессу формирования нового проекта, как это было сделано в
лабораторной работе №1.
После того, как проект сформирован, приступаем к созданию новой программы. Возможный
вариант такой программы приведен в листинге 1. В программе появился оператор, который требует
описания.
#asm()
Это специальная системная функция, позволяющая в программе на СИ выполнять команды
Ассемблера. Параметр функции – это строковая переменная или строковая константа, значение
которой представляет собой текст команды на Ассемблере. Подобная функция добавляет программе
значительную гибкость. В строке 31 программы (листинг 1) при помощи функции #asm() выполняется
ассемблерная команда разрешения прерывания sei. Команды такого уровня не имеют аналогов в
традиционном синтаксисе языка СИ. Да и нецелесообразно выдумывать новые команды, когда
удобнее просто выполнить команду Ассемблера.

Описание программы (листинг 1)


Текст программы, сформированный мастером, содержит две функции, а точнее их заготовки.
Во-первых, это главная функция main, которая в программе занимает строки 11 – 42.

Листинг 1

1. «include <tiny2313 h> // Описание глобальных переменных


5
2. unsigned char rab;

3. interrupt [TIM1_COMP] void timer1_comp_isr (void)


{ // Прерывание по совпадению таймера T1
4. if (PIND.0==1) // Проверка состояния переключателя
{
5. rab = rab >> 1; // Сдвиг разрядов
6. if (rab==0) rab = 0b10000000; // Если дошло до конца
}
7. else
{
8. rab = rab <<1; // Сдвиг разрядов
9. if (rab==0) rab = 0b00000001; // Сдвиг влево
}
10. P0RTB=rab^0xFF; // Запись в порт с инверсией
}

11. void main(void)


12. CLKPR=0x80; // Отключить деление частоты системного генератора
13. CLKPR=0x00;
14. P0RTA=0x00; // Инициализация порта А
15. DDRA=0x00;
16. P0RTB=0xFF; // Инициализация порта В
17. DDRB=0xFF;
18. P0RTD=0x7F; // Инициализация порта D
19. DDRD=0x00;
20. TCCR0A=0x00; // Инициализация таймера Т0
21. TCCR0B=0x00;
22. TCNT0=0x00;
23. OCR0A=0x00;
24. OCR0B=0x00;
25. TCCR1A=0x00; // Инициализация таймера T1
26. TCCR1B=0x0D;
27. TCNT1H=0x00,
28. TCNT1L=0x00;
29. ICA1H=0X00;
30. ICR1L=0x00;
31. OCR1AH=0x03; // Коэффициент деления (030CH = 780)
32. OCR1AL=0x0C;
6
33. OCR1BH=0x00,
34. OCR1BL=0x00;
35. GIMSK=0x00; // Инициализация внешних прерываний
36. MCUCR=0x00;
37. TIMSK=0x40; // Запись маски прерываний
38. USICR=0x00; // Инициализация универсального последовательного интерфейса
39. ACSR=0x80; // Инициализация аналогового компаратора
40. гаb=0b00010000; // Присвоение начального значение переменной rab
41. #asm("sei") // Команда разрешения прерывании
42. while (1) {} }

Кроме главной функции, первоначальная автоматически сформированная программа содержит


заготовку еще одной функции – функции обработки прерывания. В строках 3 – 10 мы можем видеть ее в
уже доработанном виде. В первоначальном виде функция main содержит только строки инициализации
(строки 12 - 39), а функция обработки (функция «timer1_comp_isr») вообще не содержит ни одного
оператора.
Описание функции timer1_comp_isr (строка 3 программы) отличается от всех встречавшихся
до сих пор описаний. Слева от стандартного описания функции добавлены еще два дополнительных
элемента. Первый – это слово Interrupt (прерывание). Это управляющее слово указывает транслятору
на то, что данная функция является процедурой обработки прерывания. Вид прерывания, которое
будет вызывать данную функцию, указывается сразу за словом Interrupt в квадратных скобках.
Выражение interrupt [ТIM1_С0МР] означает, что данная функция является процедурой обработки
прерывания по совпадению таймера Т1.
Имя функции обработки прерывания, автоматически данное мастером (timerl_comp_isr), не
является обязательным. Если вы пожелаете разработать программу без участия мастера, вы можете
выбрать имя для вашей функции по своему усмотрению. Вы можете также поменять имя и в
автоматически сформированной программе.
Функция обработки прерывания, как и функция main, не должна иметь параметров и не
возвращает никаких значений. Поэтому перед именем функции и в круглых скобках всегда стоит
слово void.
Теперь посмотрим, что же мы изменили в программе вручную:
 из автоматически сформированной программы были удалены все лишние комментарии, а вместо
них были добавлены другие, на русском языке;
 в программу были внесены новые команды и операторы, реализующие нужные нам алгоритмы.
И первое, что нам пришлось сделать – это создать переменную rab. Эта переменная будет нужна для
операций сдвига, и использоваться она будет как в функции main, так и в функции обработки прерывания.
То есть переменная должна быть глобальной. Поэтому описание этой переменной мы поместили вне обеих
функций в самом начале программы (строка 2).
Функция main претерпела наименьшие изменения. Потребовалось лишь добавить команду

7
присвоения начального значения переменной rab (строка 40) и команду разрешения прерываний
(строка 41). Главный же цикл программы оставлен пустым, как и в программе на Ассемблере.
Функция main работает как основная программа. После выполнения команд конфигурации и
разрешения прерывания, таймер/счетчик будет запущен в режиме сброса при совпадении. Каждые
200 мс он будет вызывать процедуру обработки прерывания, то есть функцию timerl_comp_isr.
Теперь посмотрим, как была доработана функция timerl_comp_isr. Основная часть доработок
пришлась именно на нее. Новые команды, составляющие тело функции, занимают в программе
строки 4 – 10. Функция обработки прерывания занимается сдвигом содержимого переменной rab на
один шаг влево или вправо и выводом полученного значения в порт РВ. Но перед тем, как выполнить
сдвиг, нужно определить направление этого сдвига.
Для этого нужно проверить состояние переключателя. Для проверки состояния переключателя
служит команда if (строка 4). Эта команда проверяет значение младшего разряда порта PD. Если
значение разряда равно единице (контакты переключателя разомкнуты), то выполняется процедура
сдвига на один бит вправо (строки 5, 6). Если младший бит PD равен нулю (контакты переключателя
замкнуты), то выполняется процедура сдвига на один бит влево (строки 8,9).
Рассмотрим подробнее процедуры сдвига. Сдвиг на один бит вправо выполняется в строке 5.
Оператор if в строке 6 проверяет, не дошла ли сдвигаемая единица до конца байта. Признаком того,
что единица уже дошла до конца, является равенство переменной rab нулю. Если условие выполняется,
то переменной rab будет присвоено значение 0b10000000. То есть, дойдя до правого края, единица
появляется слева. Таким образом реализуется эффект кругового движения единичного бита.
Обратите внимание, что в команде if в строке 6 не используются фигурные скобки. Язык СИ
допускает опускать фигурные скобки только в том случае, когда в них заключен всего один оператор.
Процедура сдвига на один бит влево (строки 8, 9) выполнена аналогичным образом.
После выполнения одной из вышеописанных процедур сдвига производится запись содержимого
переменной rab в порт РВ с одновременным инвертированием этого содержимого (строка 10).

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


1. Прочитать описания работы.
2. Запустить CodeVisionAVR. Используя мастер создать заготовку будущей программы, задав
настройки прерывания от таймера T1.
3. Добавить в текст заготовки программы недостающие строки описания переменных и строки
подпрограммы обработки прерывания.
4. Выполнить компиляцию программы и убедиться, что отсутствуют ошибки.
5. Выполнить пошаговую отладку программы в AVR Studio. Убедиться, что программа работает
верно. Результат показать преподавателю.
6. Выполнить отчет по итогам работы, который должен содержать постановку задачи,
принципиальную схему устройства, расчет значений регистров, блок-схему алгоритма, листинг
отлаженной программы.