佳礼资讯网

 找回密码
 注册

ADVERTISEMENT

查看: 2385|回复: 6

【分享】简单8051钢琴乐器模拟程式。

[复制链接]
发表于 14-5-2013 10:55 PM | 显示全部楼层 |阅读模式
这里看起来很冷清。之前我曾经在中国crystalradio论坛里,那里的论坛蛮活跃。我希望可以分享一些资料也让马来西亚对电子有兴趣的朋友可以活跃起来。

这里我是用STC15F104E 的单晶片,用定时器0 的TL0 8bits加中断来产生PWM。PWM的frequency大约117Khz左右来代替简易的8bits DAC。比如当输入值是30时,就设定 P3。0为1,然后把255-30 或者用反值30 (0011 0000 为 1100 1111)写入 TL0 ,TL0 就从225 开始算起到了 Overflow时就 中断cpu, 当CPU测试 P3.0为1时就 把 P3.0 写为0 ,然后直接把30 放进TL0 在return 中断。这样以来就可以利用 TL0加中断来完成 简单的PWM。

除了 TL0 可以用来做简易的PWM,也可以用来做分频时钟给其他的LUT。这个程式有一些问题待遇改善,例如音调不准,只能单旋。

不好意思,本人其实不太会解释。不过可以看看一下的程式就可以了解了。其他的原理可以看看这个网页。
http://elm-chan.org/works/mxb/report.html

演戏效果可以看看这个
http://www.youtube.com/watch?v=m0aAVJ73zwo

这个是之前用电脑实验的钢琴波。

程式如下。
----------------------------------------------------------
;STC15F104E @ 30Mhz
;ZANARKAND
3.0 PWM output TO SPEAKER OR AMPLIFIER


A                .EQU        0E0H
B                .EQU        0F0H
SP                .EQU        081H
DPL                .EQU        082H
DPH                .EQU        083H
TCON                .EQU        088H
TMOD                .EQU        089H
TL0                .EQU        08AH
TL1                .EQU        08BH
TH0                .EQU        08CH
TH1                .EQU        08DH
AUXR                .EQU        08EH
PORT0                .EQU        080H
PORT1                .EQU        090H
PORT2                .EQU        0A0H
PORT3                .EQU        0B0H
P1ASF                .EQU        09DH
P1M1                .EQU        091H
P1M0                .EQU        092H
P0M1                .EQU        093H
P0M0                .EQU        094H
P2M1                .EQU        095H
P2M0                .EQU        096H
P3M1                .EQU        0B1H
P3M0                .EQU        0B2H
IE                .EQU        0A8H
IP                .EQU        0B8H
ADC_CONTR        .EQU        0BCH
ADC_RES                .EQU        0BDH
ADC_RESL        .EQU        0BEH
INT_CLKO        .EQU        08FH
;----------BIT ADDRESS --------------
EA                .EQU        0AFH                ;GLOBAL INTERRUPT ENABLE
ET0                .EQU        0A9H                ;TIMER 0 INTERRUPT ENABLE
ET1                .EQU        0ABH                ;TIMER 1 INTERRUPT ENABLE
TR0                .EQU        08CH                ;TIMER 0 ENABLE
TR1                .EQU        08EH                ;TIMER 1 ENABLE
P0.0                .EQU        080H
P0.1                .EQU        081H
P1.7                .EQU        097H
P1.5                .EQU        095H
P3.0                .EQU        0B0H
P3.1                .EQU        0B1H
P3.2                .EQU        0B2H
P3.3                .EQU        0B3H
P3.4                .EQU        0B4H
P3.5                .EQU        0B5H
P3.7                .EQU        0B7H
A.7                .EQU        0E7H
;----------------------------------
SETTING                .EQU        37H
DACSET                .EQU        31H
X1                .EQU        32H
NOTEP                .EQU        33H
X2                .EQU        34H
TEMP                .EQU        35H
X5                .EQU        36H
SIGN_BIT        .EQU        00H                ;BITS ADDRESS
DOT_OUT                .EQU        01H

                .ORG         0H
                LJMP        INIT
                .ORG        0BH
                SJMP        INTSRV

;----------------Interrupt Service-----------------
INTSRV:               
                PUSH        A
                CLR        TR0                        ;DISABLE TIMER 0
                JB        P3.0,CLR_PWM                ;TEST P3.0 ,IF 1 JUMP TO CLR_PWM
                MOV        A,DACSET                ;255 - DACSET = TL0
                CPL        A
                MOV        TL0,A
                SETB        P3.0
                SETB        TR0
                POP        A
                RETI


