蜂鸣器实验$ \6 l# [: B7 k L8 K( m/ n; V
本章,我们将通过另外一个例子继续讲述STM32H7的IO口作为输出的使用,不同的是本章讲的不是用IO口直接驱动器件,而是通过三极管间接驱动。我们将利用一个IO口来控制板载的有源蜂鸣器。5 K6 V1 k; \+ `0 ^$ w
$ q8 ?% B, }. d: p; t: o
14.1 蜂鸣器简介
2 u% ?. f2 Q! x5 Y+ q/ G! I蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件。蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型。
$ E4 ]7 D; h3 F. L0 A; L; BMiniPRO STM32H750开发板板载的蜂鸣器是电磁式的有源蜂鸣器,如图14.1.1所示:- g( b: e5 M) h$ H6 |6 B, }! v/ F
: P# z/ a- J/ q2 T# q
( [& ~: E5 Z+ O e( k9 q' B
& W1 I- ]8 t$ Z0 R2 {
图14.1.1 有源蜂鸣器% i1 V) T. ~* ?* j
这里的有源不是指电源的 “源”,而是指有没有自带震荡电路,有源蜂鸣器自带了震荡电路,一通电就会发声;无源蜂鸣器则没有自带震荡电路,必须外部提供2~5Khz左右的方波驱动,才能发声。7 \' u6 u* T) I! x4 P M" N! H' V( J
上一章,我们利用STM32的IO口直接驱动RGB灯,本章的蜂鸣器,我们能否直接用STM32的IO口驱动呢?让我们来分析一下:STM32H7的单个IO最大可以提供25mA电流(来自数据手册),而蜂鸣器的驱动电流是30mA左右,两者十分相近,但是全盘考虑,STM32H7整个芯片的电流,最大也就150mA,如果用IO口直接驱动蜂鸣器,其他地方用电就得省着点了,所以我们不用STM32H7的IO直接驱动蜂鸣器,而是通过三极管扩流后再驱动蜂鸣器,这样STM32H7的IO只需要提供不到1mA的电流就足够了。- e2 n$ `0 C4 f9 F1 Q
IO口使用虽然简单,但是和外部电路的匹配设计,还是要十分讲究的,考虑越多,设计就越可靠,可能出现的问题也就越少。( `& b7 j Q. \. p
9 W7 o! f& j! @5 C
14.2 硬件设计+ O6 d& q* k1 Q3 |
1.例程功能
$ [. O) B/ t& D蜂鸣器每隔300ms响或者停一次。LED0每隔300ms亮或者灭一次。LED0亮的时候蜂鸣器不叫,而LED0熄灭的时候,蜂鸣器叫。6 D, O1 j' }% d: a
2.硬件资源$ c7 ]7 h" [) Y- Z
1)RGB灯; |2 I1 M( A; N0 Y7 m6 |
LEDR : LED0 - PB4(红)$ W5 v0 [) r* C: ~/ S
2)蜂鸣器
; C N! G/ O/ p3 s* o) mBEEP(PE4)
1 j/ U/ T' u8 U3 Q0 h3.原理图
% g1 _5 `, e; Q7 s8 A+ k( W5 [蜂鸣器在硬件上是直接连接好了的,不需要经过任何设置,直接编写代码就可以了。蜂鸣器的驱动信号连接在STM32H7的PE4上。如图14.2.1所示:5 A# x# ?7 B6 {* c& m$ E8 E" e
5 U3 |7 ]; ]8 R$ w4 G8 X+ b
: W! Y2 \0 e0 }图14.2.1 蜂鸣器与STM32H7连接原理图# D) U; V% _8 t
图中我们用到一个NPN三极管(S8050)来驱动蜂鸣器,R30主要用于防止蜂鸣器的误发声。驱动信号通过R29和R30间的电压获得,芯片上电时默认电平为低电平,故上电时蜂鸣器不会直接响起。当PE4输出高电平的时候,蜂鸣器将发声,当PE4输出低电平的时候,蜂鸣器停止发声。
2 O( f4 s; C) q- U/ Q; s5 Y0 L& M6 ]; F$ P4 y2 d, M d
14.3 程序设计1 ]$ `" u( |6 C# U* W5 ~5 d4 j5 `
本实验我们只是用到GPIO外设输出功能,关于HAL库的GPIO的API函数请看跑马灯实验的介绍。下面我们直接分析本实验的程序流程图。0 g+ d' z) D3 X6 {1 F% e
14.3.1 程序流程图
* }5 r$ T2 n4 ^( ^& u. s
- [6 G# \$ p1 T" a
3 j* {. o- O) o. B0 |/ F: [$ L
& x. D. v4 Y3 a% @1 V图14.3.1.1 蜂鸣器实验程序流程图
, H8 b0 p# r5 q2 |9 R% T6 @$ L: p1 y7 W" X& C; H0 @
14.3.2 程序解析
) T$ K) l% @7 |9 s0 Z4 {2 L1.蜂鸣器驱动代码" O5 M: S8 ~6 b9 J' f
这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。蜂鸣器(BEEP)驱动源码包括两个文件:beep.c和beep.h。3 J, @: n' X9 ` D" \! y
下面我们先解析beep.h的程序,我们把它分两部分功能进行讲解。9 r; A* i; a* w p5 |3 J8 \' J6 _
由硬件设计小节,我们知道驱动蜂鸣器的三极管在硬件上连接到PE4,我们做了下面的引脚定义。9 ~2 J- N5 d; j% {* D
- /*****************************************************************************/
: @& C, _: T& v' d& |* c - /* 引脚 定义 */
4 x6 r, j3 x% q4 t0 I& s$ |* p
% V" ?/ s4 c) K' O+ t9 E- #define BEEP_GPIO_PORT GPIOE
+ t* {% U" _# ]3 e1 R - #define BEEP_GPIO_PIN GPIO_PIN_4
3 G' p$ Y& v: Z6 j+ k4 a% Y$ M - /* PE口时钟使能 */& e% l0 H7 O8 z, h
- #define BEEP_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0)! B- l2 `4 @: t0 ~; i
- /*****************************************************************************/9 O- z/ b4 _% P( E, e2 F2 U+ @
- 可以看到这样定义跟跑马灯实验的是类似。8 h7 ^6 M# z% F+ f
- 为了后续对蜂鸣器进行便捷的操作,我们为蜂鸣器操作函数做了下面的定义。" F2 U- c% v3 V# ]' U A7 O8 m( e
- /* 蜂鸣器控制 */
, R' j. |& y8 l0 z" | - #define BEEP(x) do{ x ? \
. L" K3 @. A& n1 h - HAL_GPIO_WritePin(BEEP_GPIO_PORT,
8 M" g! l8 b' @: W0 A - BEEP_GPIO_PIN, GPIO_PIN_SET) : \
+ v9 A4 H2 a: v2 G7 c - HAL_GPIO_WritePin(BEEP_GPIO_PORT, 8 y' K* g4 C* f$ }9 j/ b6 Z
- BEEP_GPIO_PIN, GPIO_PIN_RESET); \
0 z3 w, }4 Q V6 G# R0 s - }while(0)
! g& ], @: |$ K6 k8 ^2 S( e% R - u: M# ~6 i: M3 R: n% K
- /* 蜂鸣器取反控制 */
. u! q- i* }! r% ` - #define BEEP_TOGGLE() do{ HAL_GPIO_TogglePin(BEEP_GPIO_PORT,
' K8 g' i1 V% | - BEEP_GPIO_PIN); }while(0) /* BEEP = !BEEP */ j" N# g% o2 l* u
- BEEP(x)这个宏定义就是控制蜂鸣器的打开和关闭的。例如:如果要打开蜂鸣器,那么调用宏定义BEEP(1)即可,如果要关闭蜂鸣器,调用宏定义BEEP(0)即可。
! W7 r1 C1 o) O2 A9 q5 c$ v2 n - BEEP_TOGGLE()是控制蜂鸣器进行翻转的。这里也利用HAL_GPIO_TogglePin函数实现IO口输出电平取反操作。
, x F2 L- _# e - 下面我们再解析beep.c的程序,这里只有一个函数beep_init,这是蜂鸣器的初始化函数,其定义如下:! n+ p+ N' X7 u* @4 H) ^5 w* {5 ]
- /** s; e4 N( F& U5 O- ^# n0 v7 A4 K
- * @brief 初始化BEEP相关IO口, 并使能时钟- t% V1 Z4 V2 G+ W6 `! t
- * @param 无4 r @( i& c. X% A" f+ s
- * @retval 无, ]" y3 j9 J, u$ J, `- @
- */7 W9 g4 `- Y! Y1 u8 K' u0 I
- void beep_init(void)
) A# C$ J' I8 e - {' ]8 \! ^3 Y$ m2 P }' K
- GPIO_InitTypeDef gpio_init_struct;% @5 B& z4 b3 C: J
- BEEP_GPIO_CLK_ENABLE(); /* BEEP时钟使能 */
" G# }! W3 H3 r4 S/ x& m: }2 S - ' P% t& ^ b; ]- v5 L# B
- gpio_init_struct.Pin = BEEP_GPIO_PIN; /* 蜂鸣器引脚 */
$ L& l" i1 T0 n8 q( _& r1 y - gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */ _6 h* ^3 f+ D9 G- g
- gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
: E; _# {6 Q3 K* f - gpio_init_struct.Speed = GPIO_SPEED_FREQ_MEDIUM; /* 中速 */
4 g5 }9 ?5 m! k- X4 T# V4 U - HAL_GPIO_Init(BEEP_GPIO_PORT, &gpio_init_struct); /* 初始化蜂鸣器引脚 */3 U$ r8 ]; v5 Y/ @
+ e# X. i, {) w0 ?( v- BEEP(0); /* 关闭蜂鸣器 */
/ r5 h* s0 J: e - }
复制代码 5 I/ M/ x* Y6 H
对蜂鸣器的引脚设置为中速上拉的推挽输出。最后关闭关闭蜂鸣器,防止没有操作就响了。
' q3 V3 _2 E; a. R! I2. main.c代码
4 y3 X' k& j$ ^* p' F在main.c里面编写如下代码:2 x$ D9 _4 |9 @! P8 P0 I2 P
! z9 N; }* h' M: p- #include "./SYSTEM/sys/sys.h"" M5 z: p+ m+ B& w; r) ]
- #include "./SYSTEM/usart/usart.h", x1 C1 {( O6 g8 a
- #include "./SYSTEM/delay/delay.h"
# P$ p# c! O4 X! q - #include "./BSP/LED/led.h"2 [; R& k5 l( [1 b
- #include "./BSP/BEEP/beep.h"
# h% E% k+ P3 y+ f7 r
* o/ E! N* J/ G8 d J K4 {- int main(void)5 K6 ?9 f6 N' e
- {7 `: t( e( [* [- s: r
- sys_cache_enable(); /* 打开L1-Cache */
3 O4 ^- N9 R8 L - HAL_Init(); /* 初始化HAL库 */0 I8 S7 b; {: W C. Z
- sys_stm32_clock_init(240, 2, 2, 4); /* 设置时钟, 480Mhz */- ~9 l* e; } N z) d, i- x, ?
- delay_init(480); /* 延时初始化 */7 c/ @. L2 Z4 v3 Z0 _) n
- led_init(); /* 初始化LED */
+ m/ X( P) i( W+ W! O/ ~5 j+ J% g - beep_init(); /* 初始化蜂鸣器 */9 n* ?8 p3 H5 s6 z3 P0 d
" s/ `. q. S( {. Y- while (1)
! {) B6 {/ T( L - {4 w y6 _% y6 ?( L8 i+ E& t
- LED0(0);9 R" [0 ? R& ~4 B# A: l
- BEEP(0);
& n% _& s" V: J( ^2 Q) S - delay_ms(300);" p. T D; ~1 A" d+ `! ^5 s2 L' h
- LED0(1);0 ^3 X3 X" [% ^: C) T: f
- BEEP(1);
. m; U# {) T7 [) b3 P - delay_ms(300);& n! C. i! h6 S
- }( @. P% J! h5 W+ h
- }
复制代码 8 W% s5 Y) w; O/ [/ S8 {- z6 y
首先是调用系统级别的初始化:sys_cache_enable函数使能I-Cache和D-Cache,然后初始化 HAL库、系统时钟和延时函数。接下来,调用led_init来初始化RGB灯,调用beep_init函数初始化蜂鸣器。最后在无限循环里面实现LED0和蜂鸣器间隔300ms交替闪烁和打开关闭一次。
0 s5 _3 p6 {2 J8 {. B8 i8 X, T/ l+ l- M# r% r# j2 f/ F
14.4 下载验证
8 t+ f$ e& S/ P* z: @& v' i* Z下载完之后,可以看到LED0亮的时候蜂鸣器不叫,而LED0熄灭的时候,蜂鸣器叫(因为他们的有效信号相反)。间隔为0.3秒左右,符合预期设计。 ?. A: ~& K. \
至此,本章的学习就结束了。通过本章,我们进一步学习IO作为输出的使用方法,同时巩固了前面知识的学习。希望大家在开发板上实际验证一下,从而加深印象。
9 |1 r0 J: l0 G' S" Y* @————————————————
% R5 Y6 J0 _0 r; z( B) D& M版权声明:正点原子( o- @# i2 I: c Q' V+ u' Y1 b+ D7 A
" B# d) L8 C4 V# e" j$ q! V% m0 f U, M( f3 W& X
|