Задача
Считать минуты и секунды, показывая секунды на двух индикаторах.
Микроконтроллер: ATmega8, кварц 4 МГц. Среда: Atmel Studio / avra (или avra / Atmel Studio). Как настроить среду и прошить контроллер — в статье программирование AVR.
Что понадобится
- ATmega8
- кварц 8 МГц + 2×22 пФ
- два индикатора
- 7 резисторов 330 Ом
- 2 транзисторных ключа
Схема подключения
| Вывод | Подключение |
|---|---|
| PB0…PB6 | сегменты |
| PD0 / PD1 | разряды индикаторов |
Алгоритм
- Рассчитать число для регистра сравнения: тактовая частота, делённая на предделитель, минус единица.
- Включить режим CTC и разрешить прерывание по совпадению.
- В обработчике увеличивать секунды, после шестидесяти — минуты.
- В основном цикле раскладывать секунды на разряды и выводить.
Листинг на ассемблере
Код проверен ассемблером и собирается без ошибок. Скачать: 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.