>>5145 ;
************
; ОБРАБОТЧИК ПРЕРЫВАНИЯ КОМПАРАТОРА
;
************
Timer1_comp1:
// Сюда ты попал после начала обработки прерывания
ldi Temp,0 ;обнуление таймера **// Положил в Temp нолик**
out TCNT1H,Temp **// Переложил нолик в старший байт счётчика**
out TCNT1L,Temp **// Переложил нолик в младший байт счётчика**
**// Ты не можешь прямо записать константу, например ноль в РВВ, такова архитектура,
алсо, инжой юр ассемблер**
------------------------------------------------------------------------------------
cpi Temp1,30 ;сравнить с крайним знач.
breq Init ;если равно - загрузка нач. знач.
**// Temp1, далее в коде, используется для позиционирования внутри массива, массив состоит из 30 элементов, т.е. 30 ячеек ПЗУ, фактически относительная нумерация элементов начинается с нулевого элемента, массив содержит элементы с 0 по 29 включительно, поэтому, если мы прибавим 30 к абсолютному адресу массива(адресу того места где расположен нулевой элемент), то вылетим за его пределы, следовательно, если Temp1 = 30,
топаем на метку Init, где пишем в Temp1 нолик и топаем на метку ReadArray теребить массив.**
------------------------------------------------------------------------------------
ReadArray:
// И вот мы теребим массив
ldi ZH,High(Array*2) ;загрузка начального адреса массива
ldi ZL,Low(Array*2) **// Тут, с помощью причудливого синтаксиса
ложим в регистровую пару ZL, ZH значение которое указывает на абсолютный адрес нулевого элемента массива в ПЗУ, поскольку регистровая пара это два восьми-разрядных РОН, а именно r30 и r31, а адрес нулевого элемента является 16ти разрядной величиной, то мы вынуждены использовать причудливую хуиту с указателями на два байта, чтобы компилер расценивал содержимое этих РОН как одно 16ти битное целое.**
-----------------------------------------------------------------------------------
// В этой части кода, складываем значение адреса нулевого элемента массива, которое уже лежит в паре ZL, ZH с значением переменной Temp1, если Temp1=0, то адресуем нулевой элемент, если Temp1=29, то адресуем двадцатьдевятый элемент. Почему надо положить в ZH нолик и прибавить содержимое флага переполнения обесню в конце.
ldi Temp,0 ;прибавление внутр. адреса
add ZL,Temp1
adc ZH,Temp
// Итак, в паре Z лежит адрес элемента массива, который был определен значением переменной Temp1. Поехали дальше. ------------------------------------------------------------------------------------
// Вот тут, начинается охуенная магия, команда lpm означает целую кучу операций со специально предназначенными для этого РОН. Происходит следующее, значение р-пары Z загружается в программный счётчик, таким образом ясный взор АЛУ обращается к ячейке ПЗУ в которой находится тот самый элемент массива, который мы теребим. Далее, восемь бит данных из этого элемента(этой ячейки ПЗУ) помещаются в r0. Зачем в r0? Потому, что мы не можем положить константу в какой-нибудь РВВ, например в PortB, поэтому, копируем константу из ячейки ПЗУ в аккумулятор r0, ложим её в РОН, а оттуда в РВВ. Инжой юр ассемблер.
lpm ;загрузка из ПЗУ
-------------------------------------------------------------------------------------
mov Temp,R0 ;копирование в РОН **// Переложили константу в РОН**
inc Temp1 ;увеличение внутр. адреса**// Увеличили Temp1 на 1, дабы, в следующем цикле теребить следующий элемент массива.**
rjmp Output ;перейти на вывод в порт**// Пошли теребить порт.**
Init: ldi Temp1,0 ;загрузить нач. значение
// Положили нолик
rjmp ReadArray **// Топаем теребить массив**
Output: out PortB,Temp ;вывод в порт
// Положили данные из элемента массива
**в порт, светодиоды загорелись, УРА!1111**
reti ;выход из обработчика **// Вышли из обработки прерывания**
Array:
//метка указывающая начало массива находится по адресу 0хХуита .db 0b10000001,0b01000010
//элементы 0 и 1, относительные адреса 0хХуита + 0, 0хХуита + 1 .db 0b00100100,0b00011000
.db 0b00011000,0b00111100
.db 0b01111110,0b11111111
.db 0b11100111,0b11000011
.db 0b10000001,0b11000001
.db 0b11100001,0b11110001
.db 0b11111001,0b11111101
.db 0b11111111,0b01111111
.db 0b00111111,0b00011111
.db 0b00001111,0b00000111
.db 0b00000011,0b00000001
.db 0b00000011,0b00000101
.db 0b00001001,0b00010001
.db 0b00100001,0b01000001
---------------------------------------------------------------------------------
Теперь десерт. Зачем нужна эта конструкция.
ldi Temp,0 ;прибавление внутр. адреса
add ZL,Temp1
adc ZH,Temp
Допустим, небеса распорядились так, что начало массива расположено по адресу ПЗУ 0х00F0, следовательно, при помещении адреса нулевого элемента массива в регистры ZL, ZH будут записаны следующие значения ZL(r30) = 0xF0(240), ZH(r31) = 0x00(0), иначе говоря:
ZH=0x00 ZL=0xF0
Z=0x00F0
Допустим, теперь мы хотим адресовать двадцать второй элемент массива, переменная Temp1 содержит значение 0х16 (22), прибавляем 0х16 к ZL в котором уже 0хF0, получаем 0х106, но регистр ZL восьми-разрядный, поэтому в нём остаётся только 0х06 и одновременно с этим в регистре состояния АЛУ устанавливается флаг переноса, т.е. SREG.0 = 1. Эту единичку нам надо поместить в ZH, чтобы получить правильный адрес 22го элемента массива.
ZH=0x01 ZL=0x06
Z=0x0106
Для этого мы и складываем ^^ничего^^ Temp, в котором ноль с учётом переноса(то есть +1 из SREG) c ZH. Довольно просто ~кашира.
Теперь ты всё понял, зайка?:3
Убежал:3