作者supergothere (幸福)
看板TTU-I90B
標題微算機實驗(六)
時間Sun Jun 6 21:14:56 2004
由於我上課都沒聽,所以有些地方是我猜的!
我是覺得沒錯啦…反正po出來,給大家看看吧…因為我看好像沒人要念這科
組合語言很好玩耶=.=||
程式碼詳解~我覺得老師的講義的註解太深奧…所以我用自己的話說^_^
不過有些是用老師的,因為我也不是說完全懂!
.nolist
.include "8515def.inc"
.list
rjmp RESET ;程式開始的地方
.def TEMP =r16
.def TEMP1 =r17
.def TEMP2 =r18
.def MUSN =r22
.def TONL =r21
.def TONH =r20
.def PLYTON =r25
.def TONSET =r24
.def TONLNG =r23
;上面是定義暫存器叫啥名字
.cseg
.org 0x06 ;這是timer1的中斷向量
intt1: RJMP OUTPM ;簡單說..就是跳到OUTPM
.org 0x010 ;發音起始位址
;發音週期計時到重新載入新計時值並將輸出埠PORTD0 轉態
;上面這句等一下解釋..
OUTPM:
OUT TCNT1H,TONH ;重新將TONH 新計時值載入TCNT1H 內
OUT TCNT1L,TONL ;重新將TONL 新計時值載入TCNT1L 內
SBIS PORTD,00 ;先檢測PORTD0 是否為1 而跳格
RJMP SETOP1 ;若是PORTD0 為0 則跳到SETOP1 令PORTD0 轉為1
SETOP0: CBI PORTD,00 ;若PORTD0 為1 則令PORTD0 轉為0
LDI MUSN,$00 ;同時令MUSN 為00 值
RETI ;回中斷前主程式並令可再次中斷
SETOP1: SBI PORTD,00 ;若PORTD0 為0 則令PORTD0 轉為1
LDI MUSN,$01 ;同時令MUSN 為01 值
RETI ;回中斷前主程式並令可再次中斷
相信程式一開始一定很多人就看無啦~
因為我第一次看…也是看不懂!
不過,上面這邊我是用猜的~
這個實驗啊!
應該是利用PD0連結蜂鳴器,然後利用計時中斷的方式,對蜂鳴器產生High和Low的
訊號,然後產生音階!至於產生的方式,是我猜的!
我的想法是,利用那個音階對照表,每一個音階的數字代表的意義是音階:
我用第一個音階的數字當例子說明!
第一個數字是63627,就是說從63627開始計時到65536然後會發生中斷,
也就是說總共數了1909次,程式預除是8(後面程式會寫),也就是頻率是1MHz
所以,週期是1/1M=1us,所以1909次總共1.909ms,程式的delay為0.2s(請參考delay
副函式),所以0.2s中總共執行中斷約104次,每次都利用High和low從PD0輸入訊號給
蜂鳴器,也就是上面程式碼的SETOP0和SETOP1,導致產生這個音階。
;主程式起始位址
RESET:
ldi temp,low(RAMEND)
out SPL,temp
ldi temp,high(RAMEND)
out SPH,temp
;上面四句就是把sp指到0025
wdr ;重設看門狗計時器
ldi temp,$0F ;WDTCR 定址$21 不可位元設定以TEMP 緩衝令WDE=D3=1
out WDTCR,temp ;並令預除為2048MS 設定WDE=1=D3 輸出到WDTCR 內
LDI MUSN,$00 ;令MUSN 為00 值
ldi temp,$00 ;令TEMP 暫存器放入00
out tccr1a,temp ;將TEMP=00 內含輸出到TCCR1a 內禁止比較器及pwm動作
out tccr1b,temp ;將TEMP=00 內含輸出到TCCR1b 內停止TC1 計時及捕抓
;這邊不懂,可以看英文那本的,解說詳細
;基本上,tccr1b和tccr1a就是用來控制timer1的register
;內容還是建議看一下英文那本!
LDI TEMP,$02 ;將02 值預存入SRAM 的0100H 內作TC1 的
STS $0100,TEMP ;TCCR1B 控制內含令TC1 為計時預除8
;這邊就是控制預除8,所以頻率是8MHz/8=1MHz
LEDA:
CLI ;中斷總開關sreg=d7=i=1,中斷總開關沒開不能使用中斷
ldi r16,0b10000000 ;令toie1=1 致能中斷
out timsk,r16 ;將R16 的D7=1 令TOIE1=1 致能中斷
;有關中斷的也可以參考英文那本,超詳細
LDI TEMP,$FF ;令TEMP=$FF 以便令DDRB 設定為輸出態
OUT DDRB,TEMP
LDI TEMP,0B11111101 ;PD1 為輸入模態其餘PD0,PD2-PD7 為輸出態
OUT DDRD,TEMP
LDI TEMP,0B11111111 ;PD1 為輸入提升電阻模態
OUT PORTD,TEMP
CLR TEMP2 ;將TEMP2,TEMP1,KSNI,SCNTT,TONLNG 等暫存器
CLR TEMP1 ;予以清除
CLR TONLNG
;上面這邊應該看的懂吧!
STARTP:
WDR ;清除看門狗計時器用以當機時可重新RESET
SBIC PIND,01 ;檢測PIND1 是否被壓按而為LOW 則跳格
RJMP STARTP ;若PIND1 仍為HI 之未起動演奏則跳回STARTP
;檢查PD1有沒有被按,就是讓音樂播放的那根pin
LDI ZH,HIGH(PLYTAB*2) ;若壓按PIND1 啟動演奏則令Z 定址於音樂盒
LDI ZL,LOW(PLYTAB*2) ;音樂演奏樂譜存放之PLYTAB*2 之起始位址
;這邊就是把Z指標指到PLYTAB
NEXMUT:
LPM ;將Z 所指PROM 之預存樂譜依次取音階及音長置於R0
MOV PLYTON,R0 ;將取出的第一個音階搬入PLYTON 作週期控制
LD R0,Z+ ;以LD R0,Z+指令使得Z 間接指標遞加1
LPM ;將Z 所指PROM 之預存樂譜依次取音長置於R0
MOV TONLNG,R0 ;將取出的第一個音長搬入TONLNG 作音長控制
OR R0,PLYTON ;將此R0 音長與音階PLYTON 作OR 運算
LD R0,Z+ ;以LD R0,Z+指令使得Z 間接指標遞加1
;上面就是把音階放入PLYTON,音長放入TONLNG
BRNE PLAYM ;若音階及音長皆非全為00,值則跳到PLAYM 演奏
;PLAYM副函式用來播放低~
LDI TEMP,$00 ;若音階及音長皆全為00,00 則為結束碼
out tccr1b,temp ;將TEMP=00 內含輸出到TCCR1b 內停止TC1 計時及捕抓
;tccr1b是用來控制timer1的register
CLI ;把中斷關掉
SBI PORTD,00 ;把蜂鳴器關掉
;程式是利用PD0來控制蜂鳴器
RJMP STARTP ;跳回STARTP 重新再等待按鍵起動發音演奏
;開始將PROM 取表所得的音階PLYTON 及音長對應予以計時發音
PLAYM:
PUSH ZH ;將啟始的PROM 間接指標定址ZH,ZL 推入堆疊
PUSH ZL ;保存以便再次取出
TST PLYTON ;檢測PLYTON 是否為0 值
BREQ MUSTD ;若為0 值則為休止符故跳到MUSTD 作音長等待
;測試是不是休止符,也就是00
LDI ZH,HIGH(MUSTAB*2) ;令Z 間接指標指著各音階控制計時器1
LDI ZL,LOW(MUSTAB*2) ;的計時控制計時值存放起始位址
;把Z指到MUSTAB
MOV TEMP,PLYTON ;將音階PLYTON 搬入TEMP 暫存器內
DEC TEMP ;第0音階空白休止音故演奏音階定址差1 而將其減1
;把音階移到TEMP,不過音階裡面沒有休止符,所以要減一!
LSL TEMP ;每個音階由2 個PROM 內2 的TCNT1H,TCNT1L 組構故乘2
ADD ZL,TEMP ;將正確的計時器1 控制音階的存表位移TEMP 加入ZL
LDI TEMP,$00 ;令TEMP=00 以便讓ZH 與進位旗號CF 相加
ADC ZH,TEMP ;將ZH 與TEMP=00 以及CF 旗號相加得到真正Z 定址值
;計算音階的真正位置。
;一開始的位置是Z,也就是指到MUSTAB,然後由選擇的第幾個音,
;來控制要加多少,像是上面TEMP中就是設定的音階,要乘二是因為
;要直接跟位置相加!
LPM ;將Z 所指PROM 之預存音階之計時長度低位值置於R0
MOV TONL,R0 ;將音階之計時長度之低位值R0 搬入TONL 內
OUT TCNT1L,R0 ;將音階之計時長度之低位值R0 也搬入TCNT1L內
LD R0,Z+ ;以LD R0,Z+指令使得Z 間接指標遞加1
LPM ;將Z 所指PROM 之預存音階之計時長度高位值置於R0
MOV TONH,R0 ;將音階之計時長度之高位值R0 搬入TONH 內
OUT TCNT1H,R0 ;將音階之計時長度之高位值R0 也搬入TCNT1H內
;把剛剛計算好的位置放到,TCNT1裡面,準備計時中斷用
POP ZL ;將ZL,ZH 由堆疊指標所指之SRAM 依次取回
POP ZH
LDS TEMP,$0100 ;將SRAM 定址0100H 之內含載入TEMP 內
OUT TCCR1B,TEMP ;將原0100H 之SRAM 內含輸出到TCCR1B 控制TC1
這邊把上面設定8的預除,送到tccr1b
SEI ;令中斷總開關=1
;也就是開始計時
MUSTD:
RCALL PLYDEL ;延時等待音階週期計時及單位音長0.2 S 副程式
;就是上面提到的延遲0.2s,所以也就是說,單音的發音時間為0.2s
DEC TONLNG ;將音長TONLNG 減1
BRNE MUSTD ;若音長TONLNG 不為0 則跳回MUSTD 再輸出音階發音
;音長的控制
RJMP NEXMUT ;若此音階及其音長發音完畢則跳到NEXTNUT
;再次取下個音階及其對應音長發音
;延時約為.2SEC 的單位延時
PLYDEL: LDI TEMP,185 ;185*1mS=185mS 即PLYDEL 為185mS
DT3: LDI TEMP1,04 ;4*250uS=1mS 即DT3 約為1mS
DT2: LDI TEMP2,250 ;250*8*125nS=250uS 即DT2 約為250US
DT1: WDR ;1T
NOP ;2T
NOP ;3T
NOP ;4T
NOP ;5T
DEC TEMP2 ;6T 將TEMP2 減1
BRNE DT1 ;8T 當TEMP2 不為0 值則共執行250*8*T=250US
DEC TEMP1 ;將TEMP1 減1
BRNE DT2 ;當TEMP1 不為0 值則共執行250*4 US=1MS
DEC TEMP ;將TEMP 減1
BRNE DT3 ;當TEMP 不為0 值則共執行185* 1 MS=185MS
RET ;回主程式
;上面就是延遲0.2s。
.EQU MUSTAB=0X0100
.EQU PLYTAB=0X0140
.cseg
.org MUSTAB ;各音階對應TC1 的TCNT1 計時週期資料存放起始位址,共36 個音階。
;1 2 3 4 5 6 7 8 9
;1. '#1.',2 '#2.'3. '4. '#4 '5. '#5.
.DW 63627,63730,63835,63927,64020,64102,64185,64259,64330
;10 11 12 13 14 15 16 17 18
;6. '#6.'7. '1 '#1 '2 '#2 '3 '4
.DW 64399,64463,64523,64579,64632,64683,64731,64776,64819
;19 20 21 22 23 24 25 26 27
;#4 '5 '#5 '6 '#6 '7 '.1 '#.1 '.2 '
.DW 64859,64897,64933,64967,64999,65029,65057,65084,65109
; 28 29 30 31 32 33 34 35 36
;#.2' .3 ' .4 '#.4 '.5 '#.5 '.6 '#.6 '.7
.DW 65133,65156,65177,65197,65216,65243,65251,65267,65282
.cseg
.org PLYTAB ;音樂盒之樂譜資料存放起始位址
; | 5 5, 6 5 |
.DB 20,02,00,01,20,01,22,04,20,04
; |.1 7 -- |
.DB 25,04,24,04,00,04
; | 5 5, 6 5 |
.DB 20,02,00,01,20,01,22,04,20,04
; |.2 .1 -- |
.DB 27,04,25,04,00,04
; | 5 5,.5 .3 |
.DB 20,02,00,01,20,01,32,04,29,04
; |.1 7 6 |
.DB 25,04,24,04,22,04
; |.4 .4 .3 .1 |
.DB 30,02,00,01,30,01,29,04,25,04
; |.2 .1 -- |
.DB 27,04,25,04,00,04
.DB 00,00 ; 音樂END
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 218.166.125.121
※ 編輯: supergothere 來自: 218.166.125.121 (06/06 21:42)
※ 編輯: supergothere 來自: 218.166.125.121 (06/06 21:52)
※ 編輯: supergothere 來自: 218.166.125.121 (06/06 21:55)
→ supergothere:我沒po換曲那個的~ 218.166.125.121 06/06
→ supergothere:因為我覺得學長寫的怪怪低 218.166.125.121 06/06
→ supergothere:我自己也有寫一個,不過是用想的.. 218.166.125.121 06/06
→ supergothere:沒跑過,所以不知道對不對…^^" 218.166.125.121 06/06
推 yannishadow:玩了一個週末的matlab,我覺得..... 140.129.39.71 06/06
→ yannishadow:matlab比組合語言好玩多了!....-_-" 140.129.39.71 06/06
推 icemint:◆ 這一篇文章值 515 銀 140.129.37.29 06/07