一、前言
SG90舵机的工作原理主要是基于PWM(脉冲宽度调制)信号来控制。 SG90舵机内部有一个基准电压,微处理器产生的PWM信号通过信号线进入舵机,产生直流偏置电压,与舵机内部的基准电压做比较获得电压差输出。电压差的正负输出到电机驱动芯片上,从而决定电机的正反转。当舵机开始旋转的时候,舵机内部通过急联减速齿轮带动电位器旋转,使得电压差为零,电机停止转动。
SG90舵机还分为180度和360度的类型,以及模拟舵机和数字舵机。模拟舵机需要不断的发送PWM信号才能旋转到指定的位置,而数字舵机只需要给一个目的地的PWM信号,就可以转动到指定的位置。
在控制SG90舵机时,PWM波形的频率是50HZ,即周期为20毫秒。在这个周期内,通过控制高电平的时长,就能够控制舵机旋转的角度。例如,高电平为0.5毫秒时,舵机旋转到0度;高电平为2毫秒时,旋转到135度;高电平为1.5毫秒时,旋转到90度。
视频讲解:
STM32驱动SG90舵机实操(写代码实测)
SG90舵机的工作原理是通过接收PWM信号,控制电机的转动,从而带动舵机的旋转,实现精确的角度控制。
下面是180°的SG90舵机商家给出的说明:写了高电平时间与转动的角度对应关系。
什么样的波形是PWM波形? 下面的图片就是一个解释。
对于舵机的驱动原理: 只需要产生一个周期为20ms,高电平宽度为0.5ms-2.5ms的PWM方波就能驱动舵机。
180°舵机 是一次PWM波形就可以转到指定的角度。
360°舵机需要持续发送PWM波形才可以转动。
一个完整的PWM是由高电平和低电平组成的。 也就是一个周期内,也就是这个20ms内。 可以自由分配 高低电平的占用时间。
这个分配 高低电平的占用时间的过程就叫:调整占空比。
只需要控制这个20ms的周期内。高电平的时间在 0.5ms-2.5ms 范围的内的PWM波形。 就可以任意控制舵机转动。 那么 0.5ms-2.5ms 之间不同的值是有什么不同的效果? 对于: 90°舵机、180°的舵机 是不一样的。
我当前是采用STM32F103单片机驱动的SG90舵机,采用的定时器1的通道1和通道4产生PWM波形,控制2个SG90转动。
定时器1的CCR1寄存器就是比较寄存器,定时器1的CNT寄存器在定时器启动之后就会不断的自增或自减(具体看配置),简单的说就是,CNT寄存器是一个时间基准;而输出的PWM占空比就是依靠CNT寄存器的值与CCR1寄存器的值进行相互比较。 比谁大谁小,从而控制当前的电平是低电平还是高电平,这个过程就是控制占空比的过程。 具体的代码表现形式就是: TIM1->CCR1=xxx
。
STM32F103RCT6单片机定时器的运行频率是72MHZ; 如果我的定时器分频为720,重装载值填2000,这样的配置,输出的一个PWM周期就是50HZ,也就一个周期的总时间是20ms。
那么如何在代码里,如何实现控制 0.5ms-2.5ms 这个范围的高电平?
如果设置为: TIM1->CCR1=1860; 就表示 2000 -1860 = 140 = 1.4ms高电平。
如果设置为: TIM1->CCR1=1880; 就表示 2000 -1880= 120 = 1.2ms高电平。
…
…
…
二、程序开发
2.1 逻辑分析仪测试
写好代码之后,可以先用逻辑分析仪检测一下单片机IO口输出的PWM情况。
如果设置为: TIM1->CCR1=1860; 就表示 2000 -1860 = 140 = 1.4ms高电平。
看下面的逻辑分析仪测量的结果:
2.2 舵机的驱动问题
SG90舵机驱动的时候,要给外部电源。 如果采用开发板USB供电,是带不动2个以及2个以上的SG90舵机,需要外接稳压电源提供足够的电流才可以正常驱动舵机转动。 这个一定要注意。
2.3 完整代码
#include "stm32f10x.h"
#include "delay.h"
#include "usart.h"
#include <string.h>
#include "timer.h"
#include <string.h>
#include <stdlib.h>
/*
STM32F103C8T6可以用的IO口:PA0-PA15, PB0-PB15, PC13-PC15
STM32F103C8T6最小系统板的IO口。
PB11 PB10 PB1 PB0 PA7 PA6 PA5 PA4 PA3 PA2 PA1 PA0 PC15 PC14 PC13
PB12 PB13 PB14 PB15 PA8 PA9 PA10 PA11 PA12 PA15 PB3 PB4 PB5 PB6 PB7 PB8 PB9
PA13(SWDIO)和PA14(SWCLK): 用作STLNK-V2下载器的-SW模式的下载口。
【】摄像头云台舵机
GND----------->GND
VC------------->5V
PA8------------>IO(上下控制舵机)-定时器1的PWM-CH1
PA11---------->IO (左右控制舵机)-定时器1的PWM-CH4
*/
//舵机停止
void motor_Ctrl_Up_Down_stop(void)
{
TIM1->CCR1=1850; //改变占空比
}
//舵机停止
void motor_Ctrl_Left_Right_stop(void)
{
TIM1->CCR4=1850; //改变占空比
}
//舵机开始转动: 正向
void motor_Ctrl_Up_Down_1(void)
{
TIM1->CCR1=1860; //改变占空比
}
//舵机开始转动: 反向
void motor_Ctrl_Up_Down_2(void)
{
TIM1->CCR1=1840; //改变占空比
}
//舵机开始转动: 正向
void motor_Left_Right_Down_1(void)
{
TIM1->CCR4=1860; //改变占空比
}
//舵机开始转动: 反向
void motor_Left_Right_Down_2(void)
{
TIM1->CCR4=1840; //改变占空比
}
//JTAG模式设置,用于设置JTAG的模式
//mode:jtag,swd模式设置;00,全使能;01,使能SWD;10,全关闭;
#define JTAG_SWD_DISABLE 0X02
#define SWD_ENABLE 0X01
#define JTAG_SWD_ENABLE 0X00
void JTAG_Set(u8 mode)
{
u32 temp;
temp=mode;
temp<<=25;
RCC->APB2ENR|=1<<0; //开启辅助时钟
AFIO->MAPR&=0XF8FFFFFF; //清除MAPR的[26:24]
AFIO->MAPR|=temp; //设置jtag模式
}
void set_pwm_1(float ms)
{
if(ms >20)
{
ms=20;
}
TIM1->CCR1=2000-(ms*100);
}
void set_pwm_4(float ms)
{
if(ms >20)
{
ms=20;
}
TIM1->CCR4=2000-(ms*100);
}
int main()
{
//开启STLINK_SWD下载模式
JTAG_Set(SWD_ENABLE);
//串口1初始化,用于打印
USART1_Init(115200);
printf("STM32串口1初始化成功.\r\n");
//初始化定时器1,输出PWM,通道1、4,控制SG90舵机
//一个周期20ms
TIM1_PWM_Init(2000,720); //计数频率 单脉冲+重复计数模式
//转动到0°
set_pwm_1(0.5);
set_pwm_4(0.5);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
while(1)
{
//转动到90°
set_pwm_1(1.5); //第一个先转90
set_pwm_4(2.5); //第二个再转180
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
set_pwm_1(0.5); //之后第一个再转到0。
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
set_pwm_1(1.5); //然后第一个再赚到90。
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
set_pwm_4(0.5);//然后第二个再占到零。
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
set_pwm_1(0.5); //然后第一个在转到零。
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
}
}