赞
踩
首先,本人希望舵机平稳控制,可以任意操控角度,并且速度可调。但网上的资料一般都是对舵机0°、45°、90°、135°、180°控制。于是我想自己是否可以写一个驱动舵机的代码。
stm32,我是刚接触没多久,对代码编写还是处于学习。但自己接触过51单片机和arduino。在去年暑假我自己买了arduino mage2560开发板,打算学习“太极创客”的mearm,了解舵机的控制(舵机速度和方向控制),但我只局限于调用里面的 <Servo.h> 库。后来查询资料,自己编写了51舵机的驱动代码。
t = 0.5ms——————-舵机会转到 0 °
t = 1.0ms——————-舵机会转到 45°
t = 1.5ms——————-舵机会转到 90°
t = 2.0ms——————-舵机会转到 135°
t = 2.5ms——————-舵机会转到 180°
由图像可知,舵机的旋转角度与频率无关,角度的小与PWM波高电平持续的时间有关
所以为了控制舵机,我们可以改变高电平持续的时间
1. 初始化定时器(100us产生一次中断), 利用定时器产生一个PWM波
2. 0°、45°、90°、135°、180°对应着0.5ms、1ms、1.5ms、2ms、2.5ms
因此,我们定义一个Count变量,中断一次Count+1;再定义一个变量Time,用来和Count比较
具体怎么实现,可以参考江科大51单片机直流电机驱动https://www.bilibili.com/video/BV1Mb411e7re?p=33
通过配置定时器2产生一个PWM波
Servos_Init(2000,720);
周期Period=2000;频率Prescaler:720
利用TIM_SetCompare1();来改变PWM高电平的持续时间,从未改变舵机旋转方向
0°、45°、90°、135°、180° 对应函数Angle_config(uint16_t Angle,uint16_t Speed)的值分别为
1950 1900 1850 1800 1750
寻找关系,我们得出他们为二元一次函数 Angle= 1950-(int)(舵机旋转的角度值*10/9);
Now_Angle = 1950-(int)((Angle/9)*10);
if(Now_Angle<Old_Angle) //通过比较前角度和后角度,判断是正传还是逆转
{ //向左转,
for(i=Old_Angle;i>=Now_Angle;i--)
{
TIM_SetCompare1(TIM2,i);
delay_ms(Speed);
}
}
Old_Angle = Now_Angle;//对前一个角度进行存储,然后计较
- #include <REGX52.H>
- #include <intrins.H>
-
- sbit ServoPin= P2^7;
-
- unsigned char Time;
- unsigned int Count;//计数值
-
- void Timer0Init() //100微秒@11.0592MHz
- {
- TMOD &= 0xF0; //设置定时器模式
- TMOD |= 0x01; //设置定时器模式
- TL0 = 0xA4; //设置定时初始值
- TH0 = 0xFF; //设置定时初始值
- TF0 = 0; //清除TF0标志
- TR0 = 1; //定时器0开始计时
- ET0=1;
- EA=1;
- }
-
- void Servo_Proc(unsigned char Angle)//舵机角度控制
- {
- Count=0;//每次调用,都对Count初始化
- switch(Angle)
- {
- case 0:Time=5;break;
- case 45:Time=10;break;
- case 90:Time=15;break;
- case 135:Time=20;break;
- case 180:Time=25;break;
- }
- }
- void Delay(unsigned int xms)//1ms的延时函数
- {
- unsigned char i, j;
- while(xms--)
- {
- i = 2;
- j = 239;
- do
- {
- while (--j);
- } while (--i);
- }
- }
-
-
- void main()
- {
- Timer0Init();//定时器0初始化
- ServoPin=0;//引脚初始化
- while(1)
- {
- Servo_Proc(0);
- Delay(500);
- Servo_Proc(45);
- Delay(500);
- Servo_Proc(90);
- Delay(500);
- Servo_Proc(135);
- Delay(500);
- Servo_Proc(180);
- Delay(500);
- }
- }
- void Timer0_Routine() interrupt 1 //从装载值100us
- {
- TL0 = 0xA4; //设置定时初始值
- TH0 = 0xFF; //设置定时初始值
- if(Time>Count){ServoPin=1;}//PWM波的占空比
- else{ServoPin=0;}
- Count++;
- Count%=200;
- }

- #include "Delay.h"
- #include "LED.h"
- #include "Time3.h"
- #include "Servos.h"
- int main(void)
- {
- u8 i;
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
- Servos_Init(2000,720);//周期20ms频率10KHz
- delay_init();
- Servos_Angle_Init(180);
- while(1)
- {
- for(i=180;i>0;i--)
- {
- Servos_Turn_Angle(i,20);
- }
-
- for(i=0;i<180;i++)
- {
- Servos_Turn_Angle(i,20);
- }
- }
- }

