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

Таймеры в Atmega128

Добавлено: Вт май 19, 2015 23:14:14
VanyaSV
Всех приветствую! Возникла небольшая проблема с таймерами в 128меге. С данным микроконтроллером работаю впервые.
Проблемы следующие:
1. Счётчик №2 настроен под шим. Баг шима в том, что при изменении значения регистра ocr2 помимо длительности импульса меняется и частота, хотя по логике вещей она не должна меняться.
2. Счётчик №1 16 бит настроен на прерывания по совпадению c ocr1a, но данное прерывание вообще не запускается.
3. Я ,конечно, не знаю, должно быть так или нет но всё же: на выводах pf4, pf7, pf5 почему-то постоянно весит лог. 1, хотя все порты настроенны на ввод без подтяжки
p.s. файл с прогой не загрузился, по этому кидаю так


.include "m128def.inc"



rjmp RESET ; Reset Handler
rjmp EXT_INT0 ; IRQ0 Handler
rjmp EXT_INT1 ; IRQ1 Handler
rjmp EXT_INT2 ; IRQ2 Handler
rjmp EXT_INT3 ; IRQ3 Handler
rjmp EXT_INT4 ; IRQ4 Handler
rjmp EXT_INT5 ; IRQ5 Handler
rjmp EXT_INT6 ; IRQ6 Handler
rjmp EXT_INT7 ; IRQ7 Handler
rjmp TIM2_COMP ; Timer2 Compare Handler
rjmp TIM2_OVF ; Timer2 Overflow Handler
rjmp TIM1_CAPT ; Timer1 Capture Handler
rjmp TIM1_COMPA; Timer1 CompareA Handler
rjmp TIM1_COMPB; Timer1 CompareB Handler
rjmp TIM1_OVF ; Timer1 Overflow Handler
rjmp TIM0_COMP ; Timer0 Compare Handler
rjmp TIM0_OVF ; Timer0 Overflow Handler
rjmp SPI_STC ; SPI Transfer Complete Handler
rjmp USART0_RXC; USART0 RX Complete Handler
rjmp USART0_DRE; USART0,UDR Empty Handler
rjmp USART0_TXC; USART0 TX Complete Handler
;rjmp ADC ; ADC Conversion Complete Handler
rjmp EE_RDY ; EEPROM Ready Handler
rjmp ANA_COMP ; Analog Comparator Handler
rjmp TIM1_COMPC; Timer1 CompareC Handler
rjmp TIM3_CAPT ; Timer3 Capture Handler
rjmp TIM3_COMPA; Timer3 CompareA Handler
rjmp TIM3_COMPB; Timer3 CompareB Handler
rjmp TIM3_COMPC; Timer3 CompareC Handler
rjmp TIM3_OVF ; Timer3 Overflow Handler
rjmp USART1_RXC; USART1 RX Complete Handler
rjmp USART1_DRE; USART1,UDR Empty Handler
rjmp USART1_TXC; USART1 TX Complete Handler
rjmp TWI ; Two-wire Serial Interface Interrupt Handler
rjmp SPM_RDY ; SPM Ready Handler



RESET: ; Reset Handler
EXT_INT0: ; IRQ0 Handler
EXT_INT1: ; IRQ1 Handler
EXT_INT2: ; IRQ2 Handler
EXT_INT3: ; IRQ3 Handler
EXT_INT4: ; IRQ4 Handler
EXT_INT5: ; IRQ5 Handler
EXT_INT6: ; IRQ6 Handler
EXT_INT7: ; IRQ7 Handler
TIM2_COMP: ; Timer2 Compare Handler
TIM2_OVF: ; Timer2 Overflow Handler
TIM1_CAPT: ; Timer1 Capture Handler
;TIM1_COMPA:; Timer1 CompareA Handler
TIM1_COMPB:; Timer1 CompareB Handler
TIM1_OVF: ; Timer1 Overflow Handler
TIM0_COMP: ; Timer0 Compare Handler
TIM0_OVF: ; Timer0 Overflow Handler
SPI_STC: ; SPI Transfer Complete Handler
USART0_RXC:; USART0 RX Complete Handler
USART0_DRE:; USART0,UDR Empty Handler
USART0_TXC:; USART0 TX Complete Handler
;ADC: ; ADC Conversion Complete Handler
EE_RDY: ; EEPROM Ready Handler
ANA_COMP: ; Analog Comparator Handler
TIM1_COMPC:; Timer1 CompareC Handler
TIM3_CAPT: ; Timer3 Capture Handler
TIM3_COMPA:; Timer3 CompareA Handler
TIM3_COMPB:; Timer3 CompareB Handler
TIM3_COMPC:; Timer3 CompareC Handler
TIM3_OVF: ; Timer3 Overflow Handler
USART1_RXC:; USART1 RX Complete Handler
USART1_DRE:; USART1,UDR Empty Handler
USART1_TXC:; USART1 TX Complete Handler
TWI: ; Two-wire Serial Interface Interrupt Handler
SPM_RDY: ; SPM Ready Handler





