STM32实战教程:SG90舵机控制原理深度解析及代码详解

发布者:RadiantRiver最新更新时间:2025-09-28 来源: cnblogs关键字:STM32  SG90  舵机控制 手机看文章 扫描二维码
随时随地手机看文章

知识点1【SG90的简述】

SG90是一款微型舵机(Micro Servo),由TowerPro等厂商提供,广泛用于机器人,舵机云台,舵机控制教学等项目中。

1、基本参数

2、工作原理

SG90内部有电机,齿轮组,电位器和控制板。通过单根线输入(相对舵机)PWM控制信号

3、外观展示

4、接线说明

线颜色说明接法说明
棕色GND单片机的地线
红色VCC(5V)建议接外部5V供电
橙色PWM信号接 STM32 的 PWM 输出引脚

知识点2【SG90分类】

SG90有180°舵机和360°舵机

  • 需要角度控制 → 选 180° 定位舵机 (Standard SG90)

  • 需要可变速度 → 选 360° 连续旋转舵机 (Continuous‑Rotation SG90)

  • 区别如下图:

    特性180° 定位舵机360° 连续旋转舵机
    控制参数意义脉宽→角度脉宽→速度方向
    是否定位
    适合应用定点定位、角度扫描速度驱动、轮式驱动
    代码实现区别设置脉宽一次,持续输出;持续输出脉宽做速度控制;
    停止方式断开 PWM 脉冲脉宽回 1.5 ms 或断开

    知识点3【180°舵机原理解析】

    控制方式:PWM(脉冲宽度调制

    1、舵机通过PWM控制旋转角度

    2、通常使用50Hz(周期20ms)的PWM信号。

    3、控制信号的高电平时间(脉宽)决定转角,如下图表:

    脉宽(ms)角度(大约值)
    0.5 ms
    1.5 ms90°
    2.5 ms180°

    知识点4【360°舵机原理解析】

    工作流程:

    1. 接收同样的 50 Hz PWM 脉冲

    2. 驱动电路不再做角度锁定,而是将脉宽映射为“速度与方向”控制

    3. 输出轴持续旋转,直到 PWM 脉冲停止或脉宽回到中立值

    脉宽旋转方向与速度
    < 1.5 ms反向旋转,脉宽越短速度越快
    ≈ 1.5 ms停止(无转矩输出)
    > 1.5 ms正向旋转,脉宽越长速度越快

    知识点5【注意事项】

    1、电源要求

    SG90的推荐工作电压时5V,不要直接使用STM32板的3.3V供电,否则容易抖动,或不工作。

    2、不要强行转动舵机输出轴

    容易破坏内部齿轮或位置反馈电位器。

    知识点4【代码演示】

    我是用的是STM32F10x系列的,TIM2CH1。


main.c


#include 'stm32f10x.h'

#include 'stm32f10x_conf.h'

#include 'usart.h'

#include 'tim.h'


int main(void)

{

//有限级组的配置

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

TIM2_CH1_Init();

TIM2_CH1_GPIO_Init();

Usart1_Init(9600);

TIM3_Init();

while(1)

{

}

}



tim.c


#include 'tim.h'

#define MAX_SPEED 60.0f

const u16 period = 1000;

u16 pulse = 0;

int speed = 0;

int state = 30;

void TIM2_CH1_Init(void)

{

TIM_TimeBaseInitTypeDef TIM2_TimeBaseStruct;

TIM_OCInitTypeDef TIM2_OCStruct;

NVIC_InitTypeDef NVIC_TIM2Struct;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

TIM_TimeBaseStructInit(&TIM2_TimeBaseStruct);

TIM2_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;

TIM2_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;

TIM2_TimeBaseStruct.TIM_Period  = period - 1;

TIM2_TimeBaseStruct.TIM_Prescaler = 1440 - 1;

TIM2_TimeBaseStruct.TIM_RepetitionCounter = 0;

TIM_TimeBaseInit(TIM2,&TIM2_TimeBaseStruct);

pulse = speed * (2/180) *50 + 25;

TIM_OCStructInit(&TIM2_OCStruct);

TIM2_OCStruct.TIM_OCMode = TIM_OCMode_PWM1;

TIM2_OCStruct.TIM_OCPolarity = TIM_OCPolarity_High;

TIM2_OCStruct.TIM_OutputState = TIM_OutputState_Enable;

TIM2_OCStruct.TIM_Pulse = pulse;

TIM_OC1Init(TIM2,&TIM2_OCStruct);

TIM_Cmd(TIM2,ENABLE);

}


void TIM3_Init(void)

{

TIM_TimeBaseInitTypeDef TIM3_TimeBaseStruct;

NVIC_InitTypeDef NVIC_TIM3Struct;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);

TIM_TimeBaseStructInit(&TIM3_TimeBaseStruct);

TIM3_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;

TIM3_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;

TIM3_TimeBaseStruct.TIM_Period  = 20000 - 1;

TIM3_TimeBaseStruct.TIM_Prescaler = 7200 - 1;

TIM3_TimeBaseStruct.TIM_RepetitionCounter = 0;

TIM_TimeBaseInit(TIM3,&TIM3_TimeBaseStruct);

NVIC_TIM3Struct.NVIC_IRQChannel = TIM3_IRQn;

NVIC_TIM3Struct.NVIC_IRQChannelCmd = ENABLE;

NVIC_TIM3Struct.NVIC_IRQChannelPreemptionPriority = 1;

NVIC_TIM3Struct.NVIC_IRQChannelSubPriority = 1;

NVIC_Init(&NVIC_TIM3Struct);

TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);

