实例1:利用蜂鸣器模拟基本音级
1.1 蜂鸣器的工作原理
蜂鸣器发声原理是电流通过电磁线圈,使电磁线圈产生磁场来驱动振动膜发声的,因此需要一定的电流才能驱动它,单片机 IO 引脚输出的电流较小,单片机输出的 TTL 电平基本上驱动不了蜂鸣器,因此需要增加一个电流放大的电路。实验板通过一个三极管 Q1 来放大驱动蜂鸣器。
1.2 蜂鸣器的分类
蜂鸣器按其是否带有信号源又分为有源和无源两种类型。有源蜂鸣器只需要在其供电端加上额定直流电压,其内部的震荡器就可以产生固定频率的信号,驱动蜂鸣器发出声音。无源蜂鸣器可以理解成与喇叭一样,需要在其供电端上加上高低不断变化的电信号才可以驱动发出声音。对于有源和无源的驱动方式,略有不同,先讲解一下有源蜂鸣器的驱动方法。有源蜂鸣器因为内含有信号源,因此只要加上额定的工作电压就可以发出固定频率的声音。对于无源的蜂鸣器,驱动其发出声音就较为复杂,因为它本身不带信号源,因此,只是通上电源,是不能发出声音的,必须要不断的重复“通电-断电”,才能使其发出声音,我们可以通过编写程序,控制 GPIO口不断的置为高电平—低电平—高电平…,这样蜂鸣器就可以不断的通、断电,从而发出声音。而通电、断电的时间不同,相当于振荡周期的不同,因此又可以得到不同频率的声音。
1.3 蜂鸣器的硬件电路图
从下面的电路图中可以看出,控制蜂鸣器发生的高低电平输入信号接口为GPIO7。通过控制GPIO7开启关闭的时间不同,就可以控制蜂鸣器得到不同频率的声音信号。
1.4 DSP如何输出组频率
为了让 dsp 发出不同频率的声音,采用定时中断来计算延时时间,只需将定时器预置不同的定时值就可实现不同时间的定时。以标准音高 A 为例: A 的频率 f=440Hz,其对应的周期为: T=1/f=1/440=2272us。
DSP 控制蜂鸣器的波形图,通过对 GPIO端口 循环的置位、清零来达到输出固定频率波形,相对于 A 音频率 440Hz 如图 T=2272us,那么 t=T/2=2272/2=1136us 所以,我们只要在程序中将 GPIO置为高电平,延时 1136us,再置为低电平,延时 1136us,如此循环,就可以得到440Hz 频率的声音。
1.5 代码实例
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include "DSP2833x_Examples.h" // DSP2833x Examples Include File
/****************端口宏定义*****************/
#define BUZZ_CLK_GENER GpioDataRegs.GPATOGGLE.bit.GPIO7 = 1; //蜂鸣器控制IO电平翻转
#define BELL_DIR GpioCtrlRegs.GPADIR.bit.GPIO7 //定义IO输出方向
#define BELL_DAT GpioDataRegs.GPADAT.bit.GPIO7 //定义IO寄存器数值
#define DISABLE_TIMER1_INT IER &= 0xFFFE; //CPU中断使能标志位清除
#define ENABLE_TIMER1_INT IER |= M_INT1; //CPU中断使能标志位使能
#define BUZZ_OFF GpioDataRegs.GPACLEAR.bit.GPIO7 = 1; //IO输出清除
Uint16 Musi[23]=
{ //单位 us,不同频率下,蜂鸣器发出不同音调的声音
0,
3816, //L_do
3496, //L_re
3215, //L_mi
2865, //L_fa
2551, //L_so
2272, //L_la
2024, //L_xi
1912, //do
1703, //re
1517, //mi
1432, //fa
1275, //so
1136, //la
1013, //xi
956, //H_do
851, //H_re
758, //H_mi
716, //H_fa
638, //H_so
568, //H_la
506, //H_xi
0xFF //STOP
};
Uint16 Song[]={1,2,3,4,5,6,7}; //乐谱:do,re,mi,fa,so,la,xi
/****************函数声明*******************/
void Init_Bell(void);
interrupt void cpu_timer0_isr(void);
void Delay(Uint16 t);
void main(void)
{
Uint16 addr=0;
Uint16 k;
InitSysCtrl(); // 初始化系统控制:
BELL_DAT=0; //设置端口为低电平
Init_Bell(); //设置蜂鸣器端口输出
DINT; // 禁止CPU全局中断
InitPieCtrl(); // 初始化PIE控制寄存器到他们的默认状态,即禁止PIE中断及清除所有PIE中断标志
IER = 0x0000; // 禁止CPU中断和清除所有CPU中断标志
IFR = 0x0000;
InitPieVectTable(); //初始化PIE中断向量表,并使其指向中断服务子程序(ISR)
EALLOW; //解除寄存器保护
PieVectTable.TINT0 = &cpu_timer0_isr;// 本例中的中断重新映射到本文件中的中断服务子程序中
EDIS; // 添加寄存器保护
InitCpuTimers(); // 初始化片内外设,本例仅需要初始化CPU定时器
ConfigCpuTimer(&CpuTimer0, 150, 1000000);// 配置CPU定时器1每秒发生一次中断
StartCpuTimer0(); //开始计时器
IER |= M_INT1; //使能CPU中断线INT1,连接到CPU定时器0的;
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;// 使能PIE组1中断7,TINT0中断;
EINT; // 使能全局中断INTM
ERTM; // 使能全局实时中断DBGM
for(k=0;k<7;k++) // 步骤 6. 中断控制蜂鸣器开关频率,延时函数定义乐拍,7次循环分别让蜂鸣器响7种乐声:
{
StopCpuTimer0(); //停止计数
DISABLE_TIMER1_INT; //不使能定时器中断
ConfigCpuTimer(&CpuTimer0, 150, Musi[Song[addr]+14]/2); //根据音节的频率设置定时时间
StartCpuTimer0(); //重启定时器
ENABLE_TIMER1_INT; //使能定时中断
Delay(8); //音乐节拍延时
StopCpuTimer0(); //停止计数
DISABLE_TIMER1_INT; //不使能定时中断
BUZZ_OFF; //关闭蜂鸣器
Delay(2); //音乐停顿
addr++; //连续发出乐谱:do,re,mi,fa,so,la,xi
}
while(1);
}
/*-----------------------------------------*/
/*形式参数:void */
/*返回值:void */
/*函数描述:初始化蜂鸣器端口为输出 */
/*-----------------------------------------*/
void Init_Bell(void)
{
EALLOW; //解除寄存器保护
BELL_DIR=1;//Bell端口输出
EDIS; //寄存器保护
}
/*------------------------------------------*/
/*形式参数:void */
/*返回值:void */
/*函数描述:定时器CPU0中断服务子程序 */
/*------------------------------------------*/
interrupt void cpu_timer0_isr(void)
{
CpuTimer0.InterruptCount++;
BUZZ_CLK_GENER; //GPIO口输出电平翻转
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; //PIEACK标志位置位,告诉PIE可以接受本组其他中断处理
}
void Delay(Uint16 t) //延时函数
{
Uint32 i=0;
Uint32 gain = 300000;
Uint32 base=0;
base=gain*t;
for(i=0;i<=base;i++);
}