CLR_PWM:
                MOV        A,DACSET                ;DACSET = TL0
                MOV        TL0,A
                CLR        P3.0
                SETB        TR0
                INC        X1                        ;117kHZ COUNT
                INC        R1
                CJNE        R1,#0FFH,IEND
                MOV        R1,#0H
                INC        R2
                CJNE        R2,#8D,IEND
                MOV        R2,#0H
                INC        R3                        ;100HZ
IEND:
                POP        A
                RETI                                ;return interrupt
;------------------------INIT----------------------
INIT:

;--------------Port initialize ---------------------       
                MOV        A,#00000011B                ;SET P3.0 ,P3.1 as output Push Pull mode
                MOV        P3M0,A                        ;The rest of port as input with pull up
                MOV        A,#0B
                MOV        P3M1,A       

;--------------Timer initialize---------------------
                MOV        A,#11000000B
                MOV        AUXR,A                        ;SET TIMER0 AND 1 AS 1T
                MOV        A,#00110011B                 
                MOV        TMOD,A                        ;SET TIMER0 AS 8BITS , NO AUTO REFILL
                MOV        A,#0B                        ;DISABLE INTERRUPT AND TIMER OUTPUT.
                MOV        INT_CLKO,A
                MOV        A,#10000010B               
                MOV        IE,A                        ;ENABLE EA(GLOBAL INTERUPT),ET0 (INTERRUPT FROM TMR0)
                MOV        R1,#0H
                MOV        A,#0H
                MOV        NOTEP,A
                MOV        A,#00010000B               
                MOV        TCON,A                        ;SET TR0 =1 ,FOR START TIMER.
               
;----------------------------------------------------               

               
START:               
                MOV        A,R5                        ;FREQUENCY MAP POINTER
                MOV        DPTR,#FREMAP                 ;LOAD FREMAP BASE ADDRESS TO DPTR
                MOVC        A,@A+DPTR
                CJNE        A,X1,START
                MOV        X1,#0
                MOV        DPTR,#PIANO                 ;LOAD PIANO BASE ADDRESS TO DPTR
                MOV        A,R4
                MOVC        A,@A+DPTR
               
                MOV        B,TEMP
                MUL        AB
                MOV        A,B

                MOV        DACSET,A
                INC        R4
                CJNE        R4,#18D,START                ;WAVETABLE POINTER
                MOV        R4,#0H
               
               
                MOV        DPTR,#MUSICTABLE
                MOV        A,NOTEP
                MOVC        A,@A+DPTR
                MOV        R5,A
               
               
                MOV        DPTR,#NOTED
                MOV        A,NOTEP
                MOVC        A,@A+DPTR
               
                MOV        X2,R3
                CJNE        A,X2,DECAY1OP
                MOV        R3,#0H
                INC        NOTEP
                MOV        A,NOTEP
                CJNE        A,#87D,START
                MOV        A,#0H
                MOV        NOTEP,A
                LJMP        START
               

DECAY1OP:
                MOV        DPTR,#DECAY1
                MOV        A,R3
                MOVC        A,@A+DPTR
                MOV        TEMP,A
                LJMP        START

               
               
                       
               
DECAY1:
                .DB 0FFH,154D,93D,92D,91D,90D,89D,88D,87D,86D,85D,84D,83D,82D,81D,80D
                .DB 79D,78D,77D,76D,75D,74D,74D,72D,71D,70D,68D,67D,66D,65D,64D,63D,62D,61D
                .DB 60D,58D,56D,54D,52D,50D,48D,46D,44D,42D,40D,38D,36D,34D,32D,30D,28D,28D,
                .DB 28D,28D,28D,28D,28D,28D,28D,28D,28D,28D,28D,28D,0D           ;65POINT
               
               
FREMAP:
                .DB 59D,53D,50D,45D,39D,37D,33D
                .DB 30D,26D,25D,22D,20D,19D,17D
                .DB 15D,13D,12D,11D,10D,9D,8D



                .DB 54D,49D,46D,41D,36D,34D,30D,27D,24D,20D                        ;7A2 ,13 A3
                .DB 18D,17D,16D,15D,13D,12D,11D,10D,9D,8D,7D ;21POINT

PIANO:
                .DB 09BH,0EEH,0D1H,078H,043H,033H
                .DB 05FH,097H,083H,07EH,065H,068H
                .DB 07FH,08AH,094H,0A9H,077H,000H                ;18POINT

                ;7A 8B 9C 10D 11E 12F 13G

