limingth 发表于 2005-6-13 13:27:34

Learn lumit Step 14: 蜂鸣器播放音乐实验

Learn lumit Step 14 : 蜂鸣器播放音乐实验
++++++++++++++++++++++++++++++++++++++++++++++++++++++

    在这一节里,我们先对程序的组织结构做一点点的调整。前面的几个例子,我们都是
将所有的源码文件和头文件放在一个 src 目录下,这样当文件多了之后就不太容易组织。
这里我们单独为 beep 设备建立一个子目录,把所有和 beep 相关的代码都放在该目录下。
同时,我们将编译过程中的目标文件和最终生成的可执行文件都统一放到 debug 目录下,
这样以后我们只需要将源码树 src 打包即可,而所有的中间文件都是可以通过 make 后
再重新生成的。

    接下来我们来看看 beep_driver.c 文件,这是 beep 设备底层的驱动。比较重要的是
两个函数 beep_open 和 beep_write :

/* set beep related gpio */
int beep_open( void )
{
        // set gpio's direction: set IOPMOD register mode bit to 1 = output
        IOPMOD = IOPMOD | 0x00010000;

        return 0;
}

/*
   if buf == 0BEEP_OFF
   elseBEEP_ON
*/   
int beep_write( char * buf, int count )
{       
        int i;
       
        for( i = 0; i < count; i++ )
        {
                if( buf )
                        IOPDATA = IOPDATA | 0x00010000;
                else
                        IOPDATA = IOPDATA & (~0x00010000);               
        }
       
        return count;
}

    从硬件连接原理图中,我们知道 beep 是通过 gpio 16 连接的,因此首先需要设置该
io 为输出方向。蜂鸣器的发声原理很简单,对该 io 口输出高电平时就开始发声,输出低
电平时就停止发声。对应程序上,就是对 io 进行 1 和 0 的赋值操作。在 beep_write
驱动接口函数实现中,我们据此做了简单的处理,即只要 buf 不为 0 则发声。通过对
bepp ON 和 OFF 的时间长短控制,就能使得蜂鸣器发出一定频率的声音。

    很多控制蜂鸣器发声的程序到此就结束了,而我们希望能做的更好一些。因此,我们
根据音乐上音符对应的频率,以及音符的长短关系,设计实现了一个 beep_note 函数 api :

/* define DO RE MI ... 对应频率 hz */
#define                P0        200
#define                P1        264
#define                P2        297
#define                P3        330
#define                P4        352
#define                P5        396
#define                P6        440
#define                P7        495

#define                P8        560
#define                P9        660

static int p_note[] = { P0, P1, P2, P3, P4, P5, P6, P7, P8, P9 };

// note: 1,2,3,4,5,6,7
// tone: 低八度,中八度,高八度 [*1, *2, *4]
// div:八分音符;四分音符
int beep_note( int note, int tone, int div )
{       
        int freq = p_note * tone;
        int loop = (1000*1000/(freq))/2;
        int count = (freq/div)*2 ;
       
        char beep_on = 1;
        char beep_off = 0;
               
        if( note > 9|| note < 0 )
                return -1;
       
        while( count-- )
        {
                beep_write( &beep_on, 1 );
                beep_delay( loop );
                beep_write( &beep_off, 1 );
                beep_delay( loop );
        }
       
        return 0;
}

    这样,就使得蜂鸣器具有更丰富的声音表达,可以播放一个具有音符、音高、音长特性的
发音设备,在此基础上,我们继而实现了播放一首曲子的 beep_music 函数 api 来播放音乐。

/* beep a song */
void beep_music( int psong[] )
{
        int i;
       
        for( i = 0; ; i++ )
        {
                if( psong >= 1 )
                        beep_note( psong, psong, psong );
                if( psong == 0 )
                        beep_rest();
                if( psong == -1 )
                        break;
        }
}

    这里我们定义的歌曲是一个三元组的序列,每一个三元组表达了一个音符,如果该三元组的
首音符为 0,则表达为一个休止符;如果是 -1,则表示该乐曲结束。

    在 beep_test 接口中,我们实现了一个简单的测试例子,用来说明如果调用这个函数:

static int test_note[] =
{       
        { 1, 2, 4 },        { 0, 0, 0 },
        { 2, 2, 4 },        { 0, 0, 0 },
        { 3, 2, 4 },        { 0, 0, 0 },
        { 4, 2, 4 },         { 0, 0, 0 },
        { 5, 2, 4 },        { 0, 0, 0 },
        { 6, 2, 4 },        { 0, 0, 0 },
        { 7, 2, 4 },        { 0, 0, 0 },
        { 1, 4, 4 },         { 0, 0, 0 },
        { 0, 0, 0 },        { 0, 0, 0 },
        { 1, 4, 4 },        { 0, 0, 0 },
        { 7, 2, 4 },        { 0, 0, 0 },
        { 6, 2, 4 },        { 0, 0, 0 },
        { 5, 2, 4 },         { 0, 0, 0 },
        { 4, 2, 4 },        { 0, 0, 0 },
        { 3, 2, 4 },        { 0, 0, 0 },
        { 2, 2, 4 },        { 0, 0, 0 },
        { 1, 2, 4 },         { 0, 0, 0 },
        { -1, 0, 0 }
};       

int beep_test( void )
{       
        beep_init();
       
        beep_music( test_note );
       
        return 0;
}

    有 lumit4510 板子的小组成员,可以把这个例子在板子上实际的跑一下,体会一下
蜂鸣器发出的带有颤动效果的音乐,呵呵。当然,只要是板子上带有类似简单发声设备
的朋友,都可以把这个程序移植到自己的板子上,正如在前面所说的,beep_api.c 在
移植过程中是可以不用修改的,反而可以扩展出更多自己的接口。需要修改的只有底层的
驱动 beep_driver.c 和 beep_driver.h,但这个修改是非常简单的。 :)

zhaoic 发表于 2005-6-18 18:11:31

:mrgreen: 东方红很不错,不过蜂鸣器的表现力还是很弱,争取尽快把MP3做出来,呵呵

nuomiyyq 发表于 2006-7-6 14:50:48

附件里面的文件什么奇怪格式啊,怎么打不开啊

zdf980318 发表于 2007-10-16 16:03:29

asdfasdfasdfasdfasdfasdf
页: [1]
查看完整版本: Learn lumit Step 14: 蜂鸣器播放音乐实验