蜂鸣器

蜂鸣器(Buzzer)是一种能够将电信号转化为声音信号的电子设备,常用于嵌入式系统中发出提示音或警报声。

蜂鸣器是一种利用直流电或交流电驱动,发出特定频率的声音的器件。它通常由外壳、振动膜片、电磁线圈或压电元件组成;根据工作原理的不同,可以分为电磁式和压电式两类;按驱动方式分类可分为有源蜂鸣器和无源蜂鸣器

有源蜂鸣器:内部集成了振荡器,直接接通电源即可发声。使用方便,只需给定直流电压即可驱动。

无源蜂鸣器:没有内置振荡器,需要通过外部信号(如PWM信号)驱动产生振荡。声音频率、节奏可以通过外部控制。

原理图

fengmingqiyuanlitu

赫兹与周期的换算

频率是指在单位时间内(1s)发生重复事件的次数,通常用赫兹(Hz)表示;周期时间则指完成一次所需时间

频率和周期的关系为:f=1/T。即频率等于周期的倒数,二者成反比。假设频率为 f = 2Hz,那么其周期 T = 1 / f = 1 / 2 = 0.5 秒(高低电平各0.25)。那么就是定时器的计数时间就应该是:

65535 - (MAIN_Fosc / (2 * 2));

那么 1047 的频率也就是一秒内要发生 1047 个重复的周期,也就是 1047 个高电平 + 1047 个低电平,那么也就是说在 1 秒内高低电平一共要被触发 1047 + 1047 = 2097 次,也就是定时器在一秒内要被触发 2097 次,所以触发时间就是:

65536 - (MAIN_Fosc / (2 * 1047));

再捋一下,此时 (MAIN_Fosc / (2 * 1047)) 这个时间就是一次高电平或者低电平的时间,那么 60036 减去这个时间就表示,每次数这么长的时间就触发一次定时中断去改变他的高低电平,这样就达到了触发 1047 这个频率的目的;

再仔细说下为什么这里是主频除以后面的频率,给我一个确定的时间 1ms 我会算,但是给频率就反应不过来怎么办?

这里可以这么想,以上面的 2097 为例,一秒内要执行 2097 次高低电平的转换,那么每次的时间就是 1 / 2097s;那么我们将这个 1 / 2097 换成主频的时钟周期数,不就是 (主频 * 1/2097),即 MAIN_Fosc / 2097 了么;2097 个这么长的时间就是 1ms(24MHz);

实现

通过定时器控制播放哆来咪发唆拉西哆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include "GPIO.h"
#include "Delay.h"
#include "Timer.h"
#include "NVIC.h"

// 蜂鸣器引脚
#define BUZZER P00

// 小字二组 哆来咪发唆拉西哆 对应的频率
// C` D` E` F` G` A` B` C``
u16 hz_note[] = {1047, 1175, 1319, 1397, 1568, 1760, 1976, 2093};

// 引脚初始化
void GPIO_Config(void) {
GPIO_InitTypeDef GPIO_Init;
GPIO_Init.Pin = GPIO_Pin_0;
// 指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Init.Mode = GPIO_OUT_PP;
GPIO_Inilize(GPIO_P0, &GPIO_Init);//初始化
}

// 定时器配置
void Timer_Config(u16 hz_buzzer) {
TIM_InitTypeDef Timer_init;

Timer_init.TIM_Mode = TIM_16BitAutoReload;
// 时钟源 TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
Timer_init.TIM_ClkSource = TIM_CLOCK_1T;
// 可编程时钟输出,如果配置ENABLE,则 P3.5 端口会同步输出时钟脉冲
Timer_init.TIM_ClkOut = DISABLE ;
// 装载初值
Timer_init.TIM_Value = 65536 - (MAIN_Fosc / (2 * hz_buzzer));
// 是否运行 ENABLE,DISABLE
Timer_init.TIM_Run = ENABLE;
// 选择定时器,并且进行配置
Timer_Inilize(Timer0, &Timer_init);
//打开中断使能
NVIC_Timer0_Init(ENABLE, Priority_1);
}

// 定时器 0 中断函数中执行的代码
handle_timer0_interrupt() {
BUZZER = ~BUZZER;
}

void main() {
int i;
// 中断总控制
EA = 1;

GPIO_Config();

while(1) {
for(i = 0; i < sizeof(hz_note) / siezeof(hz_note[0]; i++)){
Timer_Config(hz_note[i]);
}
// 每播放一个轮次,就停三秒钟不要出声,再继续播放;
stop();

delay_ms(250);
delay_ms(250);
delay_ms(250);
delay_ms(250);

delay_ms(250);
delay_ms(250);
delay_ms(250);
delay_ms(250);

delay_ms(250);
delay_ms(250);
delay_ms(250);
delay_ms(250);
}
}

问题

一、定时器的效果是如何作用于蜂鸣器的

定时器的效果作用于蜂鸣器,主要是通过控制蜂鸣器电源的开关状态(即高电平或低电平)来实现的;定时周期决定了蜂鸣器发声的频率,因为频率是单位时间内周期性事件的次数。

也就是说,在一秒内,以不同的频率给蜂鸣器发送高低电平就可以控制它发出不同的声音。

二、为什么高低电平各占一半呢,高低电平的占比不是和占空比有关么

这样做可以简化控制逻辑,同时确保蜂鸣器发出的声音具有稳定的频率和音色。他可能并不是真的各占一半。