自19日收到开发板已快一周。以前一直以为STM32莫测高深,通过看配套的视频、配套的学习资料,发现要入门也不难。在学习了GPIO、TIM的应用后,突发奇想,如果弄首音乐在开发板上演奏,是什么情况?
说干就干!
GPIO用于控制LED的闪亮,开发板的喇叭(蜂鸣器)接在PB8,复用功能是TIM4_CH3,如果让TIM4_CH3工作于输出比较匹配翻转模式,当写入一定参数时,岂不能输出固定频率的方波,如果将音符对应的频率做成数据,顺序输出相应频率驱动喇叭,音乐不能成了。按照以上思路,写好程序,烧入开发板,运行程序,果然开发板发出了对应的音乐。不过开发板上装的是有源蜂鸣器,发出声音有点嘶哑,为此,将蜂鸣器更换为无源的,音乐动听多了。
以下是音乐文件,上面有《卡秋莎》、《铃儿响叮铛》,当在music.h文件的开头宏定义了MUSIC1时,演奏《卡秋莎》,否则演奏《铃儿响叮铛》。
/************************************
* 定义音乐文件二维数组{x,y} *
* x:对应音符音阶,0表示何止符 *
* y:对应音符节拍,0表示音乐结束 *
************************************/
#include "sys.h"
#define MUSIC1 1
#ifdef MUSIC1 //如果定义了MUSIC1音乐为《卡秋莎》
u16 music_data[][2]=
{
{440,600},{494,200},{523,600},{443,200},{523,400},{494,200},
{440,200},{494,400},{330,400},{494,600},{523,200},{578,600},
{494,200},{578,400},{523,200},{494,200},{440,800},{659,400},
{880,400},{784,400},{880,200},{784,200},{698,400},{659,200},
{578,200},{659,400},{440,400},{ 0,200},{698,400},{578,200},
{659,600},{523,200},{494,200},{330,200},{523,200},{494,200},
{440,800},{659,400},{880,400},{784,400},{880,200},{784,200},
{698,400},{659,200},{578,200},{659,400},{440,400},{ 0,200},
{698,400},{578,200},{659,600},{523,200},{494,200},{330,200},
{523,200},{494,200},{440,800},{ 0, 0}
};
#else //否则音乐为《铃儿响叮铛》
u16 music_data[][2]=
{
{392,200},{659,200},{587,200},{523,200},{392,400},{ 0,200},
{392,100},{392,100},
{392,200},{659,200},{587,200},{523,200},{440,400},{ 0,400},
{440,200},{698,200},{659,200},{587,200},{494,400},{ 0,400},
{784,200},{784,200},{698,200},{587,200},{659,800},
{392,200},{659,200},{587,200},{523,200},{392,400},{ 0,200},
{392,100},{392,100},
{392,200},{659,200},{587,200},{523,200},{440,400},{ 0,200},
{440,200},
{440,200},{698,200},{659,200},{587,200},{784,200},{784,200},
{784,200},{784,200},
{880,200},{784,200},{698,200},{587,200},{523,600},{ 0,200},
{659,200},{659,200},{659,400},{659,200},{659,200},{659,400},
{659,200},{784,200},{523,300},{587,100},{659,600},{ 0,200},
{698,200},{698,200},{698,300},{698,100},{698,200},{659,200},
{659,200},{659,100},{659,100},{659,200},{587,200},{587,200},
{554,200},{587,400},{784,400},
{659,200},{659,200},{659,400},{659,200},{659,200},{659,400},
{659,200},{784,200},{523,300},{587,100},{659,600},{ 0,200},
{698,200},{698,200},{698,300},{698,100},{698,200},{659,200},
{659,200},{659,100},{659,100},{784,200},{784,200},{698,300},
{587,100},{523,600},{ 0,200},
{ 0, 0}
};
#endif
TIM初始化函数如下:
void TIM4_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure; //设一个IO变量
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //设一个定时器变量
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //使能TIM2
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //使能PWM输出端口
//配置PWM输出端口:TIM4 CH3 PWM GPIOB.8
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //TIM2_CH4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //置入
TIM_TimeBaseStructure.TIM_Period = arr; //计数上限
TIM_TimeBaseStructure.TIM_Prescaler =psc; //分频系数
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM2向上计数
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //配置数据
//???TIM4 Channel3 PWM??
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle; //TIM_OCMode_PWM2; //???????:TIM????????2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //??????
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //????:TIM???????
TIM_OC3Init(TIM4, &TIM_OCInitStructure); //??T??????????TIM2 OC4
TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable); //??TIM3?CCR2????????
// TIM_Cmd(TIM4, ENABLE); //??TIM2
}
主函数(演奏音乐在这里完成)如下:
#include "stm32f10x_tim.h"
#include "timer.h"
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "music.h"
void sound(u16 k)
{
u16 x;
x=music_data[k][0]; //读取音阶数据
if(x!=0)
{
x=4000000/x; //计算计数值
TIM4->ARR = x; //计数值写入重装载寄存器
GPIOB->CRH&=0XFFFFFFF0;
GPIOB->CRH|=0X0000000B; //PB.8复用推挽输出
TIM_Cmd(TIM4, ENABLE); //开声音
}
else
{
TIM_Cmd(TIM4, DISABLE); //关声音disenable
GPIOB->CRH&=0XFFFFFFF0;
GPIOB->CRH|=0X00000003; //PB.8推挽输出
  Bout(8)=0; ////停止时蜂鸣器管脚低电平
}
}
int main(void)
{
u8 i=0;
TIM4_Init(2000,9); //初始化定时器4,预分频9,计数频率8M
LED_Init();
delay_init();
while (1)
{
while(music_data[1]!=0) //等待音乐结束
{
LED0 = 0; //每切换一个音符,LED0闪一下
sound(i); //播放音符
delay_ms(50);
LED0 = 1;
delay_ms(music_data[1]-50);//音符时长
LED1 = !LED1; //每切换一个音符,LED1反一种状态
i++; //下一个音符
TIM_Cmd(TIM4, DISABLE); //每两个音符间停止一小会
GPIOB->CRH&=0XFFFFFFF0;
GPIOB->CRH|=0X00000003; //PB.8推挽输出
GPIO_ResetBits(GPIOB,GPIO_Pin_8);//停止时蜂鸣器管脚低电平
delay_ms(20);
}
TIM_Cmd(TIM4, DISABLE); //音乐结束,停止播放
delay_ms(1500);//延时后继续
delay_ms(1500);
i=0; //从头开始
}
}
完整的工程文件如下:
(此工程仅为初学练习,由于不懂之处还很多,程序采用了库函数、寄存器共用方式。让各位高手见笑!请多指点!)
|