/**********************************************************************
|
* Copyright: (C)2024 LingYun IoT System Studio
|
* Author: GuoWenxue<guowenxue@gmail.com>
|
* Description: ISKBoard buzzer/beeper driver and music play
|
*
|
* ChangeLog:
|
* Version Date Author Description
|
* V1.0.0 2024.08.29 GuoWenxue Release initial version
|
***********************************************************************/
|
|
#include "tim.h"
|
#include "buzzer.h"
|
|
#define mdelay(ms) HAL_Delay(ms)
|
#define ARRAY_SIZE(song) (sizeof(song)/sizeof(song[0]))
|
|
/* 音符频率定义(Hz) */
|
#define NOTE_C4 524
|
#define NOTE_D4 588
|
#define NOTE_E4 660
|
#define NOTE_F4 698
|
#define NOTE_G4 784
|
#define NOTE_A4 880
|
#define NOTE_B4 988
|
#define NOTE_C5 1046
|
#define NOTE_D5 1174
|
#define NOTE_E5 1318
|
#define NOTE_F5 1396
|
#define NOTE_G5 1568
|
#define NOTE_A5 1760
|
#define NOTE_B5 1976
|
#define NOTE_C6 2093
|
#define REST 0
|
|
#define BEAT 400 /* 一拍时长(ms),可自行调整节奏快慢 */
|
|
/* 《小星星》简谱:
|
* 1 1 5 5 6 6 5 - 4 4 3 3 2 2 1
|
* 5 5 4 4 3 3 2 - 5 5 4 4 3 3 2
|
* 1 1 5 5 6 6 5 - 4 4 3 3 2 2 1
|
* (C=1, D=2, E=3, F=4, G=5, A=6, B=7)
|
*/
|
const Note_t twinkle[] =
|
{
|
/* Twinkle twinkle little star */
|
{NOTE_C4, BEAT}, {NOTE_C4, BEAT}, {NOTE_G4, BEAT}, {NOTE_G4, BEAT},
|
{NOTE_A4, BEAT}, {NOTE_A4, BEAT}, {NOTE_G4, BEAT * 2},
|
|
/* How I wonder what you are */
|
{NOTE_F4, BEAT}, {NOTE_F4, BEAT}, {NOTE_E4, BEAT}, {NOTE_E4, BEAT},
|
{NOTE_D4, BEAT}, {NOTE_D4, BEAT}, {NOTE_C4, BEAT * 2},
|
|
/* Up above the world so high */
|
{NOTE_G4, BEAT}, {NOTE_G4, BEAT}, {NOTE_F4, BEAT}, {NOTE_F4, BEAT},
|
{NOTE_E4, BEAT}, {NOTE_E4, BEAT}, {NOTE_D4, BEAT * 2},
|
|
/* Like a diamond in the sky */
|
{NOTE_G4, BEAT}, {NOTE_G4, BEAT}, {NOTE_F4, BEAT}, {NOTE_F4, BEAT},
|
{NOTE_E4, BEAT}, {NOTE_E4, BEAT}, {NOTE_D4, BEAT * 2},
|
|
/* Twinkle twinkle little star (repeat) */
|
{NOTE_C4, BEAT}, {NOTE_C4, BEAT}, {NOTE_G4, BEAT}, {NOTE_G4, BEAT},
|
{NOTE_A4, BEAT}, {NOTE_A4, BEAT}, {NOTE_G4, BEAT * 2},
|
|
/* How I wonder what you are (repeat) */
|
{NOTE_F4, BEAT}, {NOTE_F4, BEAT}, {NOTE_E4, BEAT}, {NOTE_E4, BEAT},
|
{NOTE_D4, BEAT}, {NOTE_D4, BEAT}, {NOTE_C4, BEAT * 2},
|
};
|
const uint32_t twinkle_count = ARRAY_SIZE(twinkle);
|
|
/* 《祝你生日快乐》(Happy Birthday to You)
|
* 该曲旋律/歌词经美国法院2015-2016年裁定确认为公有领域作品,可放心使用。
|
* 简谱: 5 5 6 5 1' 7 | 5 5 6 5 2' 1' | 5 5 5' 3' 1' 7 6 | 4' 4' 3' 1' 2' 1'
|
*/
|
const Note_t happy_birthday[] =
|
{
|
/* Happy Birthday to you */
|
{NOTE_G4, BEAT / 2}, {NOTE_G4, BEAT / 2}, {NOTE_A4, BEAT}, {NOTE_G4, BEAT},
|
{NOTE_C5, BEAT}, {NOTE_B4, BEAT * 2},
|
|
/* Happy Birthday to you */
|
{NOTE_G4, BEAT / 2}, {NOTE_G4, BEAT / 2}, {NOTE_A4, BEAT}, {NOTE_G4, BEAT},
|
{NOTE_D5, BEAT}, {NOTE_C5, BEAT * 2},
|
|
/* Happy Birthday dear friend */
|
{NOTE_G4, BEAT / 2}, {NOTE_G4, BEAT / 2}, {NOTE_G5, BEAT}, {NOTE_E5, BEAT},
|
{NOTE_C5, BEAT}, {NOTE_B4, BEAT}, {NOTE_A4, BEAT * 2},
|
|
/* Happy Birthday to you */
|
{NOTE_F5, BEAT / 2}, {NOTE_F5, BEAT / 2}, {NOTE_E5, BEAT}, {NOTE_C5, BEAT},
|
{NOTE_D5, BEAT}, {NOTE_C5, BEAT * 2},
|
|
/* 结尾留白 */
|
{REST, BEAT * 2},
|
};
|
const uint32_t happy_birthday_count = ARRAY_SIZE(happy_birthday);
|
|
/* 《Jingle Bells》(铃儿响叮当)
|
* 1857年James Lord Pierpont创作,早已进入公有领域。
|
* (下面是常见的简化版本,节奏为大致还原,供播放测试使用)
|
*/
|
const Note_t jingle_bells[] =
|
{
|
/* Jingle bells, jingle bells, jingle all the way */
|
{NOTE_E4, BEAT}, {NOTE_E4, BEAT}, {NOTE_E4, BEAT * 2},
|
{NOTE_E4, BEAT}, {NOTE_E4, BEAT}, {NOTE_E4, BEAT * 2},
|
{NOTE_E4, BEAT}, {NOTE_G4, BEAT}, {NOTE_C4, BEAT}, {NOTE_D4, BEAT},
|
{NOTE_E4, BEAT * 4},
|
|
/* Oh what fun it is to ride in a one-horse open sleigh */
|
{NOTE_F4, BEAT}, {NOTE_F4, BEAT}, {NOTE_F4, BEAT}, {NOTE_F4, BEAT},
|
{NOTE_F4, BEAT}, {NOTE_E4, BEAT}, {NOTE_E4, BEAT}, {NOTE_E4, BEAT / 2}, {NOTE_E4, BEAT / 2},
|
{NOTE_E4, BEAT}, {NOTE_D4, BEAT}, {NOTE_D4, BEAT}, {NOTE_E4, BEAT},
|
{NOTE_D4, BEAT * 2}, {NOTE_G4, BEAT * 2},
|
|
/* 结尾留白 */
|
{REST, BEAT * 2},
|
};
|
const uint32_t jingle_bells_count = ARRAY_SIZE(jingle_bells);
|
|
/*
|
*+----------------------------+
|
*| PWM buzzer API |
|
*+----------------------------+
|
*/
|
|
/**
|
* @brief 设置蜂鸣器发声频率(占空比固定50%)
|
*/
|
static inline void Buzzer_SetFreq(uint32_t freq)
|
{
|
/* TIM1 初始化 PSC = 79,计数时钟 = 80MHz/80 = 1MHz */
|
uint32_t arr = 1000000U / freq - 1U;
|
__HAL_TIM_SET_AUTORELOAD(&htim1, arr);
|
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_4, arr / 2U);
|
__HAL_TIM_SET_COUNTER(&htim1, 0);
|
}
|
|
/**
|
* @brief 让蜂鸣器响 $times 次,每次间隔 $interval 毫秒
|
*/
|
void beep_start(uint16_t times, uint16_t interval)
|
{
|
Buzzer_SetFreq(2700);
|
|
while( times-- )
|
{
|
/* Start buzzer */
|
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4);
|
|
mdelay(interval);
|
|
/* Stop buzzer */
|
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_4);
|
|
mdelay(interval);
|
}
|
}
|
|
/**
|
* @brief 播放单个音符
|
*/
|
static void Buzzer_PlayNote(uint32_t freq, uint32_t duration_ms)
|
{
|
if (freq == 0)
|
{
|
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_4);
|
mdelay(duration_ms);
|
return;
|
}
|
|
Buzzer_SetFreq(freq);
|
|
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4);
|
mdelay(duration_ms - 30);
|
|
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_4);
|
|
mdelay(30);
|
}
|
|
/**
|
* @brief 播放歌曲
|
*/
|
void Play_Song(const Note_t *song, uint32_t note_count)
|
{
|
for (uint32_t i = 0; i < note_count; i++)
|
{
|
Buzzer_PlayNote(song[i].freq, song[i].duration);
|
}
|
}
|