舵机控制So easy

本文详细介绍了舵机的工作原理及控制方法,包括信号调制、电机驱动等关键环节,并通过实例展示了如何使用定时器0模拟PWM输出进行精确控制。

难者不会,会者不难。就只看你愿不愿意尝试,硬件的乐趣又何止于此。
硬件于我何加焉?


1.原理

  • 真正了解一个东西和会用一个东西我一直认为那是两个境界。欲达登峰造极的地步,必须究其理那是必须的。
  • 控制信号由接收机的通道进入信号调制芯片,获得直流偏置电压。它内部有一个基准电路,产生周期为20ms,宽度为1.5ms的基准信号,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。最后,电压差的正负输出到电机驱动芯片决定电机的正反转。当电机转速一定时,通过级联减速齿轮带动电位器旋转,使得电压差为0,电机停止转动。

一张动图理解下原理。
原理

2.控制

  • 舵机的控制一般需要一个20ms左右的时基脉冲,该脉冲的高电平部分一般为0.5ms-2.5ms范围内的角度控制脉冲部分,总间隔为2ms。以180度角度伺服为例,那么对应的控制关系是这样的:
    0.5ms————–0度;
    1.0ms————45度;
    1.5ms————90度;
    2.0ms———–135度;
    2.5ms———–180度;

注意:

  • 舵机的输入线共有三条,红色中间,是电源线,一边黑色的是地线,这两根线给舵机提供最基本的能源保证,主要是电机的转动消耗。电源有两种规格,一是4.8V,一是6.0V,分别对应不同的转矩标准,即输出力矩不同,6.0V对应的要大一些,具体看应用条件;另外一根线是控制信号线,Futaba的一般为白色,JR的一般为桔黄色。

本人所用舵机为红色VCC,橙色信号线,棕色GND

上程序:(定时器0模拟PWM输出)

#include <reg52.h>

sbit PWMOUT = P1^0;

unsigned char HighRH = 0;  //高电平重载值的高字节
unsigned char HighRL = 0;  //高电平重载值的低字节
unsigned char LowRH  = 0;  //低电平重载值的高字节
unsigned char LowRL  = 0;  //低电平重载值的低字节

void ConfigPWM(unsigned int fr, unsigned char dc);
void ClosePWM();

void main()
{
    unsigned int i;

    EA = 1;     //开总中断

    while (1)
    {
        ConfigPWM(50, 2);    
        for (i=0; i<40000; i++);
        ClosePWM();
        ConfigPWM(50, 5);   
        for (i=0; i<40000; i++);
        ClosePWM();
        ConfigPWM(50, 7);    
        for (i=0; i<40000; i++);
        ClosePWM();            
        ConfigPWM(50, 10);    
        for (i=0; i<40000; i++);
        ClosePWM();
        ConfigPWM(50, 12);    
        for (i=0; i<40000; i++);
        ClosePWM();
        ConfigPWM(50, 10);    
        for (i=0; i<40000; i++);
        ClosePWM();
        ConfigPWM(50, 7);    
        for (i=0; i<40000; i++);
        ClosePWM();
        ConfigPWM(50, 5);   
        for (i=0; i<40000; i++);
        ClosePWM(); 
    }
}
/* 配置并启动PWM,fr-频率,dc-占空比 */
void ConfigPWM(unsigned int fr, unsigned char dc)
{
    unsigned int  high, low;
    unsigned long tmp;

    tmp  = (11059200/12) / fr;  //计算一个周期所需的计数值
    high = (tmp*dc) / 100;      //计算高电平所需的计数值
    low  = tmp - high;          //计算低电平所需的计数值
    high = 65536 - high + 12;   //计算高电平的重载值并补偿中断延时
    low  = 65536 - low  + 12;   //计算低电平的重载值并补偿中断延时
    HighRH = (unsigned char)(high>>8); //高电平重载值拆分为高低字节
    HighRL = (unsigned char)high;
    LowRH  = (unsigned char)(low>>8);  //低电平重载值拆分为高低字节
    LowRL  = (unsigned char)low;
    TMOD &= 0xF0;   //清零T0的控制位
    TMOD |= 0x01;   //配置T0为模式1
    TH0 = HighRH;   //加载T0重载值
    TL0 = HighRL;
    ET0 = 1;        //使能T0中断
    TR0 = 1;        //启动T0
    PWMOUT = 1;     //输出高电平
}
/* 关闭PWM */
void ClosePWM()
{
    TR0 = 0;     //停止定时器
    ET0 = 0;     //禁止中断
    PWMOUT = 1;  //输出高电平
}
/* T0中断服务函数,产生PWM输出 */
void InterruptTimer0() interrupt 1
{
    if (PWMOUT == 1)  //当前输出为高电平时,装载低电平值并输出低电平
    {
        TH0 = LowRH;
        TL0 = LowRL;
        PWMOUT = 0;
    }
    else              //当前输出为低电平时,装载高电平值并输出高电平
    {
        TH0 = HighRH;
        TL0 = HighRL;
        PWMOUT = 1;
    }
}

