Для коррекции задействуем Timer 2 с коэффициентом 1:256, получаем на выходе 15 625 Гц (при тактовой частоте 4 МГц). Если использовать прерывание по сравнению с величиной 156, получаем примерно 100 Гц (или 10 мс). Кккор мы будем хранить в EEPROM (по адресу KоrrEE), и переписывать его в RAM (по адресу KorrRAM) — эти адреса выбираются из любых свободных. Процедура для инициализации регистра сравнения таймера и коэффициента коррекции приведена в листинге 19.2 (в секторе начальной загрузки, о самой программе см. главу 16).

Листинг 19.2

;команду ldi temp,(1<

          ldi temp, (1«TOIE0)|(1<<ОСIЕ2)

;добавляем:

          ldi temp,156

            out OCR2,temp  ;получаем 100 Гц Timer2

;коэффициент коррекции ============

          clr ZH;addr eepr

          ldi ZL,KorrEE

          rcall ReadEEP

          cpi temp,$FF

          brne corr_K

          ldi temp,100  ;если = FF, то по умолчанию 100

corr_K:

            ldi ZH,1

            ldi ZL,KorrRAM

            st Z,temp

Величина задержки по умолчанию определяется на основе предварительных изысканий по уходу конкретного кварца (здесь часы спешили примерно на 1 с в сутки). Не забудем заменить в четвертой сверху строке таблицы прерываний reti на rjmp TIM2_comp. Отведем для счета прерываний регистр count_msek (пусть будет r12). Бит 4 регистра Flag будет сигнализировать о том, отстают часы или спешат (если отстают, то бит установлен). Значение этого бита и регистра count_msek будем устанавливать в момент, когда будет вызываться процедура коррекции (см. далее), там же часы останавливаются. Сам обработчик приведен в листинге 19.3.

Листинг 19.3

ТIМ2_СОМР:

            dec count_msek

            brne end_t  ;если еще не 0, то на выход

            sbrs Flag,4

            rjmp k_minus  ;если спешат, то пропустить если отстают

            cbr Flag,8  ;очищаем бит к следующему разу; устанавливаем часы на 01 сек. и заводим их

            ldi temp,1

            rcall IniSek

            ldi count_sek,1  ;меняем значение в регистре секунд

            ldi ZH,1

            ldi ZL,Sek

            st Z,count_sek

            rjmp end_korr

k_minus:

;если спешат, просто заводим часы обратно

            clr temp

            rcall IniSek

end_t:

reti  ;конец прерывания коррекции

Теперь собственно процедура вызова коррекции: будем выполнять ее в полночь. Она довольно громоздкая, потому что приходится определять момент, когда полночь настала. Мы можем вклинить ее туда, где часы проверяются на кратность трем (0 минут и 0 секунд нам обеспечены). Однако сразу после этого производится запись во flash (а иногда и не производится), и она нам будет непредсказуемо тормозить коррекцию. Потому будем ее проводить в одну минуту первого (00:01:00). Сразу после метки sek_0 вписываем фрагмент кода, содержащийся в листинге 19.4.

Листинг 19.4

sek_0:

          ldi ZL,1  ;загружаем минуты

          ld temp,Z+;

          cpi temp,1  ;сравниваем минуты, если 1 — коррекция

          breq min_1

          cpi temp,0  ;сравниваем минуты, если 0 — запись

          breq mm0  ;на проверку трехчасового цикла

          reti  ;иначе выходим

min_1:

          ld temp,Z  ;загружаем часы

          cpi temp,0  ;сравниваем часы = 0

          breq hour_0  ;если равны 0, то на коррекцию

          reti  ;иначе выходим

hour_0:

         ldi ZL,KorrRAM  ;коэффициент коррекции Id

         count_msek,Z  ;в счетчик

         ldi temp,128

         ср count_msek,temp  ;определяем его величину

         brlo k_plus

         com count_msek  ;если больше 127, то вычитаем из 255

         sbr Flag,8  ;значит отстают

k_plus:  ;если меньше — часы отстают

         ldi temp,$80

         rcall IniSek  ;останавливаем часы

         ldi temp,0Ь00000110  ;заводим таймер

         out TCCR2,temp  ;Timer2 1:256

reti

mm:  ;далее по тексту программы

Перейти на страницу:

Поиск

Похожие книги