ldi R16,low(RAMEND)
out SPL,R16
ldi R16,high(RAMEND)
out SPH,R16

ldi r16,0x00
out DDRA,r16

ldi r16,0x01
out PORTA,r16

ldi r16,0x80
out DDRB,r16

ldi r16,0x00
out PORTB,r16

ldi r16,0x01
out DDRC,r16

ldi r16,0x00
out PORTC,r16

ldi r16,0x00
out DDRD,r16

ldi r16,0x00
out PORTD,r16

ldi r16,0x00
out DDRE,r16

ldi r16,0x00
out PORTE,r16

ldi r16,0x00
out DDRF,r16

ldi r16,0x00
out PORTF,r16

ldi r16,0x00
out DDRG,r16

ldi r16,0x00
out PORTG,r16




ldi r16,0xe9
out TCCR2,r16

ldi r16,0x2f
out OCR2,r16


ldi r16,0x09
out TCCR1B,r16

ldi r16,0x10
out TIMSK,r16



ldi r16,high(1000)
out OCR1AH,r16


ldi r16,low(1000)
out OCR1AL,r16


sei



cycle: rjmp cycle





TIM1_COMPA: push r16
in r16,SREG
push r16
in r16, portc
ldi r22,0x01
eor r16,r22
out portc,r16
pop r16
out SREG,r16
pop r16
reti

Re: Таймеры в Atmega128

Добавлено: Ср май 20, 2015 03:36:25
akl
У mega128 адреса таблицы векторов прерываний занимают 2 слова каждый, поэтому происходит смещение адресов при заполнении таблицы командами RJMP. Можно явно указать адрес вектора и использовать команду RJMP, если её возможности хватит для перехода или JMP для перехода по всей области памяти.

Код: Выделить всё

.org	$0018
	rjmp TIM1_COMPA; Timer1 CompareA Handler
Попробуйте достучаться до этих портов командами STS вместо OUT и LDS вместо IN.

Код: Выделить всё

	ldi r16,0xFF
	STS DDRF,r16

	ldi r16,0x00
	STS PORTF,r16
;	out PORTF,r16


	ldi r16,0xFF
	STS DDRG,r16

	ldi r16,0x00
	STS PORTG,r16
на выводах pf4, pf7, pf5 почему-то постоянно весит лог. 1, хотя все порты настроенны на ввод без подтяжки
Отключите JTAG

При работе с таймерами лучше сначала их настраивать, а потом запускать

Код: Выделить всё

	ldi r16,0x2f
	out OCR2,r16

	ldi r16,0xe9
	out TCCR2,r16

	ldi r16,high(1000-1)
	out OCR1AH,r16
	ldi r16,low(1000-1)
	out OCR1AL,r16

	ldi r16,0x10
	out TIMSK,r16
	OUT TIFR,R16

	ldi r16,0x09
	out TCCR1B,r16

;ldi r16,high(1000)
;out OCR1AH,r16
;ldi r16,low(1000)
;out OCR1AL,r16
В качестве совета, оставьте в прошлом тяжёлое наследие аккумуляторных контроллеров. Ширшее используйте регистровый файл. Например, объявив один регистр нулём, можно значительно сократить программу.

Код: Выделить всё

.include "m128def.inc"

.def	ZERO=R15

.
.
        out SPH,R16

	CLR	ZERO
        OUT DDRA,ZERO


;ldi r16,0x00
;out DDRA,r16
Или обработчик прерывания можно сделать так

Код: Выделить всё

TIM1_COMPA:
;	push r16
	in r0,SREG
;	push r16
	in r1, portc
	ldi r22,0x01
	eor r1,r22
	out portc,r1
;	pop r16
	out SREG,r0
;	pop r16
	reti

Re: Таймеры в Atmega128

Добавлено: Ср май 20, 2015 09:13:50
ChipKiller
akl писал(а):Попробуйте достучаться до этих портов командами STS вместо OUT и LDS вместо IN.
.. а еще лучше уметь пользоваться тем, что есть - макросредствами. В начале программы вставим

Код: Выделить всё

.macro  outi
	ldi	tmp,@1
   .if(@0 > 0x3F)
   	sts @0,tmp
   .else
   	out @0,tmp
   .endif
.endm
и вместо двух строк

Код: Выделить всё

ldi r16,0x00
   STS xxx,r16
или

Код: Выделить всё

ldi r16,0x00
   OUT xxx,r16
пишем одну outi xxx,0x00 , а макрос сам разберется подставлять STS или OUT

Re: Таймеры в Atmega128

Добавлено: Ср май 20, 2015 12:27:00
VanyaSV
akl писал(а):В качестве совета, оставьте в прошлом тяжёлое наследие аккумуляторных контроллеров. Ширшее используйте регистровый файл. Например, объявив один регистр нулём, можно значительно сократить программу.
Я так и делаю, просто чтобы людям программа была максимально понятна решил не использовать регистровые файлы
akl писал(а):Или обработчик прерывания можно сделать так

