找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1690|回复: 5
打印 上一主题 下一主题
收起左侧

关于单片机舵机控制

[复制链接]
跳转到指定楼层
楼主
ID:900557 发表于 2021-4-27 12:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
用51单片机控制两个舵机,设置按钮控制舵机转动角度,4个按钮,一个控制转到-90,一个转到0,第三个控制一个舵机逆时针转一个小角度一个舵机顺时针转动一个小角度,最后一个和第三个相反,为什么第三个和第四个顺时针转动的舵机转到90度之后就没办法在增加角度了,我改了下程序发现舵机是可以转到正90的,外部电源共地也用上了,希望得到解决。
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:883167 发表于 2021-4-27 13:13 | 只看该作者
这个没有看到具体程序,也不好判断,最好分段注释掉,每一步在里面调试,看出在哪个代码上有问题!

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

板凳
ID:900557 发表于 2021-4-27 13:30 | 只看该作者
林大侠 发表于 2021-4-27 13:13
这个没有看到具体程序,也不好判断,最好分段注释掉,每一步在里面调试,看出在哪个代码上有问题!

这是具体程序
#include "reg51.h"

#define uint8        unsigned char    //无符号字符型
#define uint16        unsigned short int
#define uint32        unsigned long

sbit SERVO0=P3^6;                        //控制舵机的PWM输出口
sbit SERVO1=P3^5;
sbit kaishi=P1^1;
sbit jieshu=P1^2;
sbit jiare=P3^3;
sbit jianre=P3^4;

uint16 Servo0PwmDuty0=1500;        //PWM脉冲宽度   1.5ms脉冲宽度
uint16 Servo0PwmDuty1=1500;
/***********************************************************
* 名    称: DelayMs(uint16 ms)
* 功    能: 延时ms毫秒
* 入口参数: ms        毫秒
* 出口参数: 无
* 说    明:                                          
/**********************************************************/
void DelayMs(uint16 ms)
{
        uint16 i,j;
        for(i=0;i<85;i++)                //89单片机用85,12系列单片机用800
                for(j=0;j<ms;j++);
}
/***********************************************************
* 名    称:InitTimer0()
* 功    能:时钟0初始化
* 入口参数:无
* 出口参数:无
* 说    明:12M晶振,12分频,所以计数器每递增一个数就是1微秒,完全满足舵机控制的精度要求
                        因为定时器是TH0,TL0都要全部计数到0xFF后在计1个数就会产生中断,所以要想产生
                        x毫秒的中断,那么TH0,TL0就应该赋值(0xFFFF-x)        从这个值开始计数产生定时中断                                         
/**********************************************************/
void InitTimer0(void)
{

        TMOD = 0x11;                //设置定时器模式
        TL0 = 0x00;                        //设置定时初值
        TH0 = 0x00;                        //设置定时初值
        TF0 = 0;                        //清除TF0标志
        TR0 = 1;                        //定时器0开始计时
        ET0 = 1;
        TL1 = 0x00;                        //设置定时初值
        TH1 = 0x00;                        //设置定时初值
        TF1 = 0;                        //清除TF0标志
        TR1 = 1;                        //定时器0开始计时
        ET1 = 1;                        //开定时器0中断
}
/***********************************************************
* 名    称:Timer0Value(uint16 pwm)  
* 功    能:给定时器0计数器赋值产生定时中断
* 入口参数:pwm                控制舵机的PWM脉冲宽度值(范围:500~2500)
* 出口参数:无
* 说    明:12M晶振,12分频,所以计数器每递增一个数就是1微秒,完全满足舵机控制的精度要求
                        因为定时器是TH0,TL0都要全部计数到0xFF后在计1个数就会产生中断,所以要想产生
                        pwm毫秒的中断,那么TH0,TL0就应该赋值(0xFFFF-pwm)        从这个值开始计数产生定时中断                                          
/**********************************************************/
void Timer0Value(uint16 pwm)
{
        uint16 value;
        value=0xffff-pwm;       
        TR0 = 0;
        TL0=value;                        //16位数据给8位数据赋值默认将16位数据的低八位直接赋给八位数据
    TH0=value>>8;                //将16位数据右移8位,也就是将高8位移到低八位,再赋值给8位数据       
        TR0 = 1;
}

