STM8 开发故事--之蜂鸣器 BEEP设计简单的音乐(三)
虽然我也不识音律。但是不妨碍我欣赏音乐。
要让单片机和蜂鸣器发出音乐必须知道音调和节拍的概念。
音调就是声音的频率,节拍就是这个频率保持的时间。通过对音调和节拍的不同组合就会发出音乐,至于是否悦耳动听则另当别论。
频率可以通过TIM1_TimeBaseInit(2,TIM1_CounterMode_Up,240,0); 函数来设置。
节拍可以写一个delay程序来实现。如果在main里面用delay来实现时间控制,会占用大量CPU资源。一般的做法是创建一个时间中断。我一般会创建一个60hz的时间中断。在时间中断里面处理如按键读取及防抖,音乐播放等功能,其他可以后台处理的程序。我以前在51上用时间中断实现了多任务同时工作的效果。别人用3颗51才能完成的功能我1颗就实现了。
在stm8项目里我用timer2启动时间中断服务程序。先设置tmi2
//tim2 发起中断 中断服务程序在 INTERRUPT_HANDLER(TIM2_UPD_OVF_TRG_BRK_USART2_TX_IRQHandler, 19)
void TIM2_Config(void)
{
TIM2_DeInit();
CLK_PeripheralClockConfig(CLK_Peripheral_TIM2, ENABLE);
TIM2_TimeBaseInit(TIM2_Prescaler_16, TIM2_CounterMode_Up, 1014);
TIM2_SetCounter(500);
TIM2_ITConfig(TIM2_IT_Update, ENABLE);
TIM2_ARRPreloadConfig(ENABLE);
TIM2_Cmd(ENABLE); //计数器使能,开始计数
}
TIM2_Config是在main里执行的。中断程序是在INTERRUPT_HANDLER(TIM2_UPD_OVF_TRG_BRK_USART2_TX_IRQHandler, 19)
里执行的。这个函数在我的工程里已经建立好了,在stm8l15x_it.c 文件里。我是通过IAR的find in file(shift+ctrl+f)功能找到的。是否启动了中断,可以通过在函数里面设断点来确认。stm8的所有中断都在里面。如果你们的工程和我的不一样 就只有自己找了。下面我贴一段代码供大家参考。
u8 music[14][2]={ {6,1},{6,1},{5,1},{7,1},{1,1},{2,1},{3,1},{2,1},{3,1},{2,1},{3,1},{4,1},{5,1},{6,1}};//乐谱第一位是音调第2是节拍
u16 tone[]={0,200,220,240,280,300,350,420};
u8 deat[]={20,30,60};
u8 music1[5][2]={ {1,1},{2,1},{3,1},{4,1},{5,1}};//乐谱第一位是音调第2是节拍
u8 music2[3][2]={ {2,1},{3,1},{4,1}};//乐谱第一位是音调第2是节拍
u8 music3[2][2]={ {2,1},{5,1}};//乐谱第一位是音调第2是节拍
u8 music4[1][2]={ {2,1}};//乐谱第一位是音调第2是节拍
u16 tone_c=0;//当前音调
u8 deat_c=0;//当前节拍长度
u8 music_c=0;//当前节拍
//u8 sw_bell=0;
u16 tone_key[]={100,1200,240};
u8 beat_key=0;//jy 按键发音长度(节拍)
u8 sw_tone=1;
INTERRUPT_HANDLER(TIM2_UPD_OVF_TRG_BRK_USART2_TX_IRQHandler, 19)
{
u8 val=0;
u8 beat_long=10;//按键发音长度
u8 aa;
TIM2_ClearFlag( TIM2_FLAG_Update);
/****************************************/
//蜂鸣器铃声,简单和旋 乐谱在music数组里
if(sw_bell>0){ //sw_bell是铃声开关
aa=sizeof(music)/sizeof(music[0]);
music_c=aa;//当前节拍
deat_c=deat[music[aa-music_c][1]];//当前节拍
tone_c=tone[music[aa-music_c][0]];//当前音调
TIM1_TimeBaseInit(2,TIM1_CounterMode_Up,tone_c,0); //tim1 pwm输出频率
// CLK_PeripheralClockConfig(CLK_Peripheral_TIM1,ENABLE);//开启TIM1时钟 蜂鸣器发声
TIM1_Cmd(ENABLE); //定时器开始计数?
sw_bell=0;
}
if (music_c>0){
if ( deat_c>0){
deat_c--;
}else{
music_c--;
if (music_c>0){
aa=sizeof(music)/sizeof(music[0]);
u8 x=music[aa-music_c][0];
deat_c=deat[music[aa-music_c][1]];//当前节拍
tone_c=tone[music[aa-music_c][0]];//当前音调
if(tone_c!=0){
TIM1_TimeBaseInit(2,TIM1_CounterMode_Up,tone_c,0); //tim1 pwm输出频率
TIM1_Cmd(ENABLE); //定时器开始计数?
}else{
sw_tone=tone_c;
TIM1_Cmd(DISABLE); //定时器停止计数 蜂鸣器不发音
}
}else{
TIM1_Cmd(DISABLE); //定时器停止计数 蜂鸣器不发音
}
}
}
}
嵌入式开发一定要通过善用中断来提高效率。高效的代码可以降低mcu主频,从而降低功耗,延长电池使用时间。
the end!