目录
1、51定时器控制单个舵机
2、51定时器控制多路舵机
3、stm32控制舵机
4、pca9685驱动模块
舵机的控制一般需要一个20ms左右的时基脉冲,该脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分,总间隔为2ms,比如说180度伺服角度,对应的关系如下。
void main(void)
{
InitTimer0(); //定时器0初始化
EA = 1; //开总中断
while(1) //大循环
{
Servo0PwmDuty = 500; //脉冲宽度在500微秒,对应-90°
DelayMs(1000); //延时1秒
Servo0PwmDuty = 1000; //脉冲宽度在1000微秒,对应-45°
DelayMs(1000);
Servo0PwmDuty = 1500;
DelayMs(1000);
Servo0PwmDuty = 2000;
DelayMs(1000);
Servo0PwmDuty = 2500;
DelayMs(1000);
}
}
void main(void)
{
uint8 i;
InitTimer0(); //定时器0初始化
EA = 1; //开总中断
while(1) //大循环
{
for(i = 0;i<8;i++)
ServoPwmDuty[i] = 500; //脉冲宽度在500微秒,对应-90°
DelayMs(1000); //延时1秒
for(i = 0;i<8;i++)
ServoPwmDuty[i] = 1000; //脉冲宽度在1000微秒,对应-45°
DelayMs(1000);
for(i = 0;i<8;i++)
ServoPwmDuty[i] = 1500; //脉冲宽度在1500微秒,对应0°
DelayMs(1000); //延时1秒
for(i = 0;i<8;i++)
ServoPwmDuty[i] = 2000; //脉冲宽度在2000微秒,对应45°
DelayMs(1000);
for(i = 0;i<8;i++)
ServoPwmDuty[i] = 2500; //脉冲宽度在2500微秒,对应90°
DelayMs(1000); //延时1秒
}
}
PWM就是脉冲宽度调制,也就是占空比可变的脉冲波形.
pwm的占空比,就是指高电平保持的时间,与该pwm时钟周期时间之比。
在应用中就是通过调节pwm占空比来控制,也就是一个周期中高电平所占的百分比来控制舵机的转角的。
在代码中要特别注意的是时基结构体的TIM_Period(自动重装载寄存器值,简称arr)和TIM_Prescaler(预分频寄存器值,简称psc),因为这两个决定了输出PWM信号的周期。具体的周期计算公式为:周期=(arr+1)*(psc+1)/CLK。其中CLK为计数器的时钟频率,我的是72MHZ,也就是72000000。最后计算结果单位为秒,结果为0.02s,也就是20ms。这样的配置就是为了让输出的PWM信号达到前面说到的舵机要求的20ms周期。
int main(void)
{
int delay_time;
delay_init(); //延时函数初始化
TIM_Init(); //定时器初始化
while(1)
{
delay_ms(1000);
TIM_SetCompare1(TIM1, 175); //对应180度
delay_ms(1000);
TIM_SetCompare1(TIM1, 180); //对应135度
delay_ms(1000);
TIM_SetCompare1(TIM1, 185); //对应90度
delay_ms(1000);
TIM_SetCompare1(TIM1, 190); //对应45度
delay_ms(1000);
TIM_SetCompare1(TIM1, 195); //对应0度
}
}
stm32驱动程序:
#include "pca9685.h"
#include "myiic.h"
#include "delay.h"
#include "math.h"
void pca_write(u8 adrr,u8 data)
{
IIC_Start();
IIC_Send_Byte(pca_adrr);
IIC_Wait_Ack();
IIC_Send_Byte(adrr);
IIC_Wait_Ack();
IIC_Send_Byte(data);
IIC_Wait_Ack();
IIC_Stop();
}
u8 pca_read(u8 adrr)
{
u8 data;
IIC_Start();
IIC_Send_Byte(pca_adrr);
IIC_Wait_Ack();
IIC_Send_Byte(adrr);
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(pca_adrr|0x01);
IIC_Wait_Ack();
data=IIC_Read_Byte(0);
IIC_Stop();
return data;
}
void pca_setfreq(float freq)
{
u8 prescale,oldmode,newmode;
double prescaleval;
freq *= 0.92;
prescaleval = 25000000;
prescaleval /= 4096;
prescaleval /= freq;
prescaleval -= 1;
prescale =floor(prescaleval + 0.5f);
oldmode = pca_read(pca_mode1);
newmode = (oldmode&0x7F) | 0x10; // sleep
pca_write(pca_mode1, newmode); // go to sleep
pca_write(pca_pre, prescale); // set the prescaler
pca_write(pca_mode1, oldmode);
delay_ms(2);
pca_write(pca_mode1, oldmode | 0xa1);
}
void pca_setpwm(u8 num, u32 on, u32 off)
{
pca_write(LED0_ON_L+4*num,on);
pca_write(LED0_ON_H+4*num,on>>8);
pca_write(LED0_OFF_L+4*num,off);
pca_write(LED0_OFF_H+4*num,off>>8);
}
void Servo_Init(float hz,u8 angle)
{
u32 off=0;
IIC_Init();
pca_write(pca_mode1,0x0);
pca_setfreq(hz);
off=(u32)(145+angle*2.4);
pca_setpwm(0,0,off);
pca_setpwm(1,0,off);
pca_setpwm(2,0,off);
pca_setpwm(3,0,off);
pca_setpwm(4,0,off);
pca_setpwm(5,0,off);
pca_setpwm(6,0,off);
pca_setpwm(7,0,off);
pca_setpwm(8,0,off);
pca_setpwm(9,0,off);
pca_setpwm(10,0,off);
pca_setpwm(11,0,off);
pca_setpwm(12,0,off);
pca_setpwm(13,0,off);
pca_setpwm(14,0,off);
pca_setpwm(15,0,off);
delay_ms(500);
}
void Servo_angle(u8 num,u8 angle)
{
u32 off = 0;
off = (u32)(158+angle*2.2);
pca_setpwm(num,0,off);
}
stm32主函数:
int main(void)
{
delay_init();//延时函数初始化
Servo_Init(50,90);//初始化舵机驱动
delay_ms(1000);
uart_init(9600);
Servo_angle(0,90);
printf("this is a drill");
}