void Timer1Value(uint16 pwm)
{
        uint16 value;
        value=0xffff-pwm;       
        TR1 = 0;
        TL1=value;                        //16位数据给8位数据赋值默认将16位数据的低八位直接赋给八位数据
    TH1=value>>8;                //将16位数据右移8位,也就是将高8位移到低八位,再赋值给8位数据       
        TR1 = 1;
}
/***********************************************************
* 名    称: main()
* 功    能: 入口函数
* 入口参数: 无
* 出口参数: 无
* 说    明:                                          
/**********************************************************/
void main(void)
{

        InitTimer0();        //定时器0初始化
        EA = 1;                        //开总中断
        while(1)                //大循环
        {       
                if(kaishi==0)
                {
                  Servo0PwmDuty0 = 1500;Servo0PwmDuty1 = 1500;
                  DelayMs(1000);
                }
                if(jieshu==0)
                {
                  Servo0PwmDuty0 = 500;Servo0PwmDuty1 = 500;
                  DelayMs(1000);
                }
                if(jiare==0)
                {
                  Servo0PwmDuty0=Servo0PwmDuty0+100;Servo0PwmDuty1=Servo0PwmDuty1-100;
                  DelayMs(1000);
                  if(Servo0PwmDuty0>=2500){Servo0PwmDuty0=2500;}
                  if(Servo0PwmDuty1<=500){Servo0PwmDuty1=500;}
                }
                if(jianre==0)
                {
                  Servo0PwmDuty0=Servo0PwmDuty0-100;Servo0PwmDuty1=Servo0PwmDuty1+100;
                  DelayMs(1000);
                  if(Servo0PwmDuty1>=2500){Servo0PwmDuty1=2500;}
                  if(Servo0PwmDuty0<=500){Servo0PwmDuty0=500;}
                }

        }
}


void Timer_0(void) interrupt 1 using 1
{
        static uint16 i = 1;        //静态变量:每次调用函数时保持上一次所赋的值,
                                                        //跟全局变量类似,不同是它只能用于此函数内部
        switch(i)
        {
                case 1:
                        SERVO0 = 1;        //PWM控制脚高电平
                        //给定时器0赋值,计数Pwm0Duty个脉冲后产生中断,下次中断会进入下一个case语句
                        Timer0Value(Servo0PwmDuty0);       
                        break;
                case 2:
                        SERVO0 = 0;        //PWM控制脚低电平
                        //高脉冲结束后剩下的时间(20000-Pwm0Duty)全是低电平了,Pwm0Duty + (20000-Pwm0Duty) = 20000个脉冲正好为一个周期20毫秒
                        Timer0Value(20000-Servo0PwmDuty0);
                        i = 0;       
                        break;         
        }
        i++;
}

void Timer_1(void) interrupt 3 using 1
{
        static uint16 j = 1;        //静态变量:每次调用函数时保持上一次所赋的值,
                                                        //跟全局变量类似,不同是它只能用于此函数内部
        switch(j)
        {
                case 1:
                        SERVO1 = 1;        //PWM控制脚高电平
                        //给定时器0赋值,计数Pwm0Duty个脉冲后产生中断,下次中断会进入下一个case语句
                        Timer1Value(Servo0PwmDuty1);       
                        break;
                case 2:
                        SERVO1 = 0;        //PWM控制脚低电平
                        //高脉冲结束后剩下的时间(20000-Pwm0Duty)全是低电平了,Pwm0Duty + (20000-Pwm0Duty) = 20000个脉冲正好为一个周期20毫秒
                        Timer1Value(20000-Servo0PwmDuty1);
                        j = 0;       
                        break;         
        }
        j++;
}
回复

使用道具 举报

地板
ID:516455 发表于 2021-4-27 16:18 | 只看该作者
通过pwm的四个通道可以同时驱动几个舵机,引脚需要自己查芯片手册

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

5#
ID:516455 发表于 2021-4-27 16:18 | 只看该作者
定时器的不同通道就可以驱动不同的舵机,具体引脚需要查看数据手册

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

6#
ID:900557 发表于 2021-4-27 16:44 | 只看该作者
我仿真是可以的,不知道实物为什么不行
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表