⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 learn-lumit-step-14-readme.txt

📁 嵌入式开发试验:蜂鸣器播放音乐实验
💻 TXT
字号:

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[i] == 0  BEEP_OFF
   else  BEEP_ON
*/   
int beep_write( char * buf, int count )
{	
	int i;
	
	for( i = 0; i < count; i++ )
	{
		if( buf[i] )
			IOPDATA = IOPDATA | 0x00010000;
		else
			IOPDATA = IOPDATA & (~0x00010000);		
	}
	
	return count;
}

    从硬件连接原理图中,我们知道 beep 是通过 gpio 16 连接的,因此首先需要设置该
io 为输出方向。蜂鸣器的发声原理很简单,对该 io 口输出高电平时就开始发声,输出低
电平时就停止发声。对应程序上,就是对 io 进行 1 和 0 的赋值操作。在 beep_write
驱动接口函数实现中,我们据此做了简单的处理,即只要 buf[i] 不为 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[i][0] >= 1 )
			beep_note( psong[i][0], psong[i][1], psong[i][2] );
		if( psong[i][0] == 0 )
			beep_rest();
		if( psong[i][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,但这个修改是非常简单的。

    在此特别感谢一下我的学音乐的女朋友,其实我的音乐理论水平只有小学三年级。
她在我写 beep_note 接口的时候,给予了很多非技术性的帮助。:)



┌-------------------------------------------------------------------------┐
│                                                                         │
│    Welcome to visit http://www.lumit.org & http://bbs.lumit.org         │
│                                                                         │
│                  [lumit] - let us make it together                      │
│                                                                         │
│                                                                         │
│                                         lumit-admin <admin@lumit.org>   │
│                                                                         │
└-------------------------------------------------------------------------┘

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -