Програма за якою працює мікропроцесор мовою асемблера АТ89С4051 має наступний вигляд:
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
ORG 0
Goto PROGRAM
sec equ H'11' ; секунди
sec10 equ H'12' ; Десятки секунд
min equ H'13' ; минути
min10 equ H'14' ; Десятки минут
hour equ H'15' ; години
hour10 equ H'16' ; Десятки годин
Indicator equ H'17' ; 7-сегментний код для загрузки в регістр DD2
Bit_counter equ H'18' ; лічильник бітів, загруженних в регістр DD2
FLAGS equ H'19' ; різні прапорці
FLAGS_2 equ H'1F'
Fig_pointer equ H'1B' ; показник виведеної цифри
TEMP equ H'1C' ; для тимчасового збереження вмісту порту A
Ind_start equ H'1D' ; адреса комірки, яка першою виводиться на індикатор
SB_delay equ H'1E' ; часова затримка
|
|
STATUS_copy equ H'21' ; копії вмісту регістрів
W_copy equ H'22'
FSR_copy equ H'23'
min_al_1 equ H'24' ; регістри першого будильника
min10_al_1 equ H'25'
hour_al_1 equ H'26'
hour10_al_1 equ H'27'
min_al_2 equ H'28' ; регістри другого будильника
min10_al_2 equ H'29'
hour_al_2 equ H'2A'
hour10_al_2 equ H'2B'
EEP_Ind_4 equ H'2C' ; регістри для індикації
EEP_Ind_3 equ H'2D' ; режиму роботи з EEPROM
EEP_Ind_2 equ H'2E'
EEP_Ind_1 equ H'2F'
Alarm_count equ H'30' ; лічильник будильника
SB4_count equ H'31' ; лічильник часу натискання на кнопку SB2
IntCount_H equ H'32' ; лічильник переповнення таймеру номер 1
IntCount_L equ H'33' ; лічильник переповнення таймеру номер 2
MaxInt_H equ H'34' ; верхня границя лічильника переривань
MaxInt_L equ H'35' ; визначає секундну затримку
TIME_SET equ H'36' ; коефіцієнт корекції часу
; ------------- Підпрограма яка добавляє хвилини ---------------
INC_MIN macro Reg1_min,Reg2_min
movfw Reg1_min ; якщо кількість менут = 9 то
xorlw 9 ; обнуляємо менути і прибавляємо десятки менут
BZ $+3 ; інакше прибавляємо менути та виходимо з підпрограми
incf Reg1_min, f
goto Main_loop
clrf Reg1_min
movfw Reg2_min
xorlw 5 ; якщо кількість десятків менут = 5,
BZ $+3 ; обнуляємо менути та взагалі та виходимо з підпрограми
|
|
incf Reg2_min, f ; інакше прибавляємо десятки менут
goto Main_loop
clrf Reg1_min
clrf Reg2_min
goto Main_loop
endm
; ------------- Підпрограма яка прибавляє години ---------------
INC_HOUR macro Reg1_hour,Reg2_hour
movfw Reg1_hour ; якщо кількість годин = 3, то перевіряємо чи
xorlw 3 ; число десятків годин = 2, якщо так то
btfss STATUS, Z; обнуляємо години взагалі (перехід із 23 годин в 00)
goto $+5
movfw Reg2_hour
xorlw 2
BZ $+D'14'
movfw Reg1_hour ; якщо число годин = 10, прибавляєм
xorlw 9 ; десятки годин і скидаємо одениці
BZ $+3 ; інакше прибавляєм одениці годин та виходимо із підпрограми
incf Reg1_hour, f
goto Main_loop
clrf Reg1_hour
movfw Reg2_hour
xorlw 2
BZ $+3
incf Reg2_hour, f
goto Main_loop
clrf Reg1_hour
clrf Reg2_hour
goto Main_loop
endm
; ------------- Підпрограма зменшення хвилин ---------------
DEC_MIN macro Reg1_min,Reg2_min
local DEC_min10,Clr
movfw Reg1_min ; зменшуєм хвилини
xorlw 0
BZ DEC_min10
decf Reg1_min,f
goto Main_loop
DEC_min10 movlw 9 ; установлюєм число хвилин = 9
movwf Reg1_min ; і зменшуєм десятки хвилин
movfw Reg2_min
xorlw 0
BZ Clr
decf Reg2_min, f
goto Main_loop
movlw 5
movwf Reg2_min
goto Main_loop
endm
; ------------- Підпрограма зменшення годин ---------------
DEC_HOUR macro Reg1_hour,Reg2_hour
local Set_hour,Clr,If_hour10_1,If_hour10_2,Dec_hour10
movfw Reg1_hour ; зменшуєм години
xorlw 0
BZ Set_hour
decf Reg1_hour, f
goto Main_loop
movfw Reg2_hour ; якщо десятки годин = 0,
xorlw 0 ; установлюємо години рівні 3
btfss STATUS, Z
goto If_hour10_1
movlw 3
movwf Reg1_hour
goto Dec_hour10
If_hour10_1 movfw Reg2_hour; якщо десятки годин = 1,
xorlw 1 ; установлюєм число годин = 9
btfss STATUS, Z
goto If_hour10_2
movlw 9
movwf Reg1_hour
goto Dec_hour10
If_hour10_2 movlw 9 ; якщо десятки годин = 2,
movwf Reg1_hour ; установлюємо години рівні 9
Dec_hour10 movfw Reg2_hour; зменшуєм десятки годин
xorlw 0
BZ Clr
decf Reg2_hour, f
goto Main_loop
Clr movlw 2
movwf Reg2_hour
goto Main_loop
endm
; ------------- Підпрограма запису в EEPROM ---------------
EE_write macro Adress,Data
movlw Adress
movwf EEADR
movfw Data
movwf EEDATA
call Write_to_EEPROM
endm
; ------------- Підпрограма читання EEPROM ---------------
EE_read macro Adress,Destination
movlw Adress
movwf EEADR
call Read_from_EEPROM
movfw EEDATA
movwf Destination
endm
; ------------------- ІНІЦІАЛІЗАЦІЯ ----------------------
PROGRAM
bsf STATUS,RP0; банк 1
clrf TRISA ; порт А на вихід
movlw B'11110000' ; RB7..RB4 - на вхід, RB3..RB0 - на вихід
movwf TRISB
movlw B'00001000' ; відключений від таймеру
movwf OPTION_REG
bcf STATUS, RP0 ; банк 0
clrf TIME_SET
clrf FLAGS
clrf FLAGS_2
clrf sec
clrf sec10
clrf min
|
|
clrf min10
clrf hour
clrf hour10
clrf SB_delay
clrf Bit_counter
clrf Alarm_count
clrf PORTB
clrf SB4_count
clrf IntCount_H
clrf IntCount_L
movlw B'00010001'
movwf PORTA
movlw H'16' ; починаєм індикацію з десятків годин
movwf Ind_start
movfw Ind_start
movwf Fig_pointer
bsf FLAGS,PT ; ввімкнення крапок на індикаторі
bsf FLAGS_2, HL1
movlw D'16' ; запускаємо таймер номер 0
movwf TMR0
EE_read 1, TIME_SET ; читаємо значення коэфіціэнту
movwf TIME_SET ; корекції часу
EE_read 2, min_al_1; читаєм показпоказники обох
EE_read 3, min10_al_1 ; будильників з EEPROM
EE_read 4, hour_al_1
EE_read 5, hour10_al_1
EE_read 6, min_al_2
EE_read 7, min10_al_2
EE_read 8, hour_al_2
EE_read 9, hour10_al_2
movfw min_al_1 ; якщо в регістрах будильника
xorlw H'11' ; були числа 0х11, тоді,
btfss STATUS,Z ; він був вімкнений при останньому
bsf FLAGS, Al_on ; записі в EEPROM
movfw min_al_2
xorlw H'11'
btfss STATUS, Z
bsf FLAGS_2, Al_on2
bsf PORTB, 3; вмикаєм світлодіод
btfsc FLAGS, Al_on
bcf PORTB, 3
btfsc FLAGS_2, Al_on2
bcf PORTB, 3
bsf INTCON, T0IE ; дозволяєм переривання
bsf INTCON, GIE
movlw H'E' ; ініціалізація регістрів для правельної індикації
movwf EEP_Ind_1 ; режим роботи EEPROM
movlw H'E'
movwf EEP_Ind_2
movfw TIME_SET; розбиваємо змінну TIME_SET
andlw B'00001111' ; на 16-розрядні десятки та одениці
movwf EEP_Ind_4 ; одениці
movfw TIME_SET
movwf EEP_Ind_3 ; десятки
swapf EEP_Ind_3, f
movlw B'00001111'
andwf EEP_Ind_3, f
|
|
;******************************************************************
; ГОЛОВНИЙ ЦИКЛ ПРОГРАМИ
******************************************************************
movlw H'21' ; задаємо верхню границю
movwf MaxInt_L ; лічби переривань = 3873
movlw H'F'
movwf MaxInt_H
movfw TIME_SET; добавляєм TIME_SET до границі
bcf STATUS, C; лічби переповнення таймера
addwf MaxInt_L, f
btfsc STATUS, C
incf MaxInt_H, f
movfw IntCount_H ; порівнюєм старший байт
xorwf MaxInt_H, w
btfss STATUS, Z
goto Main_loop
movfw IntCount_L ; порівнюєм молотший байт
xorwf MaxInt_L, w
btfss STATUS, Z
goto Main_loop
goto ADD1s ; секунда пройшла
; ------- Процедура перекодування числа в семисегментний код --------
Table
addwf PCL,f
retlw B'00000010'; цифра 0
retlw B'10011110'; цифра 1
retlw B'00100100'; цифра 2
retlw B'00001100'; цифра 3
retlw B'10011000'; цифра 4
retlw B'01001000'; цифра 5
retlw B'01000000'; цифра 6
retlw B'00011110'; цифра 7
retlw B'00000000'; цифра 8
retlw B'00001000'; цифра 9
retlw B'11111110'; пусте місце (код 10h)
retlw B'11111100'; тире (код 11h)
;********************* Режим індикації секунд ***********************
Show_seconds
clrf SB4_count
btfsc FLAGS,Sec ; якщо на індикаторі показані секунди
goto Show_hour ; повертаємся до нормального вигляду
movlw H'14'
movwf Ind_start
bsf FLAGS, Sec
movwf SB_delay
goto Main_loop
Show_hour
movlw H'16'
movwf Ind_start
bcf FLAGS,Sec
movwf SB_delay
goto Main_loop
;***************** Добавляєм менути реального часу ******************
ADDmin_button
clrf sec
clrf sec10
INC_MIN min, min10
goto Main_loop
;******************Добавляєм години реального часу ******************
ADDh_button
clrf sec
clrf sec10
INC_HOUR hour, hour10
goto Main_loop
END ; кінець програми
Рисунок 3.2.1 - Блок-схема роботи пристрою