- #include "stm32f10x.h" // Device header
- #include "Servos.h"
- #include "delay.h"
-
- //变量声明区
- uint16_t temp;
- u8 Start_Stop=1;
- u8 flag,flag1;
- uint16_t Now_Angle,Old_Angle;//前一个角度值和后一个角度值
- //子函数
- /**
- Tout= ((arr+1)*(psc+1))/Tclk;
- Tclk: TIM3 的输入时钟频率(单位为 Mhz)。72Mhz
- Tout: TIM3 溢出时间(单位为 ms)
- Period : 自动重装值。
- Prescaler : 时钟预分频数
- **/
- /**
- * @brief 舵机IO初始化
- * @param Period:自动重装值。
- * @param Prescaler:时钟预分频数
- * @retval 无
- */
- void Servos_Init(u16 Period,u16 Prescaler)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
- TIM_OCInitTypeDef TIM_OCInitStructure;
-
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE);//打开GPIOB时钟/AFIO时钟
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//打开定时器时钟
-
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//PA0初始化/复用推挽输出
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOA,&GPIO_InitStructure);
-
- TIM_TimeBaseStructure.TIM_Period = Period - 1;//自动重装载寄存器周期的值
- TIM_TimeBaseStructure.TIM_Prescaler = Prescaler - 1;//TIMx 时钟频率除数的预分频值
- TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//设置了时钟分割
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//计数器模式
- TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
-
- TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;//PWM模式2
- TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//使能PWM输出
- TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//有效为高电平
- TIM_OC1Init(TIM2,&TIM_OCInitStructure);
-
- TIM_OC1PreloadConfig(TIM2,TIM_OCPreload_Enable);//使能TIM3在CCR2上的预装载寄存器
- TIM_ARRPreloadConfig(TIM2,ENABLE);//开启自动预装载寄存器
- TIM_Cmd(TIM2,ENABLE);
- }
-
- /** 角度 计数值
- X Y
- t = 0.5ms——————-舵机会转到 0 ° 1950
- t = 1.0ms——————-舵机会转到 45° 1900
- t = 1.5ms——————-舵机会转到 90° 1850
- t = 2.0ms——————-舵机会转到 135° 1800
- t = 2.5ms——————-舵机会转到 180° 1750
- **/
- /**
- * @brief Servos角度初始化
- * @param Angle:角度值
- * @retval 无
- */
- void Servos_Angle_Init(uint16_t Angle)//周期位20ms,不管频率如何
- { //只要确保角度固定的高电平时间一致
- temp = 1950-(int)(Angle*10/9); //设角度为“x”计数值为“y”列y=kx+b
- TIM_SetCompare1(TIM2,temp); //k=-10/9 b=1950
- delay_ms(500);
- }
-
- /**
- * @brief 把舵机角度初始化数据传到后面函数
- * @param 无
- * @retval temp
- */
- uint16_t return_Angle()
- {
- return temp;
- }
-
- /**
- * @brief 舵机旋转方向和速度
- * @param Angle :角度
- * @param Speed :速度
- * @retval 无
- */
- void Servos_Turn_Angle(uint16_t Angle,uint16_t Speed)
- {
- uint16_t i;
- if(flag==0){Old_Angle = return_Angle();flag=1;}//void Servos_Angle_Init(u8 Angle)
- if(Start_Stop) //争对获取舵机初始化是的值,只操作一次
- {
- Now_Angle = 1950-(int)((Angle/9)*10);
- if(Now_Angle<Old_Angle) //通过比较前角度和后角度,判断是正传还是逆转
- { //向左转,
- for(i=Old_Angle;i>=Now_Angle;i--)
- {
- TIM_SetCompare1(TIM2,i);
- delay_ms(Speed);
- }
- }
- if(Now_Angle>Old_Angle) //向右转
- {
- for(i=Old_Angle;i<=Now_Angle;i++)
- {
- TIM_SetCompare1(TIM2,i);
- delay_ms(Speed);
- }
- }
- Old_Angle = Now_Angle;//对前一个角度进行存储,然后计较
- }
- }
-
- /**
- * @brief 舵机旋转方向和速度,和 Servos_Turn_Angle(uint16_t Angle,uint16_t Speed)功能一样
- * @param Angle :角度
- * @param Speed :速度
- * @retval 无
- */
- void Angle_config(uint16_t Angle,uint16_t Speed)
- {
- Servos_Turn_Angle(Angle,Speed);
- }
- /**
- * @brief 启动舵机运行,一般用于舵机停转后启动
- * @param 无
- * @retval 无
- */
- void Start_Servos(void)
- {
- Start_Stop = 1;
- }
-
- /**
- * @brief 停止舵机运行,一般用于舵机旋转结束停止
- * @param 无
- * @retval 无
- */
- void Stop_Servos(void)
- {
- Start_Stop = 0;
- }

- #ifndef __Servos_H
- #define __Servos_H
- #include "sys.h"
- void Servos_Init(u16 Period,u16 Prescaler);//初始化IO、定时器
- void Servos_Angle_Init(uint16_t Angle);//初始化舵机初始位置
- void Servos_Turn_Angle(uint16_t Angle,uint16_t Speed);
-
- //用户操作层
- void Start_Servos(void);//开启舵机
- void Stop_Servos(void);//停止舵机
- void Angle_config(uint16_t Angle,uint16_t Speed);//舵机控制
- #endif
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。