10+ лет назад писано, i8051 - at89c2051. Стрелочные часы на граф. дисплее. name main
;*********************************************************************************
; mail.asm;
; Эта программа подсчитывает время и выводит данные на lcd (96x65).
;**********************************************************************************
$Include (C:\MyPrj\dat.asm)
Extrn Code (init_lcd,clr_lcd,send_spi,change_co,lcd_norm_mode,lcd_inv_mode)
Extrn Code (delay_1ms,delay_250ms)
Extrn Code (start_i2c,send_i2c,read_i2c,read_i2c_no_ack,stop_i2c,read_one_byte,write_one_byte)
main segment CODE
rseg main
ORG 0000H ; Начинаем программу с нулевого адреса
jmp start ; Отсюда стартует программа после включения/сброса
ORG 0003H
jmp int_hour ; Внешнее прерывание 0 (по часовой кнопке)
ORG 000BH
jmp int_timer0 ; Прерывание по таймеру 0
ORG 0013H
jmp int_minute ; Внешнее прерывание 1 (по минутной кнопке)
ORG 001BH
jmp int_timer1 ; Прерывания по таймеру 1
ORG 0023H
reti ; Заглушка на вектор последовательному каналу
ORG 0030H ; Сдесь будут подпрограммы
;##########################################################
;## Макросы ##
;##########################################################
m_send_spi macro arg
mov a,arg
call send_spi
endm
m_change_co macro arg_x,arg_y
mov r0,arg_x
mov r1,arg_y
call change_co
endm
m_send_i2c macro arg
mov a,arg
call send_i2c
endm
;#####################################################################
; Подпрограммы
;#####################################################################
;*********************************************************************
; Процедура сложения двух 16-ых чисел
;*********************************************************************
; r7,r6 - слогаемое
; r5,r4 - слогаемое
; r5,r4 - сумма
;---------------------------------------------------------------------
add2_2:
mov a,r6
add a,r4
mov r4,a
mov a,r7
addc a,r5
mov r5,a
ret
;*********************************************************************
; Процедура вычитания двух 16-ых чисел
;*********************************************************************
; R5,R4 - уменьшаемое
; R7,R6 - вычитаемоу
; R5,R4 - разность
;------------------------------------------------------------
sub2_2:
mov a,r4
clr c
subb a,r6
mov r4,a
mov a,r5
subb a,r7
mov r5,a
ret
;*********************************************************************
; Процедура увеличения 16-го числа на #00040h
;*********************************************************************
; r5,r4 - увеличиваемое число
; r5,r4 - результат
;---------------------------------------------------------------------
inc40h:
mov a,#040h
add a,r4
mov r4,a
clr a
addc a,r5
mov r5,a
ret
;*********************************************************************
; Читать 65 байт и выводитьна экран (только для show_watch)
;*********************************************************************
read_and_show_65:
mov r4,#65
read_1s:
call read_i2c
call send_spi
djnz r4,read_1s
ret
;*********************************************************************
; Вывод на экран циферблата со стрелками
;*********************************************************************
show_watch:
mov r5,#001h ; Создание белой
mov r4,#024h ; точки
call read_one_byte ; в
mov b,#0feh ; центре
anl a,b ; экрана
call write_one_byte ; (ось вращения стрелок)
call start_i2c
m_send_i2c #0a0h
m_send_i2c #000h ; Адрес
m_send_i2c #000h ; зеркала
call start_i2c
m_send_i2c #0a1h
m_change_co #0,#0
mov r3,#8
nxt_shw2:
call read_and_show_65
inc r1
call change_co
djnz r3,nxt_shw2
mov r4,#64
read_sack2:
call read_i2c
call send_spi
djnz r4,read_sack2
call read_i2c_no_ack
call stop_i2c
ret
;*********************************************************************
; Отображение заставки
;*********************************************************************
title_lcd:
m_change_co #0,#0
call start_i2c
m_send_i2c #0a0h
m_send_i2c #025h ; Адрес
m_send_i2c #000h ; заставки
call start_i2c
m_send_i2c #0a1h ; Старт чтения
mov r0,#0
mov r1,#0
mov r5,#9 ; 9x96 циклов
next_read_title2:
mov r4,#96
call change_co
inc r1
next_read_title1:
call read_i2c
call send_spi
call delay_1ms
djnz r4,next_read_title1
djnz r5,next_read_title2
call read_i2c_no_ack
call stop_i2c
mov r4,#16
next_delay1:
call delay_250ms
djnz r4,next_delay1
ret
;*********************************************************************
; Сохранение 32-х байт из 24с256 в буфер
;*********************************************************************
load_from_24c256:
call start_i2c
m_send_i2c #0a0h
m_send_i2c high_adr_load
m_send_i2c low_adr_load
call start_i2c
m_send_i2c #0a1h
mov r4,#32
mov r0,#buffer
next_red:
call read_i2c
mov @r0,a
inc r0
djnz r4,next_red
call read_i2c_no_ack
mov @r0,a
call stop_i2c
ret
;*********************************************************************
; Запись 32-х байт в 24с256 из буфера
;*********************************************************************
safe_to_24c256:
call start_i2c
m_send_i2c #0a0h
m_send_i2c high_adr_safe
m_send_i2c low_adr_safe
mov r4,#32
mov r0,#buffer
next_rec:
mov a,@r0
call send_i2c
inc r0
djnz r4,next_rec
call stop_i2c
ret
;*********************************************************************
; Процедура инкрементирования адресов 24с256
;*********************************************************************
inc_adr:
mov r7,high_adr_load ; Увеличение
mov r6,low_adr_load ; адреса
mov r5,#0 ; источника
mov r4,#32 ; на 32-мь
call add2_2 ; байт
mov high_adr_load,r5 ;
mov low_adr_load,r4 ;
mov r7,high_adr_safe ; Увеличение
mov r6,low_adr_safe ; адреса
mov r5,#0 ; приёмника
mov r4,#32 ; на 32-мь
call add2_2 ; байт
mov high_adr_safe,r5 ;
mov low_adr_safe,r4 ;
ret
;*********************************************************************
; Саздание редактируемой копии картинки в памяти (зеркало)
;*********************************************************************
miror_creation:
mov high_adr_load,#07dh
mov low_adr_load,#0afh
mov high_adr_safe,#000h
mov low_adr_safe,#000h
mov r2,#18
next_copy:
call load_from_24c256
call safe_to_24c256
call inc_adr
djnz r2,next_copy
ret
;*********************************************************************
; Процедура для преобразования координат дисплея в адрес 24с256
; r4-x, r5-y <----->r5,r4-адрес
;*********************************************************************
calculation_adr:
mov a,#65
mov b,r5
mul ab
mov r7,b
mov r6,a
mov r5,#0
call add2_2
ret
;*********************************************************************
; Чтение в буфер 64-х байт из 24с256 по адресу r5,r4
;*********************************************************************
read_to_buf:
call start_i2c
m_send_i2c #0a0h
m_send_i2c r5
m_send_i2c r4
call start_i2c
m_send_i2c #0a1h
mov r4,#69
mov r0,#buffer
next_reds:
call read_i2c
mov @r0,a
inc r0
djnz r4,next_reds
call read_i2c_no_ack
mov @r0,a
call stop_i2c
ret
;#####################################################################
; Отрисовка стрелок, адрес стрелки в r5,r4
;#####################################################################
strelka:
call read_to_buf ; Запись в ОЗУ из ПЗУ данных о стреке
clr coord ; Сброс флага(если 0, то считать четвертый байт как колич. смен ко.)
mov r0,#buffer ; Заносим в r0 указатель на буфер(ОЗУ)
next_coord:
mov a,@r0 ; Копируем в рег. r4 первый байт,
inc r0 ; Инкремент адреса(ОЗУ)
mov r4,a ; это X-я координата
mov a,@r0 ; Копируем в рег. r5 второй байт,
inc r0 ; Инкремент адреса(ОЗУ)
mov r5,a ; это Y-я координата
call calculation_adr ; Находим адрес этой области экрана в ПЗУ
mov a,@r0 ; Чтение третьего байта, колич. байт данных до след смены ко.
inc r0
mov r2,a
jb coord,no_coor ; Переход если количество смен координат уже было прочитано
mov a,@r0 ; Чтение четвёртого байта, количество смен координат
inc r0
mov r3,a
setb coord
no_coor:
next_data:
mov b,@r0 ; Чтение пятого байта - это первый байт данных
inc r0
call read_one_byte ; Чтение байта па адресу найденому calculation_adr
orl a,b ; Наложение стрелки на фон
call write_one_byte ; Запись байта па адресу найденому calculation_adr
mov r7,#000h ; Увеличение
mov r6,#001h ; адреса
call add2_2 ;
djnz r2,next_data
djnz r3,next_coord
ret
;*********************************************************************
; Процедура циклического инкриментирования адреса секундной стрелки
;*********************************************************************
sec_adr_inc:
mov r4,sec_low_adr
mov r5,sec_high_adr
cjne r5,#011h,sec_next_inc ; Проверка на то, что текущий адрес
cjne r4,#040h,sec_next_inc ; это аднес 59-ой стрелки.
mov r5,#002h ; Установка адреса
mov r4,#080h ; 0-ой стрелки.
mov sec_low_adr,r4
mov sec_high_adr,r5
setb sec_0
ret
sec_next_inc:
call inc40h
mov sec_low_adr,r4
mov sec_high_adr,r5
ret
;*********************************************************************
; Процедура циклического инкриментирования адреса минутной стрелки
;*********************************************************************
min_adr_inc:
jb sec_0,min_inc
mov r5,min_high_adr
mov r4,min_low_adr
ret
min_inc:
clr sec_0
mov r4,min_low_adr
mov r5,min_high_adr
cjne r5,#023h,min_next_inc ; Проверка на то, что текущий адрес
cjne r4,#040h,min_next_inc ; это аднес 59-ой стрелки.
mov r5,#014h ; Установка адреса
mov r4,#080h ; 0-ой стрелки.
mov min_low_adr,r4
mov min_high_adr,r5
setb min_0
ret
min_next_inc:
call inc40h
mov min_low_adr,r4
mov min_high_adr,r5
ret
;*********************************************************************
; Процедура циклического инкриментирования адреса часовой стрелки
;*********************************************************************
hour_adr_inc:
jb min_0,hour_inc
mov r4,hour_low_adr
mov r5,hour_high_adr
ret
hour_inc:
clr min_0
mov r4,hour_low_adr
mov r5,hour_high_adr
cjne r5,#014h,hour_next_inc ; Проверка на то, что текущий адрес
cjne r4,#040h,hour_next_inc ; это аднес 11-ой стрелки.
mov r5,#011h ; Установка адреса
mov r4,#080h ; 0-ой стрелки.
mov hour_low_adr,r4
mov hour_high_adr,r5
ret
hour_next_inc:
call inc40h
mov hour_low_adr,r4
mov hour_high_adr,r5
ret
;#####################################################################
; Основная программа
;#####################################################################
start:
call init_lcd ; Инициализация экрана
call clr_lcd ; Очистка экрана
call title_lcd
call clr_lcd ; Очистка экрана
mov ie, #10001010b ; Регистр разрешения прерываний
mov ip, #00001010b ; Регистр приоритетов прерываний
mov tmod,#00010001b ; Регистр режимов Т/С
mov th0,#013h ; начальная инициализация
mov tl0,#048h ; таймера Т0
mov th1,#0ffh ; начальная инициализация
mov tl1,#0dfh ; таймера Т1
setb tr0 ; запуск таймера Т0
call miror_creation
mov sec_high_adr,#003h ; Начальная позиция
mov sec_low_adr,#0c0h ; секундной стрелки
mov min_high_adr,#01eh ; Начальная позиция
mov min_low_adr,#080h ; минутной стрелки
mov hour_high_adr,#012h ; Начальная позиция
mov hour_low_adr,#000h ; часовой стрелки
clr Green_LED
background:
mov ie, #10001111b ; Разрешения прерываний от кнопок когда нет др. задач
nop
jnb show,background ; Переход если флаг сброшен
mov ie, #10001010b ; Запрет прерываний от кнопок
call show_watch ; Отображение текущего времени
call miror_creation
call sec_adr_inc
call strelka
call min_adr_inc
call strelka
call hour_adr_inc
call strelka
clr show ; Сброс флага отображения
jmp background
;#####################################################################
; Обработчикии прерываний
;#####################################################################
int_timer0: ; Прерывание от таймета 0
mov th0,#013h
mov tl0,#048h
setb tr1 ; Запуск на один
clr tr1 ; МЦ таймера 1
reti
int_timer1: ; Прерывание от таймета 1
mov th1,#0ffh
mov tl1,#0dfh
setb show ; Установка флага, сигнал о необходимости отобразить время
cpl White_LED
cpl Green_LED
reti
int_hour: ; Внешнее прерывание 0 (по часовой кнопке)
clr tr0 ; Остановка таймеров на время этого прерывания
call lcd_inv_mode
call miror_creation
mov r5,sec_high_adr
mov r4,sec_low_adr
call strelka ; Отрисовка секундной стрелки в зеркале
mov r5,min_high_adr
mov r4,min_low_adr
call strelka ; Отрисовка минутной стрелки в зеркале
setb min_0
call hour_adr_inc ; Инкримент адреса часовой стрелки
call strelka ; Отрисовка часовой стрелки в зеркале
call show_watch
call lcd_norm_mode
setb tr0 ; Запуск таймеров
reti
int_minute: ; Внешнее прерывание 1 (по минутной кнопке)
clr tr0 ; Остановка таймеров на время этого прерывания
call lcd_inv_mode
call miror_creation ; Создание зеркала
mov r5,sec_high_adr
mov r4,sec_low_adr
call strelka ; Отрисовка секундной стрелки в зеркале
clr min_0
mov r5,hour_high_adr
mov r4,hour_low_adr
call strelka ; Отрисовка часовой стрелки в зеркале
setb sec_0
call min_adr_inc ; Инкримент адреса минутной стрелки
call strelka ; Отрисовка минутной стрелки в зеркале
call show_watch ; Отображение зеркала на дисплее
call lcd_norm_mode
setb tr0 ; Запуск таймеров
reti
;#####################################################################
; Конец программы
;#####################################################################
end