MUSICTABLE:        .DB 11D,8D,11D,12D,13D,12D,11D,10D,11D,10D,8D,11D,8D,11D,12D,13D,12D,13D,14D,13D,14D,15D
               
                ;    E  ,B ,E,  F.  G,  F,  E.  D,  E,  D.  B.  E, B, E, F.   G, F,    G.  A1,G,A1. B1,
                .DB 11D,8D,11D,12D,13D,12D,11D,10D,11D,10D,8D,6D,7D,8D,8D,8D,8D,7D,10D
                ; E,B,E,F. G,F,E. D,E,D. B,G0,A. B,B,B. B,A,D.
                .DB 6D,6D,5D,3D,4D,4D,6D,9D,11D,4D,6D,9D,11D,13D
                ;G0,G0,F0,D0. E0,E0,G0,C. E,E0,G0,C,E,G.
                .DB 07D,11D,11D,10D,9D,8D,13D,13D,15D,18D,18D,14D,18D,17D,16D,8D,12D,12D,11D,10D
               
                ;A,E. E,D,C. B,G. G. B1,E1. E1. A1,E1.D1,C1,B,F.F,E,D.
                .DB 9D,14D,14D,13D,11D,8D,8D,12D,7D,5D,7D,8D                ;32+
                ;C,A1.A1.G,E,B.B,F.A,F0,A.B.

NOTED:
                .DB 30D,10D,10D,10D,20D,20D,20D,30D,10D,20D,60D,30D,10D,10D,10D,20D,20D,20D,30D,10D,20D,60D ; 87POINT
                ;3 1 1 1.2 2 2.3 1 2. 6. 3 1 1 1.2 2 2.3 1 2. 6
                .DB 30D,10D,10D,10D,20D,20D,20D,30D,10D,20D,40D,10D,10D,20D,20D,20D,20D,20D,20D
                ;3 1 1 1. 2 2 2. 3 1 2.4 1 1. 2 2 2.2 2 2.
                .DB 30D,10D,10D,10D,30D,10D,10D,10D,10D,10D,10D,10D,10D,10D
                ; 3 1 1 1. 3 1 1 1. 1 1 1 1 1 1.
                .DB 40D,20D,20D,20D,20D,40D,20D,60D,40D,20D,60D,40D,20D,20D,40D,40D,20D,20D,20D,20D
                ;4,2. 2,2,2. 4,2. 6. 4,2. 6. 4,2. 2,4. 4,2. 2,2,2.
                .DB 40D,20D,60D,20D,20D,20D,40D,20D,30D,10D,20D,60D
                ;4,2. 6. 2,2,2. 4,2. 3,1,2. 6.

       
                .END


回复

使用道具 举报


ADVERTISEMENT

发表于 18-5-2013 01:49 PM | 显示全部楼层
我记得,我在论坛的第一帖 ,2005年 4月, 就是问, 怎样产生Polyphonic 音效。。。
当时没有人回复。。

后来, 我知道一个简单的方法来产生polyphonic 多炫, 其实是三角波, 方波, 正炫波组合产生的音效。

下面是简单产生方波和三角波的列表 (Wave Table)
const byte square[] = {
0x64,0x64,0x64,0x64,0x00,0x00,0x00,0x00
};

const byte triangle[] = {
0x00,0x16,0x32,0x48,0x64,0x48,0x32,0x16
}

只要循环读上面的列表,送去DAC,  在一定的速度下就可以产生简单的音效, 类似 以前旧手机的那种振铃。
基本原理是和楼主的一样。。

还有一种是FM sound, 在以前的sound card 使用的技术
这个有比较复杂的数学计算, 波形是计时计算混合计算输出的。。
有兴趣的可以耐心看范例



后来, 也有玩过简单的放音。。
【电路】简易语音或音效在MCU播放的概念电路
http://cforum2.cari.com.my/forum.php?mod=viewthread&tid=1099321

而现在, 如果要用MCU 产生, 可以考虑用dsPIC, DSP  之类的。。
而实际上, 产生音乐的有特定的晶片可以使用,用编程的方式只是好玩学习罢了。。
回复

使用道具 举报

 楼主| 发表于 18-5-2013 04:57 PM | 显示全部楼层
