stm32控制舵机旋转到不同角度

2019-08-23来源: eefocus关键字:stm32  控制舵机  旋转  角度

最近学习了stm32,就想用它来控制舵机,然后写下这篇文章分享给大家,如果有理解不到位的地方欢迎大家指正。(我使用的是stm32f103ve型号的开发板,即使和你的型号不同,也有参考价值)


想要控制舵机的转动,首先你得知道舵的工作原理。


舵机的主要组成部分为伺服电机,所谓伺服就是服从信号的要求而动作。在信号来之前,转子停止不动;信号来到之后,转子立即运动。因此我们就可以给舵机输入不同的信号,来控制其旋转到不同的角度。

舵机接收的是PWM信号,当信号进入内部电路产生一个偏置电压,触发电机通过减速齿轮带动电位器移动,使电压差为零时,电机停转,从而达到伺服的效果。简单来说就是给舵机一个特定的PWM信号,舵机就可以旋转到指定的位置。

舵机上有三根线,分别是GND、VCC和SIG,也就是地线、电源线和信号线,其中的PWM波就是从信号线输入给舵机的。

一般来说,舵机接收的PWM信号频率为50HZ,即周期为20ms。当高电平的脉宽在0.5ms-2.5ms之间时舵机就可以对应旋转到不同的角度。如下图。

那么我们如何使用stm32给舵机输入信号,让它听从我们的指挥呢?


想要输出PWM信号自然就得用上TIM定时器,而基本定时器没有PWM信号的输出功能,所以只能选用通用定时器和高级定时器。对于初始化这些外设无非也就是那些套路,我总结为如下几点:1、开启该外设的时钟2、配置初始化结构体(如果有对应的GPIO还需要初始化该GPIO)3、调用结构体初始化函数4、该使能的使能

对于TIM来说初始化结构体有两个,分别是时基结构体和输出比较结构体,除此之外还需要做的是先选择具体开启哪条输出通道,我选择的是TIM1(高级定时器)的CH1(通道一),对应的GPIO是PA8。我还初始化了通道一的互补通道PB13,为了更加方便测试。下面是初始化部分的代码。


static void TIM_GPIO_Config(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

 

  // 输出比较通道 GPIO 初始化

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_8;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

 

  // 输出比较通道互补通道 GPIO 初始化

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_13;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOB, &GPIO_InitStructure);

// BKIN引脚默认先输出低电平

GPIO_ResetBits(ADVANCE_TIM_BKIN_PORT,ADVANCE_TIM_BKIN_PIN);

}

 

static void Advance_TIM_Config(void)

{

  // 开启定时器时钟,即内部时钟CK_INT=72M

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);

 

/*--------------------时基结构体初始化-------------------------*/

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断

TIM_TimeBaseStructure.TIM_Period= (200-1);

// 驱动CNT计数器的时钟 = Fck_int/(psc+1)

TIM_TimeBaseStructure.TIM_Prescaler= (7200-1);

// 时钟分频因子 ,用于配置死区时间,没用到,随意

TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;

// 计数器计数模式,设置为向上计数

TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;

// 重复计数器的值,没用到,可以随意设置

TIM_TimeBaseStructure.TIM_RepetitionCounter=0;

// 初始化定时器

TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

 

/*--------------------输出比较结构体初始化-------------------*/

TIM_OCInitTypeDef  TIM_OCInitStructure;

// 配置为PWM模式2

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;

// 输出使能

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

// 互补输出使能

TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; 

// 设置占空比大小

TIM_OCInitStructure.TIM_Pulse = 0;

// 输出通道电平极性配置

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

// 互补输出通道电平极性配置

TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;

// 输出通道空闲电平极性配置

TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;

// 互补输出通道空闲电平极性配置

TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;

TIM_OC1Init(ADVANCE_TIM, &TIM_OCInitStructure);

TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);

// 使能计数器

TIM_Cmd(TIM1, ENABLE);

// 主输出使能,当使用的是通用定时器时,这句不需要

TIM_CtrlPWMOutputs(TIM1, ENABLE);

}

 

void TIM_Init(void)

{

TIM_GPIO_Config();

Advance_TIM_Config();

}

在代码中要特别注意的是时基结构体的TIM_Period(自动重装载寄存器值,简称arr)和TIM_Prescaler(预分频寄存器值,简称psc),因为这两个决定了输出PWM信号的周期。具体的周期计算公式为:周期=(arr+1)*(psc+1)/CLK。其中CLK为计数器的时钟频率,我的是72MHZ,也就是72000000。最后计算结果单位为秒,结果为0.02s,也就是20ms。这样的配置就是为了让输出的PWM信号达到前面说到的舵机要求的20ms周期。


在初始化完成之后,就可以在main函数中实现信号的输出了。

前面说过,在周期20ms的PWM信号中,不同的脉宽对应舵机不同的转动角度,在0.5ms-2.5ms间有效,因此我们可以在main函数中配置几个不同的脉宽。要注意的是stm32并不直接配置脉宽,而是通过配置占空比来配置脉宽的。


配置占空比有个重要的函数TIM_SetCompare1(),具体用法如果不懂可以去看手册。main函数代码如下。


#include "stm32f10x.h"

#include "bsp_Advance_tim.h"

#include "delay.h"

 

