You are on page 1of 4

;*** Програма до розрахунково-графічної роботи (стенд EV8031/AVR)*****

;*** При кожному повороті енкодера за годинниковою стрілкою на 4 тіки,


;*** здійснюється декремент першого 1-розрядного шістнадцяткового лічильника (із
простором станів F -> 0),
;*** стани якого відображаються на другому лівому знакомісць статичного
семисегментного індикатора
;*** а при повороті проти годинникової стрілки на 4 тіків -
;*** декремент другого 1-розрядного шістнадцяткового лічильника (із простором
станів F -> 0),
;*** стани якого відображаються на другому правому знакомісці статичного
семисегментного індикатора
;*** При натисканні на інкрементальний енкодер як на кнопку обидва лічильника
повертаються в початковий стан - F та 0 відповідно.

.include "m8515def.inc" ;підключення модуля контролера ATmega8515

;*** Призначення символічних імен регістрів ***

.def digl = r16 ;регістр, що зберігає значення лівого знакомісця


.def digr = r17 ;регістр, що зберігає значення правого знакомісця
.def temp = r18 ;регістр тимчасового зберігання

;Регістр, що зберігає попередній стан інкрементального енкодера


.def last_encoder_state = r19
;Регістр, що зберігає наступний стан інкрементального енкодера
.def next_encoder_state = r20

.def counter1 = r21 ;кількість тіків проти годинникової стрілки


.def counter2 = r22 ;кількість тіків за годинниковою стрілкою
.def counter3 = r24 ;кількість натискань енкодера-
.def is_permission_to_read_encoder = r23 ;прапор дозволу на читання енкодера

;*** Призначення констант ***

;адреса пари лівих знакомісць статичного семисегментного індикатора


.EQU stat_7seg_counter1 = 0xA000
;адреса пари правих знакомісць статичного семисегментного індикатора
.EQU stat_7seg_counter2 = 0xB000
;адреса регістра керування запаленням/гасінням точок/знакомісць статичного
семисегментний індикатора
.EQU stat_7seg_control = 0xA004

;***** Початок програми *****

.CSEG ;визначаємо початок сегмента коду


.ORG 0x0000 ;визначаємо адресу початку сегмента коду в пам'яті програм

;*** Таблиця векторів переривань контролера ***

rjmp Init; вектор переривання по скиданню


reti; rjmp EXT_INT0; IRQ0 Handler
reti; rjmp EXT_INT1; IRQ1 Handler
reti; rjmp TIM1_CAPT; Timer1 Capture Handler
rjmp TIM1_COMPA; Timer1 Compare A Handler
reti; rjmp TIM1_COMPB; Timer1 Compare B Handler
reti; rjmp TIM1_OVF; Timer1 Overflow Handler
reti; rjmp TIM0_OVF; Timer0 Overflow Handler
reti; rjmp SPI_STC; SPI Transfer Complete Handler
reti; rjmp USART_RXC; USART RX Complete Handler
reti; rjmp USART_UDRE; UDR0 Empty Handler
reti; rjmp USART_TXC; USART TX Complete Handler
reti; rjmp ANA_COMP; Analog Comparator Handler
reti; rjmp EXT_INT2; IRQ2 Handler
reti; rjmp TIM0_COMP; Timer0 Compare Handler
reti; rjmp EE_RDY; EEPROM Ready Handler
reti; rjmp SPM_RDY; Store Program memory Ready

;*** Початкова ініціалізація контролера ***

Init:
ldi temp, low (RAMEND)
out SPL, temp
ldi temp, high (RAMEND)
out SPH, temp ;установка SP на останню адресу в SRAM
sbi ACSR, 7 ;відключення живлення аналогового компаратора

ldi temp, 0b10000000 ;дозволяємо роботу із зовнішньою пам'яттю


out MCUCR, temp
;*** Налаштування переривань ***

ldi temp, 1 << OCIE1A


out TIMSK, temp; //дозволяємо переривання по співпадінню Aтаймера/лічильника
T1
ldi temp, 0x03
out OCR1AH, temp
ldi temp, 0x99
out OCR1AL, temp; //завантажуємо в регістрову пару OCR1AH:OCR1AL число 0x0399
;//тобто задаємо значення, при досягненні якого
;//таймер/лічильник T1 згенерує переривання по співпадінню А
ldi temp, 1 << PSR10
out SFIOR, temp; //скидаємо переддільник,
;//фактично в цей момент відбувається початок відліку
ldi temp, 0
out TCCR1A, temp
ldi temp, 1 << WGM12 | 1 << CS11;//встановлюємо дільник
out TCCR1B, temp

;Встановлюємо вказівник X на адресу лівого знакомісця статичного індикатора


ldi XL, low (stat_7seg_counter1)
ldi XH, high (stat_7seg_counter1)

;Встановлюємо вказівник Y на адресу правого знакомісця статичного індикатора