TIM_Cmd(TIM3,ENABLE);

}


void TIM2_CH1_GPIO_Init(void)

{

GPIO_InitTypeDef GPIOA_InitStruct;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

GPIO_StructInit(&GPIOA_InitStruct);

GPIOA_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

GPIOA_InitStruct.GPIO_Pin = GPIO_Pin_0;

GPIOA_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_Init(GPIOA,&GPIOA_InitStruct);

}


void TIM3_IRQHandler(void)

{


if(TIM_GetITStatus(TIM3,TIM_IT_Update) == SET)

{

TIM_ClearITPendingBit(TIM3,TIM_IT_Update);

speed += state;

if(speed >= 60)

{

state = -30;

}

else if(speed <= -60)

{

state = 30;

}

//角度处理

pulse = (u16)(speed * (1.0f/20) *(period / MAX_SPEED) + 1.5f / 20 * 1000);

printf('Speed:%d r/s\n',speed);

TIM_SetCompare1(TIM2,pulse);

}

}



usart.c


//串口1初始化

void Usart1_Init(u32 Baud)

{

GPIO_InitTypeDef GPIOB_InitStruct;

USART_InitTypeDef USART1_InitStruct;

//时钟配置 USART1,TX:PA9,RX:PA10

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

//端口配置

GPIOB_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;

GPIOB_InitStruct.GPIO_Pin = GPIO_Pin_9;

GPIOB_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA,&GPIOB_InitStruct);

GPIOB_InitStruct.GPIO_Pin = GPIO_Pin_10;

GPIOB_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_Init(GPIOA,&GPIOB_InitStruct);

//串口初始化

USART1_InitStruct.USART_BaudRate = Baud;

USART1_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

USART1_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;

USART1_InitStruct.USART_Parity = USART_Parity_No;

USART1_InitStruct.USART_StopBits = USART_StopBits_1;

USART1_InitStruct.USART_WordLength = USART_WordLength_8b;

USART_Init(USART1,&USART1_InitStruct);

//使能串口

USART_Cmd(USART1,ENABLE);

}


//串口1发送数据函数发送数据

void USART1_Trans(u8 c)

{

while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);

USART_SendData(USART1,c);

while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);

}


int fputc(int c,FILE *stream)

{

USART1_Trans((u8)c);

return c;

}


 代码运行结果

结束

代码重在练习!

代码重在练习!

代码重在练习!

关键字:STM32  SG90  舵机控制 引用地址:STM32实战教程:SG90舵机控制原理深度解析及代码详解

上一篇:基于STM32F103精灵开发板点亮LED灯实战教程:以PA0为例
下一篇:STM32 OTA 中断向量表重定向详解

推荐阅读最新更新时间:2026-03-25 10:40

