Страница 1 из 1

Не срабатывает прерывание таймера 0. ATmega8535. Асемблер

Добавлено: Пт июл 03, 2026 21:52:15
Cfif123123
Доброго времени суток! Пытаюсь найти ошибку в своем коде написанном на ассемблере. Что то не получается и решил написать сюда. Буду очень благодарен за помощь!
Я пытался реализовать на ATmega8535 ,с помощью семи сегментных индикаторов с общем анодом, вывод чисел из регистров r14 and r15. Microchip Studio ошибок не выдает. Прикладываю скриншот с proteus. С течение времени ситуация не меняется в симуляции не меняется. Я добавлял отладку в обработку прерывание и оно не запускалось. Полагаю прерывание не запускается, но я не могу понять почему. Так же меня смущает логическая единица, что находится на выводе PB0, хотя я порт B вообще не настраивал.
Буду очень благодарен, если вы укажите мне на мою проблему, также благодарен любому совету. Продублирую код в сообщении:


;filename = main.asm
; Программа будет выводить значение записаное в регистре с помощью 3х семисигметных индикаторов с общим анодом.

; регистры проекта:
; R16 и R17 регистры для временного хранения данных.

; Регистры, которые содержать значения выводимые на семисегментые индикаторы.
.DEF REG0_SEG = R14 ; Первые 4 бит это нулевой индикатор, вторые 4 бит это первый индикатор.
.EQU REG0_SEG0_M = 0b00001111 ; маска которая отвечает какие разряды занимает число выводимое на индикатор SEG0 ; менять их надо с опаской. Код подрузомевает что они менно такие, но это можно обощить.
.EQU REG0_SEG1_M = 0b11110000
.DEF REG1_SEG = R15 ; Первые 4 бит это второй индикатор, вторые 4 бит это резерв(можно подключить еще один идикатор)
.EQU REG1_SEG2_M = 0b00001111

;Порт 8 выводов котрого отданы индикаторам
.EQU DDR_SEG = DDRA
.EQU PORT_SEG = PORTA
.EQU PIN_SEG = PINA

; Порт и 3 вывода которые отданы для питания общего анода индикаторов. А также маски-константы для этих 3х выводов
.EQU DDR_SEG_VCC = DDRC
.EQU PORT_SEG_VCC = PORTC
.EQU PIN_SEG_VCC = PINC
.EQU SEG0 = 0 ; Это номер вывода к которому подключено питание 0 индикатора
.EQU SEG1 = 1
.EQU SEG2 = 2
;В соответсвии со схемой индикатора(лежит в файле проекта) называем вывода так же как обозначены светодиоды за которые они отвечают
.EQU A = PA0
.EQU B = PA1
.EQU C = PA2
.EQU D = PA3
.EQU E = PA4
.EQU F = PA5
.EQU G = PA6
.EQU DP = PA7


.CSEG
.ORG $0000
; адреса для прерываний
rjmp RESET ; RESET
reti ; INT0
reti ; INT1
reti ; TIMER2_COMP
reti ; TIMER2_OVF
reti ; TIMER1_CAPT
reti ; TIMER1_COMPA
reti ; TIMER1_COMPB
reti ; TIMER1_OVF
reti ; TIMER0_OVF
reti ; SPI_STC
reti ; UART_RXC
reti ; UART_UDRE
reti ; UART_TXC
reti ; ADC
reti ; EE_RDY
reti ; ANA_COMP
reti ; TWI
reti ; INT2
rjmp TIMER0_COMP; TIMER0_COMP
reti ; SPM_RDY

RESET:
;выставляем начальное положение вершины стека на конец памяти RAM
ldi r16, $02
out SPH, r16
ldi r16, $5F
out SPL, r16

; Даем общее разрешение прерываний
sei

; настраиваем все необходимые выводы портов DDR_SEG and DDR_SEG_VCC
ser r16
out DDR_SEG, r16
clr r16
ori r16, (1 <<SEG0 | 1 <<SEG1 | 1<<SEG2 )
out DDR_SEG_VCC, r16
clr r16
ori r16, (1 <<SEG0 | 0 <<SEG1 | 0<<SEG2 )
out PORT_SEG_VCC, r16

; Запишим в регистры со значением, выводимом на семисегментые индикаторы калибровочное число. 987
ldi r16, 0b00001001
mov REG1_SEG, r16
ldi r16, 0b10000111
mov REG0_SEG, r16

; настраиваем таймер 0 для последовательного включения индикаторов.
in r16, TCCR0
ori r16, (1 << WGM01 | 1 << CS02 | 1 << CS01 | 1 << CS00) ; !!!! устанавлием режим СТС и деление частоты на 1024(тестово)
out TCCR0, r16
in r16, TIMSK
ori r16, (1 << OCIE0)
out TIMSK, r16
ser r16
out OCR0, r16


rjmp main

TIMER0_COMP:
push r16
push r17

; определяем какой индикатор сейчас включен
in r16, PORT_SEG_VCC;
andi r16, (1 <<SEG0 | 1 <<SEG1 | 1<<SEG2 ) ; В ходе этой операции в r17 осталось еденица только на выводе SEG на котором сейчас логическая еденица.
; проверяем какой из выводов сейчас был включен
cpi r16, (0 <<SEG0 | 1 <<SEG1 | 1<<SEG2 ) ; если по итогу получиться 0, то был включен SEG0
breq HANDLE_SEG0
cpi r16, (1 <<SEG0 | 0<<SEG1 | 1<<SEG2 )
breq HANDLE_SEG1
cpi r16, (1 <<SEG0 | 1 <<SEG1 | 0<<SEG2 )
breq HANDLE_SEG2
; По итогу этих выборов изменился подвод питания к нужному индикатору, а также в регистре r17 теперь находиться число которое нужно вывести на новый индикатор
DONE:
cpi r17, $00
breq PRINT_0
cpi r17, $01
breq PRINT_1
cpi r17, $02
breq PRINT_2
cpi r17, $03
breq PRINT_3
cpi r17, $04
breq PRINT_4
cpi r17, $05
breq PRINT_5
cpi r17, $06
breq PRINT_6
cpi r17, $07
breq PRINT_7
cpi r17, $08
breq PRINT_8
cpi r17, $09
breq PRINT_9

