写作目的:今天在尝试使用舵机的时候遇到了一点问题,所以想把这些问题记录下来,方便以后再次遇到的时候,可以快速解决,也方便大家遇到的时候可以快速解决。
一.180°的舵机安装
在安装舵机之前,应该先调试舵机,如果用-90°——90°来表示方向的话,则应该先确定舵机的零度的位置,再进行安装;如果用0°——180°来表示方向的话,则应该确定90°的位置,再进行安装。先确定位置再安装的方法会使舵机的角度就会比较容易调节,或者说比较容易设定。
二自由度云台(舵机)安装图
/*
周期为20ms
0.5ms——-90°
1 ms——-45°
1.5ms—— 0°
2 ms—— 45°
2.5ms—— 90°
当高级定时器TIM8周期为20ms时
arr=200 pcs=16800
TIM8_Init(200,16800);//5ms
高电平时间 t=(crr/arr)*20ms=crr/10ms
当ccr为10时对应的高电平为1ms
公式推导——线性变化:
令servo_angle=a*t+b (t以ms为单位)
==>0.5a+b=-90
==>a+b=-45
==>a=90,b=-135
==>servo_angle=90/10*crr-135=9*crr-135 ==>crr=(servo_angle+135)/9
*/
void servo_angle(int yaw_angle,int pitch_angle)
{
int ccr;
if(yaw_angle>90) yaw_angle=90;
else if(yaw_angle<-90) yaw_angle=-90;
if(pitch_angle>90) pitch_angle=90;
else if(pitch_angle<-90) pitch_angle=-90;
TIM8->CCR1=(yaw_angle+135)/9; //(这个安装刚刚好)
TIM8->CCR2=(pitch_angle+135-50)/9;//(-50)是为了矫正安装误差
}
第一种方式表示代码以及推导过程
/*
周期为20ms
0.5ms—— 0°
1 ms——45°
1.5ms——90°
2 ms——135°
2.5ms——180°
当高级定时器TIM8周期为20ms时
arr=200 pcs=16800
TIM8_Init(200,16800);//5ms
这样表示更容易理解:
crr=(servo_angle/180)*20+5 (servo_angle/180是一种对应的占比,20对应180最大时的crr,5对应0°时的基数)
当servo_angle=0时 crr=5刚好 t=(crr/arr)*20ms=0.5ms 对应0°
当servo_angle=180时 crr=25刚好 t=(crr/arr)*20ms=2.5ms 对应180°
这样就是一种线性关系
完全正:Servo_SetAngle(90,40); (因为是刚刚接触,所以没有找到正确的脚度就可以安装,所以存在误差)
pitch_angle越小,越往下(但好像不只是180°)
yaw_angle越小,从上往下看顺时针
*/
void Servo_SetAngle(float yaw_angle,float pitch_angle)
{
if(yaw_angle>180) yaw_angle=180;
else if(yaw_angle<0) yaw_angle=0;
if(pitch_angle>180) pitch_angle=180;
else if(pitch_angle<0) pitch_angle=0;
TIM_SetCompare1(TIM8, (yaw_angle * 20/ 180 + 5));
TIM_SetCompare2(TIM8, (pitch_angle * 20/ 180 + 5));
}
第二种方式表示代码以及推导过程
二.舵机的调试
舵机的调试比较简单,如果代码没有遗落的话,基本都是可以直接套用就行,但是我在调试的用的是高级定时器TIM8,在调试的时候,就忽略了两个问题,一个是直接用stm32f1芯片的板子时候定时器的引脚是可以直接用的,但是这一次不知道为什么需要先复用引脚PC6,PC7才能正常使用,就因为这两语句废了我两小时;另一个原因是因为我用的是高级定时器TIM8所以需要添加一个语句“TIM_CtrlPWMOutputs(TIM8,ENABLE);//高级定时器输出必须使能这句”,原因可能是(个人的理解):
在stm32单片机中,高级定时器(Advanced Timer)具有多个输出通道。定时器TIM8有多个PWM输出通道。这些输出通道可以用于控制电机、LED灯等外部设备的电平或电流。
为了使用这些输出通道并使其产生PWM信号,需要通过使能(enable)相关的定时器输出来启动它们的工作。而在stm32单片机中,默认情况下,高级定时器的输出是禁用的,需要通过特定的函数来启用它们。通过调用"TIM_CtrlPWMOutputs(TIM8, ENABLE)"这句代码,将定时器TIM8的PWM输出功能使能。这样,定时器TIM8的输出通道将开始产生PWM信号,以控制外部设备的电平或电流。
上面这两个问题就是我在调试过程中遇到的问题以及对应问题可能的原因,希望对大家有帮助!
以下是完整的代码:
#include "timer.h"
#include "servo_lhw.h"
int main(void)
{
//Delay function initialization
//延时函数初始化
delay_init(168);
TIM8_Init(200-1,16800-1);//20ms
while(1)
{
Servo_SetAngle(90,40);
}
}
void TIM8_Init(u16 arr, u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
GPIO_InitTypeDef GPIO_InitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8,ENABLE); //TIM8时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);//使能GPIOC时钟
GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_TIM8); //GPIOC6复用为定时器8(这句话也要加上去)
GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_TIM8); //GPIOC7复用为定时器8(这句话也要加上去)
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_6 |GPIO_Pin_7; //TIM8对应引脚PC6,PC7
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度100MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOC,&GPIO_InitStructure); //初始化PC6,7
/*** Initialize timer 8 || 初始化定时器8 ***/
//Set the counter to automatically reload //设定计数器自动重装值
TIM_TimeBaseStructure.TIM_Period = arr;
//Pre-divider //预分频器
TIM_TimeBaseStructure.TIM_Prescaler = psc;
//Set the clock split: TDTS = Tck_tim //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
//TIM up count mode //TIM向上计数模式
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
//Initializes the timebase unit for TIMX based on the parameter specified in TIM_TimeBaseInitStruct
//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;/*PWM模式*/
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;/*输出*/
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;/*比较极性高*/
TIM_OCInitStructure.TIM_Pulse = 0; //CCR
TIM_OC1Init(TIM8,&TIM_OCInitStructure);
TIM_OC2Init(TIM8,&TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM8,TIM_OCPreload_Enable);/*输出比较预装载使能*/
TIM_OC2PreloadConfig(TIM8,TIM_OCPreload_Enable);/*输出比较预装载使能*/
// Advanced timer output must be enabled
TIM_ARRPreloadConfig(TIM8,ENABLE);/*自动重载预装载使能*/
TIM_CtrlPWMOutputs(TIM8,ENABLE);//高级定时器输出必须使能这句
//Enable timer //使能定时器
TIM_Cmd(TIM8, ENABLE);
}
#include "servo_lhw.h"
/*
周期为20ms
0.5ms——-90°
1 ms——-45°
1.5ms—— -0°
2 ms—— 45°
2.5ms—— 90°
当定时器周期为20ms时
arr=200 pcs=16800
TIM8_Init(200,16800);//5ms
高电平时间 t=(crr/arr)*20ms
当ccr为10时对应的高电平为1ms
servo_angle=90/10*crr-135 ==>crr=(servo_angle+135)/9
*/
void servo_angle(int yaw_angle,int pitch_angle)
{
int ccr;
if(yaw_angle>90) yaw_angle=90;
else if(yaw_angle<-90) yaw_angle=-90;
if(pitch_angle>90) pitch_angle=90;
else if(pitch_angle<-90) pitch_angle=-90;
TIM8->CCR1=(yaw_angle+135)/9; //(这个安装刚刚好)
TIM8->CCR2=(pitch_angle+135-50)/9;//(-50)是为了矫正安装误差
}
/*
周期为20ms
0.5ms—— 0°
1 ms——45°
1.5ms——90°
2 ms——135°
2.5ms——180°
当定时器周期为20ms时
arr=200 pcs=16800
TIM8_Init(200,16800);//5ms
高电平时间 t=(crr/arr)*20ms
当ccr为10时对应的高电平为1ms
servo_angle=90/10*crr-135 ==>crr=(servo_angle+135)/9
完全正:Servo_SetAngle(90,40); (因为是刚刚接触,所以没有找到正确的脚度就可以安装,所以存在误差)
pitch_angle越小,越往下(但好像不只是180°)
yaw_angle越小,从上往下看顺时针
*/
void Servo_SetAngle(float yaw_angle,float pitch_angle)
{
if(yaw_angle>180) yaw_angle=180;
else if(yaw_angle<0) yaw_angle=0;
if(pitch_angle>180) pitch_angle=180;
else if(pitch_angle<0) pitch_angle=0;
TIM_SetCompare1(TIM8, (yaw_angle * 20/ 180 + 5));
TIM_SetCompare2(TIM8, (pitch_angle * 20/ 180 + 5));
}
附带stm32引脚图