我被要求用中断(full instructions)重写我的代码。我们还没有真正涵盖课堂上的中断,我不确定如何使用它们或如何实现它们。这是我在没有使用中断的情况下编写的代码,它基本上使键盘成为钢琴或可以播放为motorola 68hc11编写的歌曲(lamb,chromsc,hall):
PORTA EQU $1000 ;The speaker port
SPEAKER EQU PORTA
SPEAKERBIT EQU %00100000
SCSR EQU $6400 ; Serial communications status register
SCDR EQU $6401 ; Serial communcations data register
TDRE EQU %00000010 ; mask for TDRE flag in SCSR
RDRF EQU %00000001 ; mask for RDRF flag in SCSR
ORG $8000; Place data at 8000
LAMB FCB 'trerttttrrrrtuuutrerttttrrtre',$00
CHROMSC FCB 'q2we4r5ty7u8i9op-[=]',$00
HALL FCB 'qwertet5w5r2rqwertetiutetu',$00
KEYMAP FDB 'q', 220, 758 ; A ;key, frequency, and 1/4 second "period"
FDB '2', 233, 715 ; A#
FDB 'w', 247, 675 ; B
FDB 'e', 262, 636 ; C
FDB '4', 277, 602 ; C#
FDB 'r', 294, 567 ; D
FDB '5', 311, 536 ; D#
FDB 't', 330, 505 ; E
FDB 'y', 349, 478 ; F
FDB '7', 370, 450 ; F#
FDB 'u', 392, 425 ; G
FDB '8', 415, 402 ; G#
FDB 'i', 440, 379 ; A
FDB '9', 466, 358 ; A#
FDB 'o', 494, 337 ; B
FDB 'p', 523, 319 ; C
FDB '-', 554, 301 ; C#
FDB '[', 587, 284 ; D
FDB '=', 622, 268 ; D#
FDB ']', 659, 253 ; E
FDB $00 ; Null termination character
PROMPT FCB $0D, 'Piano program - use QWERTY row to play notes', $0D, $00 ;Prompt String
ORG $8800
LDS #$DFFF
;;;;;;;;;; Main Start ;;;;;;;;;;
LDX #PROMPT
PSHX ;Push the argument to the stack
JSR printString ;Print the promp string
PULX
ALWAYS DES
JSR getChar ;Get a character from the keyboard
JSR putChar
PULA ;put the character in A
PSHA ;Push character to the stack
JSR playTone ;Play the tone
PULA
CMPA #'a'
BNE SKIPLAMB
LDX #HALL
PSHX
JSR playSong
PULX
SKIPLAMB CMPA #'s'
BNE BRAALW
LDX #LAMB
PSHX
JSR playSong
PULX
BRAALW BRA ALWAYS ;Loop to the top and continue playing
;;;;;;;;;; Main End ;;;;;;;;;;
;;;;;;;;;; playTone Start ;;;;;;;;;; Passed an ascii character and a length on the stack
playTone PSHB ;for transparency
PSHA
PSHX
PSHY
TSY ;make Y point to the top of the stack
LDAA 8,Y ;load A with the passed argument
LDX #KEYMAP ;make Y point to the KEYMAP
CBAALWAYS LDAB 1,X ;load B with the ascii value
BEQ EXITPT ;If current value is $00, end of table, no key match, exit routine
CBA ;Compare B to A
BEQ SKIPTESTS ;If value are equal, skip rest of test to play tone
XGDX
ADDD #6 ;Make X point to the next character to compare
XGDX
BRA CBAALWAYS ;Branch until the end of table is reached
SKIPTESTS LDD 2,X ;Load D with the frequency
LSRD ;Number of times to toggle the speaker in a 1/4 second
LSRD ;this shortens the tone to an 1/8 note
;LSRD ;this plays a 1/16 note
;LSRD ;this plays a 1/32 note
PERIODLOOP LDY 4,X ;Load Y with the delay between toggles
FREQLOOP DEY ;Decrement Y until it's 0
BNE FREQLOOP ;Branch until X is 0
PSHB ;preserve D
PSHA
LDAA PORTA ;Load A with the speaker
EORA #SPEAKERBIT ;Toggle the speaker bit
STAA PORTA ;Store back into the speaker
PULA ;restore D
PULB
SUBD #1 ;Decrement D
CPD #0 ;Compare D to 0
BNE PERIODLOOP ;Branch until D is 0
EXITPT PULY
PULX
PULA
PULB ;return the stack to normal
RTS ;return to the main program
;;;;;;;;;; playTone End ;;;;;;;;;;
;;;;;;;;;; playSong Start;;;;;;;;;;
playSong PSHB ;Reference is passed on the stack
PSHA ;Pushes for transparency
PSHX
PSHY
TSX
LDX 8,x ;Load X with the passed value
LOOPSTRING LDAA 0,X ;Load A with the ith character of the string
BEQ ENDPSTRING ;Skips to end of subroutine if current character is null character
PSHA ;Pass the argument in A to putChar
JSR playTone
INS ;Return the stack to normal
INX ;increments X to point to the next character
BRA LOOPSTRING
ENDPSTRING PULY
PULX
PULA
PULB
RTS
;;;;;;;;;; playSong End ;;;;;;;;;;
;;;;;;;;;; putChar start ;;;;;;;;;; Passed argument should be an ascii value
putChar PSHB ;is passed an argument on the stack
PSHA ;for transparency
PSHX
PSHY
TSY ;stack frame
LDX #SCSR ;Load in address of SCSR (Serial Communication Status Register)
GCWAIT BRCLR 0,X TDRE GCWAIT ;Loop
LDAA 8,Y ;Load A with the passed value
STAA SCDR ;Write A to the SCDR
PULY
PULX
PULA
PULB
RTS
;;;;;;;;;; putChar end ;;;;;;;;;;
;;;;;;;;;; getChar start ;;;;;;;;;; ascii value is returned
getChar PSHB ;No argument. Passes result back on the stack.
PSHA ;For transparency
PSHX
PSHY
TSY
LDX #SCSR ;Load in address of SCSR (Serial Communication Status Register)
PCWAIT BRCLR 0,X RDRF PCWAIT ;Loop when the
LDAA SCDR ;Load A with what's in the SCDR (should be the pressed key)
STAA 8,Y ;Store it to the stack to be passed back
PULY
PULX
PULA
PULB
RTS
;;;;;;;;;; getChar end ;;;;;;;;;;
;;;;;;;;;; printString start ;;;;;;;;;; argument passed on the stack in ascii
printString PSHB ;Reference is passed on the stack
PSHA ;Pushes for transparency
PSHX
PSHY
TSX
LDX 8,x ;Load X with the passed value
LOOPSTRING1 LDAA 0,X ;Load A with the ith character of the string
BEQ ENDPSTRING1 ;Skips to end of subroutine if current character is null character
PSHA ;Pass the argument in A to putChar
JSR putChar
INS ;Return the stack to normal
INX ;increments X to point to the next character
BRA LOOPSTRING1
ENDPSTRING1 PULY
PULX
PULA
PULB
RTS
;;;;;;;;;; printString end ;;;;;;;;;;
有人可以给我一个例子,说明如何有效地实现或只是提示如何开始编写中断,以便我可以用它们重写我的代码。
答案 0 :(得分:5)
要在hc11上使用中断,您需要做四件事:
对于接下来的步骤,我假设您正在使用IRQ中断。它只是hc11上的一个简单中断引脚,当电压降至低电平时会中断系统。但是,任何其他中断的步骤都非常相似。
您需要初始化中断服务程序的起始位置。当触发中断时,处理器将检查向量表以确定它需要去的位置。因此,例如当IRQ被触发时,它将转到对应于IRQ($ FFF2)的表条目,然后跳转到存储在那里的地址。我们将标记中断服务例程IRQ_INT
并将其存储在与IRQ相对应的表条目中,以便在触发IRQ时它将开始执行标签IRQ_INT
处的代码。
ORG $FFF2
FDB IRQ_INT
接下来,您需要启用中断,以便处理器在触发时识别它。您需要再次检查手册中的值以及存储该值的寄存器以启用它。要使能IRQ,必须在中断控制寄存器(INTCR)中将IRQ使能位(IRQEN)设置为1。然后可以使用CLI
命令启用它。
INTCR EQU $001E ;address of interrupt control register
INTCR_IN EQU $60 ;sets IRQEN bits
LDAA #INTCR_IN
STAA INTCR
CLI
最后,您需要编写中断服务程序。这是每次触发中断时将执行的代码。它将从我们之前在向量表中设置的标签开始,并在它到达指令RTI
时结束。从中断返回指令告诉处理器服务程序已完成,它应该返回到触发中断之前执行的任何操作。
IRQ_INT
<instructions go here>
RTI
我的猜测是你会想要键盘上的某种中断,当键被击中时会触发。一旦键被击中,中断将触发处理器进入中断服务程序。在那里,你必须编写代码来确定哪个键被击中并播放正确的音符。
答案 1 :(得分:2)
你必须编写两个ISR,基本上是子程序。每个似乎都是由定时器触发的硬件中断。
一个isr是切换扬声器音调并自动触发(开/关)的一个因此产生N个周期的音调。首先要熟悉如何编程定时器TOC3
另一个是定时器int循环,每隔1 ms寻找输入并监视RDRF标志并通过之前执行的某个项目读取数据。熟悉TOC2的编程
您需要初始化ISR,这意味着您必须设置CPU以告知它ISR例程所在的位置。你的指示已经说明了如何为TOC3做这个,并且应该与TOC2相似,阅读你的讲义以查看jmp表对于toc2的位置,他给你了toc3的位置。
Memory $FFE4 contains
$00D9, so insert a JMP XXXX instruction at $00D9 (where XXXX is the
address of your TOC3 service routine. Note: the opcode for JMP is $7E.
所以做这样的事情:
org $00d9
jmp YourTOC3ISR
;;;;;;;;;;;;;主要程序
initialize timer registers ie setup toc2 and toc3
initialize interrupt registers
2) Read the current Timer Count from TCNT (pg. 374), add your DELAY to it,
and store the result in TOC3 (pg. 409). This defines when you want the
first interrupt to occur.
3) Set OC3I bit in TMSK1 to enable TOC3 interrupts (pg. 410).
4) Clear the OC3F bit in TFLG1 to clear any previous interrupt condition.
(pg. 410). IMPORTANT!!! Note that you must write a 1 to this bit to
clear it! Do not use BSET! See the discussion on page 387.
5) Optional: Write to OM3 and OL3 bits in TCTL1 register to define how the
OC3 output pin will behave when the interrupt occurs (pg. 412).
6) Enable interrupts globally. (See SEI and CLI instructions.)
do lab 7 code
;;;;;;;;;;;;;;;;; toc3 isr例程YourTOC3Isr,playtone?
save the regs and flags
1) Define when the next interrupt should occur by adding your DELAY to TOC3.
2) Do whatever it is you want done in the service routine ie speaker togggle stuff
3) Clear the OC3F bit in TFLG1 to clear the interrupt condition (SEE ABOVE).
4) Return from interrupt when done (pg. 181).
unsave reg and flags
rti
;;;;;;;;;;;;;;; toc2 isr例程
保存reg和标志
然后它会检查RDRF标志,如果不是 然后返回。如果已设置,它将从接收中读取字符 注册,将其写入传输寄存器(您可以使用旧的putchar例程), 然后调用playtone并从中断返回。
这部分听起来好像他要你调用另一个中断例程toc3, 所以只需写入启动定时器和中断的TOC3控制寄存器 应该小心自己。
unsave reg和flags 器R
希望这有帮助, 中号