简单 三角波,脉冲,锯齿波,加杂声,中学时我一直在找的,记得我在diploma是曾经问过一个我荷兰朋友frank 他告诉我是Programmable sound generator ,这些好像用在小天才(红白机),Gameboy colour gameboy里。 我在网上找到SN76489,后来失望,没有一个地方有卖。我就去注意FM synthesizer 用Bassle function的,那时很多电脑声卡都是有FM synthesizer.我自己的ESS1868也有FM synthesizer。 当时我找到 Yamaha的 YM2413, 也是卖不到。去年在中国里买到了10个,还没开始实验。。

很多年前我在elm-chan那里看到他用AVR做6旋,wavetable synthesizer。
http://elm-chan.org/works/mxb/report.html

这个project其实是要完成我中学初中1时候的梦想,自制 电子游戏机。当时我很成谜在 SNES的 圣剑宣说3,rudra的秘宝等。。 才开始进如微处理器在初中2。也不知不觉的玩进MCU里。自己学微处理器,不过学校老师教什么我都不知道,成绩还考的很差。。 全班最后几名有的排。。
回复

使用道具 举报

 楼主| 发表于 18-5-2013 05:05 PM | 显示全部楼层
以上的STC15F104E是8脚的 价钱还很便宜不到RM2. 这个是1T的MCU如果用传统的8051需要大约360Mhz的 时钟。

我有sdPIC30F2011, 试验过闪灯,写了一个简单的FIR filter ,不过还没真真测试过。最近我都在专注着 这个1T的8051 。。我还在实验用assembly 从0写起来跑 SD卡, 已经能读档案了。不过没有FAT16管理功能。需要自己输入sector在能读,不过FAT1,FAT2,Rootdir, cluster2。的pointer都可以自己计算出来了。

回复

使用道具 举报

发表于 19-5-2013 11:35 AM | 显示全部楼层
哥哥些  你们都是用汇编语言的啊。。。。

楼主的解释比汇编语言好懂多了


为什么你menu不用C语言呢  我学过一段时间汇编,要写一个功能出来,程序太复杂了
用C语言简单的多哦


简单一句话   上面的汇编我直接跳过不看的   你说的这段程序在我看过的《实例解读51单片机》里面有

二楼的三角波倒是个好东西
回复

使用道具 举报

 楼主| 发表于 19-5-2013 03:44 PM | 显示全部楼层
我不懂c语言啊。。。 一直都看不懂。。 我昨天刚写完,直接用assembly 管理 FAT 16 来播放SD卡的WAV file, 没有lib,不用别人lib,从0写起。。之前有用过c 语言,个人感觉好像很多东西都是别人写好给我,也不懂处理器里面怎么操作,就是有那种感觉,到最后还是坚持用assembly 写。我也曾经用assembly写过游戏在PIC。
  
http://www.youtube.com/watch?v=7JtlyspCMn4&feature=youtu.be

我比较偏向system engineering,比较靠近硬体的,比如,当我自己设计我自己的微处理器,soft processor,我是需要用 machine code 来测试的,机器语言和assembly比较靠近。
回复

使用道具 举报

Follow Us
发表于 13-6-2013 01:10 AM | 显示全部楼层
sougisyou 发表于 19-5-2013 03:44 PM
我不懂c语言啊。。。 一直都看不懂。。 我昨天刚写完,直接用assembly 管理 FAT 16 来播放SD卡的WAV file ...

我是电脑工程系的学生,这学期刚学完8051 embedded system的开发。我们是用C来编写程序的了。assembly不是不好,而是开发时的难度会更高,而且也会很长,对开发者的水准要求也比较高。至于C,那是大部分工程系学生都会的语言,通过SDCC (Small Device C Compiler)来开发8051会大大的减低难度,也不需那么长的code,所以也节省了时间。因为Compiler会帮你处理一些内置的运作,比如说memory等等,在assembly,开发者能够知道自己的资料储存在哪里,但是如果用C,这部分便省略了,compiler会自动帮你找适合的location储存。

在这之前我学过8085的assembly language,觉得assembly在开发一些复杂的system上确实会比较难,但它也有好处,那就是让你能真正了解你的microcontroller/microprocessor的architecture和运作。总的来说,C和Assembly是个有千秋,但是随着 SDCC的不断改善,已经越来越多人选择用C来开发了。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

 

ADVERTISEMENT



ADVERTISEMENT



ADVERTISEMENT

ADVERTISEMENT


版权所有 © 1996-2023 Cari Internet Sdn Bhd (483575-W)|IPSERVERONE 提供云主机|广告刊登|关于我们|私隐权|免控|投诉|联络|脸书|佳礼资讯网

GMT+8, 17-4-2024 12:33 AM , Processed in 0.068099 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表