From c6a1e7c00cd2946cef7716b205026a907136778b Mon Sep 17 00:00:00 2001
From: guowenxue <guowenxue@gmail.com>
Date: Sun, 12 Jul 2026 18:41:28 +0800
Subject: [PATCH] Add ex1.servo-sg90

---
 ex1.servo-sg90/Board/buzzer.c |  191 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 191 insertions(+), 0 deletions(-)

diff --git a/ex1.servo-sg90/Board/buzzer.c b/ex1.servo-sg90/Board/buzzer.c
new file mode 100644
index 0000000..f39e80c
--- /dev/null
+++ b/ex1.servo-sg90/Board/buzzer.c
@@ -0,0 +1,191 @@
+/**********************************************************************
+*   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);
+    }
+}

--
Gitblit v1.10.0