SG90 是一款广泛应用的微型伺服舵机,以其小巧、经济和易于控制的特点,成为机器人、航模和各类创意项目中的常客。

在这里插入图片描述

一、出厂参数

  • 尺寸与重量:约 23×12×29mm,重约 9g。
  • 工作电压:推荐 5V,工作范围 4.8V - 6V。
  • 扭矩:约 1.8 - 2.5 kg・cm(塑料齿轮版本)。
  • 速度:约 0.18 - 0.22 秒 / 60°(无负载)。
  • 角度范围:标准为 0° - 180°,也有 360° 连续旋转的特殊版本。

SG90 舵机有两种常见版本:可控角度(0°–180°)和 360° 连续旋转(控速)。两者外观与接线相同,但内部结构、控制逻辑和适用场景不同。

二、核心对比

关于SG90两种版本的舵机,这里给出一张表进行对比:

项目 可控角度版(0°–180°) 360° 连续旋转版(控速)
内部结构 带角度检测电位器,闭环角度控制 无角度检测,电机可连续旋转
控制信号 50Hz PWM,周期 20ms 50Hz PWM,周期 20ms
脉宽 - 功能映射 0.5ms≈0°;1.5ms≈90°;2.5ms≈180° <1.5ms:反向转,脉宽越短速度越快1.5ms:停止>1.5ms:正向转,脉宽越长速度越快
角度 / 速度能力 角度定位,可停在任意目标角度 速度控制,无角度定位功能
适用场景 舵面、云台、机械臂关节等需要角度控制的地方 轮式机器人驱动、传送带、风扇等需要连续转动和调速的地方
停止方式 保持目标脉宽可锁定角度;断电或停发 PWM 停止 发送 1.5ms 脉宽或断电停止
接线方式 三线制:VCC、GND、SIG(信号) 三线制:VCC、GND、SIG(信号)

选用建议

  • 需要精确定位角度 → 选可控角度版(0°–180°)
  • 需要连续旋转并调节速度和方向 → 选 360° 连续旋转版

两种版本外观和引脚定义完全一致,仅控制逻辑不同,使用前需确认版本并调整代码,否则可能出现无法定位或方向相反的情况。本次我们使用的是可控角度的sg90数字舵机

二、工作原理

SG90 内部是一个完整的闭环控制系统,主要由四部分构成:

  1. 直流电机:提供原始动力。
  2. 减速齿轮组:降低电机转速,放大扭矩,驱动输出轴。
  3. 电位器:与输出轴联动,实时检测当前角度,并将其转化为电信号反馈给控制电路。
  4. 控制电路:这是舵机的 “大脑”。它接收外部的 PWM 控制信号,与电位器反馈的当前角度进行比较,然后驱动电机正转或反转,直到输出轴达到目标角度。

简单来说,对于我们控制其运行主要在于理解PWM控制信号,通过给SG90舵机输入合适的PWM信号,即可实现对其转动角度的控制或者转速的控制了。

三、控制原理

舵机通过接收特定频率和脉宽的 PWM(脉冲宽度调制)信号来确定目标位置。

在这里插入图片描述

  • 信号周期:固定为 20ms(即频率 50Hz)。
  • 脉宽与角度:在 20ms 的周期内,高电平(ON)的时间(即脉宽)决定了舵机的目标角度。
    • 0.5ms 的脉宽 ≈
    • 1.5ms 的脉宽 ≈ 90° (中立位置)
    • 2.5ms 的脉宽 ≈ 180°
img

四、使用场景

由于其体积小、控制简单,SG90 的应用非常广泛:

  • 机器人:用于控制关节的转动、机械臂的抓取等。
  • 航模 / 车模:控制飞机的升降舵、方向舵,或车辆的转向。
  • 云台:调整摄像头的俯仰或水平方向。
  • 智能家居:如自动窗帘、小型机械开关。
  • 教学与实验:是学习 PWM 控制和闭环系统的经典教具。

五、一般接线方法

SG90 使用标准的三线制接口,线色定义清晰:

在这里插入图片描述

  • 棕色线 (GND):接地,连接到控制器的 GND。
  • 红色线 (VCC):接电源正极,通常为 5V。
  • 橙色线 (SIG):信号控制线,连接到控制器(如STM32)的 PWM 输出引脚。

重要提示:接线时务必确认正负极,接反可能会立即烧毁舵机。

六、控制案例:按键控制舵机转动特定角度

6.1 接线方式