stm32控制舵机
#include stm32f10x.h void GPIO_TimPWM(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //TIM_CH2 GPIOA_Pin_7输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50M
[单片机]
<font color='red'>stm32</font><font color='red'>控制</font><font color='red'>舵机</font>
STM32之使用PWM控制多路舵机
前言 最近在玩一个6自由度的机械臂,我手上这台机械臂的核心控制器件就是那六个能够180度旋转的舵机了。想想之前在学校还没有系统性的把舵机给玩明白,所以就索性拿手上的STM32来自己写驱动代码,将6个舵机给驱动起来。 舵机控制原理 舵机的控制原理还是比较简单的,而且控制的角度和精度能够比较好的按照开发者的意愿来进行,因此经常被应用与一些控制类器械中,如机械手、云台、2自由度摄像头等产品中。 舵机的外接线一般分为3根线,电源线、地线和信号线,而控制舵机转动,就是通过信号线给舵机发送一系列的周期信号(一般的舵机的能接收的信号周期为20ms),然后通过控制周期信号的高电平的持续时间来达到控制舵机转动的目的。我手上的
[单片机]
<font color='red'>STM32</font>之使用PWM<font color='red'>控制</font>多路<font color='red'>舵机</font>
stm32控制舵机DS3115转动
一、舵机DS3115 一般来讲,舵机主要由以下几个部分组成, 舵盘、减速齿轮组、位置反馈电位计5k、直流电机、控制电路板等。 工作原理:控制电路板接受来自信号线的控制信号(具体信号待会再讲),控制电机转动,电机带动一系列齿轮组,减速后传动至输出舵盘。舵机的输出轴和位置反馈电位计是相连的,舵盘转动的同时,带动位置反馈电位计,电位计将输出一个电压信号到控制电路板,进行反馈,然后控制电路板根据所在位置决定电机的转动方向和速度,从而达到目标停止。 舵机的基本结构是这样,但实现起来有很多种。例如电机就有有刷和无刷之分,齿轮有塑料和金属之分,输出轴有滑动和滚动之分,壳体有塑料和铝合金之分,速度有快速和慢速之分,体积有大中小三种之分等等,组合不
[单片机]
ARM9无线遥控视频实时监控小车(二)--------摄像头舵机控制模块
舵机控制原理及使用说明更具一下地址的文件就可以了 http://wenku.baidu.com/view/8902f4125f0e7cd18425361d.html 最主要是的怎么样让我的ARM开发板产生PWM波 S3C2440的开发板上义工也就5个定时器 我主要用的是定时器0和定时器1,可以根据自己的手册找到他们所在的位置 我的ARM班的两个GPB0和GPB1分别对应开发板上的蜂鸣器和R47 因为我不用液晶屏所以用掉GPB0是没有关系的,还有我把蜂鸣其给卸了 接下来是编写驱动,定时器驱动网上有很多参考的推荐看楼下的,第一篇看不懂看第二篇 http://apps.hi.baidu.com/share/detail/
[单片机]
舵机中的直流电机控制原理和方法
本文简单介绍在舵机中的直流电机控制原理和方法。下图是控制器原理图,单片机选择stm32f030,驱动选择fm116b,ldo为lp2992,这个可以任意选择兼容的芯片,电压反馈端用tl431进行分流稳压,确保反馈电阻器供电电压的稳定。 舵机的工作原理很简单,处理器实时获取电阻器的ADC值来计算获得当前的角度,如果与预期的角度一致,就不做任何操作,保持当前状态;如果与预期角度不同,就计算出当前角度与预期角度的差值,然后通过PID算法计算出控制量,根据控制量输出PWM控制电机旋转,随着电机旋转,实时角度会越来越接近预期值,控制输出也会越来越小,直到最后为0,就转到了预期的位置。 本方案通过I2C接口获取控制命令,可以实现比传统
[单片机]
<font color='red'>舵机</font>中的直流电机<font color='red'>控制</font>原理和方法
ZigBee-CC2530单片机 - 1路硬件PWM控制舵机角度(精度为1us)
程序源码 #include ioCC2530.h typedef unsigned char uchar; typedef unsigned int uint; //系统时钟初始化 void SystemClockInit() { CLKCONCMD &= ~0x40; //设置系统时钟源为32MHZ晶振 while(CLKCONSTA & 0x40); //等待晶振稳定为32M CLKCONCMD &= ~0x07; //设置系统主时钟频率为32MHZ } //定时器1输出PWM void Timer1PwmInit() { uint value; CLKCONCMD |= 0x28;
[单片机]
S3C2440开发板裸机程序系列09—PWM控制舵机
1. Timer1的PWM控制舵机 S3C2440的Timer0、Timer1、Timer2和Timer3具有PWM功能,以前的blog已经叙述过,详见: S3C2440开发板裸机程序系列05—定时器PWM TQ2440开发板的Timer0的TOUT0输出连接了Beep,所以,这次利用Timer1的TOUT1输出来连接舵机的控制信号。 舵机的内部有一个基准电路,产生周期为20ms,宽度为1.5ms的基准信号,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。通过调整控制信号的高电平宽度,即可实现舵机不同转角的控制。 舵机控制原理详见:舵机的原理和控制 程序思路很简单: 设置GPB1为TOUT1的输出格
[单片机]
S3C2440开发板裸机程序系列09—PWM<font color='red'>控制</font><font color='red'>舵机</font>
51单片机-遥控器控制舵机
1.题目要求 我们在第九章第2讲第一个例程“按键控制舵机桨”的基础上,实现用红外遥控器的前三行按键控制舵机桨停留在我们想要的位置,这样就实现了无线遥控控制机械结构运动的简单功能。 2.main.c测试代码 #include reg52.h #include function.h //详见第六章第8讲 #include timer.h //详见第八章第11讲 #include infrared.h //详见第十三章第2讲 sbit PWMOUT=P1^7; u8 highval = 10; void main() { LED_Init(); //初始化LED硬件模块 EA = 1; Ini
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved