一、前言

很多刚入门 STM32 的同学做蜂鸣器实验时,会遇到蜂鸣器不响、常鸣、声音微弱、分不清有源 / 无源蜂鸣器的问题。本文基于 STM32F103C8T6,搭配高电平有效有源蜂鸣器模块+I2C OLED 显示屏,实现每隔 1 秒蜂鸣器鸣叫 / 停止切换,OLED 实时打印 GPIO 电平与蜂鸣器工作状态;同时补充三极管分立元件驱动电路原理,解决单片机 IO 口驱动能力不足、3.3V 控制 5V 负载电压衰减问题,硬件接线、原理、源码、实物调试全部讲透,新手可直接复刻。

视频讲解:STM32F103驱动有源蜂鸣器+OLED显示状态完整教程(含三极管驱动电路讲解)https://www.bilibili.com/video/BV1x4bD6ZE41/?share_source=copy_web&vd_source=91b967b41a17a5686913521545a8c3fb

实验实现效果

单片机 PA7 引脚周期性输出高低电平控制蜂鸣器,循环逻辑:

  1. PA7 输出高电平 → 蜂鸣器鸣叫 1s,OLED 显示 LEVEL:HIGH、BUZZER:ON
  2. PA7 输出低电平 → 蜂鸣器静音 1s,OLED 显示 LEVEL:LOW、BUZZER:OFF 无限循环切换,全程屏幕同步反馈引脚状态,直观观察 GPIO 输出逻辑。

二、硬件清单与接线说明

1. 所需器件

  • STM32F103C8T6 最小系统板
  • 有源蜂鸣器模块(高电平有效,带板载驱动)
  • 0.96 寸 I2C OLED 显示屏
  • S8050 NPN 三极管、1K 电阻 ×2、LED(拓展电路使用)
  • 杜邦线若干、3.3V/5V 直流电源

2. 模块直连单片机简易接线(推荐新手)

适用于自带驱动电路的有源蜂鸣器模块,无需额外三极管,接线极简:

外设模块引脚 STM32 引脚 功能说明
蜂鸣器 IN/S PA7 蜂鸣器控制信号,高电平触发鸣叫
蜂鸣器 VCC 3.3V/5V 按模块丝印供电,3.3V 模块接 3.3V,5V 模块接 5V
蜂鸣器 GND 开发板 GND 系统共地,必接!
OLED SCL PB8 I2C 时钟信号线
OLED SDA PB9 I2C 数据信号线
OLED VCC 3.3V OLED 供电,禁止接 5V 易烧屏
OLED GND 开发板 GND 屏幕共地

重点:为什么所有模块必须共地?

STM32 单片机识别高低电平是以自身 GND 作为电压参考基准。如果蜂鸣器、OLED 不与单片机共地,IO 输出的 3.3V/0V 电平无法被模块正确识别,会出现蜂鸣器不发声、持续乱响、OLED 花屏、显示错乱等故障,接线时所有 GND 必须连在一起。

3. 拓展:S8050 三极管分立驱动电路(解决 IO 驱动弱问题)

若使用无驱动裸蜂鸣器,或想用 3.3V 单片机控制 5V 蜂鸣器,需搭配 S8050 三极管搭建开关电路,电路连线逻辑:

  1. 单片机 PA7 → 1K 限流电阻 R1 → S8050 三极管基极 B
  2. 三极管集电极 C 接系统 VCC
  3. 三极管发射极 E 分两路并联负载:
    • 支路 1:1K 限流电阻 R2 + LED 正极,LED 负极接 GND
    • 支路 2:有源蜂鸣器正极,蜂鸣器负极接 GND

三、电路工作原理详解

3.1 成品有源蜂鸣器模块驱动原理(直接接 PA7 方案)

有源蜂鸣器内部集成振荡电路,不需要单片机输出 PWM 方波,仅靠直流高低电平即可控制启停:

  1. PA7 输出 0V 低电平:模块输入无效,内部振荡电路停止,蜂鸣器静音;
  2. PA7 输出 3.3V 高电平:模块输入有效,内置振荡器驱动发声元件持续振动,输出固定音调声响。

单片机将 PA7 配置为 50MHz 推挽输出模式,推挽输出可以主动拉至高电平、拉低至 0V,驱动模块输入引脚;程序中通过两个函数控制电平:

  • GPIO_SetBits (PA7):拉高引脚,蜂鸣器开启
  • GPIO_ResetBits (PA7):拉低引脚,蜂鸣器关闭

