STM32--舵机(SG90)

文章目录

      • 一、介绍
      • 二、 工作原理
      • 三、舵机的控制
      • 四、 设计流程
      • 五、代码实现
      • 六、舵机工程代码
      • 七、备注

舵机

一、介绍

  舵机是一种位置(角度)伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。目前在高档遥控玩具,如航模,包括飞机模型,潜艇模型;遥控机器人中已经使用得比较普遍。舵机是一种俗称,其实是一种伺服马达。

二、 工作原理

  控制信号由接收机的通道进入信号调制芯片,获得直流偏置电压。它内部有一个基准电路,产生周期为20ms,宽度为1.5ms的基准信号,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。最后,电压差的正负输出到电机驱动芯片决定电机的正反转。当电机转速一定时,通过级联减速齿轮带动电位器旋转,使得电压差为0,电机停止转动。当然我们可以不用去了解它的具体工作原理,知道它的控制原理就够了。就象我们使用晶体管一样,知道可以拿它来做开关管或放大管就行了,至于管内的电子具体怎么流动是可以完全不用去考虑的。

三、舵机的控制

舵机的控制一般需要一个20ms左右的时基脉冲,该脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分。以180度角度伺服为例,那么对应的控制关系是这样的:

时间 角度
0.5ms 0度
1ms 45度
1.5ms 90度
2.0ms 135度
2.5ms 180度
STM32--舵机(SG90)_第1张图片

四、 设计流程

  单片机系统实现对舵机输出转角的控制,必须首先完成两个任务:首先是产生基本的PWM周期信号,本设计是产生20ms的周期信号;其次是脉宽的调整,即单片机模拟PWM信号的输出,并且调整占空比。
  当系统中只需要实现一个舵机的控制,采用的控制方式是改变单片机的一个定时器中断的初值,将20ms分为两次中断执行,一次短定时中断和一次长定时中断。这样既节省了硬件电路,也减少了软件开销,控制系统工作效率和控制精度都很高。
  具体的设计过程:例如想让舵机转向左极限的角度,它的正脉冲为2ms,则负脉冲为20ms-2ms=18ms,所以开始时在控制口发送高电平,然后设置定时器在2ms后发生中断,中断发生后,在中断程序里将控制口改为低电平,并将中断时间改为18ms,再过18ms进入下一次定时中断,再将控制口改为高电平,并将定时器初值改为2ms,等待下次中断到来,如此往复实现PWM信号输出到舵机。用修改定时器中断初值的方法巧妙形成了脉冲信号,调整时间段的宽度便可使伺服机灵活运动。
  为保证软件在定时中断里采集其他信号,并且使发生PWM信号的程序不影响中断程序的运行(如果这些程序所占用时间过长,有可能会发生中断程序还未结束,下次中断又到来的后果),所以需要将采集信号的函数放在长定时中断过程中执行,也就是说每经过两次中断执行一次这些程序,执行的周期还是20ms。
STM32--舵机(SG90)_第2张图片

五、代码实现

舵机主要使用PWM信号进行控制,需要用到定时器输出PWM信号,这里使用的是定时器3和定时器4,没有使用复用功能,具体的引脚如下图:
STM32--舵机(SG90)_第3张图片
sg90.c

#include "sg90.h"
#include "usart.h"

//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void PWM_Init(u16 arr,u16 psc)
{
    GPIO_InitTypeDef GPIO_InitStructure;              //定义GPIO结构体 需要用结构体类型参数时候一定要先在前面定义
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;    //定义TIMx定时器结构体
    TIM_OCInitTypeDef TIM_OCInitStructure;            //定义定时器脉宽调制结构体
    
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3|RCC_APB1Periph_TIM4,ENABLE);          //使能TIM3、4时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);//使能GPIOA时钟和GPIOB时钟
    