int main(void)

{

int delay_time;

delay_init(); //延时函数初始化

TIM_Init(); //定时器初始化

delay_time = 500;

while(1)

{

delay_ms(delay_time);

TIM_SetCompare1(ADVANCE_TIM, 175); //对应180度

        delay_ms(delay_time);

TIM_SetCompare1(ADVANCE_TIM, 180); //对应135度

        delay_ms(delay_time);

TIM_SetCompare1(ADVANCE_TIM, 185); //对应90度

        delay_ms(delay_time);

TIM_SetCompare1(ADVANCE_TIM, 190); //对应45度

        delay_ms(delay_time);

TIM_SetCompare1(ADVANCE_TIM, 195); //对应0度

}

}

如果在定时器初始化时TIM_OCInitStructure.TIM_OCMode配置的是PWM1模式那么main中的占空比就依次为25、20、15、10、5。在你们自己试验时,可以将占空比设置成各种不同的值,看看有什么不同的效果。


在这补充一点如何连线:可以用杜邦线将舵机的电源与stm32的5v或3.3v引脚连接,将地线与stm32的GND连接,将舵机的信号线与stm32的PWM信号输出引脚连接。

关键字:stm32  控制舵机  旋转  角度

编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic472314.html
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:一步一步实现STM32-FOTA系列教程之Bootloader编写
下一篇:用PWM控制舵机(以是stm32为例)

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

秉火429笔记之一初识STM32

1. STM32概述STM32,ST为意法半导体,M是Microelectronics的缩写,32表示32位,简而言之,STM32即为ST公司开发的32位微控制器。2. STM32分类STM32包含多个系列,从内核分为Cortex-M0、M3、M4、M7,每个内核有大概分为主流、高性能和低功耗。3. STM32命名规则
发表于 2019-09-12
秉火429笔记之一初识STM32

基于STM32的简单电子书的实现

;,16,RED,WHITE,0);printf("res=%x",res);return 1;         }else{       fnShowString(10,120,"open ok",16,RED,WHITE,0);}        f_lseek(&f1,32*((H8-0xa0-1)*94+(L8-0xa0-1)));                 
发表于 2019-09-12

stm32 各头文件或C文件功能

stm32f10x_con.h配置文件:加载哪个外设、使能assert 对参数进行检查,如果使能了assert 需要在main文件中添加 _assert_faild 函数。 使能assert会增大编译出执行文件的大小,调试完后可以将assert 屏蔽。stm32f10x.h头文件中包含了stm32f10x_conf.h 。stm32f10x.h1、对所有的外设的地址进行映射,映射到存储区,即定义某外设结构体变量,因为结构体是连续存储的只要将外设的基地址强制转换为结构体类型的指针,那么该外设的寄存器就可以通过指针进行访问,以GPIO为例:定义外设的结构体,结构体变量都是volatile类型,告诉编译器不要进行优化,读取值从内存读取
发表于 2019-09-12

stm32通过spi连接esp8266的hspi 开发

刚刚做了stm32通过spi连接esp8266的开发,目前已经解决了遇到的大多数问题,基本可以交付使用了,写一篇文章留作记录,也可以给以后做这个的朋友做为参考。esp8266模块本身发布的时候默认里边烧写的是AT固件,虽然硬件上有spi的引脚,但是并不支持spi的通信,如果要支持spi的通信,自行修改编译esp8266的sdk,写自己需要的代码来实现。本身sdk中有相关的例程,根据例程的代码修改调试就可以实现相应的功能。使用spi的好处,第一 可以节省一个串口,因为stm的串口资源是比较有限的。另外spi的通讯速度要比串口快一些。这篇文章将包含如下的一些内容:1,stm32 spi的驱动如何开发?2,esp8266端的驱动如何开发
发表于 2019-09-12
stm32通过spi连接esp8266的hspi 开发

stm32的SPI设置步骤,SPI配置参数

用stm32的库进行深入SPI接口主要应用在EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。四根线MISO 主设备数据输入,从设备数据输出。MOSI 主设备数据输出,从设备数据输入。SCLK时钟信号,由主设备产生。CS从设备片选信号,由主设备控制。外设的写操作和读操作是同步完成的。如果只进行写操作,主机只需忽略接收到的字节时钟极性CPOL对传输协议没有重大的影响,代表串行同步时钟的空闲状态下的电平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升
发表于 2019-09-12

关于STM32f103 SPI时钟速度的问题

STM32f103 中APB1的最高频率是36MHz,APB2的最高频率是72MHz,而PCLK1和PCLK2一般也默认配置为其最高工作频率36M和72M。如下图(STM32F10xx_参考手册(第7版) 第46页)时钟树所示:SPI1时钟由APB2时钟分频而来,可以选择2、4、8、16、32、64、128、256这几个分频系数。而手册规定STM32的SPI时钟最快是18MHz。对于STM32F103的SPI1接口时钟,由72M的PCLK2分频得到,所以分配系数大于等于4(72M/4 = 18M)。对于STM32F103的SPI2/SPI3接口时钟,由36M的PCLK1分频得到,所以分配系数大于等于2(36M/2 = 18M
发表于 2019-09-12
关于STM32f103 SPI时钟速度的问题

小广播

何立民专栏

单片机及嵌入式宝典

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

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