外设模块 引脚连接(STM32F103C8T6) 接线细节
轻触按键 PB7 按键一端接 PB7,另一端接 GND
SG90 舵机 信号线 → PA0 舵机 GND 接单片机 GND,舵机 5V 接外部 5V 电源(或单片机 5V 引脚)
ST-Link V2 SWDIO → IO 引脚
SWCLK → CLK 引脚
GND → GND 引脚
VCC → 3.3V 引脚
严格对应引脚,避免接反电源

6.2 案例效果

基于 STM32F103C8T6 微控制器,实现通过按键控制 180 度 SG90 舵机的角度循环切换。

  • 初始状态:舵机固定在 90 度
  • 按键功能:每按下一次,舵机按 180 度 → 90 度 → 0 度 → 90 度 的顺序循环切换,满足简单机械角度控制场景需求。

6.3 核心代码

6.3.1 PWM信号生成
/*
 * @Descripttion: 定时器配置,生成PWM信号
 * @Author: JaRyon
 * @version: 
 * @Date: 2025-09-11 10:26:38
 */
// FileName: tim2.c 

#include "includes.h"

/**
 * @brief TIM2_Init 用于输出PWM信号,提供给SG90舵机
 * @param void 
 * @return void
 */
void TIM2_Init(void) 
{
    /* 1. 开启时钟 PA0 */
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
    RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;

    /* 2. 配置GPIO工作模式: 复用推挽输出 50MHz */
    GPIOA->CRL |=  GPIO_CRL_MODE0;
    GPIOA->CRL |= GPIO_CRL_CNF0_1;
    GPIOA->CRL &= ~GPIO_CRL_CNF0_0;

    /* 3. 定时器配置 20ms */
    // 3.1 设置预分频值
    TIM2->PSC = TIM2_PSC; // 72000000 / 720 = 100000 10^5Hz 1/100000s=1/100ms 

    // 3.2 设置重装载值
    TIM2->ARR = TIM2_ARR;  // 20ms / 0.01 = 2000 - 1
    TIM2->CR1 |= TIM_CR1_ARPE;  // 使能自动重装载预装载

    // 3.3 配置计数方向: 向上计数 0,1...
    TIM2->CR1 &= ~TIM_CR1_DIR;

    // 3.4 设置比较值 0.5~2.5ms中值
    TIM2->CCR1 = 150;

    // 3.5 配置pwm模式 
    TIM2->CCMR1 &= ~TIM_CCMR1_CC1S;     // 输出模式
    TIM2->CCMR1 |= (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1);   // PWM模式1
    TIM2->CCMR1 &= ~TIM_CCMR1_OC1M_0;
    TIM2->CCMR1 |= TIM_CCMR1_OC1PE;     // 产生更新事件时写入

    // 3.6 配置输出极性和使能
    TIM2->CCER &= ~TIM_CCER_CC1P;
    TIM2->CCER |= TIM_CCER_CC1E;

}

/**
 * @brief TIM2_Start 开启定时器
 * @param void 
 * @return void
 */
void TIM2_Start(void) 
{
    TIM2->EGR |= TIM_EGR_UG;     // 产生更新事件
    TIM2->CR1 |= TIM_CR1_CEN;    // 使能定时器
}

/**
 * @brief TIM2_Close 关闭定时器
 * @param void 
 * @return void
 */
void TIM2_Close(void) 
{
    TIM2->CR1 &= ~TIM_CR1_CEN;    // 使能定时器
    TIM2->EGR &= ~TIM_EGR_UG;     // 产生更新事件  
}

/**
 * @brief TIM2_SetCompare 设置pwm占空比
 * @param  uint16_t compare
 * @return void
 */
void TIM2_SetCompare(uint16_t compare) 
{
    TIM2->CCR1 = compare;
}

6.3.2 舵机角度控制
/*
 * @Descripttion: 舵机控制
 * @Author: JaRyon
 * @version: 
 * @Date: 2025-09-11 10:28:49
 */
// FileName: servo.c 

#include "includes.h"

// 当前舵机角度 默认中值 (内部使用)
static uint8_t current_angle = MID_SERVO_ANGLE;
// 当前角度状态
static uint8_t angle_state = 2;  // 1-0° 2-90° 3-180°(初始90°)


/**
 * @brief SERVO_Init
 * @param void 
 * @return void
 */
void SERVO_Init(void) 
{
    TIM2_Init();
    TIM2_Start();
    SERVO_SetAngle(MID_SERVO_ANGLE);
}

/**
 * @brief SERVO_Angle2Compare 角度转换为占空比
 * @param uint8_t angle 
 * @return static uint16_t
 * @attention 内部调用
 */