TIM1_COMPA:
; push r16
in r0,SREG
; push r16
in r1, portc
ldi r22,0x01
eor r1,r22
out portc,r1
; pop r16
out SREG,r0
; pop r16
reti
[
это глупо, так как нет никакого смысла гадить зря регистры. К тому же для этих целей и придумали стек. Плюс ко всему в программе, которую я пишу, будет чтение из пзу, а значение ячейки пзу сохраняется в r0 :)

Jtag отключил. Лог 1 пропала, спасибо!! но вот чисто случайно решил потыкать все выводы осциллографом и обнаружил, что pd7, pg0, pg1 тоже в 1, хотя настроенны на ввод без резисторов.

Решил использовать 0 таймер. Он идентичен 2. С точно такими же настройками он работает! и частота даже не плавает. А вот прерывание по 1 таймеру так и не срабатывает(

Re: Таймеры в Atmega128

Добавлено: Пт май 22, 2015 14:51:40
Alkul
akl писал(а):У mega128 адреса таблицы векторов прерываний занимают 2 слова каждый, поэтому происходит смещение адресов при заполнении таблицы командами RJMP.
Неверно. У команд RJMP "дальности перехода" не хватит на всю память mega128. Компилятор сможет и пропустить этот баг, в результате переход по вектору будет сделан в "левое" место памяти.
Для МК с памятью программ больше 16КБ в AVRовском ассемблере есть команда JMP. Она, во-первых, занимает 2 слова (4 байта) в памяти, а во-вторых, адресует всю память МК

Re: Таймеры в Atmega128

Добавлено: Пт май 22, 2015 16:15:16
akl
Alkul Написал же. Не знаю, как ещё понятнее написать.
akl писал(а):У mega128 адреса таблицы векторов прерываний занимают 2 слова каждый, поэтому происходит смещение адресов при заполнении таблицы командами RJMP. Можно явно указать адрес вектора и использовать команду RJMP, если её возможности хватит для перехода или JMP для перехода по всей области памяти.

Код: Выделить всё

.org	$0018
	rjmp TIM1_COMPA; Timer1 CompareA Handler

Re: Таймеры в Atmega128

Добавлено: Пт май 22, 2015 17:58:49
Alkul
akl писал(а):Не знаю, как ещё понятнее написать.
И я тоже не знаю, как еще понятней написать.
Что толку с того, что Вы команду перехода разместите в нужном месте, если она не обеспечит переход в пределах всей памяти? Конечно, если у Вас в 128меге кода на полкилобайта, тогда вопросов нет. Но нужно сразу приучаться писать программы правильно, а не закладывать в них мины замедленного действия.
Вот выдержка из описания команд ассемблера:
2015-05-22_213732.jpg
(62.54 КБ) 569 скачиваний
Видите? Команда RJMP обеспечивает переход на 2 килослова (4 КБ) вперед и на столько же назад относительно того адреса в памяти программ, где находится эта команда RJMP. Что тут непонятного? И если у вас программа длинная - больше 4 КБ, то стоящая в нулевом адресе команда RJMP не обеспечит переход до требуемого адреса, если он в памяти отстоит от команды RJMP больше, чем на 4КБ.

Re: Таймеры в Atmega128

Добавлено: Ср май 27, 2015 15:49:42
VanyaSV
rjmp на jmp исправил. А как правильно объявить заголовок для ОЗУ? просто строчки объявления стека:

ldi R16,low(RAMEND)
out SPL,R16
ldi R16,high(RAMEND)
out SPH,R16

почему-то не хотят работать. Контроллер чудесным образом попал в прерывание (выставляет меандр), а вот если объявить регистр флагов и выставлять в прерывании какие-то биты, то они почему-то не устанавливаются(

Re: Таймеры в Atmega128

Добавлено: Ср май 27, 2015 20:16:07
Alkul
VanyaSV писал(а):А как правильно объявить заголовок для ОЗУ?
Через команды IN и OUT доступны только регистры с адресами от 00h до 3Fh
Для того, чтобы обратиться к регистрам с более старшими адресами, используют команды LDS и STS
Вам нужно написать так:

Код: Выделить всё

ldi R16,low(RAMEND)
sts SPL,R16
ldi R16,high(RAMEND)
sts SPH,R16
Только это не "заголовок для ОЗУ". Правильно это действие называется "Инициализация вершины стека", ибо регистр SP как раз и хранит текущий адрес вершины стека. То, что в AVR стек "растет сверху вниз" Вы уже знаете?
Если не инициализировать корректно вершину стека, то не смогут работать никакие подпрограммы, вызываемые по командам CALL и RCALL, не смогут работать обработчики прерываний и команды PUSH и POP. Вам понятно, почему?