本文完整的工程代码获取方式放在文末,需要的自行获取。
如需其它模块学习教程,可在评论区留言或私信作者,免费更新!
前言
通过本文可以学到STM32F103C8T6控制多个舵机,相同的代码适用多种型号的舵机,如SG90、SG92R、MG90S、MG995、MG996R等舵机。
本文示例代码为控制四个SG90舵机(180°)的转动,可以控制舵机转动到任意特定的角度。
一、使用到的工具
1.Jiayou-01主控板(包含四路舵机控制口,使用方便);
2.SG90舵机四个;
3.12V锂电池(供电);
二、舵机介绍
1.什么是舵机?
舵机是一种位置(角度)伺服的驱动器,内部安装了一个电位器(或其它角度传感器)检测输出轴转动角度,控制板根据电位器的信息能比较精确的控制和保持输出轴的角度。这样的直流电机控制方式叫闭环控制,所以舵机更准确的说是伺服马达,英文servo。
舵机的转动由PWM脉冲控制,每经过一个脉冲舵机转过一个特定的角度。同时舵机是一个闭环控制系统,因为,伺服电机本身具备发出脉冲的功能,所以伺服电机每旋转一个角度,都会发出对应数量的脉冲,这样,和伺服电机接受的脉冲形成了呼应,或者叫闭环,如此一来,系统就会知道发了多少脉冲给伺服电机,同时又收了多少脉冲回来,这样,就能够很精确的控制电机的转动,从而实现精确的定位。广泛应用于航模、遥控玩具、机器人、云台等等需要控制角度的场合。
2.常见的舵机
SG90、SG92R、MG90S、MG995、MG996R等,这几款舵机区别主要就在齿轮材质和扭矩以及旋转角度的不同,SG90是基础使用的较为广泛的。MG90S相当于SG90的加强版,有金属齿可选,扭矩加大,在安装尺寸和SG90略微不同。同型号舵机的180度版本和360度版本在尺寸和外观上是一样的,只是可控旋转角度不同,如下图所示。
3.舵机接口定义
舵机共有三条线,分别为VCC、GND、S(信号线);
对于供电电压(本文SG90采用5V供电),可以根据自己使用的舵机型号而定,通过电商平台购买的在商品参数处可以查到对应舵机的供电电压。如下图所示:
4.舵机的控制方式
我们通常说的和较常用的舵机一般指的是180度的舵机,也就是在0-180°内可控旋转的舵机,给这样的舵机一个特定的PWM信号,舵机会在0-180°内转到一个特定的角度。而给360度舵机一个特定的PWM信号,舵机会以一个特定的速度转动,转动方向也可以控制,但是不能控制旋转到某个特定的角度,类似于无级变速的减速电机,但与减速电机不同的是,360舵机是闭环控制,速度控制稳定。
舵机的控制一般需要一个20ms(50Hz)左右的时基脉冲,该脉冲的高电平部分为0.5ms-2.5ms范围内的角度控制脉冲部分,总间隔为2ms。
以180度角度为例,那么对应的控制关系是这样的:
三、项目硬件接线原理
系统选用了Jiayou-01主控板,主控板包含四个舵机驱动接口,本项目采用Jiayou-01主控板驱动舵机。(杜邦线接线电路稳定性极低,不建议用杜邦线连接,选购链接如下,需要的读者可以根据自己的情况选择性购买,购买主控板免费提供技术支持)
1.供电电源(注:供电不足舵机工作可能会不正常)
因为舵机功率比较大,为了确保供电的稳定性,本项目采用12V锂电池供电,电池接到主控板通过降压模块降压至5V给舵机供电。降压电路如下图所示。
2.舵机接线图
①四个舵机分别接到STM32F103C8T6单片机PA0、PA1、PA2、PA3引脚上。
PA0、PA1、PA2、PA3是STM32F1定时器2 PWM输出的四个通道。
②实物电路连接图
四、代码实现
1.初始化TIM2产生频率为50Hz的PWM方波。
/*
*** TIM2 配置定时器2PWM控制SG90舵机 ***
*** PWM频率:50Hz ***
*** 接口:PA0->舵机1 PA1->舵机2 PA2->舵机3 PA3->舵机4 ***
*** 作者:陈加油嗯 ***
***关注微信公众号学习更多单片机知识:微信搜索“陈加油嗯” ***
*/
void myServo_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能定时器2时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIO外设;————假如要AFIO复 用功能模块时钟则要加上( | RCC_APB2Periph_AFIO)
//GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射 TIM3_CH2->PB5
//初始化输出TIM2四个通道PWM脉冲波形的引脚(CH1->PA0 CH2->PA1 CH3->PA2 CH4->PA3)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; //CH1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO
//初始化TIM2
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
//初始化TIM2 Channe 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(TIM2, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM2 OC1
TIM_OC2Init(TIM2, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM2 OC2
TIM_OC3Init(TIM2, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM2 OC3
TIM_OC4Init(TIM2, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM2 OC4
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); //使能TIM2在CCR1上的预装载寄存器
TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); //使能TIM2在CCR1上的预装载寄存器
TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable); //使能TIM2在CCR1上的预装载寄存器
TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable); //使能TIM2在CCR1上的预装载寄存器
TIM_Cmd(TIM2, ENABLE); //使能TIM 2
}
2.控制TIM2通道的占空比,控制舵机。
舵机回零代码和转到最大角度代码如下:
/*
*** TIM2 四个通道输出PWM 控制SG90舵机 舵机回零 ***
*** PWM频率:50Hz 高电平0.5ms ***
*** 接口:PA0->舵机1 PA1->舵机2 PA2->舵机3 PA3->舵机4 ***
*** 作者:陈加油嗯 ***
***关注微信公众号学习更多单片机知识:微信搜索“陈加油嗯” ***
*/
void Servo1234_0du(void)
{
TIM_SetCompare1(TIM2,50); //舵机1 0.5ms
TIM_SetCompare2(TIM2,50); //舵机2 0.5ms
TIM_SetCompare3(TIM2,50); //舵机3 0.5ms
TIM_SetCompare4(TIM2,50); //舵机4 0.5ms
Delay_ms(500);
}
/*
*** TIM2 四个通道输出PWM 控制SG90舵机 舵机转到最大角度 ***
*** PWM频率:50Hz 高电平2.5ms ***
*** 接口:PA0->舵机1 PA1->舵机2 PA2->舵机3 PA3->舵机4 ***
*** 作者:陈加油嗯 ***
***关注微信公众号学习更多单片机知识:微信搜索“陈加油嗯” ***
*/
void Servo1234_180du(void)
{
TIM_SetCompare1(TIM2,250); //舵机1 2.5ms
TIM_SetCompare2(TIM2,250); //舵机2 2.5ms
TIM_SetCompare3(TIM2,250); //舵机3 2.75ms
TIM_SetCompare4(TIM2,250); //舵机4 2.75ms
Delay_ms(500);
}
3.主函数代码
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "oled.h"
#include "myServo.h"
/*
*** main 主函数代码 ***
*** 定时器2初始化(控制舵机) OLED初始化 ***
*** 作者:陈加油嗯 ***
***关注微信公众号学习更多单片机知识:微信搜索“陈加油嗯” ***
*/
int main(void)
{
Delay_ms(100); //延时100ms,等电压稳定下来再初始化代码(可以防止OLED上电不亮等问题)
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
myServo_Init(1999,719); //定时器2,产生PWM波,周期20ms,50HZ,控制舵机
OLED_Init(); //OLED初始化
OLED_ColorTurn(0); //0正常显示,1 反色显示
OLED_DisplayTurn(0); //0正常显示 1 屏幕翻转显示
OLED_Clear(); //清屏
OLED_Refresh(); //更新显存到OLED(即刷新刚写入的数据,刷新屏幕)
//OLED静态显示字符
OLED_ShowString(0,0,"chenjiayou!",16,1);
OLED_Refresh(); //更新显存到OLED(即刷新刚写入的数据,刷新屏幕)
while(1)
{
Servo1234_0du(); //舵机转到0°
Servo1234_180du(); //舵机转到180°
}
}
五、实验现象
根据原理图接好线路,把工程代码下载到STM32F103单片机中,打开电源开关可以看到舵机在0度至180度之间循环转动。(可以根据自己的需求修改代码,可以控制舵机转动到任意你需要的角度)