3.2 S8050 三极管射极跟随驱动电路原理

  1. PA7 输出高电平:基极获得电流,三极管导通,发射极输出电压(3.3V-0.7V≈2.6V),LED 点亮、蜂鸣器发声;
  2. PA7 输出低电平:基极无压差,三极管完全截止,发射极无电压输出,LED 熄灭、蜂鸣器停止。
电路缺陷与优化方案

该射极跟随电路存在电压压降问题:3.3V 单片机 IO 驱动 5V 蜂鸣器时,负载仅得到 2.6V 电压,蜂鸣器音量微弱。 优化方案:改用共射极低侧开关电路,将蜂鸣器、LED 放在 VCC 与三极管集电极之间,发射极直接接地,消除电压损耗,3.3V IO 可完美驱动 5V 负载。

3.3 有源蜂鸣器 VS 无源蜂鸣器核心区别

很多新手踩坑分不清两者,这里整理对比表:

对比项 有源蜂鸣器(本实验使用) 无源蜂鸣器
内部电路 自带振荡源 无振荡电路
控制方式 直流高低电平即可控制 必须定时器 PWM 方波驱动
恒定高电平效果 持续固定声音 仅 “咔” 一声,无法长鸣
音调修改 音调固定,无法软件调节 修改 PWM 频率即可变音
开发难度 简单,仅操作普通 GPIO 复杂,需配置定时器

四、STM32 GPIO 配置底层逻辑

  1. 开启外设时钟:操作 GPIOA 前必须开启 APB2 时钟,时钟相当于端口工作许可,不开时钟 IO 口完全失效;
  2. 引脚模式配置:PA7 配置为通用推挽输出,速度 50MHz;推挽输出兼具灌电流、拉电流能力,适合驱动外部模块;
  3. 初始化防误响设计:初始化函数中先拉低 PA7 电平,再配置输出模式,避免上电瞬间电平抖动导致蜂鸣器乱响;
  4. 状态翻转函数:读取引脚当前输出电平,自动反向输出,适合按键触发、循环报警场景。

五、完整源代码分区(可直接复制)

5.1 工程文件架构

程序分层设计,蜂鸣器驱动单独封装,方便其他项目复用:

  1. HARDWARE/BEEP/BEEP.h:引脚宏定义、函数声明
  2. HARDWARE/BEEP/BEEP.c:蜂鸣器初始化、开关、翻转底层函数
  3. USER/main.c:主逻辑、OLED 状态打印、1 秒循环切换逻辑

5.2 BEEP.h 头文件

#ifndef __BEEP_H
#define __BEEP_H

#include "stm32f10x.h"

/* 有源蜂鸣器连接到 PA7,引脚输出高电平时蜂鸣器鸣叫。 */
#define BEEP_GPIO_PORT       GPIOA
#define BEEP_GPIO_PIN        GPIO_Pin_7
#define BEEP_GPIO_CLK        RCC_APB2Periph_GPIOA

/* 初始化蜂鸣器 GPIO,初始化完成后蜂鸣器保持关闭。 */
void BEEP_Init(void);

/* PA7 输出高电平,开启蜂鸣器。 */
void BEEP_On(void);

/* PA7 输出低电平,关闭蜂鸣器。 */
void BEEP_Off(void);

/* 切换蜂鸣器当前状态。 */
void BEEP_Toggle(void);

#endif

5.3 BEEP.c 驱动文件

#include "BEEP.h"

void BEEP_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	/* 开启 GPIOA 外设时钟。 */
	RCC_APB2PeriphClockCmd(BEEP_GPIO_CLK, ENABLE);

	/* 配置输出模式前先将输出寄存器置低,避免初始化时蜂鸣器误响。 */
	GPIO_ResetBits(BEEP_GPIO_PORT, BEEP_GPIO_PIN);

	/* 将 PA7 配置为 50 MHz 通用推挽输出。 */
	GPIO_InitStructure.GPIO_Pin = BEEP_GPIO_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(BEEP_GPIO_PORT, &GPIO_InitStructure);

	/* 初始化结束后确保蜂鸣器处于关闭状态。 */
	BEEP_Off();
}

void BEEP_On(void)
{
	/* 有源蜂鸣器为高电平有效,PA7 置高后开始鸣叫。 */
	GPIO_SetBits(BEEP_GPIO_PORT, BEEP_GPIO_PIN);
}

void BEEP_Off(void)
{
	/* PA7 输出低电平,蜂鸣器停止鸣叫。 */
	GPIO_ResetBits(BEEP_GPIO_PORT, BEEP_GPIO_PIN);
}

