【STM32F103】谁在用蜂鸣器弹奏一曲东风破(无源蜂鸣器&PWM)

无源蜂鸣器

蜂鸣器一般可以分为两种,一种是有源蜂鸣器,另一种是无源蜂鸣器。

有源蜂鸣器中的源是指震荡源,也就是给了电压再给个触发信号就会以固定的频率发出声响。

而无源蜂鸣器内部没有震荡源,我们可以将触发信号的频率传给无源蜂鸣器,这样就可以发出不同音阶的声响了。

下面是我买的无源蜂鸣器的原理图以及实物图。

【STM32F103】谁在用蜂鸣器弹奏一曲东风破(无源蜂鸣器&PWM)_第1张图片

【STM32F103】谁在用蜂鸣器弹奏一曲东风破(无源蜂鸣器&PWM)_第2张图片

可以看得出有三个引脚,VCC接3.3V~5V(以你们手上的无源蜂鸣器为准),GND接地。

中间的 I/O 接PWM信号。

我这里是低电平驱动,因此给的PWM信号中低电平占比越高,发出的声响越大。也就是占空比越小,声音越大。

而无源蜂鸣器发出的音调是和PWM的频率有关。

【STM32F103】谁在用蜂鸣器弹奏一曲东风破(无源蜂鸣器&PWM)_第3张图片

STM32&PWM

具体怎么发出PWM,可以查看我同专栏之前的文章。

简而言之就是利用STM32的定时器来发出PWM,也就是说PWM的频率和定时器的频率是一样的。

定时器溢出频率=72MHz/预分频器的值+1/自动重装器的值

所以PWM的频率跟两个参数有关,一个是预分频器,一个是自动重装器。

而自动重装器跟PWM的阈值有关,也就是调整占空比的,因此我们一般不会去动。所以我们就只能是通过调整预分频器来调整频率了。

TIM_PrescalerConfig

【STM32F103】谁在用蜂鸣器弹奏一曲东风破(无源蜂鸣器&PWM)_第4张图片

第三个参数(表格中输入参数1,输入参数2好像有点问题,因为上面函数原型中参数有三个)我们就选择即时装入。

在输出PWM的基础上,我们再通过上面的函数来动态调增预分频器,以此来改变PWM的频率,就可以发出不同声调的声音了。

“演奏”“东风破”代码

 根据我几乎没有的乐理知识编写了下面的代码,“演奏”了副歌部分的一半,依稀可以听出来大概的调调。

【STM32F103】谁在用蜂鸣器弹奏一曲东风破(无源蜂鸣器&PWM)_第5张图片

需要注意的是我这里用的是TIM2,输出通道1,所以PWM输出在GPIOA的0号引脚,如果要改动的话,需要去参考引脚定义表。

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

const uint16_t music[3][8]={    //低中高音对应频率所需的预分频数
    {0,381,340,303,286,255,227,202},
    {0,191,170,151,143,127,113,101},
    {0,95,85,75,71,63,56,50}
};

void play(uint8_t i,uint8_t j,uint16_t time){
    //调整定时器的预分频器达到调整频率的效果
    TIM_PrescalerConfig(TIM2,music[i][j],TIM_PSCReloadMode_Immediate);  
    Delay_ms(time);
}

int main(void){
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);     //打开TIM2的外设时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    GPIO_InitTypeDef gitd;
    gitd.GPIO_Mode=GPIO_Mode_AF_PP;                         //配置为复用推挽输出
    gitd.GPIO_Pin=GPIO_Pin_0;
    gitd.GPIO_Speed=GPIO_Speed_2MHz;
    GPIO_Init(GPIOA,&gitd);
    
    TIM_InternalClockConfig(TIM2);                          //选择内部时钟(72MHz)作为时钟源
    TIM_TimeBaseInitTypeDef itd;
    itd.TIM_ClockDivision=TIM_CKD_DIV1;                     //时钟1分频
    itd.TIM_CounterMode=TIM_CounterMode_Up;                 //向上计数模式
    itd.TIM_Period=720-1;                                   //设置自动重装器的值
    itd.TIM_Prescaler=0;                                    //设置预分频器的值
    itd.TIM_RepetitionCounter=0;                            //重复计数器的值,但是仅高级定时器有效
    TIM_TimeBaseInit(TIM2,&itd);
    
    TIM_OCInitTypeDef itd1;
    itd1.TIM_OCMode = TIM_OCMode_PWM1;                      //比较输出模式为PWM1
    itd1.TIM_OCPolarity = TIM_OCPolarity_High;              //输出极性为高电平
    itd1.TIM_OutputState=TIM_OutputState_Enable;            //使能
    itd1.TIM_Pulse=710;                                     //初始化输出比较的阈值          
    TIM_OC1Init(TIM2,&itd1);
    
    TIM_Cmd(TIM2,ENABLE);                                   //使能定时器
    while(1){
        play(1,5,1200);
        play(1,6,800);
        play(1,7,400);
        play(1,6,400);
        play(1,5,400);
        play(1,3,800);
        play(1,2,800);
        TIM_SetCompare1(TIM2,720);
        Delay_ms(800);
        TIM_SetCompare1(TIM2,710);
        play(1,5,1200);
        play(1,3,400);
        play(1,2,600);
        play(1,1,600);
        play(1,2,400);
        play(1,1,400);
        play(1,2,400);
        play(1,3,800);
        TIM_SetCompare1(TIM2,720);
        Delay_ms(800);
        TIM_SetCompare1(TIM2,710);
        play(0,7,400);
        play(1,1,400);
        play(1,2,400);
        play(1,3,400);
        play(1,2,400);
        play(1,3,400);
        play(1,5,400);
        play(1,3,400);
        play(1,2,400);
        play(1,1,200);
        play(1,2,400);
        play(0,6,400);
        TIM_SetCompare1(TIM2,720);
        Delay_ms(800);
        TIM_SetCompare1(TIM2,710);
        play(1,1,800);
        play(1,2,400);
        play(1,3,400);
        play(1,2,400);
        play(1,3,400);
        play(1,5,400);
        play(1,6,400);
        play(1,5,600);
        play(1,3,1200);
        play(1,2,600);
        TIM_SetCompare1(TIM2,720);
        Delay_ms(800);
        TIM_SetCompare1(TIM2,710);
    }
}

参考

《STM32F103xx固件函数库用户手册》

你可能感兴趣的:(STM32F103,stm32,嵌入式硬件,单片机)