Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Помогите новичку с таймером на Меге16
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему
DimaSPB
Я - любитель и только начал разбираться с Мегой16. Глядя в книжки и даташит написал учебную программу, сигнализирующую переполнение таймера 1 в нормальном режиме хотя бы один раз. Ниже прилагаю код. Увы, эффекта нет((( Ломаю голову уже 16 часов, сил больше нет...
Прошу помощи! В чем ошибка???

; АТМега16
; Учебная программа работы с таймером 1 в нормальном режиме
; Первое прерывание по любому событию таймера 1 зажигает светодиод

.include "m16def.inc" ; Присоединение файла описаний
.list ; Включение листинга

.def temp = r16 ; Определение главного рабочего регистра

;------------------------- Вектора прерывания
rjmp RESET
reti ;rjmp Прерывание 1
reti ;rjmp Прерывание 2
reti ;rjmp Прерывание 3
reti ;rjmp Прерывание 4
rjmp TIM1 ;Прерывание 5 Захват таймера-счетчика 1
rjmp TIM1 ;Прерывание 6 Совпадение А таймера-счетчика 1
rjmp TIM1 ;Прерывание 7 Совпадение В таймера-счетчика 1
rjmp TIM1 ;Прерывание 8 Переполнение таймера-счетчика 1
reti ;rjmp Прерывание 9
reti ;rjmp Прерывание 10
reti ;rjmp Прерывание 11
reti ;rjmp Прерывание 12
reti ;rjmp Прерывание 13
reti ;rjmp Прерывание 14
reti ;rjmp Прерывание 15
reti ;rjmp Прерывание 16
reti ;rjmp Прерывание 17
reti ;rjmp Прерывание 18
reti ;rjmp Прерывание 19
reti ;rjmp Прерывание 20

RESET:
cli ; общий запрет прерываний

ldi temp, 0x80 ;Выключение компаратора
out ACSR, temp

;-------------------------- Инициализация стека

ldi temp, 0x7F ; Выбор адреса вершины стека
out SPL, temp ; Запись его в регистр стека


;-------------------------- Инициализация портов ВВ
ldi temp, 0xFF ; Запись числа $FF в регистр temp
out DDRB, temp ; Запись этого числа в DDRB (порт PB на вывод)
out PORTB, temp ; Запись то же числа в PORTB (потушить светодиод)

;--------------------------- Инициализация таймера-счетчика 1
out TIMSK, temp ;Разрешение прерываний по любому событию таймеров

ldi temp,0b00000000
out TCCR1A, temp ;Нормальный режим Таймера 1

ldi temp,0b00000011 ;Нормальный режим Таймера 1, Предделитель 1/64
out TCCR1B, temp
;---------------------------

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

;-------------------------- Основной пустой цикл
main:
nop
rjmp main ; К началу цикла

;-------------------------- Прерывания по таймеру 1
; Если хотя бы раз происходит прерывание, загорается светодиод
TIM1:
ldi temp, 0x00 ; Записываем число $00 в регистр temp
out PORTB, temp ; Записываем число 0x00 в PORTB (включить светодиод)
reti
Leen
Проверял в симуляторе... Прога-то работает нормально... И прерывание происходит... Вот только одного не понял, почему вдруг у меги 16 TIM1_OVF уехал на адрес 8???? Выспитесь, потом откройте ман на сабж на стр. 45. И все будет путемsmile.gif
P.S. и пара маленьких замечаний: 1) никогда (тем более при отладке) не разрешайте ВСЕХ прерываний - программа улетит куда-нибудь, потом не найдете; 2) если таймер работает в режиме нормала, странно от него ожидать генерации прерываний по захвату и сравнению...
Успехов.
DASM
Цитата(Leen @ Dec 2 2007, 04:14) *
не понял, почему вдруг у меги 16 TIM1_OVF уехал на адрес 8???? Выспитесь, потом откройте ман на сабж на стр. 45. И все будет путемsmile.gif

правильно у него все, только в даташите от 1 нумерация, а у товарища от нуля. SPH он еще забыл записать, но это не причина
Leen
Пардон, с бодуна считать тяжеловато, оказывается... Не прав был... не 8, а 9.
Ну не знаю...
.org 0x10
rjmp TIM1

ну или везде ставить
rjmp ...
reti
Чтобы по 2 адреса занимать...
Глюк-то в том, что последняя запись rjmp TIM1 лежит по адресу 0х8, а не 0х10, как должна. Только тогда не надо reti в точке выхода из подпрограммы TIM1 ставить.
DASM
Я Вас не понял. reti равно как jmp занимают по 2 байта. TIM1OVF и так ложится куда положено, то есть на 0x10
Вообще хорошо бы у автора спросить - он без всяких прерываний светодиод то зажег ?
Leen
Так... Все чудесатее и чудлесатее...
хекс:
Код
:020000020000FC
:1000000014C018951895189518951FC01EC01DC0CE
:100010001CC0189518951895189518951895189549
:1000200018951895189518951895F89400E808B93A
:100030000FE70DBF0FEF07BB08BB09BF00E00FBD07
:1000400003E00EBD78940000FECF00E008BB1895D9
:00000001FF

В самом деле, здесь вроде все в порядке...

Дизасм в аврстудии
Код
11:       rjmp RESET
+00000000:   C014        RJMP    PC+0x0015        Relative jump
12:       reti;rjmp Ïðåðûâàíèå 1
+00000001:   9518        RETI                     Interrupt return
13:       reti;rjmp Ïðåðûâàíèå 2
+00000002:   9518        RETI                     Interrupt return
14:       reti;rjmp Ïðåðûâàíèå 3
+00000003:   9518        RETI                     Interrupt return
15:       reti;rjmp Ïðåðûâàíèå 4
+00000004:   9518        RETI                     Interrupt return
16:       rjmp TIM1;Ïðåðûâàíèå 5 Çàõâàò òàéìåðà-ñ÷åò÷èêà 1
+00000005:   C01F        RJMP    PC+0x0020        Relative jump
17:       rjmp TIM1;Ïðåðûâàíèå 6 Ñîâïàäåíèå À òàéìåðà-ñ÷åò÷èêà 1
+00000006:   C01E        RJMP    PC+0x001F        Relative jump
18:       rjmp TIM1;Ïðåðûâàíèå 7 Ñîâïàäåíèå  òàéìåðà-ñ÷åò÷èêà 1
+00000007:   C01D        RJMP    PC+0x001E        Relative jump
19:       rjmp TIM1; прер. 8 - переп. ТС1
+00000008:   C01C        RJMP    PC+0x001D        Relative jump
20:       reti;rjmp Ïðåðûâàíèå 9
+00000009:   9518        RETI                     Interrupt return
21:       reti;rjmp Ïðåðûâàíèå 10
+0000000A:   9518        RETI                     Interrupt return
22:       reti;rjmp Ïðåðûâàíèå 11
+0000000B:   9518        RETI                     Interrupt return
23:       reti;rjmp Ïðåðûâàíèå 12
+0000000C:   9518        RETI                     Interrupt return
24:       reti;rjmp Ïðåðûâàíèå 13
+0000000D:   9518        RETI                     Interrupt return
25:       reti;rjmp Ïðåðûâàíèå 14
+0000000E:   9518        RETI                     Interrupt return
26:       reti;rjmp Ïðåðûâàíèå 15
+0000000F:   9518        RETI                     Interrupt return
27:       reti;rjmp Ïðåðûâàíèå 16
+00000010:   9518        RETI                     Interrupt return//здесь оказываемся по прерыванию
28:       reti;rjmp Ïðåðûâàíèå 17
+00000011:   9518        RETI                     Interrupt return
29:       reti;rjmp Ïðåðûâàíèå 18
+00000012:   9518        RETI                     Interrupt return
30:       reti;rjmp Ïðåðûâàíèå 19
+00000013:   9518        RETI                     Interrupt return
31:       reti;rjmp Ïðåðûâàíèå 20
+00000014:   9518        RETI                     Interrupt return

Странно... Какие мысли? Кто не прав? Может, студия? Платформу назначил правильно, мега 16, версия студии 4.12.460.
DASM
Со студией не работал, видать она словами адреса считает, а не байтами просто
DimaSPB
Здравствуйте! Спасибо всем за участие!!! beer.gif
Я выспался wassat.gif 1111493779.gif

Таблицу прерываний я использовал из книги Евстифеева, а там ресет нулевой, а прерывания начинаются с единицы.

"1) никогда (тем более при отладке) не разрешайте ВСЕХ прерываний - программа улетит куда-нибудь, потом не найдете; 2) если таймер работает в режиме нормала, странно от него ожидать генерации прерываний по захвату и сравнению..."

Как я понимаю, у меня прерывния разрешены только от таймеров. Разве остальные не замкнуты на возврат? Все события от таймера 1 я указал от отчаяния smile3046.gif , чтобы не прозевать чего от таймера rolleyes.gif
Кстати, попутно практический вопрос - если надо использовать только одно прерывание обязательно ли воспроизводить всю таблицу, замыкая ненужные на reti?

В SPH у Меги16 записать FF?

"Вообще хорошо бы у автора спросить - он без всяких прерываний светодиод то зажег?"

Да, зажег. При переносе кода из прерывания:
ldi temp, 0x00 ; Записываем число $00 в регистр temp
out PORTB, temp ; Записываем число 0x00 в PORTB (включить светодиод)

перед основным циклом светодиод зажигается сразу после запуска. Мега стоит на макетке вместе с самодельным аналогом STK200.
К сожалению, я пока не умею работать симуляторами, код делаю в AVR-студии... Там же и эмулировать можно?
DASM
в SPH пишите high (RAMEND)
RAMEND у Меги16 0x45F
Значит в SPL пишем 0x5f , а в SPH - 0x04
Таблицу все необязательно, но лучше как говорится на всякий случай. И все таки разрешите только прерывание OVF.
А еще лучше CTC mode попробуйте. Пока идей других нет, с Мегами давно не работал
Кстати в прерываниях еще необходимо SREG сохранять. Правда в такой простой программе это не суть важно. Да и остальные регистры, используемые в прерывании тоже надо
DimaSPB
Оставил в таблице только прерывание OVF таймера 1
В указатель стека загружать стал два байта
Увы, не помогло sad.gif

Есть в нете толковое русское описание AVR-студии?
Leen
По поводу проблемы с неправильным позиционированием прерывания:
У мег область флэша имеет длину 16 бит, аврстудия в дизассемблере показывает адреса в словах. Т.е. адрес 0x10 - это не 16 байт, а 16 слов, что я и видел.
Поэтому работоспособен такой код:
Код
.org 0
rjmp RESET; starting
.org 0x10
rjmp TIM1_OVF; go to interrupt service routine for timer 1 overflow

Что касается почему стартовый код (то есть таблица прерываний) уважаемого DimaSPB не работает.
Инструкция rjmp имеет длину 16 бит и укладывается в одно слово памяти программ. Чтобы такая таблица работала, после каждого ржампа надо поставить ноп, дабы занять еще одно слово. На каждый вектоп прерывания (и на ресет тоже) отводится не по 2 байта, а по два слова, чтобы туда помещался не только короткий переход (rjmp), но и длинный (jmp), занимающий 2 слова (4 байта). Смотрите AVR Instruction Set, описание вышеназванных команд.
Также в даташите по меге 16 на стр. 46 есть такие вот строчки:
Цитата
The most typical and general program setup for Reset and Interrupt Vector Addresses in ATmega16 is:
address label code comments
$000 jmp RESET ; Reset Handler
$002 jmp EXT_INT0 ; IRQ0 Handler
$004 jmp EXT_INT1 ; IRQ1 Handler
$006 jmp TIM2_COMP ; IRQ0 Handler
...

Т.е. атмелы в своем типичном примере используют 4-хбайтовую команду для прыжка. Можно сделать так же. Тогда точно работать будет.
Или так:
Код
rjmp RESET; смещение 0 слов
nop; заполняем промежуток - смещение 1 слово
rjmp EXT_INT0; смещение 2 слова
nop; заполняем промежуток - смещение 3 слово


2 DimaSPB: под разрешением всех прерываний я имел ввиду запись FF в TIMSK при настройке. Это вредно - ведь Вы разрешаете не только то прерывание, которое хотите использовать, но и неиспользуемые. Зачем? Просто
Код
ldi temp, 4
out TIMSK, temp


[quote]Есть в нете толковое русское описание AVR-студии?[/qoute]Лучше подучите английский. Всяко полезней будет. А описание я не встречал, кроме встроенной справки (правда, там все по-английски smile.gif)
DimaSPB
Два дня не было нета crying.gif

Leen,
Огромное спасибо за совет! Все заработало! yeah.gif wink.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.