; Часы с возможностью редактирования времени ; На базе ЖКИ модуля (LCD10 - HT1610 фирмы HOLTEK) ; от импортных телефонных аппаратов. ; (10 знакомест, последовательный ввод по 2 линиям, встроенные часы и таймер) ; Программа выполняет примерно те же функции, которые уже "зашиты" в LCD10 ; Однако встроенные в LCD10 часы недоступны для внешнего управления ; Схема включения и описание LCD10 можно найти на WWW.HOLTEK.COM ; Используется кварц 4 МГц ; ; В программе использованы куски чужих программ, свободно ; или с оговорками распространяемые в интернете. ; ; Основная проблема - при частом выводе на дисплей "подсвечиваются" ; неиспользуемые символы ЖКИ. Особенно это заметно при наблюдении ; индикатора под некоторым углом. Вывод значений на ЖКИ 1 раз в ; секунду заметно уменьшает этот эффект. ; ;Пушкарев Олег oleg.omsk@usa.net ;============================================================= LIST P=16F84 include __CONFIG 3FF9h ; XT mode #define _int flag,0 ; флаг 'пpеpывание пpоизошло' #define _sec flag,1 ; флаг 'cекунда прошла' #define _min flag,2 ; флаг 'минута прошла' #define _hour flag,3 ; флаг 'час прошел' #define _migh flag,4 ; флаг 'мигание часов' #define _migm flag,5 ; флаг 'мигание минут' #define _key_ok flag,6 ; флаг 'мигание минут' #define _zw PORTA,0 ; выход на динамик #define _di PORTA,1 ; выход данных на HT1610 #define _clk PORTA,3 ; выход стробирования -|_ данных для LCD #define _sel PORTB,7 ; вход выбор позиции корректировки (час-мин) ; Нажатие - подача 0 на ножку порта #define _set PORTB,6 ; кнопка изменение текущего времени (часы-минуты) ; Нажатие - подача 0 на ножку порта zw1ton equ d'80' zw2ton equ d'95' zw3ton equ d'115' zw4ton equ d'130' ; Используемые МАКРОКОМАНДЫ cmp macro f,const movlw const subwf f,w endm mvi macro f,const movlw const movwf f endm sz macro btfss STATUS,Z endm snz macro btfsc STATUS,Z endm sc macro btfss STATUS,C ; 3,0 endm snc macro btfsc STATUS,C endm CBLOCK .12 ; РАБОЧИЕ РЕГИСТРЫ ДЛЯ ПРЕОБРАЗОВАНИЯ HEX -> BCD ; из шестнадцатеричной системы в двоично-десятичный формат R0,R1,temp ENDC CBLOCK .12 ; ГДЕ ИСПОЛЬЗУЕТСЯ rab1 ; подпрограммы задержек - delay100 rab2 ; delay20, zw... rab3 ; delay20, zw... rab4 ; sound1 - cчетчик писков, txt_out rab5 ; #Period# zw.... t50ms,t1sec,t1min,t1hour ; счетчики вpемени tms50,sec1, min1 ; счетчик 50 мс, секунд, минут (+1...) push_W ; Раб ячейки под сох W и STATUS пpи INT... push_S flag ; Регистр флагов (битовый) ENDC org 0x00 goto start org 0x04 goto interrupt ; на прерывания каждые 50 мСек start call init_reg ; начальная инициализация регистров call clrlcd ; очистили дисплей call sound1 ; звук "Начало программы" ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ОСНОВНОЙ ЦИКЛ - ИНДИКАЦИЯ ЧАСОВ (вывод времени только раз в секунду) ; При выводе на индикатор чаще - заметны (слегка) мерцание цифр... ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main btfss _sec ; ждем изменения секунды goto select ; на проверку кнопок "установка времени" call lcd_t10 ; индикация 10 символов на LCD10 bcf _sec ; чтобы не повторялся вывод постоянно btfss _hour ; наступил новый час? goto select ; нет, идем на проверку кнопок call slong1 ; каждый час "Бой часов" call del1s call slong2 call del1s call slong3 bcf _hour ; очистили флаг, чтобы не попасть на эту ветку ; опять в течение этого же часа goto main select ; Для редактирования времени нужен 0 на RB7 btfsc _sel ; кнопка "выбор позиции редактирования" goto main ; не нажата, на главный цикл call tedit ; редактирование текущего времени goto main ; ============================================================== ; Заполнение 10-ти позиций LCD: часы-минуты-секунды (символы) lcd_t10 ; bcf _int ; синхронизация с прерываниями ; ; для уменьшения (???) мерцания цифр ;wqe btfss _int ; ждем прерывания (максим. задержка 50 мСек) ; goto wqe call lcd_time ; вывод текущего времени ЧЧ-ММ (до 23-59) call lcd_s2 ; вывод секунд (2 цифры) movlw .10 ; пусто call wlcd ; вывод на ЖКИ числа из W movlw .10 goto wlcd ; Эти коды приводят к индикации таких символов ; movlw .10; пусто ; movlw .11; F ; movlw .12; _| ; movlw .13; |_ ; movlw .14; P ; movlw .15; - ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% lcd_time ; ВЫВОД НА LCD текущего времени ЧС-ММ movf t1hour,w call b8d2 ; преобразование БАЙТА в 2 десятичных числа btfss _migh ; проверка признака _мигающие часы_ goto nomigh ; используем мигание при редактировании ; !!! мигание не будет работать, если обновление ЖКИ привязано к 1 сек ; Обновление ЖКИ раз в секунду уменьшает "дрожание" изображения при выводе btfss tms50,3 ; мигаем чаще 1 сек... goto nomigh movlw .10 ; пусто call wlcd movlw .10 ; _пусто_ вместо цифры call wlcd goto tire nomigh call lcd2 ; на LCD двe цифр(R0,1) результат BCD tire btfsc _migh ; если мигают часы, то тире не мигает goto noti btfsc _migm ; если мигают минуты, то тире не мигает goto noti ; btfss sec1,0 ; мигание тире (1раз в 2 сек) ; goto blank noti movlw .15 ; тире (если было бы 0Ah, то вывелся бы пробел) call wlcd ; вывод на lcd 1-го символа из W goto min_o blank movlw .10 ; пусто (между цифрами) call wlcd min_o movf t1min,w call b8d2 btfss _migm ; признак _мигающие минуты_ goto nomigm btfss tms50,3 ; мигаем чаще 1 раз в сек... goto nomigm movlw .10 ; бланк call wlcd movlw .10 goto wlcd ; бланк и ВЫХОД nomigm goto lcd2 ; на LCD двe цифр R0,1: результат BCD ; ВЫВОД СЕКУНД lcd_s2 movlw .15 ; тире (если было бы 0Ah, то вывелся бы пробел) call wlcd ; вывод на lcd 1-го символа из W lcds2 movf t1sec,w call b8d2 ;====================================================================== ; вывод на LCD двух цифр - результат BCD R0(старший) и R1(младший байт) ;====================================================================== lcd2 movf R0,w call wlcd ;вывод на LCD одной цифры из W (младшая тетрада) movf R1,W ; Вывод на LCD одной цифры из W (младшая тетрада) ; Заменяем 0 в W на 0А(hex), если 0Ah, то очистка поля (0 на LCD) ; Это все согласно кодировке этого ЖКИ ; эту подпрограмму можно использовать отдельно как драйвер... wlcd bsf _clk ; CLK в неактивное состояние movwf temp ; сохраним пока... movlw 0Ah xorwf temp,w ; temp=10 (т.е. "ПУСТО") snz ; W не равно 10 goto mwyw ; в W теперь 0, т.е. BLANK (пусто) movf temp,w ; восстановили W andlw 0fh ; define Z (=0 ?) snz movlw .10 ; (1010) - это отображается как 0 mwyw movwf temp ; если заменили 0 на 10 то сменим и temp rlf temp,f ; требуемый бит (старший первым) в разряд 4 (---В:----) call bitlcd ; вывод бита из разряда 4 temp на DI (bit3) rlf temp,f ; сдвиг для следующего бита (2) call bitlcd rlf temp,f ; next - bit1 call bitlcd rlf temp,f ; last - bit0 call bitlcd call mks4 ; пауза между символами не менее 5 мкс goto mks4 ; ...и выход ; bitlcd bsf _clk ; неактивное состояние _clk btfss temp,4 ; bit out from bit4 temp goto lowbit bsf _di goto outclk lowbit bcf _di outclk call mks4 ; пауза не менее 2 мкс для установления данных bcf _clk ; стробирование данных call mks4 ; длина строба не менее 2 мкс (Кварц=4MHz) ; clk хоть в 0 хоть в 1 оставляй, но без повторяющегося ; вывода на дисплей - он, через несколько секунд переходит в режим ; внутреннего таймера (???) goto mks4 ; CLK остается в 0 (встроенный в LCD таймер как бы не включен) ; ; Задержка немного больше нормы ; Оказалось важно! ; При 1 "nop" - были сбои индикатора mks4 nop nop return ;********************************************************** ; Редактирование текущего времени 2-мя кнопками (sel и set) ;********************************************************** ; Если войти в режим редактирования и не нажимать на кнопки ; происходит автоматический выход в режим отображения (основной) tedit call zw11 ; перешли в режим установки времени (hour) call delay300 bsf _migh ; включили мигание часов clrf sec1 ; счетчик времени отведенного на редактирование csh1 btfsc sec1,2 ; отведенное на установку время кончилось? goto wselm csh call lcd_t10 btfss _sel ; кнопка "ВЫБОР" нажата? goto wselm ; в реж "УСТАНОВКА ЧАСОВ" нажата _sel => на уст минут call delay100 ; задержка между выводом на дисплей bsf _migh ; включаем мигание часов btfsc _set ; кнопка "УСТАНОВКА" нажата? goto csh1 ; нет, не нажата call zw2 ; Нажали clrf sec1 ; если кнопки нажимаются, время продляем... call delay100 incf t1hour,f ; увеличиваем час на 1 cmp t1hour,.24 ; если достигли 24, то установка в 0 sz goto csh clrf t1hour goto csh wselm call zw4 ; зв. сигнализация выбора другой позиции для изменения call zw3 ; или перехода в режим установки минут по времени call zw2 call zw1 call delay300 bcf _migh ; убрали мигание часов clrf sec1 csm1 btfsc sec1,2 ; если кнопки не нажимать, режим снимается автомат. goto done csm call lcd_t10 btfss _sel ; кнопка ВЫБОР нажата? goto selend ; в реж "УСТАНОВКА МИНУТ" нажата _sel => Выход call delay100 bsf _migm ; включаем мигание минут btfsc _set ; кнопка УСТ нажата? goto csm1 ; КНОПКА НЕ НАЖАТА - ОТОБРАЖАЕМ ТЕКУЩЕЕ И МИГАЕМ call zw4 ; нажали кнопку - пискнем в ответ clrf sec1 call delay100 incf t1min,f ; увеличиваем число минут на +1 cmp t1min,.60 ; достигли 60? sz goto csm clrf t1min goto csm selend call slong1 ; звуковая индикация конца редактирования clrf t1sec ; после уст часов и минут ОБНУЛЯЕМ секунды done bcf _migm ; снимаем мигание минут return ; если не успел отпустить кнопку ; ======================================================== ; Очистка дисплея (вывод 10 символов пробела (код=10)) ; ======================================================== clrlcd mvi rab1,.10 cklclr movlw .10 ; это пустое знакоместо (пробел) call wlcd decfsz rab1,f goto cklclr return ;+++++++++++++++++++++++++++++++++++++ ; Начальная инициализация регистров ;+++++++++++++++++++++++++++++++++++++ init_reg bsf STATUS,RP0 ; страница 1 movlw b'00010111' ; ПРЕДД НА 256, ЕСЛИ rb -ВХОД, ТО R на + есть ; внутр. резисторы необходимы, т.к. внешних нет movwf 01h ; OPTION_REG ; счет от внутреннего генератора, делитель к RTCC movlw b'11001111' ; поpт В5,В4 - вывод, B7,B6,B0...B3 - in movwf PORTB ; TRISB movlw b'11110100' ; A2,A4 - ввод, А3,А1,А0 - вывод movwf PORTA ; TRISA bcf STATUS,RP0 ; страница 0 clrf TMR0 ; обнуление таймеpа и пpедделителя movlw d'61' movwf TMR0 call settr ; уст нач знач пеpеменных вpемени movlw b'10100000' ; pазpешение общих и таймеpных пpеpываний movwf INTCON bcf _clk ; изначально внутр таймер LCD не может работать return settr clrf t1hour mvi t1hour,.23 ; для начальной установки clrf t1min mvi t1min,.59 clrf t1sec ; mvi t1sec,.00 clrf t50ms clrf sec1 clrf min1 clrf flag return ; *************** ПОДПРОГРАММЫ ЗАДЕРЖЕК РАЗНОЙ ДЛИНЫ **************** ; ВНИМАНИЕ! Большая глубина вложений подпрограмм - если вызывать из ; других подпрограмм, то следует следить за переполнением стека. del1s call delay500 ; 1 секунда delay500 call delay100 ; 0.5 сек delay400 call delay100 delay300 call delay100 delay200 call delay100 delay100 movlw d'5' movwf rab1 cd call delay20 decfsz rab1,f goto cd return delay20 movlw d'23' movwf rab2 dly1 clrf rab3 decfsz rab2,f goto dly2 return dly2 decfsz rab3,f ;510mks goto dly2 goto dly1 ; ******************* РАЗНЫЕ ЗВУКИ ********************* sound1 movlw d'10' ; starting bell 10 time movwf rab4 so1 call zw1 call zw2 call zw3 call zw4 decfsz rab4,f goto so1 return sound11 call delay20 call zw4 call delay20 call zw4 call delay20 goto zw4 slong1 ; длинный звук mvi rab4,.10 goto so2 slong2 ; длиииинный звук mvi rab4,.30 goto so2 slong3 ; длиииииииииинный звук mvi rab4,.60 so2 call zw2 decfsz rab4,f goto so2 return zw11 call zw1 call zw1 call zw2 call zw2 call zw3 call zw3 call zw4 goto zw4 ; КОРОТКИЕ ЗВУКИ РАЗНОЙ ВЫСОТЫ zw1 movlw zw1ton goto zp zw2 movlw zw2ton goto zp zw3 movlw zw3ton goto zp zw4 movlw zw4ton goto zp zp movwf rab5 ; period movlw d'36' zwuk movwf rab2 one_period bsf _zw call onetdel nop nop nop nop bcf _zw call onetdel decfsz rab2,f goto one_period return onetdel movf rab5,w ; period movwf rab3 c_del_1p decfsz rab3,f goto c_del_1p return ; Для отладочных целей - звуковой тупик err call zw1 call del1s call slong1 call del1s goto err ;======================================================= ;==== interrupt program =====***обpаботчик пpеpываний*** ;======================================================= interrupt bcf INTCON,T0IF ; очистка флага пpеpывания !вpучную! movwf push_W ; сохpанение "W" swapf push_W,f swapf STATUS,w movwf push_S ; сохpанение флагов STATUS (поменяны тетрады) movlw d'61' ; коэффициент деления 256-61=195 (х256=49920) movwf TMR0 ; для кваpца 4 МГц ; Q=4 Mhz Кдел = 256 х 195 = 49920 НА ВЫХОДЕ 20.032051282 Гц ; ЗА 20 ТИКОВ ПРОЙДЕТ 20 Х 0.049920 = 0.998400 СЕК ; ВМЕСТО 60 СЕКУНД БУДЕТ 59.904 СЕК (СПЕШАТ) ; КОРРЕКЦИЯ 96 мс в мин (ДОБАВЛЯЕМ 2 ТИКА=99.84 мс) ЛИШНИЕ 3.84 мс ; Каждый час НАБЕГАЕТ 230.4 ЛИШНИХ мс (УБИРАЕМ 4 ТИКА = 199.680 мс) incf tms50,f incf t50ms,f cmp t50ms,d'20' sz goto ret_pr clrf t50ms incf sec1,f bsf _sec ; установка флага "прошла секунда" incf t1sec,f cmp t1sec,d'60' sz goto ret_pr clrf t1sec mvi t50ms,d'254'; будет 22, (вместо20) корр от "бегут" каждую минуту incf min1,f bsf _min ; установка флага "прошла минута" incf t1min,f cmp t1min,d'60' sz goto ret_pr clrf t1min ; correction 230 мс / hour/ small last correcton (ОТСТАЮТ НА 230 МС) ; КОРРЕКТИРУЕМ ТОЛЬКО 199.68 мс mvi t50ms,.11 ; отстают на 0.5 сек в день bsf _hour ; установка бита "час прошел" (flag) incf t1hour,f cmp t1hour,d'24' sz goto ret_pr clrf t1hour ; вставим последнюю коррекцию (исполняется раз в сутки...) mvi t50ms,.19 ; т.к .11 уже корр кажд час, еще доб-ем... ret_pr bsf _int ; установили флаг "было пpеpывание" swapf push_S,w ; восстановили STATUS movwf STATUS ; при сохран тетрады были также обменяны swapf push_W,w ; восстановили W retfie ;********************************************************************* ;This routine converts a 8 Bit binary Number to a 2 Digit BCD Number. ;********************************************************************* b8d2 clrf R0 ; десятки movwf R1 ; единицы gten movlw .10 subwf R1,w btfss STATUS,0 ; CARRY goto over movwf R1 ; остаток в R1 incf R0,f ; десятки goto gten over return END