#51单片机#如何用摇杆丝滑驱动舵机

基于51单片机,如何用摇杆更加丝滑地控制舵机。自己写的,用摇杆控制舵机有明显的延迟,想请教一下代码还可以有哪些优化的?想要的:摇杆的角度越大,舵机旋转的角度也越大。摇杆归位,舵机也归位。

有两个51单片机,二者串口通信,摇杆用了一个AD转换模块以后想做一个四足机器人

//接收机,用于驱动舵机
#include "reg52.h"

//控制8个舵机
sbit PWM0=P1^0;
sbit PWM1=P1^1;
sbit PWM2=P1^2;
sbit PWM3=P1^3;
sbit PWM4=P1^4;
sbit PWM5=P1^5;
sbit PWM6=P1^6;
sbit PWM7=P1^7;

int jishu_max=200,jishu_min=0,jishu=0,PWM0_H,PWM1_H,PWM2_H,PWM3_H,PWM4_H,PWM5_H,PWM6_H,PWM7_H;
int gaibian=0;
//static int time=0;//当前是否为空闲时间
char da[10];//接收串口数据
int i=0,temp;//temp 中间值,i 记录接收字符个数
void tim() interrupt 1
{
    jishu=jishu+1;
    if(jishu<26)
    {
        if(jishu==PWM0_H)
        {
            PWM0=0;
        }
        if(jishu==PWM1_H)
        {
            PWM1=0;
        }
        if(jishu==PWM2_H)
        {
            PWM2=0;
        }
        if(jishu==PWM3_H)
        {
            PWM3=0;
        }
        if(jishu==PWM4_H)
        {
            PWM4=0;
        }
        if(jishu==PWM5_H)
        {
            PWM5=0;
        }
        if(jishu==PWM6_H)
        {
            PWM6=0;
        }
        if(jishu==PWM7_H)
        {
            PWM7=0;
        }
        
    }
    else
    {
        if(jishu==jishu_max)//到了20ms
        {
//            time=0;
            jishu=0;
            PWM0=1;
            PWM1=1;
            PWM2=1;
            PWM3=1;
            PWM4=1;
            PWM5=1;
            PWM6=1;
            PWM7=1;
            
        }
//        else
//        {
//            time=1;
//        }
    }
}
void InitTimer0(void)
{
    TMOD = 0x22;
    TH0 = 0x0A4;
    TL0 = 0x0A4;
    EA = 1;
    ET0 = 1;
    TR0 = 1;
}


void InitUART(void)
{
    SCON = 0x50;
    TH1 = 0xFA;
    TL1 = TH1;
    PCON = 0x80;
    ES=1;
    IP=0x02;
    TR1 = 1;
}

void SendOneByte(unsigned char c)//串口发送单个字符
{
    SBUF = c;
    while(!TI);
    TI = 0;
}

//接收格式a05~a25
void UARTInterrupt(void) interrupt 4
{
    if((RI==1) && (jishu>26) &&(jishu<196))//jishu在26196范围内,代表为空闲时间
    {
        
//        time=0;//        每个周期的空闲时间里只允许改变1次PWM值    
        RI = 0;
        da[i]=SBUF;
        i=i+1;
        if((da[0]=='a')|| (da[0]=='b')||(da[0]=='c')||(da[0]=='d')|| (da[0]=='e')||(da[0]=='f')||(da[0]=='g')|| (da[0]=='h'))//a,b,c....分别对应舵机
        {    
            gaibian=1;    //收到的字符串收个字符符合,准备改变pwm_h的值
            if((gaibian==1) && (i==2))
            {
                gaibian=0;
                temp=da[1]/1;
                i=0;
                if((temp<=25) &&(temp>=5))
                {
                    switch(da[0])
                    {
                        case 'a':PWM0_H=temp;break;
                        case 'b':PWM1_H=temp;break;
                        case 'c':PWM2_H=temp;break;
                        case 'd':PWM3_H=temp;break;
                        case 'e':PWM4_H=temp;break;
                        case 'f':PWM5_H=temp;break;
                        case 'g':PWM6_H=temp;break;
                        case 'h':PWM7_H=temp;break;
                    }
                }

            }
        }
        else
        {
            gaibian=0;
            i=0;
        }
        
    }
    else
    {
        RI=0;
        i=0;
        TI = 0;
    }
    
}
int main()
{
//    time=0;
    P1=1;
    InitTimer0();//定时器初始化,每100us溢出
    InitUART();//串口初始化
    PWM0_H=25;//5~25 修改这,高电平持续的时间:t=PWM_H*100 (单位:us)
    PWM1_H=25;//5~25 修改这
    PWM2_H=25;//5~25 修改这
    PWM3_H=25;//5~25 修改这
    PWM4_H=25;//5~25 修改这
    PWM5_H=25;//5~25 修改这
    PWM6_H=25;//5~25 修改这
    PWM7_H=25;//5~25 修改这
    while(1);

}