static uint16_t SERVO_Angle2Compare(uint8_t angle) 
{
    // 角度限幅
    if (angle > MAX_SERVO_ANGLE)    {angle = MAX_SERVO_ANGLE;}
    if (angle < MIN_SERVO_ANGLE)    {angle = MIN_SERVO_ANGLE;}
    
    // 90 -> 150 180 -> 250 线性映射y=lx+b 
    // 0 + delta cycle / delta angle * angle
    return (uint16_t)(MIN_TIM2_COMPARE + (uint16_t)(MAX_TIM2_COMPARE - MIN_TIM2_COMPARE) / (uint8_t)(MAX_SERVO_ANGLE - MIN_SERVO_ANGLE) * angle);
}

/**
 * @brief SERVO_SetAngle 设置舵机角度
 * @param  uint8_t angle
 * @return void
 */
void SERVO_SetAngle(uint8_t angle) 
{
    uint16_t compare;

    // 角度限幅
    if (angle > MAX_SERVO_ANGLE)    {angle = MAX_SERVO_ANGLE;}
    if (angle < MIN_SERVO_ANGLE)    {angle = MIN_SERVO_ANGLE;}
    
    /* 角度更新与转换 */
    current_angle = angle;
    compare = SERVO_Angle2Compare(angle);
    TIM2_SetCompare(compare);
}

/**
 * @brief SERVO_GetServoAngle 获取当前舵机角度(0~180)
 * @param void 
 * @return uint8_t
 */
uint8_t SERVO_GetServoAngle(void) 
{
    return current_angle;
}


/**
 * @brief SERVO_NextAngle 切换当前舵机角度(0~180)
 * @param void 
 * @return void
 */
void SERVO_NextAngle(void)
{
    // 循环切换角度状态
    angle_state++;
    if (angle_state > 4)
    {
        angle_state = 1;
    }
    
    // 根据状态设置对应角度
    switch (angle_state)
    {
        case 1:
            SERVO_SetAngle(ANGLE_0);
            break;
        case 2:
            SERVO_SetAngle(ANGLE_90);
            break;
        case 3:
            SERVO_SetAngle(ANGLE_180);
            break;
        case 4:
            SERVO_SetAngle(ANGLE_90);
            break;
    }
}

6.3.3 按键中断处理
void EXTI9_5_IRQHandler(void)
{
    // 检查是否是PB7触发的中断
    if (EXTI->PR & EXTI_PR_PR7)
    {
        // 清除中断标志位(必须手动清除)
        EXTI->PR |= EXTI_PR_PR7;

        // 软件消抖
        Delay_ms(10);

        // 确认按键按下(PB7接GND,按下时为低电平)
        if (!(GPIOB->IDR & GPIO_IDR_IDR7))
        {
            // 调用舵机角度切换函数(需在其他文件实现)
            SERVO_NextAngle();
        }
    }
}

6.4 完整程序获取

点击链接进入即可查看

STM32F103C8T6 按键控制 SG90 舵机


七、相关注意事项

  1. 稳定供电:舵机在启动和承受负载时电流会瞬时增大,建议使用独立、稳定的 5V 电源供电,并确保电源线有足够的电流承载能力。
  2. 避免堵转:不要强行用手扳动正在工作的舵机输出轴,或让其在到达极限位置后仍长时间通电,这会导致电机堵转、过热,严重时会烧毁舵机。
  3. 信号频率:严格遵守 50Hz 的控制信号频率(即 20ms 的周期),频率不当会导致舵机抖动、失效或损坏。
  4. 区分版本:标准的 180° 舵机和 360° 连续旋转舵机的控制逻辑完全不同。360° 版本实际上是将脉宽信号解读为速度和方向(1.5ms 为停止,小于 1.5ms 为一个方向旋转,大于 1.5ms 为另一个方向旋转),它不具备角度定位功能。

稳定供电:舵机在启动和承受负载时电流会瞬时增大,建议使用独立、稳定的 5V 电源供电,并确保电源线有足够的电流承载能力。
2. 避免堵转:不要强行用手扳动正在工作的舵机输出轴,或让其在到达极限位置后仍长时间通电,这会导致电机堵转、过热,严重时会烧毁舵机。
3. 信号频率:严格遵守 50Hz 的控制信号频率(即 20ms 的周期),频率不当会导致舵机抖动、失效或损坏。
4. 区分版本:标准的 180° 舵机和 360° 连续旋转舵机的控制逻辑完全不同。360° 版本实际上是将脉宽信号解读为速度和方向(1.5ms 为停止,小于 1.5ms 为一个方向旋转,大于 1.5ms 为另一个方向旋转),它不具备角度定位功能。


笔者小白,能力有限,以上内容难免存在不足和纰漏,仅供参考,各位阅读时请带着批判性思维学习,遇到问题多查查。同时欢迎各位评论区批评指正。谢谢。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