//    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);                     //TIM3部分重映射 TIM3_CH2->PB5
	
    //设置该引脚为复用输出功能,输出TIM3、4 的PWM脉冲波形	GPIOB.0、1、6、7、8、9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;                               
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                         //复用输出 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;                       //配置输出速率
    GPIO_Init(GPIOB,&GPIO_InitStructure);                                   //初始化GPIOB
	
	 //设置该引脚为复用输出功能,输出TIM3 的PWM脉冲波形	GPIOA 6、7
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;                               
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                         //复用输出 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;                       //配置输出速率
    GPIO_Init(GPIOA,&GPIO_InitStructure);                                   //初始化GPIOA
	

	
	//初始化TIM3
    TIM_TimeBaseStructure.TIM_Period = arr;                                 //设置自动重装载寄存器周期的值 arr=value-1
    TIM_TimeBaseStructure.TIM_Prescaler = psc;                              //设置预分频值 psc=value-1
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;                            //设置时钟分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;             //TIM向上计数模式
    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);                          //初始化TIMx时间基数
    
	//初始化TIM4
    TIM_TimeBaseStructure.TIM_Period = arr;                                 //设置自动重装载寄存器周期的值 arr=value-1
    TIM_TimeBaseStructure.TIM_Prescaler = psc;                              //设置预分频值 psc=value-1
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;                            //设置时钟分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;             //TIM向上计数模式
    TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStructure);                          //初始化TIMx时间基数
	
	//初始化TIM3 Channel2 PWM模式     
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                       //选择定时器模式:TIM脉冲宽度调制模式1(改变占空比)
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;           //使能比较输出
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;               //输出极性:TIM输出比较极性高
	TIM_OC1Init(TIM3,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM3 OC1
    TIM_OC2Init(TIM3,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM3 OC2
	TIM_OC3Init(TIM3,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM3 OC2
	TIM_OC4Init(TIM3,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM3 OC2
	
	
    //初始化TIM4 Channel2 PWM模式     
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                       //选择定时器模式:TIM脉冲宽度调制模式1
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;           //使能比较输出
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;               //输出极性:TIM输出比较极性高
	TIM_OC1Init(TIM4,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM4 OC1
    TIM_OC2Init(TIM4,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM4 OC2
	TIM_OC3Init(TIM4,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM4 OC2
	TIM_OC4Init(TIM4,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM4 OC2

 
//    TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);                        //使能TIM3在CCR2上的预装载寄存器
    TIM_Cmd(TIM3, ENABLE);                                                  //使能TIM3
	TIM_Cmd(TIM4, ENABLE);                                                  //使能TIM4
}

main.c

 int main(void)
 {
 	vu8 key=0;	
	delay_init();	    	 //延时函数初始化	  
	LED_Init();		  		//初始化与LED连接的硬件接口
	KEY_Init();         	//初始化与按键连接的硬件接口
	PWM_Init(199,7199); //舵机初始化   不分频。PWM频率=72000000/900=80Khz
	LED0=0;					//先点亮红灯
	 
//计算,假设PWM周期设置为20ms
//公式为:溢出时间Tout=(arr+1)*(psc+1)/Tclk,Tclk为通用定时器的时钟,如果APB1没有分频,则就为系统时钟,72MHZ
	while(1)
	{
 		key=KEY_Scan(0);	//得到键值
	   	if(key)
		{						   
			switch(key)
			{				 
				case WKUP_PRES:	//控制舵机
				TIM_SetCompare1(TIM4,5);//定时器4通道1---0度
				delay_ms(1000);
				TIM_SetCompare1(TIM4,15);//定时器4通道1---90度
				delay_ms(1000);
					break; 
				case KEY1_PRES:	//控制LED1翻转	 
					LED1=!LED1;
					break;
				case KEY0_PRES:	//同时控制LED0,LED1翻转 
					LED0=!LED0;
					LED1=!LED1;
					break;
			}
		}else delay_ms(10); 
	}	 
}

六、舵机工程代码

舵机工程代码

七、备注

  1. 本文章是个人总结,如有错误请指正;
  2. 部分资料来源于网络和开发手册,如有侵权请联系我删除;
  3. 如需上方资料,请与我联系。

你可能感兴趣的:(STM32,stm32,单片机)