ldi YL, low (stat_7seg_counter2)
ldi YH, high (stat_7seg_counter2)

;Встановлюємо вказівник Z на адресу регістра керування статичним індикатором


ldi ZL, low (stat_7seg_control)
ldi ZH, high (stat_7seg_control)

ldi temp, 0b00001001


st Z, temp ;вимикаємо всі крапки, гасимо всі крайні знакомісця

ldi digl, 0xFF ;початкове значення лівого знакомісця


ldi digr, 0x00 ;початкове значення правого знакомісця sei

st X, digl ;видаємо на ліве знакомісце


st Y, digr ;видаємо на праве знакомісце
sei
Infinite_loop:; нескінченний цикл
tst is_permission_to_read_encoder
breq Infinite_loop

in next_encoder_state, PINB ;читаємо поточний стан каналів енкодера

;Отримуємо стан бітів порту, що відповідають за поточний стан енкодера


andi next_encoder_state, 0x90

cp next_encoder_state, last_encoder_state
breq Next_iterate ;якщо стан енкодера не змінився - продовжуємо його читати

cpi last_encoder_state, 0x00 ;якщо в каналі В енкодера не було "0" і в каналі


А теж не було "0"
brne Next_iterate; переходимо до подальших дій

cpi next_encoder_state, 0x10 ;якщо в каналі A енкодера залишився "0", а в


каналі B з'явилася "1", то енкодер повернули проти годинниковою стрілкою
breq Decr_counter2 ;переходимо до декременту правого знакомісця

cpi next_encoder_state, 0x80 ;якщо в каналі A енкодера з'явилася "1", а в


каналі B залишився "0", то енкодер повернули за годинниковою стрілкою
breq Decr_counter1 ;переходимо до декременту лівого знакомісця

rjmp Next_iterate ;якщо в жодному з каналів не стався фронт - йдемо далі

Decr_counter1:
inc counter2; додаємо 1 до лічильника імпульсів енкодера
cpi counter2, 0x04 ;якщо зроблено 4 тіки за годинникової стрілки
brne Next_iterate; лічильник != 4
rjmp Click_count1

Decr_counter2:
inc counter1; додаємо 1 до лічильника імпульсів енкодера
cpi counter1, 0x03
brne Next_iterate;лічильник != 3
rjmp Click_count2

Click_count1:
in temp, PINB ;читаємо поточний стан каналів енкодера
;Отримуємо стан біта порту, що відповідає за натискання енкодера як кнопки
andi temp, 0x20
tst temp ;якщо енкодер натиснуто як кнопку, то скидаємо значення
знакомісць
brne Click_count_add_1
cpi counter3, 0x03
brne Click_count1 ;лічильник != 3
rjmp Count_add_1

Click_count2:
in temp, PINB ;читаємо поточний стан каналів енкодера
;Отримуємо стан біта порту, що відповідає за натискання енкодера як кнопки
andi temp, 0x20
tst temp ;якщо енкодер натиснуто як кнопку, то скидаємо значення
знакомісць
brne Click_count_add_2
cpi counter3, 0x04
brne Click_count2 ;лічильник != 4
rjmp Count_add_2

Click_count_add_1:
inc counter3
rjmp Click_count1

Click_count_add_2:
inc counter3
rjmp Click_count2

Count_add_1:
subi digr, 0x10 ;віднімаємо 1 від старшого розряду регістра
clr counter1; обнуляємо регістр
clr counter3; обнуляємо регістр
rjmp Next_iterate ;переходимо до подальших дій

Count_add_2:
subi digl, 0x01 ;віднімаємо 1 від молодшого розряду регістра
clr counter2; обнуляємо регістр
clr counter3; обнуляємо регістр
rjmp Next_iterate ;переходимо до подальших дій

Next_iterate: ;перехід на цю мітку здійсниться в будь-якому випадку!


in temp, PINB ;читаємо поточний стан каналів енкодера

;Отримуємо стан біта порту, що відповідає за натискання енкодера як кнопки


andi temp, 0x20

tst temp ;якщо енкодер натиснуто як кнопку, то скидаємо значення


знакомісць
brne End_of_iteration
ldi digl, 0xFF;скидаємо до початкового стану
ldi digr, 0x0F;скидаємо до початкового стану

End_of_iteration:
st X, digl ;видаємо на ліве знакомісце
st Y, digr ;видаємо на праве знакомісце
mov last_encoder_state, next_encoder_state ;підготовка до наступної
ітерації опитування стану енкодера
;Присвоюємо попереднього стану енкодера його поточний стан
clr is_permission_to_read_encoder ;очищення прапора дозволу на читання
енкодера
rjmp Infinite_loop

TIM1_COMPA: ;обробник переривання


ldi is_permission_to_read_encoder, 1;встановлюємо прапорець дозволу
опитування енкодера
reti
.EXIT; кінець програми

You might also like