EXIT:
pop r17
pop r16
reti
;подподпрограммы
HANDLE_SEG0:
;меняем подачу питания к другому индикатору
cbi PORT_SEG_VCC, SEG0
sbi PORT_SEG_VCC, SEG1

mov r17, REG0_SEG;
andi r17, REG0_SEG0_M ; Теперь в r17 4 старших бита нулевые, а 4 младших наше число
rjmp DONE


HANDLE_SEG1:
cbi PORT_SEG_VCC, SEG1
sbi PORT_SEG_VCC, SEG2

mov r17, REG0_SEG;
andi r17, REG0_SEG1_M
swap r17 ; дальше этот регистр r17 обрабатывается одинаково во всех случах поэтому он должен имет одинаковый вид во всех случаях 0b0000xxxx
rjmp DONE

HANDLE_SEG2:
cbi PORT_SEG_VCC, SEG2
sbi PORT_SEG_VCC, SEG0

mov r17, REG1_SEG;
andi r17, REG1_SEG2_M
rjmp DONE

PRINT_0:
in r16, PORT_SEG
ori r16, (0 << A | 0 <<B | 0<< C| 0 << D| 0 << E| 0 << F | 1 <<G)
out PORT_SEG, r16
rjmp EXIT

PRINT_1:
in r16, PORT_SEG
ori r16, ( 1 <<A | 0 << B| 0 << C | 1 <<D | 1 <<E| 1 <<F| 1 <<G)
out PORT_SEG, r16
rjmp EXIT

PRINT_2:
in r16, PORT_SEG
ori r16, (0 << A | 0 <<B | 1<< C| 0 << D| 0 << E| 1 << F | 0 <<G)
out PORT_SEG, r16
rjmp EXIT

PRINT_3:
in r16, PORT_SEG
ori r16, (0 << A | 0 <<B | 0<< C| 0 << D| 1 << E| 1 << F | 0 <<G)
out PORT_SEG, r16
rjmp EXIT

PRINT_4:
in r16, PORT_SEG
ori r16, (1 << A | 0 <<B | 0<< C| 1 << D| 1<< E| 0 << F | 0 <<G)
out PORT_SEG, r16
rjmp EXIT

PRINT_5:
in r16, PORT_SEG
ori r16, (0 << A | 1 <<B | 0<< C| 0 << D| 1 << E| 0 << F | 0 <<G)
out PORT_SEG, r16
rjmp EXIT

PRINT_6:
in r16, PORT_SEG
ori r16, (0 << A | 1 <<B | 0<< C| 0 << D| 0 << E| 0 << F | 0 <<G)
out PORT_SEG, r16
rjmp EXIT

PRINT_7:
in r16, PORT_SEG
ori r16, (0 << A | 0 <<B | 0<< C| 1 << D| 1 << E| 1 << F | 1 <<G)
out PORT_SEG, r16
rjmp EXIT

PRINT_8:
in r16, PORT_SEG
ori r16, (0 << A | 0 <<B | 0<< C| 0 << D| 0 << E| 0 << F | 0 <<G)
out PORT_SEG, r16
rjmp EXIT

PRINT_9:
in r16, PORT_SEG
ori r16, (0 << A | 0 <<B | 0<< C| 0 << D| 1 << E| 0 << F | 0 <<G)
out PORT_SEG, r16
rjmp EXIT
main:

rjmp main

Re: Не срабатывает прерывание таймера 0. ATmega8535. Асемблер

Добавлено: Сб июл 04, 2026 09:33:13
Demiurg
Я сейчас в командировке, занят. Дам вам архив старого проекта как есть. Поставьте AVR-Studio 4.19. это самая стабильная версия для ассемблера. Научитесь работать и симулировать проекты в этой студии. Сторонние программы типа Proteus часто неправильно показывают работу МК AVR.

Re: Не срабатывает прерывание таймера 0. ATmega8535. Асемблер

Добавлено: Сб июл 04, 2026 16:19:07
VNS
Cfif123123 писал(а): Пт июл 03, 2026 21:52:15 Я пытался реализовать на ATmega8535 ,с помощью семи сегментных индикаторов с общем анодом, вывод чисел из регистров r14 and r15.
Тестовая прошивка для трёхразрядного индикатора с ОА по вашей схеме... МК тактируется на частоте 1МГц. Значения вначале формируются в регистрах r14 и r15, а затем из этих регистров выводятся на индикатор.
test.hex
(1.28 КБ) 0 скачиваний

Re: Не срабатывает прерывание таймера 0. ATmega8535. Асемблер

Добавлено: Сб июл 04, 2026 16:24:04
akl
Посмотрите настройку таймера.Сейчас он настроен на внешние импульсы.

Re: Не срабатывает прерывание таймера 0. ATmega8535. Асемблер

Добавлено: Вт июл 07, 2026 06:24:00
>TEHb<
На этих ногах случайно JTAG не включён? Не помню как в этой модели с завода.

Re: Не срабатывает прерывание таймера 0. ATmega8535. Асемблер

Добавлено: Вт июл 07, 2026 07:11:39
akl
mega8535 не имеет JTAGа