📄 prog44f.asm
字号:
; PROG44f - Control From the Keyboard
;
; Simple Application to Run Different Songs/Sounds Using the Keyboard and
; Turn OFF when the Bottom Right Button On the Keyboard is Pressed.
;
; Myke Predko
; 98.05.31
;
; Hardware Notes:
; AT89C2051 is used as the Microcontroller
; - Oscillator Speed is 1.8432 MHz
; P1 is Connected to the 4x3 Keyboard
;
; P1.1 - 3rd Row
; P1.2 - 1st Column
; P1.3 - 2nd Column
; P1.4 - 1st Row
; P1.5 - 4th Row
; P1.6 - 3rd Column
; P1.7 - 2nd Row
;
; P1.1 - 1 | |
; P1.2 - 2 2-4 | 3-4 | 4-6
; P1.3 - 3 -----+-----+-----
; P1.4 - 4 | |
; P1.5 - 5 2-7 | 3-7 | 6-7
; P1.6 - 6 -----+-----+-----
; P1.7 - 7 | |
; 1-2 | 1-3 | 1-6
; -----+-----+-----
; | |
; 2-5 | 3-5 | 5-6
;
; P3.7 is Connected to a 8 Ohm Speaker Through 0.47 uF Cap
; Constant Declarations
NLA EQU 81 ; A - 880 Hz
NLAS EQU 91 ; A# - 932 Hz
NLB EQU 101 ; B - 988 Hz
NLC EQU 109 ; C - 1046 Hz
NLCS EQU 117 ; C# - 1108 Hz
NLD EQU 125 ; D - 1174 Hz
NLDS EQU 133 ; D# - 1249 Hz
NLE EQU 139 ; E - 1318 Hz
NLF EQU 146 ; F - 1396 Hz
NLFS EQU 152 ; F# - 1480 Hz
NLG EQU 158 ; G - 1568 Hz
NLGS EQU 164 ; G# - 1662 Hz
NHA EQU 169 ; A - 1760 Hz
NHAS EQU 174 ; A# - 1873 Hz
NHB EQU 178 ; B - 1976 Hz
NHC EQU 183 ; C - 2094 Hz
NHCS EQU 187 ; C# - 2218 Hz
NHD EQU 191 ; D - 2350 Hz
; Note Offset Table
LA EQU 1 ; A - 880 Hz
LAS EQU 2 ; A# - 932 Hz
LB EQU 3 ; B - 988 Hz
LC EQU 4 ; C - 1046 Hz
LCS EQU 5 ; C# - 1108 Hz
LD EQU 6 ; D - 1174 Hz
LDS EQU 7 ; D# - 1249 Hz
LE EQU 8 ; E - 1318 Hz
LF EQU 9 ; F - 1396 Hz
LFS EQU 10 ; F# - 1480 Hz
LG EQU 11 ; G - 1568 Hz
LGS EQU 12 ; G# - 1662 Hz
HA EQU 13 ; A - 1760 Hz
HAS EQU 14 ; A# - 1873 Hz
HB EQU 15 ; B - 1976 Hz
HC EQU 16 ; C - 2094 Hz
HCS EQU 17 ; C# - 2218 Hz
HD EQU 18 ; D - 2350 Hz
; Variable Declarations
; R0 - Note Delay Timer
; R1 - Next Tune Value
; R2 - Note Beat Count
; R3 - Current Tune
; R4 - Current Row Number Pulled Down
; R5 - Keyboard Value Pressed
Flags EQU 020h ; Bit 0 Is Set for a "Pause"
; Bit 1 Is Set for "Done"
; Bit 2 Is Complemented by
; Macros
MACRO Note (Value,Duration)
db (Value+(Duration SHL 5))
ENDMAC
; Mainline
org 0 ; Execution Starts Here
ajmp Mainline
org 003h ; _Int0 Pin Interrupt
reti ; Just Return
org 00Bh ; Timer0 Interrupt
Timer0:
jb 0,Timer0End ; If a Pause, Don't Trigger the Timer
cpl P3.7 ; Toggle the Timer
Timer0End:
reti
org 01Bh
Timer1: ; Interrupt Every 0.02 Seconds
push ACC ; Save the Accumulator
push PSW
djnz R0,Timer1End ; If Not Zero, Then Don't Change Note
mov R0,#4 ; Reset the Delay Timer
djnz R2,Timer1End ; Decrement the Beat Counter
inc R1 ; Point to the Next Value
mov A,R1 ; Get the Next Note
acall GetTune ; Get the Tune in R3
jz TuneEnd ; Are we at the End of the Tune?
mov B,A ; Save the Note Value
anl A,#0E0h ; Save the Delay Bits
swap a
rr a
mov R2,A ; Save the Delay Value
mov A,B ; Now, Get the Note
anl A,#01Fh
clr 0 ; Can we Output the Note?
acall GetNote
mov TL0,A ; Save the Next Note
mov TH0,A
jnz Timer1End ; If Zero Returned, Then a Pause
setb 0 ; Indicate the Pause
Timer1End: ; Timer1 Interrupt Handler Finished
pop PSW
pop ACC ; Restore the Accumulator
reti
TuneEnd: ; At the End of the Tune
setb 0 ; Put the Output into "Pause" Mode
mov A,R3 ; Can We Set the "Done" Flag?
jz PauseEnd ; Not if Just Pausing
mov R2,#1 ; Just One Beat for the Pause
mov R3,#0 ; Run the "Pause"
mov R1,#0 ; At the First Note
setb 1 ; Indicate that the Tune Has Ended
pop PSW
pop ACC ; Restore the Accumulator
reti
PauseEnd: ; Return Here After a Pause
mov R2,#1 ; Just One Beat for the Pause
mov R3,#0
mov R1,#0
pop PSW
pop ACC
reti
MainLine: ; Mainline of the Program
mov R0,#4 ; R0 is the Beat Timer
mov R1,#0FFh ; R1 is the Note Counter
mov R3,#0 ; Start with "Pause"
mov R4,#0 ; Use R4 as the Row Check
setb 0 ; Start with a Pause
clr 1 ; Turn Off the Program Ending
mov R2,#1 ; Very Short Pause
mov TMOD,#%00000010 ; Run Timer0 in Mode 2 and Timer1 in Mode 1
mov TH0,#0 ; Enable the Timer to Reload at Maximum Speed
mov TL0,#0
orl TCON,#051h ; Enable Timer0 to Run
; _Int0 is Edge Triggered
mov IE,#%10001010 ; Enable Timer0 Interrupt
Loop:
cjne R3,#0,PlayTune
mov R4,#0 ; Now, Wait for a Keypress
KeyLoop:
mov A,R4 ; Get the Key Stroke
acall GetRow ; Get the Row to Display
mov P1,A ; Output the Value to Check
nop ; Wait for the Data to Stabilize
mov A,P1 ; Now, Look at the Buttons
anl A,#%01001100 ; Clear All Bits but the Buttons
xrl A,#%01001100 ; Now, Was Anything Pressed?
jnz HaveKey ; If Not Zero, Then we Do
inc R4 ; Increment the Key Row Check Value
anl 4,#%00000011 ; Make Sure it doesn't go above 3
ajmp KeyLoop
HaveKey: ; Key Pressed, Figure Out What it is
cjne A,#%01000000,NotHaveKey6
mov R5,#2 ; Have Key Six
ajmp HaveKeyColumn
NotHaveKey6:
cjne A,#%00001000,HaveKey2 ; Check for Column 3
mov R5,#1
ajmp HaveKeyColumn
HaveKey2:
mov R5,#0
HaveKeyColumn:
mov A,R4 ; Now, Get the Column Offset
rl a ; Multiply by 2
add A,R4 ; Add 1 to Multiply by 3
add A,R5 ; Add the Row Number
mov R5,A ; Have the Row/Column Information
OpenLoop: ; Wait for the Key to be Released
mov A,P1
anl A,#%01001100 ; Should Have Zero for Release
xrl A,#%01001100
jnz OpenLoop
mov A,R5 ; Now, We Have the Tune To Play
inc A ; Don't Want to Have a "Pause"
clr IE.7 ; Disable Interrupts During Tune Change
mov R3,A
mov R1,#0FFh ; Start at the First Note When Possible
clr 1 ; Clear the "Done" bit
setb IE.7 ; Enable Interrupts for Tune Change
ajmp Loop
PlayTune: ; Wait for the Tune to End
jnb 1,PlayTune ; Loop On the Tune Being Played
clr 1 ; Clear the "Done" Bit
cjne R5,#11,Loop ; If Not Button 11, then Loop Around Again
mov P1,#%10111100 ; Enable the Idle Mode Reset
nop
clr TCON.1 ; Clear TCON Interrupt
mov IE,#081h ; Just Enable Pin _Int0
orl PCON,#1 ; Put the AT89C2051 Into "Idle" Mode
mov P1,#0FCh ; Put All of the Lines High Again
nop
mov IE,#08Ah ; Turn Off the _Int0 Pin and Turn On Timer Interrupts
mov A,R5 ; Play the Note Again
inc A ; Don't Want to Have a "Pause"
clr IE.7 ; Disable Interrupts During Tune Change
mov R3,A
mov R1,#0FFh ; Start at the First Note When Possible
clr 1 ; Clear the "Done" bit
mov R5,#0 ; Make Sure We Don't Fall Into a Loop
setb IE.7 ; Enable Interrupts for Tune Change
ajmp Loop ; Now, Wait for the Next Keystroke
GetNote: ; Return the Note Value for the Index in "A"
add A,#(NoteTable-InitNoteTable) ; Restore the Table Position with Note
movc A,@A+PC ; Get the Table Value
InitNoteTable: ; Table Offset to Display
ret
NoteTable: ; Table of Notes
db 0 ; First Value is a "Pause"
db NLA
db NLAS
db NLB
db NLC
db NLCS
db NLD
db NLDS
db NLE
db NLF
db NLFS
db NLG
db NLGS
db NHA
db NHAS
db NHB
db NHC
db NHCS
db NHD
GetRow: ; Return the Next Table Value to Drop
add A,#(RowTable-InitRowTable) ; Restore the Table Position with Note
movc A,@A+PC ; Get the Table Value
InitRowTable: ; Table Offset to Display
ret
RowTable: ; Table of Rows to Disable
db 0EEh ; Row 4 (First Row)
db 07Eh ; Row 7 (Second Row)
db 0FCh ; Row 1 (Third Row)
db 0DEh ; Row 5 (Fourth Row)
GetTune: ; According to R3, Get the Correct Tune
push ACC ; Save the Tune Value
mov DPTR,#TuneTable
mov A,R3 ; Get the Song to Play
rl a
jmp @A+DPTR ; Jump to the Correct Song Subroutine
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -