我正在学习汇编程序AVR并发现它令人困惑,下面这个简单的程序使用两个定时器,TIMER1用于使“OC1”以特定频率振动(CTC并切换OC1),TIMER0用于启动中断在一定的时间间隔内,此中断从SRAM加载字节并修改OCR1AL以更改频率。 (播放旋律)只有在特定的TIMER1间隔时,一切正常,当我将OCR0更改为更长或更短的间隔时,某些音符缺失,任何想法为什么?另一个问题是存储到存储器的最后一个音符没有被中断作为第一个加载,我必须存储一个额外的(空或任何值)以匹配st Z +和ld -Z。我做错了什么?感谢
使用的芯片是Atmega32a/*
* Melody.asm
*
* Created: 03/04/14 8:17:54 PM
* Author: Michal
*/
.equ MelodyStartAddr = 0x0301
.equ NoteC1 = 0xEF // C
.equ NoteD1 = 0xD4 // D
.equ NoteE1 = 0xBD // E
.equ NoteF1 = 0xB3 // F - 5 698 Hz
.equ NoteG1 = 0x9F // G
.equ NoteA1 = 0x8E // A
.equ NoteH1 = 0x7E // H
.equ NoteC2 = 0x77 // C
.def Temp = r16
.def TempH = r17
.def Zero = r0
.def Max = r1
//.cseg
.org 0x000
rjmp Start1
.org 0x014
jmp ChangeNote
Start1:
sei
ldi Temp, HIGH(RAMEND)
out SPH, Temp
ldi Temp, LOW(RAMEND)
out SPL, Temp
ldi Temp, 0b11111111 //
out DDRD, Temp
ldi YH, HIGH(MelodyStartAddr)
ldi YL, LOW(MelodyStartAddr)
ldi Temp, 0x00 // END
st Z+, Temp
ldi Temp, NoteE1
st Z+, Temp
ldi Temp, NoteE1
st Z+, Temp
ldi Temp, NoteE1
st Z+, Temp
ldi Temp, NoteE1
st Z+, Temp
ldi Temp, NoteF1
st Z+, Temp
ldi Temp, NoteF1
st Z+, Temp
ldi Temp, NoteG1
ldi Temp, NoteG1
st Z+, Temp
ldi Temp, NoteG1
st Z+, Temp
ldi Temp, NoteA1
st Z+, Temp
ldi Temp, NoteG1
st Z+, Temp
ldi Temp, NoteG1
st Z+, Temp
ldi Temp, NoteG1
st Z+, Temp
ldi Temp, NoteF1
st Z+, Temp
ldi Temp, NoteA1
st Z+, Temp
ldi Temp, NoteF1
st Z+, Temp
ldi Temp, NoteF1
st Z+, Temp
ldi Temp, NoteF1
st Z+, Temp
ldi Temp, NoteF1
st Z+, Temp
ldi Temp, NoteF1
st Z+, Temp
ldi Temp, NoteF1
st Z+, Temp
ldi Temp, NoteG1
st Z+, Temp
ldi Temp, NoteA1
st Z+, Temp
ldi Temp, NoteA1
st Z+, Temp
ldi Temp, NoteC2
st Z+, Temp
ldi Temp, NoteA1
st Z+, Temp
ldi Temp, NoteA1
st Z+, Temp
ldi Temp, NoteA1
st Z+, Temp
ldi Temp, NoteC2
st Z+, Temp
ldi Temp, NoteC2
st Z+, Temp
ldi Temp, NoteC2
st Z+, Temp
ldi Temp, NoteC2 // This is the extra Note that is not loaded in the interrupt
st Z+, Temp
// ************* TIMER 1 ***********************
ldi Temp, 0b01000000 // toggle oc1
out TCCR1A, Temp
ldi Temp, 0b00001010 // WGM11, prescaler x8
out TCCR1B, Temp
ldi Temp, 0x00
out OCR1AH, Temp
//********** TIMER 0*******************************
ldi Temp, 0b00011101 // 0b00011011 x64
OUT TCCR0, Temp
ldi Temp, 0xea // Speed Works with 0xef, but not with 0xaf or 0xff or 0xea, any idea ?
out OCR0, Temp
ldi Temp, 0b00000010
OUT TIMSK, Temp
Loop:
nop
rjmp Loop
ChangeNote:
push Temp
in Temp, SREG
push Temp
ldi Temp, 0x00
out OCR1AH, Temp
ld Temp, -Z
cpi Temp, 0x00
breq StopPlaying
out OCR1AL, temp
pop Temp
out SREG, Temp
pop Temp
reti
StopPlaying:
ldi Temp, 0x00
out TIMSK, Temp
ldi Temp, 0b00000000 // toggle oc1
out TCCR1A, Temp
ret
Delay:
clr R1
ldi TempH, 0xaf
mov R2, TempH
DelayLoop:
dec R1
brne DelayLoop
clr R1
dec R2
brne DelayLoop
ret
答案 0 :(得分:0)
为什么要将内存缓冲区的偏移量加载到Y
寄存器,然后使用Z
寄存器来存储和加载旋律?
ldi YH, HIGH(MelodyStartAddr)
ldi YL, LOW(MelodyStartAddr)
...
st Z+, Temp
...
ld Temp, -Z
答案 1 :(得分:0)
在对您的代码进行合理彻底检查后,我也无法看到计时器ISR的问题。应该真的有效。如果它在模拟器中工作,则可能存在某种硬件问题。
旁注:你没有初始化OCR1AL
(尽管在重置后它应该为0)。
至于你的第二个问题:
我必须存储一个额外的(空的或任何值)以匹配st Z + 用ld -Z
你不应该这样做。
st Z+, Temp
ld Temp, -Z
将存储Temp
并立即检索存储的值。 Z+
是"后递增",这意味着Temp
存储到Z
,然后 Z
递增。 -Z
是"预先减少",其中Z
递减,然后从现在指向的位置Z
检索值。