最新教程下載:http://www.armbbs.cn/forum.php?mod=viewthread&tid=93255
第20章 STM32F407的GPIO應用之無源蜂鳴器
本章教程為大家介紹STM32F407的GPIO應用之無源蜂鳴器,蜂鳴器也是GPIO控制的經典測試例程,可以讓大家對STM32F407應用有個簡單的整體認識。
20.1 初學者重要提示
20.2 蜂鳴器硬件設計
20.3 蜂鳴器軟件驅動設計
20.4 蜂鳴器板級支持包(bsp_beep.c)
20.5 蜂鳴器驅動移植和使用(裸機版)
20.6 使用例程設計框架
20.7 實驗例程說明(MDK)
20.8 實驗例程說明(IAR)
20.9 總結
20.1 初學者重要提示
- 學習本章節前,務必保證已經學習了第13,14和15章。
- 注意有源蜂鳴器和無源蜂鳴器的區別,本章教程的17.2.1小節有專門說明。
- 開發板是采用的無源蜂鳴器,需要PWM驅動,而截至本章節還沒有講到PWM,會在第XX章節專門為大家講解(更新到相應章節時再添),程序中是通過一個宏定義控制使能和關閉,所以對於初學者來說,當前階段僅需了解到使能和關閉方法即可,后面學習到PWM章節了,再深入了解。
- 無源蜂鳴器的控制采用的非阻塞方式,實際項目中比較實用。
20.2 蜂鳴器硬件設計
蜂鳴器的硬件設計如下:
通過這個硬件設計,有如下兩點需要學習:
20.2.1 蜂鳴器分類
蜂鳴器主要有電磁式和電壓式兩種,而且都有無源蜂鳴器和有源蜂鳴器兩類。開發板使用的是電磁式無源蜂鳴器,而有源和無源的區別是有源蜂鳴器內部自帶振盪器,給個電壓就能發聲,但頻率是固定的,只能發出一種聲音,而無源蜂鳴器頻率可控,給個方波才可以發聲,並且根據不同頻率發出不同的聲音效果。
拓展知識
關於有源蜂鳴器和無源蜂鳴器區別:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=89764 。
20.2.2 硬件設計
關於硬件驅動,這里主要有三點需要大家認識到:
- S8050TL1是NPN型三極管,這里是當開關使用,PA8輸出高電平的時候三極管導通,輸出低電平,三極管關閉。
- 電阻R70起到限流的作用。
- 電阻R47在這里有特別的作用,首先要普及一個知識點,這里使用的是電磁式蜂鳴器,屬於感性負載,切斷這種負載必須要注意,如果電流消失,電感兩端的電壓將急劇上升,這種感應沖擊足以損壞邏輯門電路或者其它形式的負載驅動電路,為了保護這個電路,可以用一個二極管或者電阻吸收感應沖擊。
拓展知識
STM32的GPIO控制三極管驅動各種負載的安全措施和注意事項:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=89776 。
20.3 蜂鳴器軟件驅動設計
軟件驅動對有源蜂鳴器和無源蜂鳴器都做了支持,默認情況下用的是無源蜂鳴器。我們使用蜂鳴器的話,大部分情況下可以配置鳴叫次數、鳴叫的時間和停止的時間。本驅動設計就是基於這種應用方式實現,基本可以滿足大部分應用情況。
設計這個軟件驅動的關鍵之處是如何避免采用阻塞式的實現方式,比如要實現鳴叫1秒,停止1秒,循環5次,如果是阻塞方式等待1秒執行完畢,那就時間太長了。鑒於這種情況,程序里面實現了一種非阻塞的方式,通過滴答定時器中斷每10ms調用一次蜂鳴器處理函數來實現鳴叫次數、鳴叫的時間和停止的時間的更新。
20.4 蜂鳴器板級支持包(bsp_beep.c)
蜂鳴器驅動文件bsp_beep.c主要實現了如下幾個API:
- BEEP_InitHard
- BEEP_Start
- BEEP_Stop
- BEEP_Pause
- BEEP_Resume
- BEEP_KeyTone
- BEEP_Pro
這里我們重點講解函數BEEP_InitHard、BEEP_Sart和BEEP_Pro。
函數BEEP_Stop、BEEP_Pause和BEEP_Resume測試效果不夠好,推薦直接使用BEEP_Sart即可,設置鳴叫時間、停止鳴叫時間和循環次數。而BEEP_KeyTone是基於BEEP_Start實現的,直接調用的BEEP_Start(5, 1, 1); /* 鳴叫50ms,停10ms, 1次 */
20.4.1 宏定義設置
此文件的開頭有一個宏定義選擇,用戶可以選擇使用有源蜂鳴器或者無源蜂鳴器。
//#define BEEP_HAVE_POWER /* 定義此行表示有源蜂鳴器,直接通過GPIO驅動, 無需PWM */ #ifdef BEEP_HAVE_POWER /* 有源蜂鳴器 */ /* PA8 */ #define GPIO_RCC_BEEP RCC_AHB1Periph_GPIOA #define GPIO_PORT_BEEP GPIOA #define GPIO_PIN_BEEP GPIO_Pin_8 #define BEEP_ENABLE() GPIO_PORT_BEEP->BSRRL = GPIO_PIN_BEEP /* 使能蜂鳴器鳴叫 */ #define BEEP_DISABLE() GPIO_PORT_BEEP->BSRRH = GPIO_PIN_BEEP /* 禁止蜂鳴器鳴叫 */ #else /* 無源蜂鳴器 */ /* PA8 ---> TIM1_CH1 */ /* 1500表示頻率1.5KHz,5000表示50.00%的占空比 */ #define BEEP_ENABLE() bsp_SetTIMOutPWM(GPIOA, GPIO_Pin_8, TIM1, 1, 1500, 5000); /* 禁止蜂鳴器鳴叫 */ #define BEEP_DISABLE() bsp_SetTIMOutPWM(GPIOA, GPIO_Pin_8, TIM1, 1, 1500, 0); #endif
- 使能了宏定義BEEP_HAVE_POWER就可以選擇使用有源蜂鳴器,默認是無源的。
- 使用無源蜂鳴器時,需要用到定時器的PWM功能,這個功能會在XX章節專門講解(制作到相應章節時再補充),這里僅需只知道配置了一個PWM來驅動蜂鳴器即可。
20.4.2 蜂鳴器結構體變量
為了方便蜂鳴器的控制,專門封裝了一個結構體變量:
typedef struct _BEEP_T { uint8_t ucEnalbe; uint8_t ucState; uint16_t usBeepTime; uint16_t usStopTime; uint16_t usCycle; uint16_t usCount; uint16_t usCycleCount; uint8_t ucMute; }BEEP_T;
- 成員ucEnalbe:用於使能或者禁止蜂鳴器。
- 成員ucState:狀態變量,用於蜂鳴器鳴叫和停止的區分。
- 成員usBeepTime:鳴叫時間,單位10ms。
- 成員usStopTime:停止鳴叫時間,單位10ms。
- 成員usCycle:鳴叫和停止的循環次數。
- 成員usCount:用於鳴叫和停止時的計數。
- 成員usCycleCount:用於循環次數計數。
- 成員ucMute:用於靜音。
20.4.3 函數BEEP_InitHard
函數原型:
/* ********************************************************************************************************* * 函 數 名: BEEP_InitHard * 功能說明: 初始化蜂鳴器硬件 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void BEEP_InitHard(void) { #ifdef BEEP_HAVE_POWER /* 有源蜂鳴器 */ GPIO_InitTypeDef GPIO_InitStructure; /* 打開GPIOF的時鍾 */ RCC_AHB1PeriphClockCmd(GPIO_RCC_BEEP, ENABLE); BEEP_DISABLE(); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; /* 設為輸出口 */ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; /* 設為推挽模式 */ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; /* 上下拉電阻不使能 */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /* IO口最大速度 */ GPIO_InitStructure.GPIO_Pin = GPIO_PIN_BEEP; GPIO_Init(GPIO_PORT_BEEP, &GPIO_InitStructure); #endif g_tBeep.ucMute = 0; /* 關閉靜音 */ }
函數描述:
此函數主要用於蜂鳴器的初始化,代碼比較好理解。條件編譯實現了一個無源蜂鳴器的初始化,配置引腳為推挽輸出模式。由於V6開發板使用的無源蜂鳴器,所有沒有開啟宏定義BEEP_HAVE_POWER。
使用舉例:
底層驅動初始化直接在bsp.c文件的函數bsp_Init里面調用即可。
20.4.4 函數BEEP_Start
函數原型:
/* ********************************************************************************************************* * 函 數 名: BEEP_Start * 功能說明: 啟動蜂鳴音。 * 形 參: _usBeepTime : 蜂鳴時間,單位10ms; 0 表示不鳴叫 * _usStopTime : 停止時間,單位10ms; 0 表示持續鳴叫 * _usCycle : 鳴叫次數, 0 表示持續鳴叫 * 返 回 值: 無 ********************************************************************************************************* */ void BEEP_Start(uint16_t _usBeepTime, uint16_t _usStopTime, uint16_t _usCycle) { if (_usBeepTime == 0 || g_tBeep.ucMute == 1) { return; } g_tBeep.usBeepTime = _usBeepTime; g_tBeep.usStopTime = _usStopTime; g_tBeep.usCycle = _usCycle; g_tBeep.usCount = 0; g_tBeep.usCycleCount = 0; g_tBeep.ucState = 0; g_tBeep.ucEnalbe = 1; /* 設置完全局參數后再使能發聲標志 */ BEEP_ENABLE(); /* 開始發聲 */ }
函數描述:
此函數主要用於蜂鳴器的初始化,代碼比較好理解。條件編譯實現了一個無源蜂鳴器的初始化,配置引腳為推挽輸出模式。由於V6開發板使用的無源蜂鳴器,所有沒有開啟宏定義BEEP_HAVE_POWER。
函數參數:
- 第1個參數_usBeepTime用於設置蜂鳴時間,單位10ms,配置為0 表示不鳴叫。
- 第2個參數_usStopTime用於設置蜂鳴時間,單位10ms,配置為0 表示不鳴叫。
- 第3個參數_ _usCycle用於鳴叫次數,配置為0 表示持續鳴叫。
使用舉例:
調用此函數前,務必優先調用函數BEEP_InitHard進行初始化。比如要實現鳴叫50ms,停10ms, 1次,就是BEEP_Start(5, 1, 1);
20.4.5 函數BEEP_Pro
函數原型:
/* ********************************************************************************************************* * 函 數 名: BEEP_Pro * 功能說明: 每隔10ms調用1次該函數,用於控制蜂鳴器發聲。該函數在 bsp_timer.c 中被調用。 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void BEEP_Pro(void) { if ((g_tBeep.ucEnalbe == 0) || (g_tBeep.usStopTime == 0) || (g_tBeep.ucMute == 1)) { return; } if (g_tBeep.ucState == 0) { if (g_tBeep.usStopTime > 0) /* 間斷發聲 */ { if (++g_tBeep.usCount >= g_tBeep.usBeepTime) { BEEP_DISABLE(); /* 停止發聲 */ g_tBeep.usCount = 0; g_tBeep.ucState = 1; } } else { ; /* 不做任何處理,連續發聲 */ } } else if (g_tBeep.ucState == 1) { if (++g_tBeep.usCount >= g_tBeep.usStopTime) { /* 連續發聲時,直到調用stop停止為止 */ if (g_tBeep.usCycle > 0) { if (++g_tBeep.usCycleCount >= g_tBeep.usCycle) { /* 循環次數到,停止發聲 */ g_tBeep.ucEnalbe = 0; } if (g_tBeep.ucEnalbe == 0) { g_tBeep.usStopTime = 0; return; } } g_tBeep.usCount = 0; g_tBeep.ucState = 0; BEEP_ENABLE(); /* 開始發聲 */ } } }
函數描述:
此函數是蜂鳴器的主處理函數,用於實現鳴叫時間、停止鳴叫時間和循環次數的處理。
使用舉例:
調用此函數前,務必優先調用函數BEEP_InitHard進行初始化。
另外,此函數需要周期性調用,每10ms調用一次。
- 如果是裸機使用,將此函數放在bsp.c文件的bsp_RunPer10ms函數里面即可,這個函數是由滴答定時器調用的,也就是說,大家要使用蜂鳴器,定時器的初始化函數bsp_InitTimer一定要調用。
- 如果是RTOS使用,需要開啟一個10ms為周期的任務調用函數BEEP_Pro。
20.5 蜂鳴器驅動移植和使用
按鍵移植步驟如下:
- 第1步:復制bsp_beep.c,bsp_beep.h,bsp_tim_pwm.c和bsp_tim_pwm.h到自己的工程目錄,並添加到工程里面。
- 第2步:根據自己使用的蜂鳴器驅動引腳和頻率,修改下面的宏定義即可
#ifdef BEEP_HAVE_POWER /* 有源蜂鳴器 */ /* PA8 */ #define GPIO_RCC_BEEP RCC_AHB1Periph_GPIOA #define GPIO_PORT_BEEP GPIOA #define GPIO_PIN_BEEP GPIO_PIN_8 #define BEEP_ENABLE() GPIO_PORT_BEEP->BSRRL = GPIO_PIN_BEEP /* 使能蜂鳴器鳴叫 */ #define BEEP_DISABLE() GPIO_PORT_BEEP->BSRRH = GPIO_PIN_BEEP /* 禁止蜂鳴器鳴叫 */ #else /* 無源蜂鳴器 */ /* PA0 ---> TIM5_CH1 */ /* 1500表示頻率1.5KHz,5000表示50.00%的占空比 */ #define BEEP_ENABLE() bsp_SetTIMOutPWM(GPIOA, GPIO_PIN_0, TIM5, 1, 1500, 5000); /* 禁止蜂鳴器鳴叫 */ #define BEEP_DISABLE() bsp_SetTIMOutPWM(GPIOA, GPIO_PIN_0, TIM5, 1, 1500, 0); #endif
- 第3步:這幾個驅動文件主要用到HAL庫的GPIO和TIM驅動文件,簡單省事些可以添加所有HAL庫.C源文件進來。
- 第4步,應用方法看本章節配套例子即可。
特別注意,別忘了每10ms調用一次按鍵檢測函數BEEP_Pro()。
20.6 實驗例程設計框架
通過程序設計框架,讓大家先對配套例程有一個全面的認識,然后再理解細節,本次實驗例程的設計框架如下:
第1階段,上電啟動階段:
- 這部分在第14章進行了詳細說明。
第2階段,進入main函數:
- 第1部分,硬件初始化,主要是HAL庫,系統時鍾,滴答定時器,蜂鳴器等。
- 第2部分,應用程序設計部分,實現了一個蜂鳴器應用。
- 第3部分,蜂鳴器程序每10ms在滴答定時中斷執行一次。
20.7 實驗例程說明(MDK)
配套例子:
V5-004_無源蜂鳴器
實驗目的:
- 學習無源蜂鳴器的控制實現。
實驗內容:
- 啟動一個自動重裝軟件定時器,每100ms翻轉一次LED2。
實驗操作:
- K1鍵按下,按鍵提示音(固定頻率1.5KHz)。
- K2鍵按下,急促鳴叫10次。
- K3鍵按下,長鳴3次。
上電后串口打印的信息:
波特率 115200,數據位 8,奇偶校驗位無,停止位 1
程序設計:
系統棧大小分配:
硬件外設初始化
硬件外設的初始化是在 bsp.c 文件實現:
/* ********************************************************************************************************* * 函 數 名: bsp_Init * 功能說明: 初始化所有的硬件設備。該函數配置CPU寄存器和外設的寄存器並初始化一些全局變量。只需要調用一次 * 形 參:無 * 返 回 值: 無 ********************************************************************************************************* */ void bsp_Init(void) { /* STM32H429 HAL 庫初始化,此時系統用的還是F407自帶的16MHz,HSI時鍾: - 調用函數HAL_InitTick,初始化滴答時鍾中斷1ms。 - 設置NVIV優先級分組為4。 */ HAL_Init(); /* 配置系統時鍾到168MHz - 切換使用HSE。 - 此函數會更新全局變量SystemCoreClock,並重新配置HAL_InitTick。 */ SystemClock_Config(); /* Event Recorder: - 可用於代碼執行時間測量,MDK5.25及其以上版本才支持,IAR不支持。 - 默認不開啟,如果要使能此選項,務必看V5開發板用戶手冊第8章 */ #if Enable_EventRecorder == 1 /* 初始化EventRecorder並開啟 */ EventRecorderInitialize(EventRecordAll, 1U); EventRecorderStart(); #endif bsp_InitKey(); /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */ bsp_InitTimer(); /* 初始化滴答定時器 */ bsp_InitUart(); /* 初始化串口 */ bsp_InitExtIO(); /* 初始化擴展IO */ bsp_InitLed(); /* 初始化LED */ BEEP_InitHard(); /* 初始化蜂鳴器 */ }
每10ms調用一次蜂鳴器處理:
蜂鳴器處理是在滴答定時器中斷里面實現,每10ms執行一次檢測。
/* ********************************************************************************************************* * 函 數 名: bsp_RunPer10ms * 功能說明: 該函數每隔10ms被Systick中斷調用1次。詳見 bsp_timer.c的定時中斷服務程序。一些處理時間要求 * 不嚴格的任務可以放在此函數。比如:按鍵掃描、蜂鳴器鳴叫控制等。 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void bsp_RunPer10ms(void) { bsp_KeyScan10ms(); BEEP_Pro(); }
主功能:
主功能的實現主要分為兩部分:
- 啟動一個自動重裝軟件定時器,每100ms翻轉一次LED2。
- 通過按鍵做蜂鳴器演示。
/* ********************************************************************************************************* * 函 數 名: main * 功能說明: c程序入口 * 形 參: 無 * 返 回 值: 錯誤代碼(無需處理) ********************************************************************************************************* */ int main(void) { uint8_t ucKeyCode; uint32_t freq = 1500; bsp_Init(); /* 硬件初始化 */ PrintfLogo(); /* 打印例程名稱和版本等信息 */ PrintfHelp(); /* 打印操作提示 */ bsp_StartAutoTimer(0, 100); /* 啟動1個100ms的自動重裝的定時器 */ printf("蜂鳴器頻率 = %dHz\r\n", freq); /* 主程序大循環 */ while (1) { bsp_Idle(); /* CPU空閑時執行的函數,在 bsp.c */ /* 判斷定時器超時時間 */ if (bsp_CheckTimer(0)) { /* 每隔100ms 進來一次 */ bsp_LedToggle(2); } /* 處理按鍵事件 */ ucKeyCode = bsp_GetKey(); if (ucKeyCode > 0) { /* 有鍵按下 */ switch (ucKeyCode) { case KEY_DOWN_K1: /* K1按鍵按下,提示音 */ BEEP_KeyTone(); printf("1按鍵按下,提示音(固定頻率1.5KHz)\r\n"); break; case KEY_DOWN_K2: /* K2按鍵按下,急促鳴叫10次*/ BEEP_Start(5, 5, 10); /* 鳴叫50ms,停止50ms,10次*/ printf("K2按鍵按下,急促鳴叫10次\r\n"); break; case KEY_DOWN_K3: /* K3按鍵按下,長鳴3次*/ BEEP_Start(50, 50, 3); /* 鳴叫500ms,停止500ms,3次*/ printf("K3按鍵按下,長鳴3次\r\n"); break; default: break; } } } }
20.8 實驗例程說明(IAR)
配套例子:
V5-004_無源蜂鳴器
實驗目的:
- 學習無源蜂鳴器的控制實現。
實驗內容:
- 啟動一個自動重裝軟件定時器,每100ms翻轉一次LED2。
實驗操作:
- K1鍵按下,按鍵提示音(固定頻率1.5KHz)。
- K2鍵按下,急促鳴叫10次。
- K3鍵按下,長鳴3次。
上電后串口打印的信息:
波特率 115200,數據位 8,奇偶校驗位無,停止位 1
程序設計:
系統棧大小分配:
硬件外設初始化
硬件外設的初始化是在 bsp.c 文件實現:
/* ********************************************************************************************************* * 函 數 名: bsp_Init * 功能說明: 初始化所有的硬件設備。該函數配置CPU寄存器和外設的寄存器並初始化一些全局變量。只需要調用一次 * 形 參:無 * 返 回 值: 無 ********************************************************************************************************* */ void bsp_Init(void) { /* STM32H429 HAL 庫初始化,此時系統用的還是F07自帶的16MHz,HSI時鍾: - 調用函數HAL_InitTick,初始化滴答時鍾中斷1ms。 - 設置NVIV優先級分組為4。 */ HAL_Init(); /* 配置系統時鍾到168MHz - 切換使用HSE。 - 此函數會更新全局變量SystemCoreClock,並重新配置HAL_InitTick。 */ SystemClock_Config(); /* Event Recorder: - 可用於代碼執行時間測量,MDK5.25及其以上版本才支持,IAR不支持。 - 默認不開啟,如果要使能此選項,務必看V5開發板用戶手冊第8章 */ #if Enable_EventRecorder == 1 /* 初始化EventRecorder並開啟 */ EventRecorderInitialize(EventRecordAll, 1U); EventRecorderStart(); #endif bsp_InitKey(); /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */ bsp_InitTimer(); /* 初始化滴答定時器 */ bsp_InitUart(); /* 初始化串口 */ bsp_InitExtIO(); /* 初始化擴展IO */ bsp_InitLed(); /* 初始化LED */ BEEP_InitHard(); /* 初始化蜂鳴器 */ }
每10ms調用一次蜂鳴器處理:
蜂鳴器處理是在滴答定時器中斷里面實現,每10ms執行一次檢測。
/* ********************************************************************************************************* * 函 數 名: bsp_RunPer10ms * 功能說明: 該函數每隔10ms被Systick中斷調用1次。詳見 bsp_timer.c的定時中斷服務程序。一些處理時間要求 * 不嚴格的任務可以放在此函數。比如:按鍵掃描、蜂鳴器鳴叫控制等。 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void bsp_RunPer10ms(void) { bsp_KeyScan10ms(); BEEP_Pro(); }
主功能:
主功能的實現主要分為兩部分:
- 啟動一個自動重裝軟件定時器,每100ms翻轉一次LED2。
- 通過按鍵做蜂鳴器演示。
/* ********************************************************************************************************* * 函 數 名: main * 功能說明: c程序入口 * 形 參: 無 * 返 回 值: 錯誤代碼(無需處理) ********************************************************************************************************* */ int main(void) { uint8_t ucKeyCode; uint32_t freq = 1500; bsp_Init(); /* 硬件初始化 */ PrintfLogo(); /* 打印例程名稱和版本等信息 */ PrintfHelp(); /* 打印操作提示 */ bsp_StartAutoTimer(0, 100); /* 啟動1個100ms的自動重裝的定時器 */ printf("蜂鳴器頻率 = %dHz\r\n", freq); /* 主程序大循環 */ while (1) { bsp_Idle(); /* CPU空閑時執行的函數,在 bsp.c */ /* 判斷定時器超時時間 */ if (bsp_CheckTimer(0)) { /* 每隔100ms 進來一次 */ bsp_LedToggle(2); } /* 處理按鍵事件 */ ucKeyCode = bsp_GetKey(); if (ucKeyCode > 0) { /* 有鍵按下 */ switch (ucKeyCode) { case KEY_DOWN_K1: /* K1按鍵按下,提示音 */ BEEP_KeyTone(); printf("1按鍵按下,提示音(固定頻率1.5KHz)\r\n"); break; case KEY_DOWN_K2: /* K2按鍵按下,急促鳴叫10次*/ BEEP_Start(5, 5, 10); /* 鳴叫50ms,停止50ms,10次*/ printf("K2按鍵按下,急促鳴叫10次\r\n"); break; case KEY_DOWN_K3: /* K3按鍵按下,長鳴3次*/ BEEP_Start(50, 50, 3); /* 鳴叫500ms,停止500ms,3次*/ printf("K3按鍵按下,長鳴3次\r\n"); break; default: break; } } } }
20.9 總結
本章節為大家介紹的無源蜂鳴器方案還是比較實用的,采用的非阻塞方式,實際項目中可以放心使用。