AFON // радиотехник affonya@mail.ru
← Проекты на AVR

Проект 25. Часы: минуты и секунды в режиме CTC

Время считает прерывание таймера в режиме CTC — секунда получается ровной, без подбора циклов. Основная программа занята только индикацией.

Задача

Считать минуты и секунды, показывая секунды на двух индикаторах.

Микроконтроллер: ATmega8, кварц 4 МГц. Среда: Atmel Studio / avra (или avra / Atmel Studio). Как настроить среду и прошить контроллер — в статье программирование AVR.

Что понадобится

  • ATmega8
  • кварц 8 МГц + 2×22 пФ
  • два индикатора
  • 7 резисторов 330 Ом
  • 2 транзисторных ключа

Схема подключения

ВыводПодключение
PB0…PB6сегменты
PD0 / PD1разряды индикаторов

Алгоритм

  1. Рассчитать число для регистра сравнения: тактовая частота, делённая на предделитель, минус единица.
  2. Включить режим CTC и разрешить прерывание по совпадению.
  3. В обработчике увеличивать секунды, после шестидесяти — минуты.
  4. В основном цикле раскладывать секунды на разряды и выводить.

Листинг на ассемблере

Код проверен ассемблером и собирается без ошибок. Скачать: a25.asm · a25.hex (готовая прошивка).

;=======================================================
; Проект 25. Часы: минуты и секунды на прерывании T1 (CTC)
; ATmega8, 8 МГц. Сегменты PB0..PB6, разряды PD0/PD1
; Показываются секунды, минуты считаются в фоне
;=======================================================
.include "m8def.inc"
.def    temp  = r16
.def    tens  = r17
.def    ones  = r18
.def    secs  = r19
.def    mins  = r20
.def    tmp2  = r21
.def    isrsav= r22
.def    d1    = r23
.def    d2    = r24

.cseg
.org    0x0000
        rjmp    RESET
.org    OC1Aaddr                        ; вектор совпадения T1
        rjmp    TIMER1_CMP

SEGTAB: .db 0b00111111, 0b00000110, 0b01011011, 0b01001111, 0b01100110
        .db 0b01101101, 0b01111101, 0b00000111, 0b01111111, 0b01101111

RESET:
        ldi     temp, low(RAMEND)
        out     SPL, temp
        ldi     temp, high(RAMEND)
        out     SPH, temp
        ldi     temp, 0x7F
        out     DDRB, temp
        ldi     temp, 0x03
        out     DDRD, temp

        ; CTC: совпадение раз в секунду при 8 МГц и предделителе 1:256
        ldi     temp, high(31249)
        out     OCR1AH, temp
        ldi     temp, low(31249)
        out     OCR1AL, temp
        ldi     temp, (1<<WGM12)|(1<<CS12)  ; режим CTC, предделитель 1:256
        out     TCCR1B, temp
        ldi     temp, (1<<OCIE1A)           ; разрешаем прерывание
        out     TIMSK, temp
        clr     secs
        clr     mins
        sei

MAIN:
        mov     temp, secs
        rcall   SPLIT                   ; секунды -> разряды
        cbi     PORTD, PD1
        mov     temp, tens
        rcall   SEG
        out     PORTB, temp
        sbi     PORTD, PD0
        rcall   DELAY5MS
        cbi     PORTD, PD0
        mov     temp, ones
        rcall   SEG
        out     PORTB, temp
        sbi     PORTD, PD1
        rcall   DELAY5MS
        rjmp    MAIN

TIMER1_CMP:
        in      isrsav, SREG
        inc     secs
        cpi     secs, 60
        brne    T1_END
        clr     secs
        inc     mins
        cpi     mins, 60
        brne    T1_END
        clr     mins
T1_END:
        out     SREG, isrsav
        reti

;--- разложить temp на десятки и единицы ---
SPLIT:
        clr     tens
SP_LOOP:
        cpi     temp, 10
        brlo    SP_END
        subi    temp, 10
        inc     tens
        rjmp    SP_LOOP
SP_END:
        mov     ones, temp
        ret

SEG:
        ldi     ZL, low(SEGTAB<<1)
        ldi     ZH, high(SEGTAB<<1)
        add     ZL, temp
        clr     temp
        adc     ZH, temp
        lpm     temp, Z
        ret

DELAY5MS:
        ldi     d2, 52
F2:     ldi     d1, 255
F1:     dec     d1
        brne    F1
        dec     d2
        brne    F2
        ret

Пояснения

  • Режим CTC даёт точный интервал: счётчик сбрасывается по совпадению, поэтому период равен ровно заданному числу тактов. При 8 МГц и предделителе 1:256 секунде соответствует значение 31249.
  • Разложение числа на разряды делается циклом вычитания десяти — деления у AVR нет.
  • Отсчёт времени в прерывании не зависит от того, чем занят основной цикл: индикация не сбивает ход часов.

Что дальше

Разобравшись с этим проектом, переходите к следующему в разделе проекты на PIC. Справочник по архитектуре и периферии контроллеров — на странице микроконтроллеры AVR.