void BEEP_Toggle(void)
{
	/* 读取 PA7 的输出状态,并切换为相反电平。 */
	if(GPIO_ReadOutputDataBit(BEEP_GPIO_PORT, BEEP_GPIO_PIN) == Bit_RESET)
	{
		BEEP_On();
	}
	else
	{
		BEEP_Off();
	}
}

5.4 main.c 主程序逻辑

/* Active buzzer and OLED teaching demonstration for STM32F103C8T6. */
#include "delay.h"
#include "oled.h"
#include "BEEP.h"

#define BEEP_STATE_TIME_MS   1000U

static void BEEP_ShowState(u8 is_on);

int main(void)
{
	delay_init();
	BEEP_Init();
	OLED_Init();
	OLED_ColorTurn(0);
	OLED_DisplayTurn(0);

	while(1)
	{
		BEEP_On();
		BEEP_ShowState(1U);
		delay_ms(BEEP_STATE_TIME_MS);

		BEEP_Off();
		BEEP_ShowState(0U);
		delay_ms(BEEP_STATE_TIME_MS);
	}
}

static void BEEP_ShowState(u8 is_on)
{
	OLED_Clear();
	OLED_ShowString(0, 0, (u8 *)"ACTIVE BEEP", 16);
	OLED_ShowString(0, 18, (u8 *)"PIN: PA7", 16);

	if(is_on != 0U)
	{
		OLED_ShowString(0, 36, (u8 *)"LEVEL: HIGH", 16);
		OLED_ShowString(0, 52, (u8 *)"BUZZER: ON", 12);
	}
	else
	{
		OLED_ShowString(0, 36, (u8 *)"LEVEL: LOW", 16);
		OLED_ShowString(0, 52, (u8 *)"BUZZER: OFF", 12);
	}

	OLED_Refresh();
}

代码修改拓展说明

修改宏定义 BEEP_STATE_TIME_MS 即可调整鸣叫节奏:

  • 改为 500:0.5 秒切换一次,急促滴滴声
  • 改为 2000:2 秒切换一次,慢速间歇报警 有源蜂鸣器无法通过代码修改音调,想要播放音乐需要更换无源蜂鸣器,增加定时器 PWM 驱动代码。

六、实物演示与调试章节

6.1 实物接线步骤

  1. 按照上文接线表,先连接所有 GND 共地线路,再依次接 OLED、蜂鸣器信号线;
  2. 给开发板上电,观察上电瞬间蜂鸣器无短促异响(初始化拉低电平生效);
  3. 屏幕点亮,第一帧显示LEVEL:LOW、BUZZER:OFF,等待 1 秒自动切换状态;
  4. 蜂鸣器交替鸣叫、静音,屏幕文字同步变化,无延迟。

6.2 万用表实测验证方法

调试时可用万用表直流电压档测量 PA7 引脚电压,验证软硬件一致性:

  1. OLED 显示 HIGH 时,PA7 电压≈3.3V;
  2. OLED 显示 LOW 时,PA7 电压≈0V; 若电压和屏幕显示不匹配,排查 GPIO 初始化、接线虚焊问题。

6.3 常见故障排查表

故障现象 排查原因 解决办法
蜂鸣器完全不响 接线漏接 GND、VCC 供电错误、PA7 虚焊 重新核对所有地线,确认蜂鸣器供电电压
上电一直长鸣 模块为低电平有效、引脚接错 修改 BEEP_On/BEEP_Off 电平逻辑,更换控制引脚测试
OLED 正常,蜂鸣器声音微弱 3.3V IO 直驱 5V 蜂鸣器,电压压降 加装三极管共射驱动电路,或更换 3.3V 蜂鸣器模块
屏幕状态和蜂鸣器声音相反 模块有效电平与代码逻辑冲突 互换 BEEP_On、BEEP_Off 内部高低电平操作
修改延时参数,音调无变化 当前使用有源蜂鸣器 更换无源蜂鸣器,新增定时器 PWM 驱动代码

七、总结

  1. 本实验使用有源蜂鸣器,仅需普通 GPIO 高低电平控制,无需 PWM,开发门槛低;
  2. 硬件接线核心要点:全部外设与 STM32 共地,蜂鸣器供电严格匹配模块额定电压;
  3. 三极管射极跟随电路可拓展驱动大功率负载,但存在电压损耗,3.3V 控 5V 负载推荐改用共射开关电路;
  4. 分层封装蜂鸣器驱动代码,配合 OLED 实时状态打印,方便直观调试 GPIO 输出逻辑;
  5. 想要实现多音调、音乐播放,必须替换无源蜂鸣器,搭配定时器输出不同频率方波驱动。
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