下面演示利用PCA模块的PWM控制舵机

注意:由于舵机硬件的要求,要想转的精度准确,首先得确保频率务必准确,如何确定频率呢?利用系统时钟分频的方法肯定是不行了。可以这样搞,利用定时器0的溢出脉冲率,来产生自己想要的脉冲。
下面这个程序演示的是右转90度的程序

#include "STC12.H"       // 包含 "STC15W4K.H"寄存器定义头文件   
void initPCA()  
{
    // 初始化定时器T0为16位自动重装方式,其溢出脉冲作PCA计数器的时钟源
    TMOD=0x01;     // 设置T0为16位装载方式
    TH0=0xff;      // 定时时间78.125uS 决定了频率为50hz对应20ms
    TL0=0xb8;       
    TR0=1;         // 启动定时器0
      ET0=1; 
    // 初始化PCA模块1为PWM输出方式
    CMOD=0x84;     // #10000100B ,选择T0为PCA计数器时钟源
    CCAPM1=0x42;   // 设置PCA模块1为8位PWM输出方式。脉冲在P1.4引脚输出,PWM无需中断支持。
    CCAP1H=0xf9;   // 设置脉冲宽度 
    EA=1;          // 开整个单片机所有中断共享的总中断控制位
    CR=1;          // 启动PCA计数器(CH,CL)计数
} 
void main (void)
{
    initPCA();
    while(1);       // 这里可以编写其它程序  
} 
void Timer0()interrupt 1
{
    TH0 = 0xFF;
    TL0 = 0xb8;
}

下面为一圈来回转的演示

#include "STC12.H"          // 包含 "STC15W4K.H"寄存器定义头文件   

void initPCA()  
{
    // 初始化定时器T0为16位自动重装方式,其溢出脉冲作PCA计数器的时钟源
    TMOD=0x01;     // 设置T0为16位装载方式
    TH0=0xFF;      // 定时时间78.125uS 决定了频率为50hz对应20ms
    TL0=0xB8;       
    TR0=1;         // 启动定时器0
    ET0=1; 
    // 初始化PCA模块1为8位PWM输出方式
    CMOD=0x84;     // #10000100B   空闲模式下停止PCA计数器工作
                   // PCA时钟源选择T0溢出信号,禁止PCA计数器溢出时中断
    CCON=0;        // 清零PCA计数器溢出中断请求标志位CF
                   // CR = 0, 不允许 PCA 计数器计数,清零PCA 各模块中断请求标志位CCFn
    CL=0;          // 清零PCA 计数器 
    CH=0;  
    CCAPM1=0x42;   // 设置PCA模块1为8位PWM输出方式。脉冲在P1.4引脚输出,PWM无需中断支持。
    PCA_PWM1=0;                // 清0 PWM 模式下的第9位
    CCAP1H=0xF9;     // 设置脉冲宽度 

    EA=1;          // 开整个单片机所有中断共享的总中断控制位
    CR=1;          // 启动PCA计数器(CH,CL)计数
}

void main (void)
{
    unsigned int i;
    initPCA();
    while(1)             // 等待中断
    {
        CCAP1H=0xF9;     // 设置脉冲宽度-90
        for (i=0; i<40000; i++);
        CCAP1H=0xF3;     // 设置脉冲宽度-45
        for (i=0; i<40000; i++); 
        CCAP1H=0xEC;     // 设置脉冲宽度 0
        for (i=0; i<40000; i++); 
        CCAP1H=0xE6;     // 设置脉冲宽度+45
        for (i=0; i<40000; i++);
        CCAP1H=0xE0;     // 设置脉冲宽度+90
        for (i=0; i<40000; i++);
        CCAP1H=0xE6;     // 设置脉冲宽度+45
        for (i=0; i<40000; i++);
        CCAP1H=0xEC;     // 设置脉冲宽度 0
        for (i=0; i<40000; i++);
        CCAP1H=0xF3;     // 设置脉冲宽度-45
        for (i=0; i<40000; i++);   
    }
} 
void Timer0()interrupt 1
{
    TH0 = 0xFF;
    TL0 = 0xb8;
}

对应关系

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ReCclay

如果觉得不错,不妨请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值