|  | 
 
| 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 == 0  BEEP_OFF
 else  BEEP_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[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[][3] )
 {
 int i;
 
 for( i = 0; ; i++ )
 {
 if( psong[0] >= 1 )
 beep_note( psong[0], psong[1], psong[2] );
 if( psong[0] == 0 )
 beep_rest();
 if( psong[0] == -1 )
 break;
 }
 }
 
 这里我们定义的歌曲是一个三元组的序列,每一个三元组表达了一个音符,如果该三元组的
 首音符为 0,则表达为一个休止符;如果是 -1,则表示该乐曲结束。
 
 在 beep_test 接口中,我们实现了一个简单的测试例子,用来说明如果调用这个函数:
 
 static int test_note[][3] =
 {
 { 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,但这个修改是非常简单的。
  | 
 
×本帖子中包含更多资源您需要 登录 才可以下载或查看,没有账号?注册  |