- •Лабораторна робота №6 Дослідження режиму переривання в мікроконтролерах
- •Теорія по структурі мп та перериванням
- •1.2. Відмінні риси.
- •1.3. Характеристики процесора.
- •1.4. Характеристики підсистеми вводу/виводу.
- •1.5. Периферійні пристрої.
- •1.6. Архітектура ядра.
- •1.7. Розміщення та опис виводів.
- •2. Архітектура мікроконтролерів aTmega8.
- •2.1. Загальні відомості.
- •2.2. Організація пам'яті
- •2.3. Регістри вводу/виводу.
- •3. Переривання.
- •3.1. Загальні відомості.
- •3.2. Таблиця векторів переривань.
- •3.3. Обробка переривань.
- •4. Регістри портів вводу/виводу.
- •Створення програми. Використання переривань по таймеру. Постановка завдання
- •Алгоритм
- •Програма на Асемблері
- •Опис програми (лістинг 6.1)
- •2.4. Порядок виконання роботи
- •1.6. Контрольні тестові питання.
- •Литература
Програма на Асемблері
Текст можливого варіанту програми на мові Асемблер приведений в лістингу 6.1. У програмі зустрічаються декілька нових для нас операторів.
Зверніть увагу. Використовується новий для нас прапор - прапор глобального дозволу переривань, який називається I.
Ми вже згадували цей прапор в розділі 3. Прапор I, так само, як прапори С і Z, є одним з розрядів регістра SREG. Проте управління прапором I відбувається зовсім по-іншому. На нього не впливають ні арифметичні, ні логічні операції, а тим більше операції порівняння. Для установки і скидання цього прапора в системі команд передбачені дві спеціальні команди (описані нижче). Якщо прапор I скинутий, то всі переривання в мікроконтролері заборонені. Якщо прапор встановлений, робота системи переривань дозволяється. Розглянемо тепер по порядку всі нові для нас оператори.
.dseg
Оператор вибору сегмента пам'яті даних. До цих пір у всіх попередніх ассемблерних програмах ми обов'язково використовували оператор .cseg, який дозволяв нам вибирати програмний сегмент пам'яті. Пора навчитися працювати і з іншими сегментами.
Наступний за значенням після програмного сегмента - це сегмент пам'яті даних, тобто сегмент ОЗП. У програмі (лістинг 1.13) у рядку 6 проводиться вибір саме цього сегмента.
. byte
Оператор резервування пам'яті. Це один з операторів, які діють в сегменті пам'яті даних. Оператор дозволяє зарезервувати один або декілька байтів (комірок ОЗП) для того, щоб потім використати їх у програмі. Ви запитаєте: навіщо це потрібно? Основна мета резервування - облік і розподіл пам'яті.
Якщо програміст буде довільно, на свій розсуд, вибирати адреси комірок ОЗП для тієї або іншої задачі, то йому доведеться уважно стежити за тим, щоб не вибрати повторно одну і ту ж комірку для зберігання різних значень. Інакше програма при записі одного значення зіпсує друге, що призведе до помилки в її роботі.
Механізм резервування пам'яті дозволяє транслятору контролювати використання пам'яті і виключати подвійне використання комірок. Крім того, подібний механізм взагалі позбавляє програміста від необхідності запам'ятовувати адреси. Все відбувається автоматично.
Оператор .byte має всього один параметр - кількість комірок, які потрібно зарезервувати. У нашій програмі застосовується лише одна команда, що резервує пам'ять (рядок 8, лістинг 1.13). У даному випадку резервується всього одна комірка пам'яті. Мітка buf, поставлена перед оператором, використовується для звернення до зарезервованої комірки.
reti
Оператор завершення підпрограми обробки переривання. Дія цього оператора аналогічна дії оператора ret. Він витягає адресу з стеку і передає управління за цією адресою. Різниця полягає в тому, що команда reti ще і встановлює в одиницю прапор глобального дозволу переривань I.
sts
Команда запису вмісту РОН в ОЗП. Має два параметри. Перший параметр - адреса комірки пам'яті, куди записуються дані.
Другий параметр - ім'я регістра джерела даних. У рядку 49 програми вміст регістра rab записується в ОЗП за адресою, що визначається міткою buf.
lds
Команда читання інформації з комірки пам'яті. Прочитана інформація записується в один з РОН. Команда також має два параметри. Перший параметр - ім'я РОН, куди записуються зчитані дані. Другий параметр – адреса комірки пам'яті (джерела даних).
set
Команда дозволу переривань. Ця команда встановлює прапор I. Тобто дозволяє все переривання.
Лістинг 6.1
|
;############################################# ;## Приклад 7 ## ;## «Біжучі вогні» ## ;## з використанням переривань від таймера ## ;############################################# ;-------------------------------------Псевдокоманди керування |
||||||
1 |
.include “tn2313def.inc” |
; Приєднання файлу опису |
|||||
2 |
.list |
; Ввімкнення лістингу |
|||||
3 |
.def temp = R16 |
; Визначення головного робочого регістру |
|||||
4 |
.def rab = R17 |
; Визначення робочого регістру для команд здвигу |
|||||
5 |
.equ kdel = 780 |
|
|||||
|
;------------------------------------ Резервування комірок пам’яті |
||||||
6 |
|
.dseg |
|
; Обираємо сегмент ОЗП |
|||
7 |
|
.org |
0x60 |
; Встановлюємо поточну адресу сегменту |
|||
8 |
buf: |
.byte |
1 |
; Один байт для збереження робочого значення |
|||
|
;------------------------------------ Початок програмного коду |
||||||
9 |
|
.cseg |
|
; Вибір сегменту програмного коду |
|||
10 |
|
.org |
0 |
; Встановлення поточної адреси на нуль |
|||
|
;------------------------------------ |
||||||
11 |
start: |
rjmp |
init |
; Перехід на початок програми |
|||
12 |
|
reti |
|
; Зовнішнє переривання 0 |
|||
13 |
|
reti |
|
; Зовнішнє переривання 1 |
|||
14 |
|
reti |
|
; Таймер/лічильник 1, захоплення |
|||
15 |
|
rjmp |
prtim1 |
; Таймер/лічильник 1, співпадіння, канал А |
|||
16 |
|
reti |
|
; Таймер/лічильник 1, співпадіння по переповненню |
|||
17 |
|
reti |
|
; Таймер/лічильник 0, співпадіння по переповненню |
|||
18 |
|
reti |
|
; Переривання UART прийом завершений |
|||
19 |
|
reti |
|
; Переривання UART регістр даних пустий |
|||
20 |
|
reti |
|
; Переривання UART передача завершена |
|||
21 |
|
reti |
|
; Переривання по компаратору |
|||
22 |
|
reti |
|
; Переривання по зміні на будь-якому контакті |
|||
23 |
|
reti |
|
; Таймер/лічильник 1, співпадіння, канал В |
|||
24 |
|
reti |
|
; Таймер/лічильник 0, співпадіння, канал В |
|||
25 |
|
reti |
|
; Таймер/лічильник 0, співпадіння, канал А |
|||
26 |
|
reti |
|
; USI готовність до старту |
|||
27 |
|
reti |
|
; USI переповнення |
|||
28 |
|
reti |
|
; EEPROM готовність |
|||
29 |
|
reti |
|
; Переповнення охоронного таймеру |
|||
|
;------------------------------- Модуль ініціалізації |
||||||
|
init: |
|
|
|
|||
|
;------------------------------------ Ініціалізація стеку |
||||||
30 |
|
ldi |
temp, RAMEND |
; Вибір адреси вершини стеку |
|||
31 |
|
out |
SPL, temp |
; Запис її в регістр стеку |
|||
|
;------------------------------------ Ініціалізація портів ВВ |
||||||
32 |
|
ldi |
temp, 0 |
; Записуємо нуль в регістр temp |
|||
33 |
|
out |
DDRD, temp |
; Записуємо цей нуль в DDRD (порт PD на ввід) |
|||
34 |
|
ldi |
temp, 0xFF |
; Записуємо число $FF в регістр temp |
|||
35 |
|
out |
DDRB, temp |
; Записуємо temp в DDRB (порт РВ на вивід) |
|||
36 |
|
out |
PORTB, temp |
; Записуємо temp в P0RTB (згасити світлодіод) |
|||
37 |
|
out |
PORTD, temp |
; Записуємо temp в P0RTD (включаємо внутр. резист.) |
|||
|
;------------------------------------ Ініціалізація таймера T1 |
||||||
38 |
|
ldi |
temp, 0x05 |
; Вибір режиму таймеру |
|||
39 |
|
out |
TCCR1B, temp |
|
|||
40 |
|
ldi |
temp, high(kdel) |
; Старший напівбайт коду співпадіння |
|||
41 |
|
out |
OCR1AH, temp |
; Запис в регістр співпадіння старшого напівбайту |
|||
42 |
|
ldi |
temp, low(kdel) |
; Молодший напівбайт коду співпадіння |
|||
43 |
|
out |
OCR1AL, temp |
; Запис в регістр співпадіння молодшого напівбайту |
|||
|
;------------------------------------ Визначення маски переривань |
||||||
44 |
|
ldi |
temp, 0b10000000 |
; Байт маски. Дозволене одне переривання. |
|||
45 |
|
out |
TIMSK, temp |
; Записуємо маску. |
|||
|
;------------------------------------ Ініціалізація компаратора |
||||||
46 |
|
ldi |
temp, 0x80 |
; Вимкнення компаратора |
|||
47 |
|
out |
ACSR, temp |
|
|||
|
;------------------------------------ Початок основної програми |
||||||
48 |
main: |
ldi |
rab, 0b00010000 |
; Запис початкового значення |
|||
49 |
|
sts |
buf, rab |
; Запис вмісту регістру rab в ОЗП |
|||
50 |
|
sei |
|
; Дозвіл переривань |
|||
51 |
m1: |
rjmp |
m1 |
; Пустий нескінченний цикл |
|||
|
;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; Підпрограма обробки переривань ;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = |
||||||
52 |
prtim1: |
push |
temp |
; Зберігаємо регістр temp |
|||
53 |
|
push |
rab |
; Зберігаємо регістр rab |
|||
54 |
|
lds |
rab, buf |
; Читаємо вміст rab з ОЗП |
|||
55 |
|
in |
temp, PIND |
; Зчитуємо вміст порту PD |
|||
56 |
|
sbrs |
temp, 0 |
; Перевірка молодшого розряду |
|||
57 |
|
rjmp |
p2 |
; Якщо не нуль, перейдемо до здвигу вліво |
|||
|
;------------------------------------- Здвиг вправо |
||||||
58 |
p1: |
lsr |
rab |
; Здвиг вмісту робочого регістру |
|||
59 |
|
brcc |
p3 |
; Якщо не дійшло до кінця регістру пропустити |
|||
60 |
|
ldi |
rab, 0b10000000 |
; Запис початкового значення |
|||
61 |
|
rjmp |
p3 |
; В кінець |
|||
|
;------------------------------------- Здвиг вліво |
||||||
62 |
p1: |
lsr |
rab |
; Здвиг вмісту робочого регістру |
|||
63 |
|
brcc |
p3 |
; Якщо не дійшло до кінця регістру пропустити |
|||
64 |
|
ldi |
rab, 0b00000001 |
; Запис початкового значення |
|||
|
;-------------------------------- Кінець процедури обробки переривання |
||||||
65 |
p3: |
ldi |
temp, 0xFF |
; Записуємо число $FF в регістр temp |
|||
66 |
|
eor |
temp, rab |
; Інверсія вмісту rab (виключаюче АБО) |
|||
67 |
|
out |
PORTB, temp |
; Вивід поточного значення в порт РВ |
|||
68 |
|
sts |
buf, rab |
; Запис вмісту регістру rab в ОЗП |
|||
69 |
|
pop |
rab |
; Відновлюємо регістр rab |
|||
70 |
|
pop |
temp |
; Відновлюємо регістр temp |
|||
71 |
|
reti |
|
|
Фото програми для перевірки: