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/servo_sg90.c |  124 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 124 insertions(+), 0 deletions(-)

diff --git a/ex1.servo-sg90/Board/servo_sg90.c b/ex1.servo-sg90/Board/servo_sg90.c
new file mode 100644
index 0000000..79e64bc
--- /dev/null
+++ b/ex1.servo-sg90/Board/servo_sg90.c
@@ -0,0 +1,124 @@
+/**********************************************************************
+*   Copyright: (C)2024 LingYun IoT System Studio
+*      Author: GuoWenxue<guowenxue@gmail.com>
+* Description: SG90 Servo Motor Driver for ISKBoard
+*
+*   ChangeLog:
+*        Version    Date       Author            Description
+*        V1.0.0  2024.08.29    GuoWenxue      Release initial version
+***********************************************************************/
+
+/**
+ * SG90 舵机控制(0° ~ 180°) : https://detail.tmall.com/item.htm?id=615779197448
+ * - 正极(红色) <-> 5V
+ * - 负极(棕色) <-> GND
+ * - 信号(黄色) <-> PA1(PWM/TIM2_CH2)
+ *
+ * 舵机控制原理:
+ * - 舵机的控制需要一个 PWM 信号,频率一般为 50Hz (周期 20ms)
+ * - 脉宽范围约为 0.5ms ~ 2.5ms。以 180° 角为例,对应的控制关系为:
+ *     角度  脉宽
+ *     0°    500 µs
+ *     45°   700 µs
+ *     90°  1500 µs
+ *    135°  2000 µs
+ *    180°  2500 µs
+ * - 角度与脉宽的线性关系公式为:pulse = 500 + angle * 2000 / 180
+ *
+ * STM32CubeMX 定时器 TIM 参数配置:
+ *   预分频(htim.Init.Prescaler) = SYS_CLK-1 -> 定时器时钟 1 MHz (1 µs/tick)
+ *   自动重装(htim.Init.Period)  = 20000-1 -> PWM 周期 20 ms (20000 µs)
+ *   htim.Init.AutoReloadPreload = Enable
+ *   脉宽范围(sConfigOC.Pulse)   = 1500 -> 默认 90° (1500 µs)
+ */
+
+#include "stm32l4xx_hal.h"
+#include "miscdev.h"
+#include "servo_sg90.h"
+#include "tim.h"
+
+/* SG90 舵机控制连接单片机引脚: PA1/TIM2_CH2 */
+#define SERVO_TIMER       &htim2
+#define SERVO_CHANNEL     TIM_CHANNEL_2
+
+/**
+ * @brief  初始化舵机, 启动 TIM PWM 输出。
+ */
+void Servo_Init(void)
+{
+    /* 启动前先设定一个明确的初始角度,避免上电盲目抖动 */
+    Servo_SetAngle(SERVO_DEFAULT_ANG);
+
+    HAL_TIM_PWM_Start(SERVO_TIMER, SERVO_CHANNEL);
+}
+
+/**
+ * @brief  设置舵机角度
+ * @param  angle  可传 0 ~ 180,但超出钳位值范围自动钳位
+ */
+void Servo_SetAngle(int angle)
+{
+    int pulse;
+
+    angle = CLAMP_ANGLE(angle);
+
+    /* 脉宽线性公式:利用 32 位 int 计算,彻底免除溢出隐患 */
+    pulse = SERVO_MIN_PULSE + (angle * (SERVO_MAX_PULSE - SERVO_MIN_PULSE)) / SERVO_MAX_ANGLE;
+
+    __HAL_TIM_SET_COMPARE(SERVO_TIMER, SERVO_CHANNEL, (uint16_t)pulse);
+}
+
+/**
+ * @brief  直接停止 PWM 输出, 立即停止舵机。
+ */
+void Servo_Stop(void)
+{
+    HAL_TIM_PWM_Stop(SERVO_TIMER, SERVO_CHANNEL);
+}
+
+/**
+ * @brief  转到安全角度后,再停止舵机
+ * @param  safe_angle  停止前舵机转到的角度 (超出钳位值范围设置默认角度)
+ */
+void Servo_SafeStop(int safe_angle)
+{
+    /* 超出钳位值范围设置默认角度 */
+    if (safe_angle <= SERVO_MIN_ANGLE || safe_angle > SERVO_MAX_ANGLE) {
+        safe_angle = SERVO_DEFAULT_ANG;
+    }
+
+    Servo_SetAngle(safe_angle);
+
+    /* SG90 空载约 100 ms/60°,转 180° 约需 300ms */
+    mdelay(1000);
+
+    Servo_Stop();
+}
+
+/**
+ * @brief 舵机测试函数
+ */
+void Servo_Test(void)
+{
+    printf("Servo Start\r\n");
+    Servo_Init();
+    mdelay(2000);
+
+    Servo_SetAngle(0);
+    mdelay(2000);
+
+    Servo_SetAngle(90);
+    mdelay(2000);
+
+    Servo_SetAngle(180);
+    mdelay(2000);
+
+    Servo_SetAngle(90);
+    mdelay(2000);
+
+    Servo_SetAngle(0);
+    mdelay(2000);
+
+    printf("Servo Stop\r\n");
+    Servo_SafeStop(SERVO_DEFAULT_ANG);
+}

--
Gitblit v1.10.0