有源蜂鳴器內(nèi)含振蕩源,只要一通電就發(fā)聲,但發(fā)生頻率固定,音色單一;無源蜂鳴器內(nèi)部不含振蕩源,內(nèi)部結(jié)構(gòu)相當(dāng)于電磁場揚聲器,可以通過給他輸出一定頻率的信號才能發(fā)聲。
人耳能聽到的頻率范圍在20Hz--20kHz之間,通過STM32的GPIO引腳快速切換高低電平輸出就能實現(xiàn)無源蜂鳴器的發(fā)聲,切換的頻率不同,發(fā)出的音調(diào)就不一樣。
二、音樂播放的實現(xiàn)
一段音樂就是不同頻率的聲音按一定的時間節(jié)拍轉(zhuǎn)換發(fā)出。所以音樂包含音調(diào)和節(jié)拍信息。
如果要實現(xiàn)歌曲“紅塵情歌”,要準(zhǔn)備相應(yīng)的數(shù)據(jù)。
歌譜如下:
程序中首先準(zhǔn)備音頻數(shù)據(jù)表:
// 低Si Do Re Mi Fa So La Si ?高Do?高Re?高M(jìn)i?高Fa?高So 無
uc16 tone[] ={247,262,294,330,349,392,440,294,523, 587, 659, 698, 784, 1000};
u8 music[]={ 5,5,6,8,7,6,5,6,13,13,……};//音調(diào)
u8 time[] = { 2,4,2,2,2,2,2,8,4, 4, ……}; //節(jié)拍時間
依次從音調(diào)數(shù)組中取music[i],然后根據(jù)music[i]的值在tone數(shù)組中得到該音的發(fā)聲頻率(tone[music[i]]),調(diào)用sound函數(shù)控制蜂鳴器發(fā)聲,聲音的發(fā)聲時間有time數(shù)組控制。
三、項目創(chuàng)建與配置
1、創(chuàng)建項目文件夾(設(shè)為pMusic)
2、通過Keil5創(chuàng)建新項目,保存在所創(chuàng)建的文件夾中(設(shè)項目名為pMusic),選擇MCU芯片為"STM32F103ZE"(本程序使用的硬件為:STM32-PZ6806L開發(fā)板)
3、在pMusic項目文件夾中新建"CMSIS"、"Device"、"Public"、"Startup"、"User"和"Lib"文件夾。
① 在"CMSIS"文件夾中復(fù)制"core_cm3.h"和"core_cm3.c"文件;
② 在" Device "文件夾中復(fù)制"stm32f10x.h"、"system_stm32f10x.h"和"system_stm32f10x.c"文件;
③ 在" Startup "文件夾中復(fù)制"startup_stm32f10x_hd.s"文件;
④在"Lib"文件夾中新建"inc"和"src"兩個子文件夾,在"inc"文件夾中復(fù)制"misc.h"、"stm32f10x_gpio.h"和"stm32f10x_rcc.h"文件;在"src"文件夾中復(fù)制"misc.c"、"stm32f10x_gpio.c"和"stm32f10x_rcc.c"文件;
4、為項目添加"CMSIS"、"Device"、"Public"、"Startup"、"User"和"Lib"組,并將上述C程序文件和"startup_stm32f10x_hd.s"啟動文件加入到相應(yīng)組中。展開項目樹如下:
5、打開“項目配置”對話框,在"Output"選項卡中選擇"Create HEX File",在"C/C++"選項卡中的"Include Paths"中添加如下包含路徑:".CMSIS;", ".Device;", ".Libinc;",".Public;"。
(以上步驟可以參看:使用STM32固件庫操作控制LED燈(CMSIS) 使用STM32固件庫函數(shù)操作控制LED燈
6、在"stm32f10x.h"中添加函數(shù)參數(shù)檢查宏
(參看:使用STM32固件庫函數(shù)操作控制LED燈)
#ifdef USE_FULL_ASSERT
/**
* @brief 這個assert_param宏用于函數(shù)參數(shù)檢查
* @param expr:如果expr是 false,就調(diào)用 assert_failed函數(shù)報告源文件名和
* 失敗的行號,如果expr是 true ,就返回一個空值
* @retval None
*/
#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t* file, uint32_t line);
#else
#define assert_param(expr) ((void)0)
#endif /* USE_FULL_ASSERT */
7、新建一個文件(system.h),保存到"Public"文件夾中,內(nèi)容為:
#ifndef __SYSTEM__H
#define __SYSTEM__H
#include "stm32f10x.h"
//定義位帶地址宏
#define BITBAND(addr,bitnum) ((addr&0xF0000000) + 0x02000000 + ((addr&0x000FFFFF)<<5) + (bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr,bitnum) MEM_ADDR(BITBAND(addr,bitnum))
//IO口地址映射
//數(shù)據(jù)輸出寄存器地址
#define GPIOA_ODR_Addr (GPIOA_BASE + 12)
#define GPIOB_ODR_Addr (GPIOB_BASE + 12)
#define GPIOC_ODR_Addr (GPIOC_BASE + 12)
#define GPIOD_ODR_Addr (GPIOD_BASE + 12)
#define GPIOE_ODR_Addr (GPIOE_BASE + 12)
#define GPIOF_ODR_Addr (GPIOF_BASE + 12)
#define GPIOG_ODR_Addr (GPIOG_BASE + 12)
//數(shù)據(jù)輸入寄存器地址
#define GPIOA_IDR_Addr (GPIOA_BASE + 12)
#define GPIOB_IDR_Addr (GPIOB_BASE + 12)
#define GPIOC_IDR_Addr (GPIOC_BASE + 12)
#define GPIOD_IDR_Addr (GPIOD_BASE + 12)
#define GPIOE_IDR_Addr (GPIOE_BASE + 12)
#define GPIOF_IDR_Addr (GPIOF_BASE + 12)
#define GPIOG_IDR_Addr (GPIOG_BASE + 12)
#endif
該文件定義了GPIO端口位帶操作的宏。
(位帶操作請參看:通過位帶地址操作GPIO在數(shù)碼管顯示數(shù)字)
8、新建文件"SysTick.h",保存到"Public"文件夾中,內(nèi)容為:
#ifndef __SysTick__H
#define __SysTick__H
#include "stm32f10x.h"
void SysTick_Init(u8 SYSCLK);
void delay_us(u32 nus);
void delay_ms(u16 nms);
#endif
新建文件"SysTick.c",保存到"Public"文件夾中,內(nèi)容為:
#include "SysTick.h"
#include "misc.h"
u8 fac_us = 0;
u16 fac_ms = 0;
void SysTick_Init(u8 SYSCLK)
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
fac_us = SYSCLK / 8;
fac_ms = (u16)fac_us*1000;
}
void delay_us(u32 nus)
{
u32 temp;
SysTick->LOAD = nus * fac_us;
SysTick->VAL = 0;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
do{
temp = SysTick->CTRL;
}while((temp&0x01)&&(!(temp&(1<<16))));
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
SysTick->VAL = 0;
}
void delay_ms(u16 nms)
{
u32 temp;
SysTick->LOAD = nms * fac_ms;
SysTick->VAL = 0;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
do{
temp = SysTick->CTRL;
}while((temp&0x01)&&(!(temp&(1<<16))));
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
SysTick->VAL = 0;
}
這兩個文件實現(xiàn)了通過SysTick精準(zhǔn)延時的函數(shù),提供給后續(xù)的音頻頻率產(chǎn)生程序使用。
(關(guān)于SysTick,請參看:在STM32項目中使用SysTick實現(xiàn)延時)
將"SysTick.c"文件添加到項目的"Public"組中。
9、實現(xiàn)發(fā)聲
①開發(fā)板無源蜂鳴器的電路連接如下:
從電路連接可以看出通過MCU的PB5(GPIOB_5)控制蜂鳴器的發(fā)聲。
②在項目文件夾的"User"文件夾下新建"Beep"文件夾,在項目中新建"beep.h"文件,保存在"User/Beep"文件夾中,文件內(nèi)容為:
#ifndef __BEEP__H
#define __BEEP__H
#include "system.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
//定義GPIOB的位地址變量宏
#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n)
#define PBeep PBout(5)
#define BEEP_PORT GPIOB
#define BEEP_PIN GPIO_Pin_5
#define BEEP_PORT_RCC RCC_APB2Periph_GPIOB
void BEEP_Init(void);
void Sound(u16 frq);
void play(void);
#endif
③在項目中新建"beep.c"文件,保存在"User/Beep"文件夾中,文件內(nèi)容為:
#include "beep.h"
#include "systick.h"
void BEEP_Init(void)
{
GPIO_InitTypeDef GPIO_mode;
RCC_APB2PeriphClockCmd( BEEP_PORT_RCC, ENABLE ); //使能GPIOB時鐘
GPIO_mode.GPIO_Pin = BEEP_PIN;
GPIO_mode.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_mode.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(BEEP_PORT, &GPIO_mode); //設(shè)置GPIOB_5為推挽輸出,50MHz速度
}
void Sound(u16 frq)
{
u32 n;
if(frq != 1000) //如果頻率不為1000則按頻率輸出,否則只延時
{
n = 500000/((u32)frq);
PBeep = 0;
delay_us(n);
PBeep = 1;
delay_us(n);
}else
delay_us(1000);
}
void play(void)
{
// 低7 1 2 3 4 5 6 7 高1 高2 高3 高4 高5 不發(fā)音
uc16 tone[] = {247,262,294,330,349,392,440,294,523,587,659,698,784,1000};//音頻數(shù)據(jù)表
//紅塵情歌
u8 music[]={ 5,5,6,8,7,6,5,6,13,13,//音調(diào)
5,5,6,8,7,6,5,3,13,13,
2,2,3,5,3,5,6,3,2,1,
6,6,5,6,5,3,6,5,13,13,
5,5,6,8,7,6,5,6,13,13,
5,5,6,8,7,6,5,3,13,13,
2,2,3,5,3,5,6,3,2,1,
6,6,5,6,5,3,6,1,
上一篇:S3C2440核心板原理圖設(shè)計:與SDRAM接線分析
下一篇:stm32使用MDK開發(fā)中的一些常見問題
推薦閱讀
史海拾趣
設(shè)計資源 培訓(xùn) 開發(fā)板 精華推薦
- Microchip 升級數(shù)字信號控制器(DSC)產(chǎn)品線 推出PWM 分辨率和 ADC 速度業(yè)界領(lǐng)先的新器件
- 意法半導(dǎo)體STM32MP23x:突破成本限制的工業(yè)AI應(yīng)用核心
- 意法半導(dǎo)體推出用于匹配遠(yuǎn)距離無線微控制器STM32WL33的集成的匹配濾波芯片
- ESP32開發(fā)板連接TFT顯示屏ST7789跳坑記
- 如何讓ESP32支持analogWrite函數(shù)
- LGVL配合FreeType為可變字體設(shè)置字重-ESP32篇
- 使用樹莓派進(jìn)行 ESP32 Jtag 調(diào)試
- ESP32怎么在SPIFFS里面存儲html,css,js文件,以及網(wǎng)頁和arduino的通訊
- ESP32 freeRTOS使用測試
- ARXML 規(guī)則下 ECU 總線通訊與 ADTF 測試方案
- 日產(chǎn)在歐洲推出第三代e-POWER技術(shù)
- 福特CEO更看好Waymo激光雷達(dá)方案:比特斯拉純視覺自動駕駛路線可靠
- 智元機器人兩大核心產(chǎn)品啟動規(guī)?;a(chǎn)
- 固態(tài)電池2026量產(chǎn)豪賭,真相還是泡沫?
- 100億元!湖北“下注”人形機器人產(chǎn)業(yè)
- 海外磷酸鐵鋰電池產(chǎn)能從0到1
- 基于多傳感器數(shù)據(jù)的自動駕駛仿真確定性驗證
- 國芯科技發(fā)布全球首款48V安全氣囊芯片,引領(lǐng)智能汽車新紀(jì)元
- 亞馬遜全球部署100萬臺機器人
- 美信基礎(chǔ)模擬IC APP下載 助力您創(chuàng)新模擬設(shè)計!
- TI 嵌入式產(chǎn)品研討會視頻曝光,下載有禮!
- TI機器人系統(tǒng)學(xué)習(xí)套件,低成本開啟你的電子工程課程實戰(zhàn)之旅
- “泰”想開車 智能篇:智能網(wǎng)聯(lián)汽車,實現(xiàn)無憂駕駛
- 羅姆有獎直播 |雙極型晶體管的實用選型方法和使用方法
- 【TI 培訓(xùn)】年度盤點:2019 TI 培訓(xùn)課程集錦,好評有禮!
- 免費下載|TE 白皮書《暖通空調(diào)制冷系統(tǒng)中壓力傳感器的重要性》
- 羅姆有獎直播|可應(yīng)用于LiDAR的激光二極管及周邊電源推薦
- 直播主題: 助力“雙碳”目標(biāo) — ADI 智能工廠方案