舵机MG90s
具体的周期计算公式为:周期=(arr+1)*(psc+1)/CLK。其中CLK为计数器的时钟频率,我的是72MHZ,也就是72000000。最后计算结果单位为秒,结果为0.02s,也就是20ms。这样的配置就是为了让输出的PWM信号达到舵机要求的20ms周期。
舵机上有三根线,分别是GND、VCC和SIG,也就是地线、电源线和信号线,其中的PWM波就是从信号线输入给舵机的。
一般来说,舵机接收的PWM信号频率为50HZ,即周期为20ms。当高电平的脉宽在0.5ms-2.5ms之间时舵机就可以对应旋转到不同的角度。如下图。
/* 系统默认时钟72MHz, 初始化定时器生成PWM, 参考正点原子的程序
* 72000000/(719+1)/(1999+1)=50Hz 1/50*1000=20ms
*/
TIM3_PWM_Init(1999,719);
...
for(i=150;i<200;i++) /* 150/2000=7.5% 90度 */
{
TIM_SetCompare2(TIM3,i); /* 调节占空比 */
delay_ms(5);
}
for(i=200;i>100;i--) /* 200/2000=10% */
{
TIM_SetCompare2(TIM3,i);
delay_ms(5);
}
for(i=100;i<150;i++) /* 100/2000=5% */
{
TIM_SetCompare2(TIM3,i);
delay_ms(5);
}
/* 以上for重复运行就可以实现舵机左右摆动 */
如图总共三根线:
棕色地线接GND
红色vcc接5v
黄色信号线接io口,输入pwm信号
main.c:
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "timer.h"
#include "OLED_I2C.h"
#include "lcd.h"
#include<string.h>
#include<stdio.h>
int main(void)
{
u16 led0pwmval=0;
// Stm32_Clock_Init(9); //系统时钟设置
// LCD_Init();
// u8 dir=1;
POINT_COLOR=RED;//设置字体为红色
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
LED_Init(); //LED端口初始化
TIM3_PWM_Init(1999,719); //不分频。PWM频率=100000/2000=50hz
while(1)
{
u8 i=0;
int angle=0;
for(i=0;i<=6;i++)
{
angle=30*i;
led0pwmval=(int)(2000*(1-( ( 2.5-(angle/90.0) )/20.0 ) ))-1;//一次转动各种占空比的角度,可以自己列式子计算
//TIM_SetCompare2(TIM3,led0pwmval);
TIM3->CCR2=led0pwmval;
LED0=!LED0;
delay_ms(500);
}
}
库函数
void TIM3_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器3时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); //使能GPIO外设和AFIO复用功能模块时钟
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射 TIM3_CH2->PB5
//设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形 GPIOB.5
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
//初始化TIM3
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(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
//初始化TIM3 Channel2 PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM3 OC2
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR2上的预装载寄存器
TIM_Cmd(TIM3, ENABLE); //使能TIM3
}
寄存器
void TIM3_PWM_Init(u16 arr,u16 psc)
{
RCC->APB2ENR|=1;//afio使能
RCC->APB2ENR|=1<<3;//gpiob使能
RCC->APB1ENR|=1<<1;//定时器三使能
AFIO->MAPR|=1<<11;//部分重隐射 TIM3-ch2映射到 pb5
GPIOB->CRL&=0XFF0FFFFF;
GPIOB->CRL|=0X00B00000;//配置pb5 fuy复用推挽输出
TIM3->ARR=arr;
TIM3->PSC=psc;
TIM3->CR1|=0<<4;//向上计数
TIM3->CR1|=0<<8;//时钟分频因子为0
TIM3->CCER|=0<<5;//输出极性高
TIM3->CCER|=1<<4;//通道输出使能
TIM3->CCMR1|=7<<12;//pwm2模式
TIM3->CR1|=1;//打开计数器 使能
}