完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
最近学习了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控制舵机旋转到不同角度完整代码。 |
|
|
|
只有小组成员才能发言,加入小组>>
2400 浏览 0 评论
8961 浏览 4 评论
36582 浏览 19 评论
4997 浏览 0 评论
24449 浏览 34 评论
1411浏览 2评论
1664浏览 1评论
2078浏览 1评论
1473浏览 0评论
431浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-1 10:07 , Processed in 1.266369 second(s), Total 78, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号