最新教程下載:http://www.armbbs.cn/forum.php?mod=viewthread&tid=93255php
本章教程爲你們介紹STM32F407的GPIO應用之無源蜂鳴器,蜂鳴器也是GPIO控制的經典測試例程,可讓你們對STM32F407應用有個簡單的總體認識。安全
20.1 初學者重要提示框架
20.2 蜂鳴器硬件設計函數
20.3 蜂鳴器軟件驅動設計學習
20.4 蜂鳴器板級支持包(bsp_beep.c)測試
20.5 蜂鳴器驅動移植和使用(裸機版)ui
20.6 使用例程設計框架spa
20.7 實驗例程說明(MDK)設計
20.8 實驗例程說明(IAR)code
20.9 總結
蜂鳴器的硬件設計以下:
經過這個硬件設計,有以下兩點須要學習:
蜂鳴器主要有電磁式和電壓式兩種,並且都有無源蜂鳴器和有源蜂鳴器兩類。開發板使用的是電磁式無源蜂鳴器,而有源和無源的區別是有源蜂鳴器內部自帶振盪器,給個電壓就能發聲,但頻率是固定的,只能發出一種聲音,而無源蜂鳴器頻率可控,給個方波才能夠發聲,而且根據不一樣頻率發出不一樣的聲音效果。
拓展知識
關於有源蜂鳴器和無源蜂鳴器區別:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=89764 。
關於硬件驅動,這裏主要有三點須要你們認識到:
拓展知識
STM32的GPIO控制三極管驅動各類負載的安全措施和注意事項:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=89776 。
軟件驅動對有源蜂鳴器和無源蜂鳴器都作了支持,默認狀況下用的是無源蜂鳴器。咱們使用蜂鳴器的話,大部分狀況下能夠配置鳴叫次數、鳴叫的時間和中止的時間。本驅動設計就是基於這種應用方式實現,基本能夠知足大部分應用狀況。
設計這個軟件驅動的關鍵之處是如何避免採用阻塞式的實現方式,好比要實現鳴叫1秒,中止1秒,循環5次,若是是阻塞方式等待1秒執行完畢,那就時間太長了。鑑於這種狀況,程序裏面實現了一種非阻塞的方式,經過滴答定時器中斷每10ms調用一次蜂鳴器處理函數來實現鳴叫次數、鳴叫的時間和中止的時間的更新。
蜂鳴器驅動文件bsp_beep.c主要實現了以下幾個API:
這裏咱們重點講解函數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次 */
此文件的開頭有一個宏定義選擇,用戶能夠選擇使用有源蜂鳴器或者無源蜂鳴器。
//#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
爲了方便蜂鳴器的控制,專門封裝了一個結構體變量:
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;
函數原型:
/* ********************************************************************************************************* * 函 數 名: 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裏面調用便可。
函數原型:
/* ********************************************************************************************************* * 函 數 名: 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。
函數參數:
使用舉例:
調用此函數前,務必優先調用函數BEEP_InitHard進行初始化。好比要實現鳴叫50ms,停10ms, 1次,就是BEEP_Start(5, 1, 1);
函數原型:
/* ********************************************************************************************************* * 函 數 名: 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調用一次。
按鍵移植步驟以下:
#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
特別注意,別忘了每10ms調用一次按鍵檢測函數BEEP_Pro()。
經過程序設計框架,讓你們先對配套例程有一個全面的認識,而後再理解細節,本次實驗例程的設計框架以下:
第1階段,上電啓動階段:
第2階段,進入main函數:
配套例子:
V5-004_無源蜂鳴器
實驗目的:
實驗內容:
實驗操做:
上電後串口打印的信息:
波特率 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(); }
主功能:
主功能的實現主要分爲兩部分:
/* ********************************************************************************************************* * 函 數 名: 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; } } } }
配套例子:
V5-004_無源蜂鳴器
實驗目的:
實驗內容:
實驗操做:
上電後串口打印的信息:
波特率 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(); }
主功能:
主功能的實現主要分爲兩部分:
/* ********************************************************************************************************* * 函 數 名: 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; } } } }
本章節爲你們介紹的無源蜂鳴器方案仍是比較實用的,採用的非阻塞方式,實際項目中能夠放心使用。