发送机,用于连接摇杆,并发送角度信号


#include<reg52.h>    //包含单片机寄存器的头文件
#include <I2C.H>

#define uchar unsigned char
#define  PCF8591 0x90    //PCF8591 地址



// 变量定义
unsigned char AD_CHANNEL;
unsigned long xdata  LedOut[8];
unsigned int  D[32];
sbit P2_0 = P2^0;
sbit P2_1 = P2^1;
sbit P2_2 = P2^2;
sbit P2_3 = P2^3;
unsigned char date;

uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,
                        0xf8,0x80,0x90};


  // 函数申明 

void display();
void delay(uchar i);
bit DACconversion(unsigned char sla,unsigned char c,  unsigned char Val);
bit ISendByte(unsigned char sla,unsigned char c);
unsigned char IRcvByte(unsigned char sla);
void Initial_com(void);
int zhuanhuan(float g)
{
    float hh;
    hh=g/1;
    return hh;
}
//******************************************************************/
main()
{  

    Initial_com();
    while(1)
    {

    /********以下AD-DA处理*************/  
    
        switch(AD_CHANNEL)
        {
            case 0: ISendByte(PCF8591,0x41);
                 D[0]=IRcvByte(PCF8591);  //ADC0 模数转换1      光敏电阻
                 break;  
            
            case 1: ISendByte(PCF8591,0x42);
                 D[1]=IRcvByte(PCF8591);  //ADC1  模数转换2      热敏电阻
                 break;  
            
            case 2: ISendByte(PCF8591,0x43);
                 D[2]=IRcvByte(PCF8591);  //ADC2    模数转换3       悬空
                 break;  
            
            case 3: ISendByte(PCF8591,0x40);
                 D[3]=IRcvByte(PCF8591);  //ADC3   模数转换4       可调0-5v
                 break;  
            
            case 4: DACconversion(PCF8591,0x40, D[4]); //DAC      数模转换
                 break;
         
        }

//        D[4]=D[3];  //把模拟输入采样的信号 通过数模转换输出
            
       if(++AD_CHANNEL>4) AD_CHANNEL=0;
    
       /********以下将AD的值通过串口发送出去*************/

    SBUF='a';
    SBUF=(D[0]/12.5+5)/1;

    
    while(!TI);
    TI=0;
    delay(100);
     if(RI)
    {
//        date=SBUF;    //单片机接受
//        SBUF=date;    //单片机发送
        RI=0;
    }     
   }
}


void delay(uchar i)
{
  uchar j,k; 
  for(j=i;j>0;j--)
    for(k=125;k>0;k--);
}

/*******************************************************************
DAC 变换, 转化函数               
*******************************************************************/
bit DACconversion(unsigned char sla,unsigned char c,  unsigned char Val)
{
   Start_I2c();              //启动总线
   SendByte(sla);            //发送器件地址
   if(ack==0)return(0);
   SendByte(c);              //发送控制字节
   if(ack==0)return(0);
   SendByte(Val);            //发送DAC的数值  
   if(ack==0)return(0);
   Stop_I2c();               //结束总线
   return(1);
}

/*******************************************************************
ADC发送字节[命令]数据函数               
*******************************************************************/
bit ISendByte(unsigned char sla,unsigned char c)
{
   Start_I2c();              //启动总线
   SendByte(sla);            //发送器件地址
   if(ack==0)return(0);
   SendByte(c);              //发送数据
   if(ack==0)return(0);
   Stop_I2c();               //结束总线
   return(1);
}

/*******************************************************************
ADC读字节数据函数               
*******************************************************************/
unsigned char IRcvByte(unsigned char sla)
{  unsigned char c;

   Start_I2c();          //启动总线
   SendByte(sla+1);      //发送器件地址
   if(ack==0)return(0);
   c=RcvByte();          //读取数据0

   Ack_I2c(1);           //发送非就答位
   Stop_I2c();           //结束总线
   return(c);
}


//*****串口初始化函数***********

//******************************
void Initial_com(void)
{
 EA=1;        //开总中断
 ES=1;        //允许串口中断
 ET1=1;        //允许定时器T1的中断
 TMOD=0x20;   //定时器T1,在方式2中断产生波特率
 PCON=0x00;   //SMOD=0
 SCON=0x50;   // 方式1 由定时器控制
 TH1=0xfd;    //波特率设置为9600
 TL1=0xfd;
 TR1=1;       //开定时器T1运行控制位

}


可以控制,就是延迟大
驱动舵机的思路,定时器0每100us中断一次,总共计数200次,即20ms。定时器0的优先级比串口高,防止一个周期不完整。串口接收数据主要在20ms一个周期的2.5ms后才能接收。
求问还有哪些能优化的,减少延迟
不知道你这个问题是否已经解决, 如果还没有解决的话:

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^