|
通过 STM32F1 芯片的一个 IO口控制板载有源/无源蜂鸣器,实现蜂鸣器控制。
( A G7 A$ g% p( H$ e. z
蜂鸣器介绍 蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件。蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型。 压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、阻抗匹配器及共鸣箱、外壳等组成。多谐振荡器由晶体管或集成电路构成,当接通电源后(1.5~15V 直流工作电压),多谐振荡器起振,输出 1.5~5kHZ 的音频信号,阻抗匹配器推动压电蜂鸣片发声。 电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。接通电源后,振荡器产生的音频信号电流通过电磁线圈,使电磁线圈产生磁场,振动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声。 其实一句话就可概括它们之间的区别,想要压电式蜂鸣器发声,需提供一定频率的脉冲信号;想要电磁式蜂鸣器发声,只需提供电源即可。无源蜂鸣器,属于压电式蜂鸣器类型;有源蜂鸣器,属于电磁式蜂鸣器类型。这里说的有源,并不是指电源的意思,而是指蜂鸣器内部是否含有振荡电路,有源蜂鸣器内部自带振荡电路,只需提供电源即可发声,而无源蜂鸣器则需提供一定频率的脉冲信号才能发声,频率大小通常在 1.5-5KHz 之间。有源蜂鸣器实物如下图。
! f3 q' R. r4 T: f* k # r) u* D( M4 {
如果给有源蜂鸣器加一个 1.5-5KHz 的脉冲信号,同样也会发声,而且改变这个频率,就可以调节蜂鸣器音调,产生各种不同音色、音调的声音。如果改变输出电平的高低电平占空比,则可以改变蜂鸣器的声音大小。
" j2 v, R: ?* d6 {# n3 G
硬件设计 在前面我们已经对 STM32 的 GPIO 做了简单介绍,并且还使用了其中 IO 口直接控制开发板上的 LED。对于本章要实现蜂鸣器的控制,我们能否直接使用 STM32 的 IO 口驱动呢?根据 STM32F103 芯片数据手册可知, 单个 IO 口的最大输出电流是 25mA,而蜂鸣器的驱动电流是 30mA 左右,两者非常接近,有的朋友就想直接用 IO 口来驱动,但是有没有考虑到整个芯片的输出电流,整个芯片的输出电流最大也就 150mA,如果在驱动蜂鸣器上就耗掉了 30mA,那么 STM32 其他的 IO 口及外设电流就非常拮据了。所以我们不会直接使用 IO 口驱动蜂鸣器,而是通过三极管把电流放大后再驱动蜂鸣器,这样 STM32 的 IO 口只需要提供不到1mA 的电流就可控制蜂鸣器。所以我们也经常说到 STM32 芯片是用来做控制的,而不是驱动。开发板上的无源蜂鸣器模块电路原理图如下所示。
" c9 j* t% ?# L+ \& r! ~ & u+ E0 @' g& C: I5 L# Q: ^0 p# A. R
开发板上的有源蜂鸣器模块电路原理图如下所示。 ; _, q0 s9 X. k# L% E" y, z3 i
& K4 H( m5 k5 I; E+ A9 A' M
从这两个电路图可以看到, 无源蜂鸣器的控制需要给其一定频率的脉冲才能发声,仅给一个高电平或者低电平是不能发声的,因此蜂鸣器模块电路直接将STM32引脚接在NPN三极管的基极上, 然后三极管的发射极连接蜂鸣器,无需考虑外界对 PB5 脚产生的高低电平会对蜂鸣器发声干扰。如果使用的是有源蜂鸣器,它只要有电源就会发声,因此就必须考虑外界对 PB5 引脚电平的干扰问题。通过电阻 R06 和 PNP 三极管 TP6 进行电流放大,从而驱动蜂鸣器。电阻 R66 是一个上拉电阻, 用来防止蜂鸣器误发声。 当 PB5 引脚输出低电平时, PNP三极管导通,蜂鸣器发声;当 PB5 引脚输出高电平时,PNP 三极管截止,蜂鸣器停止发声。 8 m ]! K* H2 `3 i+ S1 E
软件设计 蜂鸣器初始化函数 打开工程中 beep.c 文件,里面代码如下: - #include "beep.h"
$ \2 _' `) d) s* V; [! h$ D - ! S- m$ l3 l2 e- k6 |7 u& \1 k
- /****************************************************************' @. B# W/ g# S) W5 _4 B3 _! Z
- b" W9 J# `9 M: V) J- ***************1 b( }9 O# r- ~
9 h& a) f/ e4 @" |0 O( O- * 函 数 名 : BEEP_Init
6 W- V% d) X V x7 e - 3 k% p- s; G2 ~9 V" q i+ e" Q5 h
- * 函数功能 : 蜂鸣器初始化: L% d& v) t- U3 [8 D/ t# n
) T* r* B/ U C4 e% d0 w7 [- * 输 入 : 无
9 b1 T; e% K6 k$ q4 h. e5 }% t
4 ^0 q4 @ A4 E4 j* z: F7 A3 c- * 输 出 : 无
* d" u, B( n1 m
/ ^& B( S, u4 G- ****************************************************************/
. A2 u: ?- `( j) ~9 g- ^- ` - & |, {0 T! G5 M+ |. G
- void BEEP_Init() //端口初始化& Z' V" R! v: W5 ?5 D
- & Z2 j( ~7 v! ^! `% M% S
- {7 m8 T/ O) ^; b) ~
i+ f& _$ N* X2 t& {* l5 J- GPIO_InitTypeDef GPIO_InitStructure; //声明一个结构体变量,用来初始化 GPIO
3 q/ x3 V5 T9 J( [& x/ y - 8 h8 u/ C% ]2 E7 j. X
- RCC_APB2PeriphClockCmd(BEEP_PORT_RCC,ENABLE); /* 开启 GPIO 时钟 */) ], L2 o! d$ a: K1 P( N# B3 l
- : S% V5 u1 q& t7 `6 K1 A- K
- /* 配置 GPIO 的模式和 IO 口 */
* e1 ?* }7 F. _" ^% h ]1 j - ; r' S& u$ z- }: G' j, b3 M# P
- GPIO_InitStructure.GPIO_Pin=BEEP_PIN; //选择你要设置的 IO口+ ~( E8 h- R; N- d) i, |3 B+ E" r
. G L/ f; B' v S" p# ?4 l- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //设置推挽输出模式
7 V5 M' r0 Q' Q* T
; k% L3 D0 X2 P; M$ c- GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //设置传输速率$ {' ~; L+ l$ o r" I& M
- % E, |# ?7 N. @6 \
- GPIO_Init(BEEP_PORT,&GPIO_InitStructure); /* 初始化 GPIO*/( O) }/ S. g+ l) Z/ j; b5 P' M
- 7 M3 c5 q4 l8 C7 E7 w
- }
复制代码
+ C- Z3 `0 `. C BEEP_Init()函数用来初始化蜂鸣器的端口及时钟,在函数内我们看到有几个参数不是库函数内的,比如 BEEP_PIN、BEEP_PORT、BEEP_PORT_RCC,这种情况一般是我们自己定义的宏,通常放在对应的头文件内,我们打开 beep.h,可以看到如下代码: - #ifndef _beep_H
|7 n0 j7 v* _/ o6 U* S$ ?8 D. G
o9 {+ p. l- x* C- #define _beep_H8 d1 z3 S( ?+ C1 \8 |& t/ k
J* m% `2 L/ A. N% ~, p7 o) @- #include "system.h"
! }2 C, J8 a% T
: @. U1 b7 n3 z9 e. t% B* {* U- /* 蜂鸣器时钟端口、引脚定义 */
+ z2 j8 u1 K2 j) ^
8 `% `# ]6 E! A3 K. ?/ R! Q- #define BEEP_PORT GPIOB3 }5 b, ~" E; W( i, }# |
3 _* l0 j7 O7 R0 y- #define BEEP_PIN GPIO_Pin_5
: s6 S" z5 a J. e5 Z1 V! _% x - 4 r* z# k# M% G s6 e
- #define BEEP_PORT_RCC RCC_APB2Periph_GPIOB
p& ~& F- r" j8 n* A( w% z$ d - + O! e0 F7 B" e+ W
- #define beep PBout(5)% k2 _/ w+ K* |) u2 `
6 u8 K; i# i& b+ J- void BEEP_Init(void);
( H; P. Y; p, x8 O# n9 `
( j( [6 v* A1 v8 v: U7 y6 K A6 g- #endif
复制代码 . t& R8 N* O4 w2 x+ Y
里面就将蜂鸣器的GPIO 端口及管脚进行了宏定义,这样做是方便大家移植程序,只需要对这个宏修改就能实现蜂鸣器的初始化修改。 7 B# W9 W" @( v+ k* w: L
主函数 我们打开工程中 main.c 文件,里面代码如下: - /****************************************************************
' z/ j: i R# M - . s8 C* [/ g Q" T; ^
- * 函 数 名 : main
7 C' L! n) X0 V' D; i - + u) A$ z3 X; r
- * 函数功能 : 主函数7 h: J( }: z v ~7 J+ o/ O
- F4 x7 q9 k; b. C3 W M- * 输 入 : 无! Q, s2 H8 X# G* e! W0 d- X* C
- ; S" _1 p, Z, c+ ~0 B' r8 _
- * 输 出 : 无
! ^2 A2 t1 {3 Q5 D+ C, T
# y# n& P; @3 N( F. _1 a+ q: ]- ****************************************************************/
* s/ H0 \8 l: e - 1 h+ `" K/ s8 J1 ^; a$ p
- int main()( ^* a! W3 l" _8 \
2 n& Y7 l7 ?- [4 m1 J- {
& |; A9 G4 b0 ~8 n
# X/ a" o( c& M! j0 J1 d- u16 i=0;) z9 ?8 \( `8 G2 s7 L
I7 k: P7 @+ D( s) l$ X5 [; V4 ^- SysTick_Init(72);% j5 }$ h( G% r
- 7 o3 {/ z% X0 T+ ^0 J) Y- ]
- LED_Init();
% [% {- r6 m, M, d- k9 {6 j - 4 V( Y [5 s8 Y, u; k
- BEEP_Init();
3 _$ C8 u6 q, ^ - / k0 N) I# j( y7 C0 N: W
- while(1)
3 T1 a; j, c1 m1 W
1 p( |! u5 h T/ i! Q' D* Q2 G' Y- {2 K6 A' `7 M. \$ {3 S& Z* i
. _, O& ~( S) T; [7 _$ Q8 V9 ]- i++;& f: B$ z3 i9 v s
; q( b. ^4 j+ x( a; P5 I- if(i%10==0)! X# h' n1 B0 H' q
- % I4 d6 f) P9 J, F
- {+ v; A1 d8 Y5 J7 ^7 l+ `3 L( _" f
# D. S. v: K, E+ t- beep=!beep;: `. l P8 p* f' ]$ I
- , ^: f @" h8 L& }. g
- }1 N. [. E# }4 T; n
3 d1 Q, R8 g' n, b- if(i%20000==0)
5 M2 B! p6 \! h* {: `- V+ y$ _
. {# L) b( l9 [2 k1 d2 ]+ J- {+ ~9 i U! J; h) z$ ~1 y
' y5 Q& _; u$ _4 e& B7 ?- led1=!led1;
& _! y3 t1 J% {' @6 V- A: {( }
0 s, y6 S/ D: r! M- }9 Q% ?( _# U: Q9 s. i* E ^# D
- 6 \5 J: q: L6 j
- delay_us(10);
4 \9 | x7 s( `7 J! x: @
7 }# T" `2 _. O! o- }
, n& L4 a7 r3 `& G
" l! T, a$ K$ m- s- }
复制代码
; J% d* N1 z& G8 _ 主函数实现的功能比较简单,首先将使用到的外设硬件进行初始化,然后进入 while 循环,间隔 100us 对蜂鸣器管脚电平翻转,这样就产生了一个频率为5KHz 的脉冲,因此无源蜂鸣器就会发声,当然有源蜂鸣器的控制可以更简单,只需要给它一个低电平即可,为了实现 2 块板子程序的兼容,这里就统一采用此种方式控制蜂鸣器。间隔 200ms 对 led1 管脚电平翻转,因为使用到了 delay_us延时函数,所以在 main 函数开始处就需要调用 SysTick_Init(72)初始化,这个在我们后面所有程序都会使用,后面就不重复。 将工程程序编译下载到开发板内,可以看到 D1 指示灯间隔 200ms 闪烁,蜂鸣器发声。
+ y- o9 A1 a7 M* D0 D( P/ z |